net: aquantia: Detach SMMU during PCI device removal

Enable support for performing SMMU detach during PCI device removal
that is required for converting the driver to a loadable module.

Change-Id: Id5361db7607fa647308ba1eaaa5159cbc0add272
Signed-off-by: Jinesh K. Jayakumar <jineshk@codeaurora.org>
This commit is contained in:
Jinesh K. Jayakumar 2019-08-04 15:05:42 -04:00 committed by Gerrit - the friendly Code Review server
parent cdfc6e8ec4
commit f4dc3ac72e
8 changed files with 139 additions and 111 deletions

View File

@ -29,20 +29,4 @@ config AQFWD
source "drivers/net/ethernet/aquantia/atlantic-fwd/Kconfig"
config AQFWD_QCOM
bool "QTI MSM/MDM target support"
depends on AQFWD
depends on ARCH_QCOM
help
Enable support for integration with Qualcomm Technologies, Inc. chipsets.
config AQFWD_QCOM_IPA
bool "QTI IPA offload support"
depends on IPA_ETH
select AQFWD_QCOM
select ATLFWD_FWD
help
Enable support for Qualcomm Technologies, Inc. IPA (Internet Protocol Accelerator).
If unsure, say N.
endif # NET_VENDOR_AQUANTIA

View File

@ -42,3 +42,24 @@ config ATLFWD_FWD_TXBUF
API enabled, 0 otherwise.
endif
config AQFWD_QCOM
bool "QTI MSM/MDM target support"
depends on AQFWD
depends on ARCH_QCOM
help
Some older targets using Qualcomm Technologies, Inc. chipsets
require peripheral drivers to explicitly set IOMMU attributes
and perform IOMMU attach. Enable this option if your platform
is affected. Using this feature will also require the user to
provide SMMU configuration via PCI device tree.
If unsure, say N.
config AQFWD_QCOM_IPA
bool "QTI IPA offload support"
depends on IPA_ETH
select AQFWD_QCOM
select ATLFWD_FWD
help
Enable support for Qualcomm Technologies, Inc. IPA (Internet Protocol Accelerator).
If unsure, say N.

View File

@ -40,8 +40,6 @@ atlantic-fwd-objs := atl_fw.o \
atlantic-fwd-$(CONFIG_ATLFWD_FWD) += atl_fwd.o
atlantic-fwd-$(CONFIG_OF) += atl_of.o
atlantic-fwd-$(CONFIG_AQFWD_QCOM) += atl_qcom.o
atlantic-fwd-$(CONFIG_AQFWD_QCOM_IPA) += atl_qcom_ipa.o

View File

