diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h index fa46e7c65e..186e32b72a 100644 --- a/qdf/inc/qdf_mem.h +++ b/qdf/inc/qdf_mem.h @@ -390,4 +390,270 @@ void qdf_mem_skb_inc(qdf_size_t size); */ void qdf_mem_skb_dec(qdf_size_t size); +/** + * qdf_mem_map_table_alloc() - Allocate shared memory info structure + * @num: number of required storage + * + * Allocate mapping table for DMA memory allocation. This is needed for + * IPA-WLAN buffer sharing when SMMU Stage1 Translation is enabled. + * + * Return: shared memory info storage table pointer + */ +static inline qdf_mem_info_t *qdf_mem_map_table_alloc(uint32_t num) +{ + qdf_mem_info_t *mem_info_arr; + + mem_info_arr = qdf_mem_malloc(num * sizeof(mem_info_arr[0])); + return mem_info_arr; +} + +/** + * qdf_update_mem_map_table() - Update DMA memory map info + * @osdev: Parent device instance + * @mem_info: Pointer to shared memory information + * @dma_addr: dma address + * @mem_size: memory size allocated + * + * Store DMA shared memory information + * + * Return: none + */ +static inline void qdf_update_mem_map_table(qdf_device_t osdev, + qdf_mem_info_t *mem_info, + qdf_dma_addr_t dma_addr, + uint32_t mem_size) +{ + if (!mem_info) { + __qdf_print("%s: NULL mem_info\n", __func__); + return; + } + + __qdf_update_mem_map_table(osdev, mem_info, dma_addr, mem_size); +} + +/** + * qdf_mem_smmu_s1_enabled() - Return SMMU stage 1 translation enable status + * @osdev parent device instance + * + * Return: true if smmu s1 enabled, false if smmu s1 is bypassed + */ +static inline bool qdf_mem_smmu_s1_enabled(qdf_device_t osdev) +{ + return __qdf_mem_smmu_s1_enabled(osdev); +} + +/** + * qdf_mem_paddr_from_dmaaddr() - get actual physical address from dma address + * @osdev: Parent device instance + * @dma_addr: DMA/IOVA address + * + * Get actual physical address from dma_addr based on SMMU enablement status. + * IF SMMU Stage 1 tranlation is enabled, DMA APIs return IO virtual address + * (IOVA) otherwise returns physical address. So get SMMU physical address + * mapping from IOVA. + * + * Return: dmaable physical address + */ +static inline qdf_dma_addr_t qdf_mem_paddr_from_dmaaddr(qdf_device_t osdev, + qdf_dma_addr_t dma_addr) +{ + return __qdf_mem_paddr_from_dmaaddr(osdev, dma_addr); +} + +/** + * qdf_os_mem_dma_get_sgtable() - Returns DMA memory scatter gather table + * @dev: device instace + * @sgt: scatter gather table pointer + * @cpu_addr: HLOS virtual address + * @dma_addr: dma address + * @size: allocated memory size + * + * Return: physical address + */ +static inline int +qdf_mem_dma_get_sgtable(struct device *dev, void *sgt, void *cpu_addr, + qdf_dma_addr_t dma_addr, size_t size) +{ + return __qdf_os_mem_dma_get_sgtable(dev, sgt, cpu_addr, dma_addr, size); +} + +/** + * qdf_mem_get_dma_addr() - Return dma address based on SMMU translation status. + * @osdev: Parent device instance + * @mem_info: Pointer to allocated memory information + * + * Get dma address based on SMMU enablement status. If SMMU Stage 1 + * tranlation is enabled, DMA APIs return IO virtual address otherwise + * returns physical address. + * + * Return: dma address + */ +static inline qdf_dma_addr_t qdf_mem_get_dma_addr(qdf_device_t osdev, + qdf_mem_info_t *mem_info) +{ + return __qdf_mem_get_dma_addr(osdev, mem_info); +} + +/** + * qdf_mem_get_dma_addr_ptr() - Return DMA address pointer from mem info struct + * @osdev: Parent device instance + * @mem_info: Pointer to allocated memory information + * + * Based on smmu stage 1 translation enablement, return corresponding dma + * address storage pointer. + * + * Return: dma address storage pointer + */ +static inline qdf_dma_addr_t *qdf_mem_get_dma_addr_ptr(qdf_device_t osdev, + qdf_mem_info_t *mem_info) +{ + return __qdf_mem_get_dma_addr_ptr(osdev, mem_info); +} + + +/** + * qdf_mem_get_dma_size() - Return DMA memory size + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * + * Return: DMA memory size + */ +static inline uint32_t +qdf_mem_get_dma_size(qdf_device_t osdev, + qdf_mem_info_t *mem_info) +{ + return __qdf_mem_get_dma_size(osdev, mem_info); +} + +/** + * qdf_mem_set_dma_size() - Set DMA memory size + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * @mem_size: memory size allocated + * + * Return: none + */ +static inline void +qdf_mem_set_dma_size(qdf_device_t osdev, + qdf_mem_info_t *mem_info, + uint32_t mem_size) +{ + __qdf_mem_set_dma_size(osdev, mem_info, mem_size); +} + +/** + * qdf_mem_get_dma_size() - Return DMA physical address + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * + * Return: DMA physical address + */ +static inline qdf_dma_addr_t +qdf_mem_get_dma_pa(qdf_device_t osdev, + qdf_mem_info_t *mem_info) +{ + return __qdf_mem_get_dma_pa(osdev, mem_info); +} + +/** + * qdf_mem_set_dma_size() - Set DMA physical address + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * @dma_pa: DMA phsical address + * + * Return: none + */ +static inline void +qdf_mem_set_dma_pa(qdf_device_t osdev, + qdf_mem_info_t *mem_info, + qdf_dma_addr_t dma_pa) +{ + __qdf_mem_set_dma_pa(osdev, mem_info, dma_pa); +} + +/** + * qdf_mem_shared_mem_alloc() - Allocate DMA memory for shared resource + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * @size: size to be allocated + * + * Allocate DMA memory which will be shared with external kernel module. This + * information is needed for SMMU mapping. + * + * Return: 0 suceess + */ +static inline qdf_shared_mem_t *qdf_mem_shared_mem_alloc(qdf_device_t osdev, + uint32_t size) +{ + qdf_shared_mem_t *shared_mem; + + shared_mem = qdf_mem_malloc(sizeof(*shared_mem)); + if (!shared_mem) { + __qdf_print("%s: Unable to allocate memory for shared resource struct\n", + __func__); + return NULL; + } + + shared_mem->vaddr = qdf_mem_alloc_consistent(osdev, osdev->dev, + size, qdf_mem_get_dma_addr_ptr(osdev, + &shared_mem->mem_info)); + if (!shared_mem->vaddr) { + __qdf_print("%s; Unable to allocate DMA memory for shared resource\n", + __func__); + qdf_mem_free(shared_mem); + return NULL; + } + + qdf_mem_set_dma_size(osdev, &shared_mem->mem_info, size); + qdf_mem_zero(shared_mem->vaddr, + qdf_mem_get_dma_size(osdev, &shared_mem->mem_info)); + qdf_mem_set_dma_pa(osdev, &shared_mem->mem_info, + qdf_mem_paddr_from_dmaaddr(osdev, + qdf_mem_get_dma_addr(osdev, + &shared_mem->mem_info))); + qdf_mem_dma_get_sgtable(osdev->dev, + (void *)&shared_mem->sgtable, + shared_mem->vaddr, + qdf_mem_get_dma_addr(osdev, + &shared_mem->mem_info), + qdf_mem_get_dma_size(osdev, + &shared_mem->mem_info)); + + shared_mem->sgtable.sgl->dma_address = + qdf_mem_get_dma_pa(osdev, &shared_mem->mem_info); + + return shared_mem; +} + +/** + * qdf_mem_shared_mem_free() - Free shared memory + * @osdev: parent device instance + * @shared_mem: shared memory information storage + * + * Free DMA shared memory resource + * + * Return: None + */ +static inline void qdf_mem_shared_mem_free(qdf_device_t osdev, + qdf_shared_mem_t *shared_mem) +{ + if (!shared_mem) { + __qdf_print("%s: NULL shared mem struct passed\n", + __func__); + return; + } + + if (shared_mem->vaddr) { + qdf_mem_free_consistent(osdev, osdev->dev, + qdf_mem_get_dma_size(osdev, + &shared_mem->mem_info), + shared_mem->vaddr, + qdf_mem_get_dma_addr(osdev, + &shared_mem->mem_info), + qdf_get_dma_mem_context(shared_mem, + memctx)); + } + qdf_mem_free(shared_mem); +} + #endif /* __QDF_MEMORY_H */ diff --git a/qdf/inc/qdf_types.h b/qdf/inc/qdf_types.h index bb306564c2..384550a875 100644 --- a/qdf/inc/qdf_types.h +++ b/qdf/inc/qdf_types.h @@ -157,6 +157,9 @@ typedef __qdf_dma_size_t qdf_dma_size_t; */ typedef __qdf_dma_context_t qdf_dma_context_t; +typedef __qdf_mem_info_t qdf_mem_info_t; +typedef __sgtable_t sgtable_t; + /** * pointer to net device */ @@ -177,6 +180,20 @@ typedef struct qdf_dma_map_info { } dma_segs[QDF_MAX_SCATTER]; } qdf_dmamap_info_t; +/** + * struct qdf_shared_mem - Shared memory resource + * @mem_info: memory info struct + * @vaddr: virtual address + * @sgtable: scatter-gather table + * @memctx: dma address + */ +typedef struct qdf_shared_mem { + qdf_mem_info_t mem_info; + void *vaddr; + sgtable_t sgtable; + qdf_dma_mem_context(memctx); +} qdf_shared_mem_t; + #define qdf_iomem_t __qdf_iomem_t; /** diff --git a/qdf/linux/src/i_qdf_mem.h b/qdf/linux/src/i_qdf_mem.h index 6951d2201e..d2643ad900 100644 --- a/qdf/linux/src/i_qdf_mem.h +++ b/qdf/linux/src/i_qdf_mem.h @@ -70,6 +70,12 @@ #endif /* __KERNEL__ */ #include +#ifdef CONFIG_ARM_SMMU +#include +#include +#include +#endif + #ifdef __KERNEL__ typedef struct mempool_elem { STAILQ_ENTRY(mempool_elem) mempool_entry; @@ -160,7 +166,7 @@ static inline uint32_t __qdf_mem_map_nbytes_single(qdf_device_t osdev, * @dir: DMA unmap direction * @nbytes: number of bytes to be unmapped. * - * @return - none + * Return - none */ static inline void __qdf_mem_unmap_nbytes_single(qdf_device_t osdev, qdf_dma_addr_t phy_addr, @@ -204,4 +210,191 @@ static inline int32_t __qdf_mem_cmp(const void *memory1, const void *memory2, return (int32_t) memcmp(memory1, memory2, num_bytes); } +/** + * __qdf_mem_smmu_s1_enabled() - Return SMMU stage 1 translation enable status + * @osdev parent device instance + * + * Return: true if smmu s1 enabled, false if smmu s1 is bypassed + */ +static inline bool __qdf_mem_smmu_s1_enabled(qdf_device_t osdev) +{ + return osdev->smmu_s1_enabled; +} + +#ifdef CONFIG_ARM_SMMU +/** + * __qdf_mem_paddr_from_dmaaddr() - get actual physical address from dma_addr + * @osdev: parent device instance + * @dma_addr: dma_addr + * + * Get actual physical address from dma_addr based on SMMU enablement status. + * IF SMMU Stage 1 tranlation is enabled, DMA APIs return IO virtual address + * (IOVA) otherwise returns physical address. So get SMMU physical address + * mapping from IOVA. + * + * Return: dmaable physical address + */ +static inline unsigned long +__qdf_mem_paddr_from_dmaaddr(qdf_device_t osdev, + qdf_dma_addr_t dma_addr) +{ + struct dma_iommu_mapping *mapping; + + if (__qdf_mem_smmu_s1_enabled(osdev)) { + mapping = pld_smmu_get_mapping(osdev->dev); + if (mapping) + return iommu_iova_to_phys(mapping->domain, dma_addr); + } + + return dma_addr; +} +#else +static inline unsigned long +__qdf_mem_paddr_from_dmaaddr(qdf_device_t osdev, + qdf_dma_addr_t dma_addr) +{ + return dma_addr; +} +#endif + +/** + * __qdf_os_mem_dma_get_sgtable() - Returns DMA memory scatter gather table + * @dev: device instace + * @sgt: scatter gather table pointer + * @cpu_addr: HLOS virtual address + * @dma_addr: dma/iova + * @size: allocated memory size + * + * Return: physical address + */ +static inline int +__qdf_os_mem_dma_get_sgtable(struct device *dev, void *sgt, void *cpu_addr, + qdf_dma_addr_t dma_addr, size_t size) +{ + return dma_get_sgtable(dev, (struct sg_table *)sgt, cpu_addr, dma_addr, + size); +} + +/** + * __qdf_mem_get_dma_addr() - Return dma addr based on SMMU translation status + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * + * Based on smmu stage 1 translation enablement status, return corresponding dma + * address from qdf_mem_info_t. If stage 1 translation enabled, return + * IO virtual address otherwise return physical address. + * + * Return: dma address + */ +static inline qdf_dma_addr_t __qdf_mem_get_dma_addr(qdf_device_t osdev, + qdf_mem_info_t *mem_info) +{ + if (__qdf_mem_smmu_s1_enabled(osdev)) + return (qdf_dma_addr_t)mem_info->iova; + else + return (qdf_dma_addr_t)mem_info->pa; +} + +/** + * __qdf_mem_get_dma_addr_ptr() - Return DMA address storage pointer + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * + * Based on smmu stage 1 translation enablement status, return corresponding + * dma address pointer from qdf_mem_info_t structure. If stage 1 translation + * enabled, return pointer to IO virtual address otherwise return pointer to + * physical address + * + * Return: dma address storage pointer + */ +static inline qdf_dma_addr_t * +__qdf_mem_get_dma_addr_ptr(qdf_device_t osdev, + qdf_mem_info_t *mem_info) +{ + if (__qdf_mem_smmu_s1_enabled(osdev)) + return (qdf_dma_addr_t *)(&mem_info->iova); + else + return (qdf_dma_addr_t *)(&mem_info->pa); +} + +/** + * __qdf_update_mem_map_table() - Update DMA memory map info + * @osdev: Parent device instance + * @mem_info: Pointer to shared memory information + * @dma_addr: dma address + * @mem_size: memory size allocated + * + * Store DMA shared memory information + * + * Return: none + */ +static inline void __qdf_update_mem_map_table(qdf_device_t osdev, + qdf_mem_info_t *mem_info, + qdf_dma_addr_t dma_addr, + uint32_t mem_size) +{ + mem_info->pa = __qdf_mem_paddr_from_dmaaddr(osdev, dma_addr); + mem_info->iova = dma_addr; + mem_info->size = mem_size; +} + +/** + * __qdf_mem_get_dma_size() - Return DMA memory size + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * + * Return: DMA memory size + */ +static inline uint32_t +__qdf_mem_get_dma_size(qdf_device_t osdev, + qdf_mem_info_t *mem_info) +{ + return mem_info->size; +} + +/** + * __qdf_mem_set_dma_size() - Set DMA memory size + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * @mem_size: memory size allocated + * + * Return: none + */ +static inline void +__qdf_mem_set_dma_size(qdf_device_t osdev, + qdf_mem_info_t *mem_info, + uint32_t mem_size) +{ + mem_info->size = mem_size; +} + +/** + * __qdf_mem_get_dma_size() - Return DMA physical address + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * + * Return: DMA physical address + */ +static inline qdf_dma_addr_t +__qdf_mem_get_dma_pa(qdf_device_t osdev, + qdf_mem_info_t *mem_info) +{ + return mem_info->pa; +} + +/** + * __qdf_mem_set_dma_size() - Set DMA physical address + * @osdev: parent device instance + * @mem_info: Pointer to allocated memory information + * @dma_pa: DMA phsical address + * + * Return: none + */ +static inline void +__qdf_mem_set_dma_pa(qdf_device_t osdev, + qdf_mem_info_t *mem_info, + qdf_dma_addr_t dma_pa) +{ + mem_info->pa = dma_pa; +} #endif /* __I_QDF_MEM_H */ diff --git a/qdf/linux/src/i_qdf_types.h b/qdf/linux/src/i_qdf_types.h index c9b032e4a7..c761e7cbbc 100644 --- a/qdf/linux/src/i_qdf_types.h +++ b/qdf/linux/src/i_qdf_types.h @@ -67,6 +67,11 @@ #include #include #include +#ifdef IPA_OFFLOAD +#include +#endif + +typedef struct sg_table __sgtable_t; #else /* @@ -79,6 +84,9 @@ typedef unsigned long dma_addr_t; #endif +typedef unsigned long phys_addr_t; +typedef unsigned long __sgtable_t; + #define SIOCGIWAP 0 #define IWEVCUSTOM 0 #define IWEVREGISTERED 0 @@ -136,6 +144,24 @@ typedef __be16 __qdf_be16_t; typedef __be32 __qdf_be32_t; typedef __be64 __qdf_be64_t; +#ifdef IPA_OFFLOAD +typedef struct ipa_wdi_buffer_info __qdf_mem_info_t; +#else +/** + * struct __qdf_shared_mem_info - shared mem info struct + * @pa : physical address + * @iova: i/o virtual address + * @size: allocated memory size + * @result: status + */ +typedef struct __qdf_shared_mem_info { + phys_addr_t pa; + unsigned long iova; + size_t size; + int result; +} __qdf_mem_info_t; +#endif /* IPA_OFFLOAD */ + #define qdf_dma_mem_context(context) dma_addr_t context #define qdf_get_dma_mem_context(var, field) ((qdf_dma_context_t)(var->field)) @@ -183,7 +209,10 @@ enum qdf_bus_type { * @dev: Pointer to device * @res: QDF resource * @func: Interrupt handler - * @mem_pool: array to pointer to mem context + * @mem_pool: array of pointers to mem pool context + * @bus_type: Bus type + * @bid: Bus ID + * @smmu_s1_enabled: SMMU S1 enabled or not */ struct __qdf_device { void *drv; @@ -198,6 +227,7 @@ struct __qdf_device { #ifdef CONFIG_MCL const struct hif_bus_id *bid; #endif + bool smmu_s1_enabled; }; typedef struct __qdf_device *__qdf_device_t;