From b1ab3a694172827210d13077f13b17052b4ba1d5 Mon Sep 17 00:00:00 2001 From: Amir Date: Thu, 30 Jul 2020 15:21:03 +0530 Subject: [PATCH] qca-wifi: Add WAR to skip status ring entry STATUS_BUFFRE_DONE tlv written in first word for a status buffer indicates that DMA is done for that status ring entry. In existing implementation, for a status ring entry if STATUS_BUFFRE_DONE tlv is not written by HW, we poll on to status ring entry until DMA is done by HW. During lmac reset it may happne that HW will not write STATUS_BUFFRE_DONE tlv in status buffer, in that case we end up polling infinitely leading to backpressure on monitor status ring. As per MAC team's suggestion, when HP + 1 entry is peeked and if DMA is not done and if HP + 2 entry's DMA done is set, replenish HP + 1 entry and start processing in next interrupt. If HP + 2 entry's DMA done is not set, poll onto HP + 1 entry DMA done to be set. Change-Id: I2da5a16ec901764fcb88c417f599d7a1344bcea0 CRs-Fixed: 2744602 --- dp/wifi3.0/dp_full_mon.c | 70 ++++++++++++++++++++++++++-------------- dp/wifi3.0/dp_full_mon.h | 17 ---------- 2 files changed, 45 insertions(+), 42 deletions(-) diff --git a/dp/wifi3.0/dp_full_mon.c b/dp/wifi3.0/dp_full_mon.c index f01ff8c43e..7c8979cb53 100644 --- a/dp/wifi3.0/dp_full_mon.c +++ b/dp/wifi3.0/dp_full_mon.c @@ -62,7 +62,7 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, uint32_t tlv_tag; void *rx_tlv; struct hal_rx_ppdu_info *ppdu_info; - enum dp_mon_reap_status status = dp_mon_status_match; + enum dp_mon_reap_status status = DP_MON_STATUS_MATCH; QDF_STATUS buf_status; uint32_t ppdu_id_diff; @@ -94,7 +94,7 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, "%s %d : HAL SRNG entry is NULL srng:-- %pK", __func__, __LINE__, mon_status_srng); - status = dp_mon_status_replenish; + status = DP_MON_STATUS_REPLENISH; goto done; } @@ -109,7 +109,7 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_DEBUG, "%s %d : buf addr is NULL -- %pK", __func__, __LINE__, mon_status_srng); - status = dp_mon_status_replenish; + status = DP_MON_STATUS_REPLENISH; goto done; } @@ -135,8 +135,28 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, FL("Monitor status ring: DMA is not done " "for nbuf: %pK buf_addr: %llx"), status_nbuf, buf_paddr); - pdev->rx_mon_stats.tlv_tag_status_err++; - status = dp_mon_status_no_dma; + status = dp_rx_mon_handle_status_buf_done(pdev, + mon_status_srng); + + if (status == DP_MON_STATUS_REPLENISH) { + union dp_rx_desc_list_elem_t *desc_list = NULL; + union dp_rx_desc_list_elem_t *tail = NULL; + + /* If this is DMA not done WAR case, + * free buffer and current SW descriptor and + * make buf_addr_info NULL, so that call to + * dp_rx_mon_status_process() replenishes entry to + * status ring + */ + qdf_nbuf_free(status_nbuf); + dp_rx_add_to_free_desc_list(&desc_list, + &tail, rx_desc); + dp_rx_add_desc_list_to_free_list(soc, &desc_list, + &tail, mac_id, rx_desc_pool); + hal_rxdma_buff_addr_info_set( + ring_entry, + 0, 0, HAL_RX_BUF_RBM_SW3_BM); + } goto done; } @@ -156,22 +176,22 @@ dp_rx_mon_status_buf_validate(struct dp_pdev *pdev, } if (pdev->mon_desc->ppdu_id < pdev->mon_desc->status_ppdu_id) { - status = dp_mon_status_lead; + status = DP_MON_STATUS_LEAD; /* For wrap around case */ ppdu_id_diff = pdev->mon_desc->status_ppdu_id - pdev->mon_desc->ppdu_id; if (ppdu_id_diff > DP_RX_MON_PPDU_ID_WRAP) - status = dp_mon_status_lag; + status = DP_MON_STATUS_LAG; } else if (pdev->mon_desc->ppdu_id > pdev->mon_desc->status_ppdu_id) { - status = dp_mon_status_lag; + status = DP_MON_STATUS_LAG; /* For wrap around case */ ppdu_id_diff = pdev->mon_desc->ppdu_id - pdev->mon_desc->status_ppdu_id; if (ppdu_id_diff > DP_RX_MON_PPDU_ID_WRAP) - status = dp_mon_status_lead; + status = DP_MON_STATUS_LEAD; } if ((pdev->mon_desc->status_buf.paddr != buf_paddr) || @@ -333,14 +353,14 @@ dp_rx_mon_reap_status_ring(struct dp_soc *soc, status = dp_rx_mon_status_buf_validate(pdev, int_ctx, mac_id); switch (status) { - case dp_mon_status_no_dma: + case DP_MON_STATUS_NO_DMA: /* If DMA is not done for status ring entry, * hold on to monitor destination ring and * deliver current ppdu data once DMA is done. */ pdev->hold_mon_dest_ring = true; break; - case dp_mon_status_lag: + case DP_MON_STATUS_LAG: /* If status_ppdu_id is lagging behind destination, * a. Hold on to destination ring * b. Drop status ppdus until ppdu id matches @@ -351,7 +371,7 @@ dp_rx_mon_reap_status_ring(struct dp_soc *soc, pdev->rx_mon_stats.ppdu_id_mismatch++; pdev->rx_mon_stats.status_ppdu_drop++; break; - case dp_mon_status_lead: + case DP_MON_STATUS_LEAD: /* If status_ppdu_id is leading ahead destination, * a. Drop destination ring ppdu until ppdu_id matches * b. Unhold monitor destination ring so status ppdus @@ -364,11 +384,11 @@ dp_rx_mon_reap_status_ring(struct dp_soc *soc, pdev->rx_mon_stats.ppdu_id_mismatch++; pdev->rx_mon_stats.dest_ppdu_drop++; break; - case dp_mon_status_replenish: + case DP_MON_STATUS_REPLENISH: /* If status ring hp entry is NULL, replenish it */ work_done = dp_rx_mon_status_process(soc, int_ctx, mac_id, 1); break; - case dp_mon_status_match: + case DP_MON_STATUS_MATCH: /* If status ppdu id matches with destnation, * unhold monitor destination ring and deliver ppdu */ @@ -381,11 +401,11 @@ dp_rx_mon_reap_status_ring(struct dp_soc *soc, /* If status ring is lagging behind detination ring, * reap only one status buffer */ - if (status == dp_mon_status_lag) + if (status == DP_MON_STATUS_LAG) status_buf_count = 1; - if (status == dp_mon_status_lag || - status == dp_mon_status_match) { + if (status == DP_MON_STATUS_LAG || + status == DP_MON_STATUS_MATCH) { work_done = dp_rx_mon_status_process(soc, int_ctx, mac_id, @@ -627,14 +647,14 @@ dp_rx_mon_deliver_prev_ppdu(struct dp_pdev *pdev, status = dp_rx_mon_status_buf_validate(pdev, int_ctx, mac_id); switch (status) { - case dp_mon_status_no_dma: + case DP_MON_STATUS_NO_DMA: /* If DMA is not done for status ring entry, * hold on to monitor destination ring and * deliver current ppdu data once DMA is done. */ pdev->hold_mon_dest_ring = true; break; - case dp_mon_status_lag: + case DP_MON_STATUS_LAG: /* If status_ppdu_id is lagging behind destination, * a. Hold on to destination ring * b. Drop status ppdus until ppdu id matches @@ -645,7 +665,7 @@ dp_rx_mon_deliver_prev_ppdu(struct dp_pdev *pdev, pdev->rx_mon_stats.ppdu_id_mismatch++; pdev->rx_mon_stats.status_ppdu_drop++; break; - case dp_mon_status_lead: + case DP_MON_STATUS_LEAD: /* If status_ppdu_id is leading ahead destination, * a. Drop destination ring ppdu until ppdu_id matches * b. Unhold monitor destination ring so status ppdus @@ -658,11 +678,11 @@ dp_rx_mon_deliver_prev_ppdu(struct dp_pdev *pdev, pdev->rx_mon_stats.ppdu_id_mismatch++; pdev->rx_mon_stats.dest_ppdu_drop++; break; - case dp_mon_status_replenish: + case DP_MON_STATUS_REPLENISH: /* If status ring hp entry is NULL, replenish it */ work = dp_rx_mon_status_process(soc, int_ctx, mac_id, 1); break; - case dp_mon_status_match: + case DP_MON_STATUS_MATCH: /* If status ppdu id matches with destnation, * unhold monitor destination ring and deliver ppdu */ @@ -677,12 +697,12 @@ dp_rx_mon_deliver_prev_ppdu(struct dp_pdev *pdev, * available for radiotap construction, so return and * check for status on next interrupt */ - if ((status == dp_mon_status_no_dma) || - (status == dp_mon_status_replenish)) { + if ((status == DP_MON_STATUS_NO_DMA) || + (status == DP_MON_STATUS_REPLENISH)) { return work_done; } - if (status == dp_mon_status_lag) { + if (status == DP_MON_STATUS_LAG) { work = dp_rx_mon_status_process(soc, int_ctx, mac_id, 1); if (!work) diff --git a/dp/wifi3.0/dp_full_mon.h b/dp/wifi3.0/dp_full_mon.h index 139a0758be..d249f6e003 100644 --- a/dp/wifi3.0/dp_full_mon.h +++ b/dp/wifi3.0/dp_full_mon.h @@ -57,21 +57,4 @@ dp_rx_mon_is_rxdma_error(struct hal_rx_mon_desc_info *desc_info) } return QDF_STATUS_E_FAILURE; } - -/* - * dp_mon_reap_status - monitor status ring ppdu status - * - * dp_mon_status_no_dma - DMA not done for status ring entry - * dp_mon_status_match - status and dest ppdu id mathes - * dp_mon_status_lag - status ppdu id is lagging - * dp_mon_status_lead - status ppdu id is leading - * dp_mon_status_replenish - status ring entry is NULL - */ -enum dp_mon_reap_status { - dp_mon_status_no_dma, - dp_mon_status_match, - dp_mon_status_lag, - dp_mon_status_lead, - dp_mon_status_replenish -}; #endif /* _DP_FULL_MON_H_ */