diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2018-06-28 00:45:10 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2018-06-28 00:45:10 -0700 |
commit | 4c492ef22eadb75a7fbbd1beabb8aef13e668820 (patch) | |
tree | 4e83d983dd286546fb79a5ed6f8a40f2016a057f | |
parent | 8f5be35a4192470a40fcaf1fe7857b817bb0ac75 (diff) | |
parent | 8b44fc2701fd65a97a4e755652f9891ecde39763 (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.c | 2 | ||||
-rw-r--r-- | drivers/net/wireless/cnss/cnss_pci.c | 79 | ||||
-rw-r--r-- | include/net/cnss.h | 2 |
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); |