@ -13,9 +13,7 @@
#include <linux/etherdevice.h>
#include <linux/rtnetlink.h>
#include "atl_qcom_ipa.h"
#include "atl_of.h"
#include "atl_qcom.h"
const char atl_driver_name[] = "atlantic-fwd";
@ -358,10 +356,6 @@ static int atl_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct atl_hw *hw;
int disable_needed;
ret = atl_parse_dt(&pdev->dev);
if (ret)
return ret;
ret = pci_enable_device_mem(pdev);
if (ret)
return ret;
@ -704,9 +698,9 @@ static int __init atl_module_init(void)
return -ENOMEM;
}
ret = atl_qcom_ipa_register(&atl_pci_ops);
ret = atl_qcom_register(&atl_pci_ops);
if (ret) {
pr_err("%s: Failed to register driver with IPA\n",
pr_err("%s: Failed to register driver with platform\n",
atl_driver_name);
destroy_workqueue(atl_wq);
return ret;
@ -714,7 +708,7 @@ static int __init atl_module_init(void)
ret = pci_register_driver(&atl_pci_ops);
if (ret) {
atl_qcom_ipa_unregister(&atl_pci_ops);
atl_qcom_unregister(&atl_pci_ops);
destroy_workqueue(atl_wq);
return ret;
}
@ -727,7 +721,7 @@ static void __exit atl_module_exit(void)
{
pci_unregister_driver(&atl_pci_ops);
atl_qcom_ipa_unregister(&atl_pci_ops);
atl_qcom_unregister(&atl_pci_ops);
if (atl_wq) {
destroy_workqueue(atl_wq);

View File

@ -1,41 +0,0 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/of.h>
#include "atl_qcom.h"
#include "atl_of.h"
static const struct of_device_id aqc_matches[] = {
{ .compatible = "aquantia,aqc-107" },
{ .compatible = "aquantia,aqc-108" },
{ .compatible = "aquantia,aqc-109" },
};
int atl_parse_dt(struct device *dev)
{
if (!dev->of_node) {
dev_dbg(dev, "device tree node is not present\n");
return 0;
}
if (!of_match_node(aqc_matches, dev->of_node)) {
dev_notice(dev, "device tree node is not compatible\n");
return 0;
}
/* Aquantia properties go here */
/* OEM properties go here */
return atl_qcom_parse_dt(dev);
}

View File

@ -1,31 +0,0 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _ATL_OF_H_
#define _ATL_OF_H_
#include <linux/device.h>
#ifdef CONFIG_OF
int atl_parse_dt(struct device *dev);
#else
static inline int atl_parse_dt(struct device *dev)
{
return 0;
}
#endif // CONFIG_OF
#endif // _ATL_OF_H_

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -10,12 +10,18 @@
* GNU General Public License for more details.
*/
#include <linux/of.h>
#include <linux/iommu.h>
#include <asm/dma-iommu.h>
#include <linux/platform_device.h>
#include "atl_qcom_ipa.h"
#include "atl_qcom.h"
static int (*atl_probe_real)(struct pci_dev *, const struct pci_device_id *);
static void (*atl_remove_real)(struct pci_dev *);
static int atl_qcom_parse_smmu_attr(struct device *dev,
struct iommu_domain *domain,
const char *key,
@ -60,7 +66,7 @@ static int atl_qcom_parse_smmu_attrs(struct device *dev,
return rc;
}
static int atl_qcom_parse_smmu(struct device *dev)
static int __atl_qcom_attach_smmu(struct device *dev)
{
int rc;
const char *key;
@ -117,14 +123,110 @@ err_release_mapping:
return rc;
}
int atl_qcom_parse_dt(struct device *dev)
static int atl_qcom_attach_smmu(struct device *dev)
{
int rc = 0;
if (!dev->of_node) {
dev_dbg(dev, "device tree node is not present\n");
return 0;
}
if (of_find_property(dev->of_node, "qcom,smmu", NULL))
rc = atl_qcom_parse_smmu(dev);
rc = __atl_qcom_attach_smmu(dev);
else
dev_dbg(dev, "SMMU config not present in DT\n");
return 0;
}
static void atl_qcom_detach_smmu(struct device *dev)
{
struct dma_iommu_mapping *mapping;
if (!dev->of_node || !of_find_property(dev->of_node, "qcom,smmu", NULL))
return;
mapping = to_dma_iommu_mapping(dev);
if (!mapping)
return;
arm_iommu_detach_device(dev);
arm_iommu_release_mapping(mapping);
}
static int atl_qcom_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int rc;
rc = atl_qcom_attach_smmu(&pdev->dev);
if (rc)
return rc;
rc = atl_probe_real(pdev, id);
if (rc) {
atl_qcom_detach_smmu(&pdev->dev);
return rc;
}
return 0;
}
static void atl_qcom_remove(struct pci_dev *pdev)
{
atl_remove_real(pdev);
atl_qcom_detach_smmu(&pdev->dev);
}
static int __atl_qcom_register(struct pci_driver *pdrv)
{
if (atl_probe_real || atl_remove_real) {
pr_err("%s: Driver already registered\n", __func__);
return -EEXIST;
}
atl_probe_real = pdrv->probe;
pdrv->probe = atl_qcom_probe;
atl_remove_real = pdrv->remove;
pdrv->remove = atl_qcom_remove;
return 0;
}
static void __atl_qcom_unregister(struct pci_driver *pdrv)
{
if (atl_probe_real) {
pdrv->probe = atl_probe_real;
atl_probe_real = NULL;
}
if (atl_remove_real) {
pdrv->remove = atl_remove_real;
atl_remove_real = NULL;
}
}
int atl_qcom_register(struct pci_driver *pdrv)
{
int rc;
rc = __atl_qcom_register(pdrv);
if (rc)
return rc;
rc = atl_qcom_ipa_register(pdrv);
if (rc) {
pr_err("%s: Failed to register driver with IPA\n", __func__);
__atl_qcom_unregister(pdrv);
return rc;
}
return 0;
}
void atl_qcom_unregister(struct pci_driver *pdrv)
{
atl_qcom_ipa_unregister(pdrv);
__atl_qcom_unregister(pdrv);
}

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
/* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -13,16 +13,17 @@
#ifndef _ATL_QCOM_H_
#define _ATL_QCOM_H_
#include <linux/pci.h>
#ifdef CONFIG_AQFWD_QCOM
int atl_qcom_parse_dt(struct device *dev);
int atl_qcom_register(struct pci_driver *pdrv);
void atl_qcom_unregister(struct pci_driver *pdrv);
#else
static inline int atl_qcom_parse_dt(struct device *dev)
{
return 0;
}
static inline int atl_qcom_register(struct pci_driver *pdrv) { return 0; }
static inline void atl_qcom_unregister(struct pci_driver *pdrv) { return; }
#endif // CONFIG_AQFWD_QCOM