From acc1ea0d14fc2392219d3a18a9e938a13cb65129 Mon Sep 17 00:00:00 2001 From: Yeshwanth Sriram Guntuka Date: Sat, 8 Aug 2020 20:41:35 +0530 Subject: [PATCH] qcacmn: Break from the desc_freelist loop on REO cmd enqueue failure UPDATE_RX_REO_QUEUE commands are queued in the REO_CMD ring as part of peer cleanup for each tid. The cb registered defers pocessing the entries in the reo_desc_freelist based on either number of pending entries or time threshold. In the scenario when these entries from the freelist are processed as part of next disconnection and if the REO_CMD enqueue fails, the while loop over reo_desc_freelist does not exit and will end up in a perpetual loop. Fix is to break from the desc_freelist loop on REO cmd enqueue failure. Change-Id: I18ee31ec6a6150cd6952903cc154634b7de4ce60 CRs-Fixed: 2751223 --- dp/wifi3.0/dp_peer.c | 54 ++++++++++++++++++++++++++++++------------- dp/wifi3.0/dp_types.h | 1 + 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/dp/wifi3.0/dp_peer.c b/dp/wifi3.0/dp_peer.c index 9097371edf..741be6263c 100644 --- a/dp/wifi3.0/dp_peer.c +++ b/dp/wifi3.0/dp_peer.c @@ -2329,10 +2329,13 @@ static inline void dp_reo_limit_clean_batch_sz(uint32_t *list_size) * @desc: desc with resend update cmd flag set * @rx_tid: Desc RX tid associated with update cmd for resetting * valid field to 0 in h/w + * + * Return: QDF status */ -static void dp_resend_update_reo_cmd(struct dp_soc *soc, - struct reo_desc_list_node *desc, - struct dp_rx_tid *rx_tid) +static QDF_STATUS +dp_resend_update_reo_cmd(struct dp_soc *soc, + struct reo_desc_list_node *desc, + struct dp_rx_tid *rx_tid) { struct hal_reo_cmd_params params; @@ -2361,7 +2364,10 @@ static void dp_resend_update_reo_cmd(struct dp_soc *soc, (qdf_list_node_t *)desc); dp_err_log("failed to send reo cmd CMD_UPDATE_RX_REO_QUEUE"); DP_STATS_INC(soc, rx.err.reo_cmd_send_fail, 1); + return QDF_STATUS_E_FAILURE; } + + return QDF_STATUS_SUCCESS; } /* @@ -2382,6 +2388,7 @@ void dp_rx_tid_delete_cb(struct dp_soc *soc, void *cb_ctxt, unsigned long curr_ts = qdf_get_system_timestamp(); uint32_t desc_size, tot_desc_size; struct hal_reo_cmd_params params; + bool flush_failure = false; if (reo_status->rx_queue_status.header.status == HAL_REO_CMD_DRAIN) { qdf_mem_zero(reo_status, sizeof(*reo_status)); @@ -2392,11 +2399,10 @@ void dp_rx_tid_delete_cb(struct dp_soc *soc, void *cb_ctxt, } else if (reo_status->rx_queue_status.header.status != HAL_REO_CMD_SUCCESS) { /* Should not happen normally. Just print error for now */ - QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, - "%s: Rx tid HW desc deletion failed(%d): tid %d", - __func__, - reo_status->rx_queue_status.header.status, - freedesc->rx_tid.tid); + dp_info_rl("%s: Rx tid HW desc deletion failed(%d): tid %d", + __func__, + reo_status->rx_queue_status.header.status, + freedesc->rx_tid.tid); } QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_LOW, @@ -2431,13 +2437,19 @@ void dp_rx_tid_delete_cb(struct dp_soc *soc, void *cb_ctxt, /* First process descs with resend_update_reo_cmd set */ if (desc->resend_update_reo_cmd) { - dp_resend_update_reo_cmd(soc, desc, rx_tid); - continue; + if (dp_resend_update_reo_cmd(soc, desc, rx_tid) != + QDF_STATUS_SUCCESS) + break; + else + continue; } /* Flush and invalidate REO descriptor from HW cache: Base and * extension descriptors should be flushed separately */ - tot_desc_size = rx_tid->hw_qdesc_alloc_size; + if (desc->pending_ext_desc_size) + tot_desc_size = desc->pending_ext_desc_size; + else + tot_desc_size = rx_tid->hw_qdesc_alloc_size; /* Get base descriptor size by passing non-qos TID */ desc_size = hal_get_reo_qdesc_size(soc->hal_soc, 0, DP_NON_QOS_TID); @@ -2456,13 +2468,22 @@ void dp_rx_tid_delete_cb(struct dp_soc *soc, void *cb_ctxt, ¶ms, NULL, NULL)) { - dp_err_rl("fail to send CMD_CACHE_FLUSH:" - "tid %d desc %pK", rx_tid->tid, - (void *)(rx_tid->hw_qdesc_paddr)); - DP_STATS_INC(soc, rx.err.reo_cmd_send_fail, 1); + dp_info_rl("fail to send CMD_CACHE_FLUSH:" + "tid %d desc %pK", rx_tid->tid, + (void *)(rx_tid->hw_qdesc_paddr)); + desc->pending_ext_desc_size = tot_desc_size + + desc_size; + dp_reo_desc_clean_up(soc, desc, reo_status); + flush_failure = true; + break; } } + if (flush_failure) + break; + else + desc->pending_ext_desc_size = desc_size; + /* Flush base descriptor */ qdf_mem_zero(¶ms, sizeof(params)); params.std.need_status = 1; @@ -2486,10 +2507,11 @@ void dp_rx_tid_delete_cb(struct dp_soc *soc, void *cb_ctxt, * In case of MCL path add the desc back to the free * desc list and defer deletion. */ - dp_err_log("%s: fail to send REO cmd to flush cache: tid %d", + dp_info_rl("%s: fail to send REO cmd to flush cache: tid %d", __func__, rx_tid->tid); dp_reo_desc_clean_up(soc, desc, &reo_status); DP_STATS_INC(soc, rx.err.reo_cmd_send_fail, 1); + break; } } qdf_spin_unlock_bh(&soc->reo_desc_freelist_lock); diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index eaa833a300..fe568cc93f 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -721,6 +721,7 @@ struct reo_desc_list_node { unsigned long free_ts; struct dp_rx_tid rx_tid; bool resend_update_reo_cmd; + uint32_t pending_ext_desc_size; }; #ifdef WLAN_FEATURE_DP_EVENT_HISTORY