aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2018-06-28 00:45:10 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2018-06-28 00:45:10 -0700
commit4c492ef22eadb75a7fbbd1beabb8aef13e668820 (patch)
tree4e83d983dd286546fb79a5ed6f8a40f2016a057f
parent8f5be35a4192470a40fcaf1fe7857b817bb0ac75 (diff)
parent8b44fc2701fd65a97a4e755652f9891ecde39763 (diff)
Merge "cnss: Add support for WLAN IPA SMMU feature" into LE.UM.2.3.2.r1.4LE.UM.2.3.2-02200-SDX24
-rw-r--r--drivers/iommu/iommu.c2
-rw-r--r--drivers/net/wireless/cnss/cnss_pci.c79
-rw-r--r--include/net/cnss.h2
3 files changed, 80 insertions, 3 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index c333a367fcbf..27ae94fcfea7 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1132,7 +1132,7 @@ int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
*/
mutex_lock(&group->mutex);
ret = -EINVAL;
- if (iommu_group_device_count(group) != 1)
+ if (iommu_group_device_count(group) == 0)
goto out_unlock;
ret = __iommu_attach_group(domain, group);
diff --git a/drivers/net/wireless/cnss/cnss_pci.c b/drivers/net/wireless/cnss/cnss_pci.c
index 8797e688241c..eab2e86dd62f 100644
--- a/drivers/net/wireless/cnss/cnss_pci.c
+++ b/drivers/net/wireless/cnss/cnss_pci.c
@@ -236,6 +236,8 @@ static struct cnss_data {
struct dma_iommu_mapping *smmu_mapping;
dma_addr_t smmu_iova_start;
size_t smmu_iova_len;
+ dma_addr_t smmu_iova_ipa_start;
+ size_t smmu_iova_ipa_len;
struct cnss_wlan_vreg_info vreg_info;
bool wlan_en_vreg_support;
struct cnss_wlan_gpio_info gpio_info;
@@ -1438,6 +1440,7 @@ static int cnss_smmu_init(struct device *dev)
{
struct dma_iommu_mapping *mapping;
int atomic_ctx = 1;
+ int fast = 1;
int ret;
mapping = arm_iommu_create_mapping(&platform_bus_type,
@@ -1458,6 +1461,15 @@ static int cnss_smmu_init(struct device *dev)
goto set_attr_fail;
}
+ ret = iommu_domain_set_attr(mapping->domain,
+ DOMAIN_ATTR_FAST,
+ &fast);
+ if (ret) {
+ pr_err("%s: set fast map attribute failed, err = %d\n",
+ __func__, ret);
+ goto set_attr_fail;
+ }
+
ret = arm_iommu_attach_device(dev, mapping);
if (ret) {
pr_err("%s: attach device failed, err = %d\n", __func__, ret);
@@ -1606,6 +1618,7 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev,
dma_addr_t dma_handle;
struct codeswap_codeseg_info *cnss_seg_info = NULL;
struct device *dev = &pdev->dev;
+ struct iommu_group *group;
cnss_pcie_set_platform_ops(dev);
penv->pdev = pdev;
@@ -1614,11 +1627,17 @@ static int cnss_wlan_pci_probe(struct pci_dev *pdev,
penv->device_id = pdev->device;
if (penv->smmu_iova_len) {
+ dev->iommu_fwspec = penv->subsysdesc.dev->iommu_fwspec;
+ group = iommu_group_get_for_dev(dev);
+ if (!group) {
+ pr_err("%s: iommu group failed\n",
+ __func__);
+ }
+
ret = cnss_smmu_init(&pdev->dev);
if (ret) {
pr_err("%s: SMMU init failed, err = %d\n",
__func__, ret);
- goto smmu_init_fail;
}
}
@@ -1714,7 +1733,6 @@ end_dma_alloc:
dma_free_coherent(dev, EVICT_BIN_MAX_SIZE, cpu_addr, dma_handle);
err_unknown:
err_pcie_suspend:
-smmu_init_fail:
cnss_pcie_reset_platform_ops(dev);
return ret;
}
@@ -2867,6 +2885,55 @@ static int cnss_init_dump_entry(void)
return msm_dump_data_register(MSM_DUMP_TABLE_APPS, &dump_entry);
}
+struct dma_iommu_mapping *cnss_smmu_get_mapping(void)
+{
+ if (!penv) {
+ pr_err("Invalid penv: data %pK\n", penv);
+ return NULL;
+ }
+
+ return penv->smmu_mapping;
+}
+EXPORT_SYMBOL(cnss_smmu_get_mapping);
+
+int cnss_smmu_map(phys_addr_t paddr, uint32_t *iova_addr, size_t size)
+{
+ unsigned long iova;
+ size_t len;
+ int ret = 0;
+
+ if (!iova_addr) {
+ pr_err("iova_addr is NULL, paddr %pa, size %zu\n",
+ &paddr, size);
+ return -EINVAL;
+ }
+
+ len = roundup(size + paddr - rounddown(paddr, PAGE_SIZE), PAGE_SIZE);
+ iova = roundup(penv->smmu_iova_ipa_start, PAGE_SIZE);
+
+ if (iova >= penv->smmu_iova_ipa_start + penv->smmu_iova_ipa_len) {
+ pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n",
+ iova,
+ &penv->smmu_iova_ipa_start,
+ penv->smmu_iova_ipa_len);
+ return -ENOMEM;
+ }
+
+ ret = iommu_map(penv->smmu_mapping->domain, iova,
+ rounddown(paddr, PAGE_SIZE), len,
+ IOMMU_READ | IOMMU_WRITE);
+ if (ret) {
+ pr_err("PA to IOVA mapping failed, ret %d\n", ret);
+ return ret;
+ }
+
+ penv->smmu_iova_ipa_start = iova + len;
+ *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE));
+
+ return 0;
+}
+EXPORT_SYMBOL(cnss_smmu_map);
+
static int cnss_probe(struct platform_device *pdev)
{
int ret = 0;
@@ -2877,6 +2944,7 @@ static int cnss_probe(struct platform_device *pdev)
struct resource *res;
u32 ramdump_size = 0;
u32 smmu_iova_address[2];
+ u32 smmu_iova_ipa[2];
if (penv)
return -ENODEV;
@@ -3028,6 +3096,13 @@ skip_ramdump:
penv->smmu_iova_len = smmu_iova_address[1];
}
+ if (of_property_read_u32_array(dev->of_node,
+ "qcom,wlan-smmu-iova-ipa",
+ smmu_iova_ipa, 2) == 0) {
+ penv->smmu_iova_ipa_start = smmu_iova_ipa[0];
+ penv->smmu_iova_ipa_len = smmu_iova_ipa[1];
+ }
+
ret = pci_register_driver(&cnss_wlan_pci_driver);
if (ret)
goto err_pci_reg;
diff --git a/include/net/cnss.h b/include/net/cnss.h
index 368d01ecc879..39b7f5e54704 100644
--- a/include/net/cnss.h
+++ b/include/net/cnss.h
@@ -120,6 +120,8 @@ enum cnss_runtime_request {
CNSS_PM_GET_NORESUME,
};
+extern struct dma_iommu_mapping *cnss_smmu_get_mapping(void);
+extern int cnss_smmu_map(phys_addr_t paddr, uint32_t *iova_addr, size_t size);
extern int cnss_get_fw_image(struct image_desc_info *image_desc_info);
extern void cnss_runtime_init(struct device *dev, int auto_delay);
extern void cnss_runtime_exit(struct device *dev);