diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index e9a0b72c8858..ccec8eab0bb2 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -1117,6 +1117,30 @@ static void dp_pdev_detach_wifi3(struct cdp_pdev *txrx_pdev, int force) qdf_mem_free(pdev); } +/* + * dp_reo_desc_freelist_destroy() - Flush REO descriptors from deferred freelist + * @soc: DP SOC handle + */ +static inline void dp_reo_desc_freelist_destroy(struct dp_soc *soc) +{ + struct reo_desc_list_node *desc; + struct dp_rx_tid *rx_tid; + + qdf_spin_lock_bh(&soc->reo_desc_freelist_lock); + 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_free(desc); + } + qdf_spin_unlock_bh(&soc->reo_desc_freelist_lock); + qdf_list_destroy(&soc->reo_desc_freelist); + qdf_spinlock_destroy(&soc->reo_desc_freelist_lock); +} + /* * dp_soc_detach_wifi3() - Detach txrx SOC * @txrx_soc: DP SOC handle @@ -1190,10 +1214,13 @@ static void dp_soc_detach_wifi3(void *txrx_soc) /* REO command and status rings */ dp_srng_cleanup(soc, &soc->reo_cmd_ring, REO_CMD, 0); dp_srng_cleanup(soc, &soc->reo_status_ring, REO_STATUS, 0); + qdf_spinlock_destroy(&soc->rx.reo_cmd_lock); qdf_spinlock_destroy(&soc->peer_ref_mutex); htt_soc_detach(soc->htt_handle); + + dp_reo_desc_freelist_destroy(soc); } /* @@ -1994,6 +2021,9 @@ void *dp_soc_attach_wifi3(void *osif_soc, void *hif_handle, goto fail2; } + qdf_spinlock_create(&soc->reo_desc_freelist_lock); + qdf_list_create(&soc->reo_desc_freelist, REO_DESC_FREELIST_SIZE); + return (void *)soc; fail2: diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index c74a0f247372..43c8c6598f04 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -491,6 +491,53 @@ static int dp_rx_tid_update_wifi3(struct dp_peer *peer, int tid, uint32_t return 0; } +/* + * dp_reo_desc_free() - Add reo descriptor to deferred freelist and free any + * aged out descriptors + * + * @soc: DP SOC handle + * @freedesc: REO descriptor to be freed + */ +static void dp_reo_desc_free(struct dp_soc *soc, + struct reo_desc_list_node *freedesc) +{ + uint32_t list_size; + struct reo_desc_list_node *desc; + unsigned long curr_ts = qdf_get_system_timestamp(); + + qdf_spin_lock_bh(&soc->reo_desc_freelist_lock); + freedesc->free_ts = curr_ts; + qdf_list_insert_back_size(&soc->reo_desc_freelist, + (qdf_list_node_t *)freedesc, &list_size); + + while ((qdf_list_peek_front(&soc->reo_desc_freelist, + (qdf_list_node_t **)&desc) == QDF_STATUS_SUCCESS) && + ((list_size >= REO_DESC_FREELIST_SIZE) || + ((curr_ts - desc->free_ts) > REO_DESC_FREE_DEFER_MS))) { + struct dp_rx_tid *rx_tid; + + qdf_list_remove_front(&soc->reo_desc_freelist, + (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_free(desc); + + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_DEBUG, + "%s: Freed: %p\n", + __func__, desc); + } + qdf_spin_unlock_bh(&soc->reo_desc_freelist_lock); +} + /* * dp_rx_tid_setup_wifi3() – Setup receive TID state * @peer: Datapath peer handle @@ -533,6 +580,7 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, hw_qdesc_size = hal_get_reo_qdesc_size(soc->hal_soc, ba_window_size); #endif + hw_qdesc_align = hal_get_reo_qdesc_align(soc->hal_soc); /* To avoid unnecessary extra allocation for alignment, try allocating * exact size and see if we already have aligned address. @@ -626,7 +674,8 @@ int dp_rx_tid_setup_wifi3(struct dp_peer *peer, int tid, static void dp_rx_tid_delete_cb(struct dp_soc *soc, void *cb_ctxt, union hal_reo_status *reo_status) { - struct dp_rx_tid *rx_tid = (struct dp_rx_tid *)cb_ctxt; + struct reo_desc_list_node *freedesc = + (struct reo_desc_list_node *)cb_ctxt; if (reo_status->rx_queue_status.header.status) { /* Should not happen normally. Just print error for now */ @@ -634,24 +683,15 @@ static void dp_rx_tid_delete_cb(struct dp_soc *soc, void *cb_ctxt, "%s: Rx tid HW desc deletion failed(%d): tid %d\n", __func__, reo_status->rx_queue_status.header.status, - rx_tid->tid); + freedesc->rx_tid.tid); } QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, "%s: rx_tid: %d status: %d\n", __func__, - rx_tid->tid, reo_status->rx_queue_status.header.status); + freedesc->rx_tid.tid, + reo_status->rx_queue_status.header.status); - /* 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_free(rx_tid); + dp_reo_desc_free(soc, freedesc); } /* @@ -666,29 +706,40 @@ static int dp_rx_tid_delete_wifi3(struct dp_peer *peer, int tid) struct dp_rx_tid *rx_tid = &(peer->rx_tid[tid]); struct dp_soc *soc = peer->vdev->pdev->soc; struct hal_reo_cmd_params params; - struct dp_rx_tid *rx_tid_copy = qdf_mem_malloc(sizeof(*rx_tid_copy)); - if (!rx_tid_copy) { + struct reo_desc_list_node *freedesc = + qdf_mem_malloc(sizeof(*freedesc)); + if (!freedesc) { QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, - "%s: malloc failed for rx_tid_copy: tid %d\n", - __func__, rx_tid->tid); + "%s: malloc failed for freedesc: tid %d\n", + __func__, tid); return -ENOMEM; } - *rx_tid_copy = *rx_tid; + freedesc->rx_tid = *rx_tid; qdf_mem_zero(¶ms, sizeof(params)); - params.std.need_status = 1; + params.std.need_status = 0; params.std.addr_lo = rx_tid->hw_qdesc_paddr & 0xffffffff; params.std.addr_hi = (uint64_t)(rx_tid->hw_qdesc_paddr) >> 32; params.u.upd_queue_params.update_vld = 1; params.u.upd_queue_params.vld = 0; + dp_reo_send_cmd(soc, CMD_UPDATE_RX_REO_QUEUE, ¶ms, NULL, NULL); + + /* Flush and invalidate the REO descriptor from HW cache */ + qdf_mem_zero(¶ms, sizeof(params)); + params.std.need_status = 1; + params.std.addr_lo = rx_tid->hw_qdesc_paddr & 0xffffffff; + params.std.addr_hi = (uint64_t)(rx_tid->hw_qdesc_paddr) >> 32; + + dp_reo_send_cmd(soc, CMD_FLUSH_CACHE, ¶ms, dp_rx_tid_delete_cb, + (void *)freedesc); + rx_tid->hw_qdesc_vaddr_unaligned = NULL; rx_tid->hw_qdesc_alloc_size = 0; + rx_tid->hw_qdesc_paddr = 0; - dp_reo_send_cmd(soc, CMD_UPDATE_RX_REO_QUEUE, ¶ms, - dp_rx_tid_delete_cb, (void *)rx_tid_copy); return 0; } diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index e5074e31301f..1d0c5f3b390c 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -271,6 +272,14 @@ struct dp_intr { to get DMA ring handles */ }; +#define REO_DESC_FREELIST_SIZE 64 +#define REO_DESC_FREE_DEFER_MS 1000 +struct reo_desc_list_node { + qdf_list_node_t node; + unsigned long free_ts; + struct dp_rx_tid rx_tid; +}; + /* SOC level structure for data path */ struct dp_soc { /* Common base structure - Should be the first member */ @@ -460,6 +469,8 @@ struct dp_soc { /*interrupt timer*/ qdf_timer_t int_timer; #endif + qdf_list_t reo_desc_freelist; + qdf_spinlock_t reo_desc_freelist_lock; }; #define MAX_RX_MAC_RINGS 2