qcacmn: Restrict RX softirq poll times
The following changes are made
-Yield dp_rx_process if poll time exceeds
-Yield dp_tx_comp_handler if poll time exceeds
-Interrupt statistics to track various interrupt contexts and
corresponding interrupt masks
-Add poll times histogram buckets to NAPI stats
Change-Id: I8c7a6bbbb97c7b3dd1dde6ac3a97113c433086a2
CRs-Fixed: 2423879
diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c
index 0c95402..1bb352b 100644
--- a/dp/wifi3.0/dp_main.c
+++ b/dp/wifi3.0/dp_main.c
@@ -285,6 +285,7 @@
{TXRX_FW_STATS_INVALID, TXRX_REO_QUEUE_STATS},
{TXRX_FW_STATS_INVALID, TXRX_SOC_CFG_PARAMS},
{TXRX_FW_STATS_INVALID, TXRX_PDEV_CFG_PARAMS},
+ {TXRX_FW_STATS_INVALID, TXRX_SOC_INTERRUPT_STATS},
};
/* MCL specific functions */
@@ -1273,6 +1274,7 @@
static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
{
struct dp_intr *int_ctx = (struct dp_intr *)dp_ctx;
+ struct dp_intr_stats *intr_stats = &int_ctx->intr_stats;
struct dp_soc *soc = int_ctx->soc;
int ring = 0;
uint32_t work_done = 0;
@@ -1286,15 +1288,27 @@
struct dp_pdev *pdev = NULL;
int mac_id;
+ dp_verbose_debug("tx %x rx %x rx_err %x rx_wbm_rel %x reo_status %x rx_mon_ring %x host2rxdma %x rxdma2host %x\n",
+ tx_mask, rx_mask, rx_err_mask, rx_wbm_rel_mask,
+ reo_status_mask,
+ int_ctx->rx_mon_ring_mask,
+ int_ctx->host2rxdma_ring_mask,
+ int_ctx->rxdma2host_ring_mask);
+
/* Process Tx completion interrupts first to return back buffers */
while (tx_mask) {
if (tx_mask & 0x1) {
- work_done = dp_tx_comp_handler(soc,
- soc->tx_comp_ring[ring].hal_srng,
- remaining_quota);
+ work_done = dp_tx_comp_handler(int_ctx,
+ soc,
+ soc->tx_comp_ring[ring].hal_srng,
+ remaining_quota);
- dp_verbose_debug("tx mask 0x%x ring %d, budget %d, work_done %d",
- tx_mask, ring, budget, work_done);
+ if (work_done) {
+ intr_stats->num_tx_ring_masks[ring]++;
+ dp_verbose_debug("tx mask 0x%x ring %d, budget %d, work_done %d",
+ tx_mask, ring, budget,
+ work_done);
+ }
budget -= work_done;
if (budget <= 0)
@@ -1306,15 +1320,17 @@
ring++;
}
-
/* Process REO Exception ring interrupt */
if (rx_err_mask) {
work_done = dp_rx_err_process(soc,
soc->reo_exception_ring.hal_srng,
remaining_quota);
- dp_verbose_debug("REO Exception Ring: work_done %d budget %d",
- work_done, budget);
+ if (work_done) {
+ intr_stats->num_rx_err_ring_masks++;
+ dp_verbose_debug("REO Exception Ring: work_done %d budget %d",
+ work_done, budget);
+ }
budget -= work_done;
if (budget <= 0) {
@@ -1328,8 +1344,11 @@
work_done = dp_rx_wbm_err_process(soc,
soc->rx_rel_ring.hal_srng, remaining_quota);
- dp_verbose_debug("WBM Release Ring: work_done %d budget %d",
- work_done, budget);
+ if (work_done) {
+ intr_stats->num_rx_wbm_rel_ring_masks++;
+ dp_verbose_debug("WBM Release Ring: work_done %d budget %d",
+ work_done, budget);
+ }
budget -= work_done;
if (budget <= 0) {
@@ -1341,16 +1360,17 @@
/* Process Rx interrupts */
if (rx_mask) {
for (ring = 0; ring < soc->num_reo_dest_rings; ring++) {
- if (rx_mask & (1 << ring)) {
- work_done = dp_rx_process(int_ctx,
- soc->reo_dest_ring[ring].hal_srng,
- ring,
- remaining_quota);
-
+ if (!(rx_mask & (1 << ring)))
+ continue;
+ work_done = dp_rx_process(int_ctx,
+ soc->reo_dest_ring[ring].hal_srng,
+ ring,
+ remaining_quota);
+ if (work_done) {
+ intr_stats->num_rx_ring_masks[ring]++;
dp_verbose_debug("rx mask 0x%x ring %d, work_done %d budget %d",
rx_mask, ring,
work_done, budget);
-
budget -= work_done;
if (budget <= 0)
goto budget_done;
@@ -1359,8 +1379,10 @@
}
}
- if (reo_status_mask)
- dp_reo_status_ring_handler(soc);
+ if (reo_status_mask) {
+ if (dp_reo_status_ring_handler(soc))
+ int_ctx->intr_stats.num_reo_status_ring_masks++;
+ }
/* Process LMAC interrupts */
for (ring = 0 ; ring < MAX_PDEV_CNT; ring++) {
@@ -1372,7 +1394,9 @@
pdev->pdev_id);
if (int_ctx->rx_mon_ring_mask & (1 << mac_for_pdev)) {
work_done = dp_mon_process(soc, mac_for_pdev,
- remaining_quota);
+ remaining_quota);
+ if (work_done)
+ intr_stats->num_rx_mon_ring_masks++;
budget -= work_done;
if (budget <= 0)
goto budget_done;
@@ -1382,8 +1406,10 @@
if (int_ctx->rxdma2host_ring_mask &
(1 << mac_for_pdev)) {
work_done = dp_rxdma_err_process(soc,
- mac_for_pdev,
- remaining_quota);
+ mac_for_pdev,
+ remaining_quota);
+ if (work_done)
+ intr_stats->num_rxdma2host_ring_masks++;
budget -= work_done;
if (budget <= 0)
goto budget_done;
@@ -1397,17 +1423,19 @@
struct dp_srng *rx_refill_buf_ring =
&pdev->rx_refill_buf_ring;
+ intr_stats->num_host2rxdma_ring_masks++;
DP_STATS_INC(pdev, replenish.low_thresh_intrs,
1);
dp_rx_buffers_replenish(soc, mac_for_pdev,
- rx_refill_buf_ring,
- &soc->rx_desc_buf[mac_for_pdev], 0,
- &desc_list, &tail);
+ rx_refill_buf_ring,
+ &soc->rx_desc_buf[mac_for_pdev],
+ 0, &desc_list, &tail);
}
}
}
qdf_lro_flush(int_ctx->lro_ctx);
+ intr_stats->num_masks++;
budget_done:
return dp_budget - budget;
@@ -6920,7 +6948,44 @@
soc->stats.tx.tcl_ring_full[2]);
DP_PRINT_STATS("Tx invalid completion release = %d",
soc->stats.tx.invalid_release_source);
+ DP_PRINT_STATS("Tx comp loop pkt limit hit = %d",
+ soc->stats.tx.tx_comp_loop_pkt_limit_hit);
+ DP_PRINT_STATS("Tx comp HP out of sync2 = %d",
+ soc->stats.tx.hp_oos2);
}
+
+/**
+ * dp_print_soc_interrupt_stats() - Print interrupt stats for the soc
+ * @soc: dp_soc handle
+ *
+ * Return: None
+ */
+static void dp_print_soc_interrupt_stats(struct dp_soc *soc)
+{
+ int i = 0;
+ struct dp_intr_stats *intr_stats;
+
+ DP_PRINT_STATS("INT: Total |txComps|reo[0] |reo[1] |reo[2] |reo[3] |mon |rx_err | wbm |reo_sta|rxdm2hst|hst2rxdm|");
+ for (i = 0; i < WLAN_CFG_INT_NUM_CONTEXTS; i++) {
+ intr_stats = &soc->intr_ctx[i].intr_stats;
+ DP_PRINT_STATS("%3u[%d]: %7u %7u %7u %7u %7u %7u %7u %7u %7u %7u %8u %8u",
+ i,
+ hif_get_int_ctx_irq_num(soc->hif_handle, i),
+ intr_stats->num_masks,
+ intr_stats->num_tx_ring_masks[0],
+ intr_stats->num_rx_ring_masks[0],
+ intr_stats->num_rx_ring_masks[1],
+ intr_stats->num_rx_ring_masks[2],
+ intr_stats->num_rx_ring_masks[3],
+ intr_stats->num_rx_mon_ring_masks,
+ intr_stats->num_rx_err_ring_masks,
+ intr_stats->num_rx_wbm_rel_ring_masks,
+ intr_stats->num_reo_status_ring_masks,
+ intr_stats->num_rxdma2host_ring_masks,
+ intr_stats->num_host2rxdma_ring_masks);
+ }
+}
+
/**
* dp_print_soc_rx_stats: Print SOC level Rx stats
* @soc: DP_SOC Handle
@@ -6962,7 +7027,11 @@
DP_PRINT_STATS("RX frags: %d", soc->stats.rx.rx_frags);
DP_PRINT_STATS("RX frag wait: %d", soc->stats.rx.rx_frag_wait);
DP_PRINT_STATS("RX frag err: %d", soc->stats.rx.rx_frag_err);
- DP_PRINT_STATS("RX HP out_of_sync: %d", soc->stats.rx.hp_oos);
+
+ DP_PRINT_STATS("RX HP out_of_sync: %d %d", soc->stats.rx.hp_oos,
+ soc->stats.rx.hp_oos2);
+ DP_PRINT_STATS("RX Reap Loop Pkt Limit Hit: %d",
+ soc->stats.rx.reap_loop_pkt_limit_hit);
DP_PRINT_STATS("RX DESC invalid magic: %u",
soc->stats.rx.err.rx_desc_invalid_magic);
DP_PRINT_STATS("RX DUP DESC: %d",
@@ -7211,6 +7280,8 @@
break;
case TXRX_NAPI_STATS:
dp_print_napi_stats(pdev->soc);
+ case TXRX_SOC_INTERRUPT_STATS:
+ dp_print_soc_interrupt_stats(pdev->soc);
break;
default:
dp_info("Wrong Input For TxRx Host Stats");
@@ -8148,6 +8219,7 @@
switch (value) {
case CDP_TXRX_PATH_STATS:
dp_txrx_path_stats(soc);
+ dp_print_soc_interrupt_stats(soc);
break;
case CDP_RX_RING_STATS:
@@ -8205,6 +8277,50 @@
}
#endif
+#ifdef WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT
+/* Max packet limit for TX Comp packet loop (dp_tx_comp_handler) */
+#define DP_TX_COMP_LOOP_PKT_LIMIT_MAX 1024
+
+/* Max packet limit for RX REAP Loop (dp_rx_process) */
+#define DP_RX_REAP_LOOP_PKT_LIMIT_MAX 1024
+
+static
+void dp_update_rx_soft_irq_limit_params(struct dp_soc *soc,
+ struct cdp_config_params *params)
+{
+ soc->wlan_cfg_ctx->tx_comp_loop_pkt_limit =
+ params->tx_comp_loop_pkt_limit;
+
+ if (params->tx_comp_loop_pkt_limit < DP_TX_COMP_LOOP_PKT_LIMIT_MAX)
+ soc->wlan_cfg_ctx->tx_comp_enable_eol_data_check = true;
+ else
+ soc->wlan_cfg_ctx->tx_comp_enable_eol_data_check = false;
+
+ soc->wlan_cfg_ctx->rx_reap_loop_pkt_limit =
+ params->rx_reap_loop_pkt_limit;
+
+ if (params->rx_reap_loop_pkt_limit < DP_RX_REAP_LOOP_PKT_LIMIT_MAX)
+ soc->wlan_cfg_ctx->rx_enable_eol_data_check = true;
+ else
+ soc->wlan_cfg_ctx->rx_enable_eol_data_check = false;
+
+ soc->wlan_cfg_ctx->rx_hp_oos_update_limit =
+ params->rx_hp_oos_update_limit;
+
+ dp_info("tx_comp_loop_pkt_limit %u tx_comp_enable_eol_data_check %u rx_reap_loop_pkt_limit %u rx_enable_eol_data_check %u rx_hp_oos_update_limit %u",
+ soc->wlan_cfg_ctx->tx_comp_loop_pkt_limit,
+ soc->wlan_cfg_ctx->tx_comp_enable_eol_data_check,
+ soc->wlan_cfg_ctx->rx_reap_loop_pkt_limit,
+ soc->wlan_cfg_ctx->rx_enable_eol_data_check,
+ soc->wlan_cfg_ctx->rx_hp_oos_update_limit);
+}
+#else
+static inline
+void dp_update_rx_soft_irq_limit_params(struct dp_soc *soc,
+ struct cdp_config_params *params)
+{ }
+#endif /* WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT */
+
/**
* dp_update_config_parameters() - API to store datapath
* config parameters
@@ -8234,6 +8350,7 @@
soc->wlan_cfg_ctx->ipa_enabled = params->ipa_enable;
soc->wlan_cfg_ctx->gro_enabled = params->gro_enable;
+ dp_update_rx_soft_irq_limit_params(soc, params);
dp_update_flow_control_parameters(soc, params);
return QDF_STATUS_SUCCESS;