From 7957fa97053948f2a95d8ec8051b282098eea877 Mon Sep 17 00:00:00 2001 From: Karunakar Dasineni Date: Thu, 23 Feb 2017 23:05:40 -0800 Subject: [PATCH] qcacmn: REO descriptor allocation change Use normal allocation instead of alloc_consistent for REO descriptors to allow freeing from interrupt context. Also fixed an issue in ba_window_size setting in REO queues. Change-Id: I91b06e04c0343eb7fe8580d8655c6bc5e33cfe06 --- dp/wifi3.0/dp_main.c | 9 +++-- dp/wifi3.0/dp_peer.c | 80 ++++++++++++++++++++++++++------------- hal/wifi3.0/hal_reo.c | 5 ++- hal/wifi3.0/hal_rx.c | 3 ++ qdf/inc/qdf_mem.h | 2 +- qdf/linux/src/i_qdf_mem.h | 2 +- 6 files changed, 67 insertions(+), 34 deletions(-) diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 77c75dc1cb..16b6659355 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -1313,10 +1313,11 @@ static inline void dp_reo_desc_freelist_destroy(struct dp_soc *soc) while (qdf_list_remove_front(&soc->reo_desc_freelist, (qdf_list_node_t **)&desc) == QDF_STATUS_SUCCESS) { rx_tid = &desc->rx_tid; - qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, - rx_tid->hw_qdesc_alloc_size, - rx_tid->hw_qdesc_vaddr_unaligned, - rx_tid->hw_qdesc_paddr_unaligned, 0); + qdf_mem_unmap_nbytes_single(soc->osdev, + rx_tid->hw_qdesc_paddr_unaligned, + QDF_DMA_BIDIRECTIONAL, + rx_tid->hw_qdesc_alloc_size); + qdf_mem_free(rx_tid->hw_qdesc_vaddr_unaligned); qdf_mem_free(desc); } qdf_spin_unlock_bh(&soc->reo_desc_freelist_lock); diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index 721a87aafd..38f8230c99 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -534,15 +534,11 @@ static void dp_reo_desc_free(struct dp_soc *soc, (qdf_list_node_t **)&desc); list_size--; rx_tid = &desc->rx_tid; - /* Calling qdf_mem_free_consistent() in MCL is resulting in kernel BUG. - * Diasble this temporarily. - */ -#ifndef QCA_WIFI_NAPIER_EMULATION - qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, - rx_tid->hw_qdesc_alloc_size, - rx_tid->hw_qdesc_vaddr_unaligned, - rx_tid->hw_qdesc_paddr_unaligned, 0); -#endif + qdf_mem_unmap_nbytes_single(soc->osdev, + rx_tid->hw_qdesc_paddr_unaligned, + QDF_DMA_BIDIRECTIONAL, + rx_tid->hw_qdesc_alloc_size); + qdf_mem_free(rx_tid->hw_qdesc_vaddr_unaligned); qdf_mem_free(desc); QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, @@ -552,6 +548,23 @@ static void dp_reo_desc_free(struct dp_soc *soc, qdf_spin_unlock_bh(&soc->reo_desc_freelist_lock); } +#if defined(QCA_WIFI_QCA8074) && defined(BUILD_X86) +/* Hawkeye emulation requires bus address to be >= 0x50000000 */ +static inline int dp_reo_desc_addr_chk(qdf_dma_addr_t dma_addr) +{ + if (dma_addr < 0x50000000) + return QDF_STATUS_E_FAILURE; + else + return QDF_STATUS_SUCCESS; +} +#else +static inline int dp_reo_desc_addr_chk(qdf_dma_addr_t dma_addr) +{ + return QDF_STATUS_SUCCESS; +} +#endif + + /* * dp_rx_tid_setup_wifi3() – Setup receive TID state * @peer: Datapath peer handle @@ -562,7 +575,7 @@ static void dp_reo_desc_free(struct dp_soc *soc, * Return: 0 on success, error code on failure */ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, - uint32_t ba_window_size, uint32_t start_seq) + uint32_t ba_window_size, uint32_t start_seq) { struct dp_rx_tid *rx_tid = &peer->rx_tid[tid]; struct dp_vdev *vdev = peer->vdev; @@ -571,6 +584,7 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, uint32_t hw_qdesc_align; int hal_pn_type; void *hw_qdesc_vaddr; + uint32_t alloc_tries = 0; if (rx_tid->hw_qdesc_vaddr_unaligned != NULL) return dp_rx_tid_update_wifi3(peer, tid, ba_window_size, @@ -600,9 +614,10 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, * exact size and see if we already have aligned address. */ rx_tid->hw_qdesc_alloc_size = hw_qdesc_size; - rx_tid->hw_qdesc_vaddr_unaligned = qdf_mem_alloc_consistent( - soc->osdev, soc->osdev->dev, rx_tid->hw_qdesc_alloc_size, - &(rx_tid->hw_qdesc_paddr_unaligned)); + +try_desc_alloc: + rx_tid->hw_qdesc_vaddr_unaligned = + qdf_mem_malloc(rx_tid->hw_qdesc_alloc_size); if (!rx_tid->hw_qdesc_vaddr_unaligned) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, @@ -616,16 +631,11 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, /* Address allocated above is not alinged. Allocate extra * memory for alignment */ - qdf_mem_free_consistent(soc->osdev, soc->osdev->dev, - rx_tid->hw_qdesc_alloc_size, - rx_tid->hw_qdesc_vaddr_unaligned, - rx_tid->hw_qdesc_paddr_unaligned, 0); - + qdf_mem_free(rx_tid->hw_qdesc_vaddr_unaligned); rx_tid->hw_qdesc_alloc_size = hw_qdesc_size + hw_qdesc_align - 1; - rx_tid->hw_qdesc_vaddr_unaligned = qdf_mem_alloc_consistent( - soc->osdev, soc->osdev->dev, rx_tid->hw_qdesc_alloc_size, - &(rx_tid->hw_qdesc_paddr_unaligned)); + rx_tid->hw_qdesc_vaddr_unaligned = + qdf_mem_malloc(rx_tid->hw_qdesc_alloc_size); if (!rx_tid->hw_qdesc_vaddr_unaligned) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, @@ -637,13 +647,8 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, hw_qdesc_vaddr = rx_tid->hw_qdesc_vaddr_unaligned + ((unsigned long)(rx_tid->hw_qdesc_vaddr_unaligned) % hw_qdesc_align); - - rx_tid->hw_qdesc_paddr = rx_tid->hw_qdesc_paddr_unaligned + - ((unsigned long)hw_qdesc_vaddr - - (unsigned long)(rx_tid->hw_qdesc_vaddr_unaligned)); } else { hw_qdesc_vaddr = rx_tid->hw_qdesc_vaddr_unaligned; - rx_tid->hw_qdesc_paddr = rx_tid->hw_qdesc_paddr_unaligned; } /* TODO: Ensure that sec_type is set before ADDBA is received. @@ -672,6 +677,27 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, hal_reo_qdesc_setup(soc->hal_soc, tid, ba_window_size, start_seq, hw_qdesc_vaddr, rx_tid->hw_qdesc_paddr, hal_pn_type); + qdf_mem_map_nbytes_single(soc->osdev, rx_tid->hw_qdesc_vaddr_unaligned, + QDF_DMA_BIDIRECTIONAL, rx_tid->hw_qdesc_alloc_size, + &(rx_tid->hw_qdesc_paddr_unaligned)); + + if (dp_reo_desc_addr_chk(rx_tid->hw_qdesc_paddr_unaligned) != + QDF_STATUS_SUCCESS) { + if (alloc_tries++ < 10) + goto try_desc_alloc; + else { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "%s: Rx tid HW desc alloc failed (lowmem): tid %d\n", + __func__, tid); + return QDF_STATUS_E_NOMEM; + } + } + + rx_tid->hw_qdesc_paddr = rx_tid->hw_qdesc_paddr_unaligned + + ((unsigned long)hw_qdesc_vaddr - + (unsigned long)(rx_tid->hw_qdesc_vaddr_unaligned)); + + if (soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup) { soc->cdp_soc.ol_ops->peer_rx_reorder_queue_setup( vdev->pdev->osif_pdev, @@ -944,7 +970,7 @@ int dp_delba_process_wifi3(void *peer_handle, * replace with a new one without queue extenstion descript to save * memory */ - dp_rx_tid_update_wifi3(peer, tid, 0, 0); + dp_rx_tid_update_wifi3(peer, tid, 1, 0); rx_tid->ba_status = DP_RX_BA_INACTIVE; diff --git a/hal/wifi3.0/hal_reo.c b/hal/wifi3.0/hal_reo.c index 4e8a195b5c..5412e6f03e 100644 --- a/hal/wifi3.0/hal_reo.c +++ b/hal/wifi3.0/hal_reo.c @@ -481,8 +481,11 @@ inline int hal_reo_cmd_update_rx_queue(void *reo_ring, struct hal_soc *soc, HAL_DESC_SET_FIELD(reo_desc, REO_UPDATE_RX_REO_QUEUE_3, IGNORE_AMPDU_FLAG, p->ignore_ampdu); + if (p->ba_window_size < 1) + p->ba_window_size = 1; + HAL_DESC_SET_FIELD(reo_desc, REO_UPDATE_RX_REO_QUEUE_4, - BA_WINDOW_SIZE, p->ba_window_size); + BA_WINDOW_SIZE, p->ba_window_size - 1); HAL_DESC_SET_FIELD(reo_desc, REO_UPDATE_RX_REO_QUEUE_4, PN_SIZE, p->pn_size); diff --git a/hal/wifi3.0/hal_rx.c b/hal/wifi3.0/hal_rx.c index c3170c0174..f5795b9284 100644 --- a/hal/wifi3.0/hal_rx.c +++ b/hal/wifi3.0/hal_rx.c @@ -136,6 +136,9 @@ void hal_reo_qdesc_setup(void *hal_soc, int tid, uint32_t ba_window_size, reg_val = TID_TO_WME_AC(tid); HAL_DESC_SET_FIELD(reo_queue_desc, RX_REO_QUEUE_2, AC, reg_val); + if (ba_window_size < 1) + ba_window_size = 1; + /* Set RTY bit for non-BA case. Duplicate detection is currently not * done by HW in non-BA case if RTY bit is not set. * TODO: This is a temporary War and should be removed once HW fix is diff --git a/qdf/inc/qdf_mem.h b/qdf/inc/qdf_mem.h index 01cfe27876..0764188216 100644 --- a/qdf/inc/qdf_mem.h +++ b/qdf/inc/qdf_mem.h @@ -210,7 +210,7 @@ static inline uint32_t qdf_mem_map_nbytes_single(qdf_device_t osdev, void *buf, * Return: none */ static inline void qdf_mem_unmap_nbytes_single(qdf_device_t osdev, - uint32_t phy_addr, + qdf_dma_addr_t phy_addr, qdf_dma_dir_t dir, int nbytes) { diff --git a/qdf/linux/src/i_qdf_mem.h b/qdf/linux/src/i_qdf_mem.h index 712a4de2d9..ac591785c9 100644 --- a/qdf/linux/src/i_qdf_mem.h +++ b/qdf/linux/src/i_qdf_mem.h @@ -160,7 +160,7 @@ static inline uint32_t __qdf_mem_map_nbytes_single(qdf_device_t osdev, * @return - none */ static inline void __qdf_mem_unmap_nbytes_single(qdf_device_t osdev, - uint32_t phy_addr, + qdf_dma_addr_t phy_addr, qdf_dma_dir_t dir, int nbytes) { dma_unmap_single(osdev->dev, phy_addr, nbytes, dir);