qcacld-3.0: Add support for WLAN-IPA SMMU Stage 1 translation

Update WLAN-IPA datapath buffer sharing for SMMU Stage 1
translation support. When SMMU Stage 1 translation is enabled,
DMA APIs return IO virtual address(IOVA) instead of physical
address. This IOVA needs to be mapped to physical address by IPA
module before accessing them.

Change-Id: I6b24cde7b7805395053a8fd8f9afbad202e6105f
CRS-Fixed: 2072960
diff --git a/Kbuild b/Kbuild
index e5a376a..a63a48f 100644
--- a/Kbuild
+++ b/Kbuild
@@ -2498,6 +2498,11 @@
 CDEFINES += -DFEATURE_MULTICAST_HOST_FW_MSGS
 endif
 
+#Flag to enable SMMU S1 support
+ifeq ($(CONFIG_ARCH_SDM845), y)
+CDEFINES += -DENABLE_SMMU_S1_TRANSLATION
+endif
+
 KBUILD_CPPFLAGS += $(CDEFINES)
 
 # Currently, for versions of gcc which support it, the kernel Makefile
diff --git a/core/cds/inc/cds_api.h b/core/cds/inc/cds_api.h
index 95f4ead..df46040 100644
--- a/core/cds/inc/cds_api.h
+++ b/core/cds/inc/cds_api.h
@@ -593,4 +593,29 @@
 uint32_t cds_get_arp_stats_gw_ip(void);
 void cds_incr_arp_stats_tx_tgt_delivered(void);
 void cds_incr_arp_stats_tx_tgt_acked(void);
+
+/**
+ * cds_smmu_mem_map_setup() - Check SMMU S1 stage enable
+ *                            status and setup wlan driver
+ * @osdev: Parent device instance
+ *
+ * This API checks if SMMU S1 translation is enabled in
+ * platform driver or not and sets it accordingly in driver.
+ *
+ * Return: none
+ */
+void cds_smmu_mem_map_setup(qdf_device_t osdev);
+
+/**
+ * cds_smmu_map_unmap() - Map / Unmap DMA buffer to IPA UC
+ * @map: Map / unmap operation
+ * @num_buf: Number of buffers in array
+ * @buf_arr: Buffer array of DMA mem mapping info
+ *
+ * This API maps/unmaps WLAN-IPA buffers if SMMU S1 translation
+ * is enabled.
+ *
+ * Return: Status of map operation
+ */
+int cds_smmu_map_unmap(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr);
 #endif /* if !defined __CDS_API_H */
diff --git a/core/cds/src/cds_api.c b/core/cds/src/cds_api.c
index ffaa6c9..f0f4045 100644
--- a/core/cds/src/cds_api.c
+++ b/core/cds/src/cds_api.c
@@ -71,6 +71,13 @@
 #include "wlan_ocb_ucfg_api.h"
 #include "qdf_platform.h"
 
+#ifdef ENABLE_SMMU_S1_TRANSLATION
+#include "pld_common.h"
+#include <asm/dma-iommu.h>
+#include <linux/iommu.h>
+#endif
+/* Preprocessor Definitions and Constants */
+
 /* Preprocessor Definitions and Constants */
 
 /* Data definitions */
@@ -2836,3 +2843,36 @@
 	if (adapter)
 		adapter->hdd_stats.hdd_arp_stats.tx_ack_cnt++;
 }
+
+#ifdef ENABLE_SMMU_S1_TRANSLATION
+void cds_smmu_mem_map_setup(qdf_device_t osdev)
+{
+	int attr = 0;
+	struct dma_iommu_mapping *mapping = pld_smmu_get_mapping(osdev->dev);
+
+	osdev->smmu_s1_enabled = false;
+	if (!mapping) {
+		cds_info("No SMMU mapping present");
+		return;
+	}
+
+	if ((iommu_domain_get_attr(mapping->domain,
+				   DOMAIN_ATTR_S1_BYPASS, &attr) == 0) &&
+				   !attr)
+		osdev->smmu_s1_enabled = true;
+}
+
+int cds_smmu_map_unmap(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
+{
+	return hdd_ipa_uc_smmu_map(map, num_buf, buf_arr);
+}
+#else
+void cds_smmu_mem_map_setup(qdf_device_t osdev)
+{
+}
+
+int cds_smmu_map_unmap(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
+{
+	return 0;
+}
+#endif
diff --git a/core/hdd/inc/wlan_hdd_ipa.h b/core/hdd/inc/wlan_hdd_ipa.h
index 825d104..4e3bae9 100644
--- a/core/hdd/inc/wlan_hdd_ipa.h
+++ b/core/hdd/inc/wlan_hdd_ipa.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved.
  *
  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
  *
@@ -141,6 +141,18 @@
  */
 void hdd_ipa_uc_info(struct hdd_context *hdd_ctx);
 
+/**
+ * hdd_ipa_uc_smmu_map() - Map / Unmap DMA buffer to IPA UC
+ * @map: Map / unmap operation
+ * @num_buf: Number of buffers in array
+ * @buf_arr: Buffer array of DMA mem mapping info
+ *
+ * This API maps/unmaps WLAN-IPA buffers if SMMU S1 translation
+ * is enabled.
+ *
+ * Return: Status of map operation
+ */
+int hdd_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr);
 #else
 
 static inline QDF_STATUS hdd_ipa_init(struct hdd_context *hdd_ctx)
@@ -316,5 +328,10 @@
 {
 }
 
+static inline int hdd_ipa_uc_smmu_map(bool map, uint32_t num_buf,
+				      qdf_mem_info_t *buf_arr)
+{
+	return 0;
+}
 #endif /* IPA_OFFLOAD */
 #endif /* #ifndef HDD_IPA_H__ */
diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c
index 8507d75..d1a4a2e 100644
--- a/core/hdd/src/wlan_hdd_driver_ops.c
+++ b/core/hdd/src/wlan_hdd_driver_ops.c
@@ -390,6 +390,7 @@
 		cds_set_load_in_progress(true);
 
 	hdd_init_qdf_ctx(dev, bdev, bus_type, (const struct hif_bus_id *)bid);
+	cds_smmu_mem_map_setup(cds_get_context(QDF_MODULE_ID_QDF_DEVICE));
 
 	if (reinit) {
 		ret = hdd_wlan_re_init();
diff --git a/core/hdd/src/wlan_hdd_ipa.c b/core/hdd/src/wlan_hdd_ipa.c
index 198ae0d..3c29e00 100644
--- a/core/hdd/src/wlan_hdd_ipa.c
+++ b/core/hdd/src/wlan_hdd_ipa.c
@@ -6378,4 +6378,22 @@
 
 	return ret;
 }
+
+int hdd_ipa_uc_smmu_map(bool map, uint32_t num_buf, qdf_mem_info_t *buf_arr)
+{
+	HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "Map: %d Num_buf: %d", map, num_buf);
+
+	if (!num_buf) {
+		HDD_IPA_LOG(QDF_TRACE_LEVEL_DEBUG, "No buffers to map/unmap");
+		return 0;
+	}
+
+	if (map)
+		return ipa_create_wdi_mapping(num_buf,
+			   (struct ipa_wdi_buffer_info *)buf_arr);
+	else
+		return ipa_release_wdi_mapping(num_buf,
+			   (struct ipa_wdi_buffer_info *)buf_arr);
+}
+
 #endif /* IPA_OFFLOAD */