OSDN Git Service

cnss2: Add support for PCIe WLAN IPA uc SMMU feature
authorFrank Liu <qiliu@codeaurora.org>
Fri, 27 Jul 2018 06:32:53 +0000 (14:32 +0800)
committerGerrit - the friendly Code Review server <code-review@localhost>
Wed, 1 Aug 2018 10:21:40 +0000 (03:21 -0700)
To add support for PCIe WLAN IPA uc SMMU feature, prvoide related
platform api for wlan driver to get the smmu map handle and do the
mapping.

Change-Id: I672b1a48879ada65b3ddb3f16c4bd787dc1b70a6
Signed-off-by: Frank Liu <qiliu@codeaurora.org>
drivers/net/wireless/cnss2/pci.c
drivers/net/wireless/cnss2/pci.h
include/net/cnss2.h

index ff053b0..0f4ef37 100644 (file)
@@ -1414,6 +1414,61 @@ void cnss_pci_fw_boot_timeout_hdlr(struct cnss_pci_data *pci_priv)
                               CNSS_REASON_TIMEOUT);
 }
 
+struct dma_iommu_mapping *cnss_smmu_get_mapping(struct device *dev)
+{
+       struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+
+       if (!pci_priv)
+               return NULL;
+
+       return pci_priv->smmu_mapping;
+}
+EXPORT_SYMBOL(cnss_smmu_get_mapping);
+
+int cnss_smmu_map(struct device *dev,
+                 phys_addr_t paddr, uint32_t *iova_addr, size_t size)
+{
+       struct cnss_pci_data *pci_priv = cnss_get_pci_priv(to_pci_dev(dev));
+       unsigned long iova;
+       size_t len;
+       int ret = 0;
+
+       if (!pci_priv)
+               return -ENODEV;
+
+       if (!iova_addr) {
+               cnss_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(pci_priv->smmu_iova_ipa_start, PAGE_SIZE);
+
+       if (iova >=
+           (pci_priv->smmu_iova_ipa_start + pci_priv->smmu_iova_ipa_len)) {
+               cnss_pr_err("No IOVA space to map, iova %lx, smmu_iova_ipa_start %pad, smmu_iova_ipa_len %zu\n",
+                           iova,
+                           &pci_priv->smmu_iova_ipa_start,
+                           pci_priv->smmu_iova_ipa_len);
+               return -ENOMEM;
+       }
+
+       ret = iommu_map(pci_priv->smmu_mapping->domain, iova,
+                       rounddown(paddr, PAGE_SIZE), len,
+                       IOMMU_READ | IOMMU_WRITE);
+       if (ret) {
+               cnss_pr_err("PA to IOVA mapping failed, ret %d\n", ret);
+               return ret;
+       }
+
+       pci_priv->smmu_iova_ipa_start = iova + len;
+       *iova_addr = (uint32_t)(iova + paddr - rounddown(paddr, PAGE_SIZE));
+
+       return 0;
+}
+EXPORT_SYMBOL(cnss_smmu_map);
+
 int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info)
 {
        int ret = 0;
@@ -2129,6 +2184,17 @@ static int cnss_pci_probe(struct pci_dev *pci_dev,
                            &pci_priv->smmu_iova_start,
                            pci_priv->smmu_iova_len);
 
+               res = platform_get_resource_byname(plat_priv->plat_dev,
+                                                  IORESOURCE_MEM,
+                                                  "smmu_iova_ipa");
+               if (res) {
+                       pci_priv->smmu_iova_ipa_start = res->start;
+                       pci_priv->smmu_iova_ipa_len = resource_size(res);
+                       cnss_pr_dbg("smmu_iova_ipa_start: %pa, smmu_iova_ipa_len: %zu\n",
+                                   &pci_priv->smmu_iova_ipa_start,
+                                   pci_priv->smmu_iova_ipa_len);
+               }
+
                ret = cnss_pci_init_smmu(pci_priv);
                if (ret) {
                        cnss_pr_err("Failed to init SMMU, err = %d\n", ret);
index 182355a..e47f14e 100644 (file)
@@ -73,6 +73,8 @@ struct cnss_pci_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;
        void __iomem *bar;
        struct cnss_msi_config *msi_config;
        u32 msi_ep_base_data;
index f80d875..53f73d4 100644 (file)
@@ -171,6 +171,9 @@ extern int cnss_get_fw_files_for_target(struct device *dev,
                                        u32 target_type, u32 target_version);
 extern int cnss_get_platform_cap(struct device *dev,
                                 struct cnss_platform_cap *cap);
+extern struct dma_iommu_mapping *cnss_smmu_get_mapping(struct device *dev);
+extern int cnss_smmu_map(struct device *dev,
+                        phys_addr_t paddr, uint32_t *iova_addr, size_t size);
 extern int cnss_get_soc_info(struct device *dev, struct cnss_soc_info *info);
 extern int cnss_request_bus_bandwidth(struct device *dev, int bandwidth);
 extern int cnss_power_up(struct device *dev);