From ec527358c2e1bee6100083dd637600a1f0f7724a Mon Sep 17 00:00:00 2001 From: Shashikala Prabhu Date: Tue, 30 Jul 2019 21:45:39 +0530 Subject: [PATCH] qcacmn: Fix issues in qdf aligned memory alloc function 1. Alloc size should be passed as input and output parameter since we need to pass the exact alloc_size while freeing the memory. 2. use qdf_align() to calculate the aligned physical address. 3. In DBR component, pass correct arguments to qdf_aligned_malloc() to fix the compilation errors. Alloc size should be passed as input and output parameter since we need to pass the exact alloc_size while freeing the DMA memory. Change-Id: I83051b8aa54bbf3bb663902d8f17f2c3c55e57bf CRs-Fixed: 2462441 --- qdf/inc/qdf_mem.h | 45 +++++---- qdf/linux/src/qdf_mem.c | 96 ++++++++++++++----- .../src/target_if_direct_buf_rx_main.c | 26 ++--- 3 files changed, 112 insertions(+), 55 deletions(-) diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h index 4cc16428ae..49fc0c0bb3 100644 --- a/qdf/inc/qdf_mem.h +++ b/qdf/inc/qdf_mem.h @@ -292,9 +292,11 @@ void qdf_mem_multi_pages_free(qdf_device_t osdev, /** * qdf_aligned_malloc() - allocates aligned QDF memory. - * @size: Number of bytes of memory to allocate. - * @ring_base_align: Base address alignment. + * @size: Size to be allocated * @vaddr_unaligned: Unaligned virtual address. + * @paddr_unaligned: Unaligned physical address. + * @paddr_aligned: Aligned physical address. + * @align: Base address alignment. * @func: Function name of the call site. * @line: Line number of the call site. * @@ -308,39 +310,44 @@ void qdf_mem_multi_pages_free(qdf_device_t osdev, * memory. If this function is unable to allocate the amount of memory * specified (for any reason) it returns NULL. */ -#define qdf_aligned_malloc(size, ring_base_align, vaddr_unaligned) \ - qdf_aligned_malloc_fl(size, ring_base_align, vaddr_unaligned, \ - __func__, __LINE__) +#define qdf_aligned_malloc(size, vaddr_unaligned, paddr_unaligned, \ + paddr_aligned, align) \ + qdf_aligned_malloc_fl(size, vaddr_unaligned, paddr_unaligned, \ + paddr_aligned, align, __func__, __LINE__) -void *qdf_aligned_malloc_fl(qdf_size_t size, uint32_t ring_base_align, - void **vaddr_unaligned, +void *qdf_aligned_malloc_fl(uint32_t *size, void **vaddr_unaligned, + qdf_dma_addr_t *paddr_unaligned, + qdf_dma_addr_t *paddr_aligned, + uint32_t align, const char *func, uint32_t line); /** * qdf_aligned_mem_alloc_consistent() - allocates consistent qdf memory * @osdev: OS device handle - * @dev: Pointer to device handle * @size: Size to be allocated * @vaddr_unaligned: Unaligned virtual address. * @paddr_unaligned: Unaligned physical address. * @paddr_aligned: Aligned physical address. - * @ring_base_align: Base address alignment. + * @align: Base address alignment. * @func: Function name of the call site. * @line: Line number of the call site. * * Return: pointer of allocated memory or null if memory alloc fails. */ -#define qdf_aligned_mem_alloc_consistent(osdev, dev, size, vaddr_unaligned, \ - paddr_unaligned, paddr_aligned, ring_base_align) \ - qdf_aligned_mem_alloc_consistent_fl(osdev, dev, size, vaddr_unaligned, \ - paddr_unaligned, paddr_aligned, \ - ring_base_align, __func__, __LINE__) +#define qdf_aligned_mem_alloc_consistent(osdev, size, vaddr_unaligned, \ + paddr_unaligned, paddr_aligned, \ + align) \ + qdf_aligned_mem_alloc_consistent_fl(osdev, size, vaddr_unaligned, \ + paddr_unaligned, paddr_aligned, \ + align, __func__, __LINE__) + +void *qdf_aligned_mem_alloc_consistent_fl(qdf_device_t osdev, uint32_t *size, + void **vaddr_unaligned, + qdf_dma_addr_t *paddr_unaligned, + qdf_dma_addr_t *paddr_aligned, + uint32_t align, const char *func, + uint32_t line); -void *qdf_aligned_mem_alloc_consistent_fl( - qdf_device_t osdev, void *dev, qdf_size_t size, - void **vaddr_unaligned, qdf_dma_addr_t *paddr_unaligned, - qdf_dma_addr_t *paddr_aligned, uint32_t ring_base_align, - const char *func, uint32_t line); #define qdf_mem_virt_to_phys(vaddr) virt_to_phys(vaddr) void qdf_mem_set_io(void *ptr, uint32_t num_bytes, uint32_t value); diff --git a/qdf/linux/src/qdf_mem.c b/qdf/linux/src/qdf_mem.c index 19455feb08..73cdb547e5 100644 --- a/qdf/linux/src/qdf_mem.c +++ b/qdf/linux/src/qdf_mem.c @@ -1435,31 +1435,57 @@ void qdf_mem_multi_pages_free(qdf_device_t osdev, qdf_export_symbol(qdf_mem_multi_pages_free); #endif -void *qdf_aligned_malloc_fl(qdf_size_t size, uint32_t ring_base_align, +void *qdf_aligned_malloc_fl(uint32_t *size, void **vaddr_unaligned, + qdf_dma_addr_t *paddr_unaligned, + qdf_dma_addr_t *paddr_aligned, + uint32_t align, const char *func, uint32_t line) { void *vaddr_aligned; + uint32_t align_alloc_size; - *vaddr_unaligned = qdf_mem_malloc_fl(size, func, line); + *vaddr_unaligned = qdf_mem_malloc_fl((qdf_size_t)*size, func, + line); if (!*vaddr_unaligned) { - qdf_warn("Failed to alloc %zuB @ %s:%d", size, func, line); + qdf_warn("Failed to alloc %uB @ %s:%d", *size, func, line); return NULL; } - if ((unsigned long)(*vaddr_unaligned) % ring_base_align) { + *paddr_unaligned = qdf_mem_virt_to_phys(*vaddr_unaligned); + + /* Re-allocate additional bytes to align base address only if + * above allocation returns unaligned address. Reason for + * trying exact size allocation above is, OS tries to allocate + * blocks of size power-of-2 pages and then free extra pages. + * e.g., of a ring size of 1MB, the allocation below will + * request 1MB plus 7 bytes for alignment, which will cause a + * 2MB block allocation,and that is failing sometimes due to + * memory fragmentation. + */ + if ((unsigned long)(*paddr_unaligned) & (align - 1)) { + align_alloc_size = *size + align - 1; + qdf_mem_free(*vaddr_unaligned); - *vaddr_unaligned = qdf_mem_malloc_fl(size + ring_base_align - 1, - func, line); + *vaddr_unaligned = qdf_mem_malloc_fl( + (qdf_size_t)align_alloc_size, func, line); if (!*vaddr_unaligned) { - qdf_warn("Failed to alloc %zuB @ %s:%d", - size, func, line); + qdf_warn("Failed to alloc %uB @ %s:%d", + align_alloc_size, func, line); return NULL; } + + *paddr_unaligned = qdf_mem_virt_to_phys( + *vaddr_unaligned); + *size = align_alloc_size; } - vaddr_aligned = (*vaddr_unaligned) + - ((unsigned long)(*vaddr_unaligned) % ring_base_align); + *paddr_aligned = (qdf_dma_addr_t)qdf_align + ((unsigned long)(*paddr_unaligned), align); + + vaddr_aligned = (void *)((unsigned long)(*vaddr_unaligned) + + ((unsigned long)(*paddr_aligned) - + (unsigned long)(*paddr_unaligned))); return vaddr_aligned; } @@ -1859,36 +1885,56 @@ qdf_export_symbol(qdf_mem_free_consistent); #endif /* MEMORY_DEBUG */ void *qdf_aligned_mem_alloc_consistent_fl( - qdf_device_t osdev, void *dev, qdf_size_t size, + qdf_device_t osdev, uint32_t *size, void **vaddr_unaligned, qdf_dma_addr_t *paddr_unaligned, - qdf_dma_addr_t *paddr_aligned, uint32_t ring_base_align, + qdf_dma_addr_t *paddr_aligned, uint32_t align, const char *func, uint32_t line) { void *vaddr_aligned; + uint32_t align_alloc_size; - *vaddr_unaligned = qdf_mem_alloc_consistent(osdev, dev, size, - paddr_unaligned); + *vaddr_unaligned = qdf_mem_alloc_consistent( + osdev, osdev->dev, (qdf_size_t)*size, paddr_unaligned); if (!*vaddr_unaligned) { - qdf_warn("Failed to alloc %zuB @ %s:%d", size, func, line); + qdf_warn("Failed to alloc %uB @ %s:%d", + *size, func, line); return NULL; } - if ((unsigned long)(*vaddr_unaligned) % ring_base_align) { - qdf_mem_free_consistent(osdev, dev, size, *vaddr_unaligned, + /* Re-allocate additional bytes to align base address only if + * above allocation returns unaligned address. Reason for + * trying exact size allocation above is, OS tries to allocate + * blocks of size power-of-2 pages and then free extra pages. + * e.g., of a ring size of 1MB, the allocation below will + * request 1MB plus 7 bytes for alignment, which will cause a + * 2MB block allocation,and that is failing sometimes due to + * memory fragmentation. + */ + if ((unsigned long)(*paddr_unaligned) & (align - 1)) { + align_alloc_size = *size + align - 1; + + qdf_mem_free_consistent(osdev, osdev->dev, *size, + *vaddr_unaligned, *paddr_unaligned, 0); - *vaddr_unaligned = qdf_mem_alloc_consistent(osdev, dev, - size + ring_base_align - 1, paddr_unaligned); + + *vaddr_unaligned = qdf_mem_alloc_consistent( + osdev, osdev->dev, align_alloc_size, + paddr_unaligned); if (!*vaddr_unaligned) { - qdf_warn("Failed to alloc %zuB @ %s:%d", - size, func, line); + qdf_warn("Failed to alloc %uB @ %s:%d", + align_alloc_size, func, line); return NULL; } + + *size = align_alloc_size; } - vaddr_aligned = *vaddr_unaligned + - ((unsigned long)(*vaddr_unaligned) % ring_base_align); - *paddr_aligned = *paddr_unaligned + ((unsigned long)(vaddr_aligned) - - (unsigned long)(*vaddr_unaligned)); + *paddr_aligned = (qdf_dma_addr_t)qdf_align( + (unsigned long)(*paddr_unaligned), align); + + vaddr_aligned = (void *)((unsigned long)(*vaddr_unaligned) + + ((unsigned long)(*paddr_aligned) - + (unsigned long)(*paddr_unaligned))); return vaddr_aligned; } diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c index 56bd90ec2b..fca229d01c 100644 --- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c +++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c @@ -371,7 +371,6 @@ static QDF_STATUS target_if_dbr_fill_ring(struct wlan_objmgr_pdev *pdev, struct direct_buf_rx_module_param *mod_param) { uint32_t idx; - void *buf, *buf_aligned; struct direct_buf_rx_ring_cfg *dbr_ring_cfg; struct direct_buf_rx_ring_cap *dbr_ring_cap; struct direct_buf_rx_buf_info *dbr_buf_pool; @@ -384,23 +383,28 @@ static QDF_STATUS target_if_dbr_fill_ring(struct wlan_objmgr_pdev *pdev, dbr_buf_pool = mod_param->dbr_buf_pool; for (idx = 0; idx < dbr_ring_cfg->num_ptr - 1; idx++) { - buf_aligned = qdf_aligned_malloc(dbr_ring_cap->min_buf_size, - dbr_ring_cap->min_buf_align, - &buf); - if (!buf_aligned) { - direct_buf_rx_err( - "dir buf rx ring buf_aligned alloc failed"); + void *buf_vaddr_unaligned, *buf_vaddr_aligned; + dma_addr_t buf_paddr_aligned, buf_paddr_unaligned; + + buf_vaddr_aligned = qdf_aligned_malloc( + &dbr_ring_cap->min_buf_size, &buf_vaddr_unaligned, + &buf_paddr_unaligned, &buf_paddr_aligned, + dbr_ring_cap->min_buf_align); + + if (!buf_vaddr_aligned) { + direct_buf_rx_err("dir buf rx ring alloc failed"); return QDF_STATUS_E_NOMEM; } - dbr_buf_pool[idx].vaddr = buf; - dbr_buf_pool[idx].offset = buf_aligned - buf; + dbr_buf_pool[idx].vaddr = buf_vaddr_unaligned; + dbr_buf_pool[idx].offset = buf_vaddr_aligned - + buf_vaddr_unaligned; dbr_buf_pool[idx].cookie = idx; status = target_if_dbr_replenish_ring(pdev, mod_param, - buf_aligned, idx); + buf_vaddr_aligned, idx); if (QDF_IS_STATUS_ERROR(status)) { direct_buf_rx_err("replenish failed with status : %d", status); - qdf_mem_free(buf); + qdf_mem_free(buf_vaddr_unaligned); return QDF_STATUS_E_FAILURE; } }