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
This commit is contained in:
Mohit Khanna 2018-11-28 14:22:48 -08:00 • committed by nshrivas
commit e5a6e94464
13 changed files with 761 additions and 142 deletions

View file

@ -204,6 +204,7 @@ enum htt_cmn_dbg_stats_type {
* @TXRX_SOC_CFG_PARAMS: Print soc cfg params info
* @TXRX_PDEV_CFG_PARAMS: Print pdev cfg params info
* @TXRX_NAPI_STATS: Print NAPI scheduling statistics
* @TXRX_SOC_INTERRUPT_STATS: Print soc interrupt stats
*/
enum cdp_host_txrx_stats {
TXRX_HOST_STATS_INVALID = -1,
@ -219,6 +220,7 @@ enum cdp_host_txrx_stats {
TXRX_SOC_CFG_PARAMS = 9,
TXRX_PDEV_CFG_PARAMS = 10,
TXRX_NAPI_STATS = 11,
TXRX_SOC_INTERRUPT_STATS = 12,
TXRX_HOST_STATS_MAX,
};
@ -1042,6 +1044,7 @@ typedef void (*data_stall_detect_cb)(struct data_stall_event_info *);
* @CDP_TXRX_STATS_28: Host Peer entry stats
* @CDP_TXRX_STATS_29: Host Soc config params info
* @CDP_TXRX_STATS_30: Host Pdev config params info
* @CDP_TXRX_STATS_31: Host DP Interrupt Stats
*/
enum cdp_stats {
CDP_TXRX_STATS_0 = 0,
@ -1075,6 +1078,7 @@ enum cdp_stats {
CDP_TXRX_STATS_28,
CDP_TXRX_STATS_29,
CDP_TXRX_STATS_30,
CDP_TXRX_STATS_31,
CDP_TXRX_STATS_HTT_MAX = 256,
CDP_TXRX_MAX_STATS = 265,
};
@ -1536,6 +1540,9 @@ struct cdp_rx_indication_msdu {
* @tx_flow_stop_queue_threshold: Value to Pause tx queues
* @tx_flow_start_queue_offset: Available Tx descriptors to unpause
* tx queue
* @tx_comp_loop_pkt_limit: Max # of packets to be processed in 1 tx comp loop
* @rx_reap_loop_pkt_limit: Max # of packets to be processed in 1 rx reap loop
* @rx_hp_oos_update_limit: Max # of HP OOS (out of sync) updates
*/
struct cdp_config_params {
unsigned int tso_enable:1;
@ -1548,6 +1555,9 @@ struct cdp_config_params {
/* Set when QCA_LL_TX_FLOW_CONTROL_V2 is enabled */
uint8_t tx_flow_stop_queue_threshold;
uint8_t tx_flow_start_queue_offset;
uint32_t tx_comp_loop_pkt_limit;
uint32_t rx_reap_loop_pkt_limit;
uint32_t rx_hp_oos_update_limit;
};

View file

@ -816,7 +816,14 @@ extern QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc,
void (*callback_fn), void *data);
extern void dp_reo_cmdlist_destroy(struct dp_soc *soc);
extern void dp_reo_status_ring_handler(struct dp_soc *soc);
/**
* dp_reo_status_ring_handler - Handler for REO Status ring
* @soc: DP Soc handle
*
* Returns: Number of descriptors reaped
*/
uint32_t dp_reo_status_ring_handler(struct dp_soc *soc);
void dp_aggregate_vdev_stats(struct dp_vdev *vdev,
struct cdp_vdev_stats *vdev_stats);
void dp_rx_tid_stats_cb(struct dp_soc *soc, void *cb_ctxt,

View file

@ -285,6 +285,7 @@ const int dp_stats_mapping_table[][STATS_TYPE_MAX] = {
{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 @@ void *hif_get_hal_handle(void *hif_handle);
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 @@ static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
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 @@ static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
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 @@ static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
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 @@ static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
/* 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 @@ static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
}
}
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 @@ static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
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 @@ static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
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 @@ static uint32_t dp_service_srngs(void *dp_ctx, uint32_t dp_budget)
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 @@ dp_print_soc_tx_stats(struct dp_soc *soc)
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_soc_rx_stats(struct dp_soc *soc)
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 @@ dp_print_host_stats(struct cdp_vdev *vdev_handle,
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 @@ static QDF_STATUS dp_txrx_dump_stats(void *psoc, uint16_t value,
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 @@ void dp_update_flow_control_parameters(struct dp_soc *soc,
}
#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 @@ QDF_STATUS dp_update_config_parameters(struct cdp_soc *psoc,
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;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016-2018 The Linux Foundation. All rights reserved.
* Copyright (c) 2016-2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -85,22 +85,24 @@ QDF_STATUS dp_reo_send_cmd(struct dp_soc *soc, enum hal_reo_cmd_type type,
return QDF_STATUS_SUCCESS;
}
void dp_reo_status_ring_handler(struct dp_soc *soc)
uint32_t dp_reo_status_ring_handler(struct dp_soc *soc)
{
uint32_t *reo_desc;
struct dp_reo_cmd_info *reo_cmd = NULL;
union hal_reo_status reo_status;
int num;
int processed_count = 0;
if (hal_srng_access_start(soc->hal_soc,
soc->reo_status_ring.hal_srng)) {
return;
return processed_count;
}
reo_desc = hal_srng_dst_get_next(soc->hal_soc,
soc->reo_status_ring.hal_srng);
while (reo_desc) {
uint16_t tlv = HAL_GET_TLV(reo_desc);
processed_count++;
switch (tlv) {
case HAL_REO_QUEUE_STATS_STATUS_TLV:
@ -173,6 +175,7 @@ next:
} /* while */
hal_srng_access_end(soc->hal_soc, soc->reo_status_ring.hal_srng);
return processed_count;
}
/**

View file

@ -1619,6 +1619,57 @@ static inline void dp_rx_desc_nbuf_sanity_check(void *ring_desc,
}
#endif
#ifdef WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT
static inline
bool dp_rx_reap_loop_pkt_limit_hit(struct dp_soc *soc, int num_reaped)
{
bool limit_hit = false;
struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx;
limit_hit =
(num_reaped >= cfg->rx_reap_loop_pkt_limit) ? true : false;
if (limit_hit)
DP_STATS_INC(soc, rx.reap_loop_pkt_limit_hit, 1)
return limit_hit;
}
static inline
bool dp_rx_hp_oos_update_limit_hit(struct dp_soc *soc, int hp_oos_updates)
{
bool limit_hit = false;
struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx;
limit_hit =
(hp_oos_updates >= cfg->rx_hp_oos_update_limit) ? true : false;
return limit_hit;
}
static inline bool dp_rx_enable_eol_data_check(struct dp_soc *soc)
{
return soc->wlan_cfg_ctx->rx_enable_eol_data_check;
}
#else
static inline
bool dp_rx_reap_loop_pkt_limit_hit(struct dp_soc *soc, int num_reaped)
{
return false;
}
static inline
bool dp_rx_hp_oos_update_limit_hit(struct dp_soc *soc, int hp_oos_updates)
{
return false;
}
static inline bool dp_rx_enable_eol_data_check(struct dp_soc *soc)
{
return false;
}
#endif /* WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT */
/**
* dp_rx_process() - Brain of the Rx processing functionality
* Called from the bottom half (tasklet/NET_RX_SOFTIRQ)
@ -1639,21 +1690,21 @@ uint32_t dp_rx_process(struct dp_intr *int_ctx, void *hal_ring,
void *ring_desc;
struct dp_rx_desc *rx_desc = NULL;
qdf_nbuf_t nbuf, next;
union dp_rx_desc_list_elem_t *head[MAX_PDEV_CNT] = { NULL };
union dp_rx_desc_list_elem_t *tail[MAX_PDEV_CNT] = { NULL };
union dp_rx_desc_list_elem_t *head[MAX_PDEV_CNT];
union dp_rx_desc_list_elem_t *tail[MAX_PDEV_CNT];
uint32_t rx_bufs_used = 0, rx_buf_cookie;
uint32_t l2_hdr_offset = 0;
uint16_t msdu_len = 0;
uint16_t peer_id;
struct dp_peer *peer = NULL;
struct dp_vdev *vdev = NULL;
struct dp_peer *peer;
struct dp_vdev *vdev;
uint32_t pkt_len = 0;
struct hal_rx_mpdu_desc_info mpdu_desc_info = { 0 };
struct hal_rx_msdu_desc_info msdu_desc_info = { 0 };
struct hal_rx_mpdu_desc_info mpdu_desc_info;
struct hal_rx_msdu_desc_info msdu_desc_info;
enum hal_reo_error_status error;
uint32_t peer_mdata;
uint8_t *rx_tlv_hdr;
uint32_t rx_bufs_reaped[MAX_PDEV_CNT] = { 0 };
uint32_t rx_bufs_reaped[MAX_PDEV_CNT];
uint8_t mac_id = 0;
struct dp_pdev *pdev;
struct dp_pdev *rx_pdev;
@ -1662,24 +1713,41 @@ uint32_t dp_rx_process(struct dp_intr *int_ctx, void *hal_ring,
struct dp_soc *soc = int_ctx->soc;
uint8_t ring_id = 0;
uint8_t core_id = 0;
qdf_nbuf_t nbuf_head = NULL;
qdf_nbuf_t nbuf_tail = NULL;
qdf_nbuf_t deliver_list_head = NULL;
qdf_nbuf_t deliver_list_tail = NULL;
int32_t tid = 0;
uint32_t dst_num_valid = 0;
struct cdp_tid_rx_stats *tid_stats;
qdf_nbuf_t nbuf_head;
qdf_nbuf_t nbuf_tail;
qdf_nbuf_t deliver_list_head;
qdf_nbuf_t deliver_list_tail;
uint32_t num_rx_bufs_reaped = 0;
uint32_t intr_id;
struct hif_opaque_softc *scn;
uint32_t hp_oos_updates = 0;
int32_t tid = 0;
DP_HIST_INIT();
/* Debug -- Remove later */
qdf_assert(soc && hal_ring);
qdf_assert_always(soc && hal_ring);
hal_soc = soc->hal_soc;
/* Debug -- Remove later */
qdf_assert(hal_soc);
qdf_assert_always(hal_soc);
hif_pm_runtime_mark_last_busy(soc->osdev->dev);
scn = soc->hif_handle;
intr_id = int_ctx->dp_intr_id;
more_data:
/* reset local variables here to be re-used in the function */
nbuf_head = NULL;
nbuf_tail = NULL;
deliver_list_head = NULL;
deliver_list_tail = NULL;
peer = NULL;
vdev = NULL;
num_rx_bufs_reaped = 0;
qdf_mem_zero(rx_bufs_reaped, sizeof(rx_bufs_reaped));
qdf_mem_zero(&mpdu_desc_info, sizeof(mpdu_desc_info));
qdf_mem_zero(&msdu_desc_info, sizeof(msdu_desc_info));
qdf_mem_zero(head, sizeof(head));
qdf_mem_zero(tail, sizeof(tail));
if (qdf_unlikely(hal_srng_access_start(hal_soc, hal_ring))) {
@ -1699,6 +1767,7 @@ uint32_t dp_rx_process(struct dp_intr *int_ctx, void *hal_ring,
* them in per vdev queue.
* Process the received pkts in a different per vdev loop.
*/
hp_oos_updates = 0;
while (qdf_likely(quota)) {
ring_desc = hal_srng_dst_get_next(hal_soc, hal_ring);
@ -1716,10 +1785,12 @@ uint32_t dp_rx_process(struct dp_intr *int_ctx, void *hal_ring,
* complete mpdu in one reap.
*/
if (qdf_unlikely(!ring_desc)) {
dst_num_valid = hal_srng_dst_num_valid(hal_soc,
hal_ring,
true);
if (dst_num_valid) {
if (dp_rx_hp_oos_update_limit_hit(soc,
hp_oos_updates)) {
break;
}
hp_oos_updates++;
if (hal_srng_dst_peek_sync(hal_soc, hal_ring)) {
DP_STATS_INC(soc, rx.hp_oos, 1);
hal_srng_access_end_unlocked(hal_soc,
hal_ring);
@ -1834,6 +1905,10 @@ uint32_t dp_rx_process(struct dp_intr *int_ctx, void *hal_ring,
dp_rx_add_to_free_desc_list(&head[rx_desc->pool_id],
&tail[rx_desc->pool_id],
rx_desc);
num_rx_bufs_reaped++;
if (dp_rx_reap_loop_pkt_limit_hit(soc, num_rx_bufs_reaped))
break;
}
done:
hal_srng_access_end(hal_soc, hal_ring);
@ -1858,6 +1933,7 @@ done:
&head[mac_id], &tail[mac_id]);
}
dp_verbose_debug("replenished %u\n", rx_bufs_reaped[0]);
/* Peer can be NULL is case of LFR */
if (qdf_likely(peer))
vdev = NULL;
@ -2069,16 +2145,6 @@ done:
dp_rx_fill_mesh_stats(vdev, nbuf, rx_tlv_hdr, peer);
}
#ifdef QCA_WIFI_NAPIER_EMULATION_DBG /* Debug code, remove later */
QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR,
"p_id %d msdu_len %d hdr_off %d",
peer_id, msdu_len, l2_hdr_offset);
print_hex_dump(KERN_ERR,
"\t Pkt Data:", DUMP_PREFIX_NONE, 32, 4,
qdf_nbuf_data(nbuf), 128, false);
#endif /* NAPIER_EMULATION */
if (qdf_likely(vdev->rx_decap_type ==
htt_cmn_pkt_type_ethernet) &&
qdf_likely(!vdev->mesh_vdev)) {
@ -2133,13 +2199,21 @@ done:
dp_peer_unref_del_find_by_id(peer);
}
/* Update histogram statistics by looping through pdev's */
DP_RX_HIST_STATS_PER_PDEV();
if (deliver_list_head)
dp_rx_deliver_to_stack(vdev, peer, deliver_list_head,
deliver_list_tail);
if (dp_rx_enable_eol_data_check(soc)) {
if (quota &&
hal_srng_dst_peek_sync_locked(soc, hal_ring)) {
DP_STATS_INC(soc, rx.hp_oos2, 1);
if (!hif_exec_should_yield(scn, intr_id))
goto more_data;
}
}
/* Update histogram statistics by looping through pdev's */
DP_RX_HIST_STATS_PER_PDEV();
return rx_bufs_used; /* Assume no scale factor for now */
}

View file

@ -3205,7 +3205,6 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc,
struct dp_peer *peer;
qdf_nbuf_t netbuf;
DP_HIST_INIT();
desc = comp_head;
while (desc) {
@ -3223,15 +3222,12 @@ dp_tx_comp_process_desc_list(struct dp_soc *soc,
if (peer)
dp_peer_unref_del_find_by_id(peer);
DP_HIST_PACKET_COUNT_INC(desc->pdev->pdev_id);
next = desc->next;
dp_tx_desc_release(desc, desc->pool_id);
desc = next;
}
DP_TX_HIST_STATS_PER_PDEV();
}
/**
@ -3342,19 +3338,41 @@ void dp_tx_process_htt_completion(struct dp_tx_desc_s *tx_desc, uint8_t *status)
}
}
/**
* dp_tx_comp_handler() - Tx completion handler
* @soc: core txrx main context
* @ring_id: completion ring id
* @quota: No. of packets/descriptors that can be serviced in one loop
*
* This function will collect hardware release ring element contents and
* handle descriptor contents. Based on contents, free packet or handle error
* conditions
*
* Return: none
*/
uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota)
#ifdef WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT
static inline
bool dp_tx_comp_loop_pkt_limit_hit(struct dp_soc *soc, int num_reaped)
{
bool limit_hit = false;
struct wlan_cfg_dp_soc_ctxt *cfg = soc->wlan_cfg_ctx;
limit_hit =
(num_reaped >= cfg->tx_comp_loop_pkt_limit) ? true : false;
if (limit_hit)
DP_STATS_INC(soc, tx.tx_comp_loop_pkt_limit_hit, 1);
return limit_hit;
}
static inline bool dp_tx_comp_enable_eol_data_check(struct dp_soc *soc)
{
return soc->wlan_cfg_ctx->tx_comp_enable_eol_data_check;
}
#else
static inline
bool dp_tx_comp_loop_pkt_limit_hit(struct dp_soc *soc, int num_reaped)
{
return false;
}
static inline bool dp_tx_comp_enable_eol_data_check(struct dp_soc *soc)
{
return false;
}
#endif
uint32_t dp_tx_comp_handler(struct dp_intr *int_ctx, struct dp_soc *soc,
void *hal_srng, uint32_t quota)
{
void *tx_comp_hal_desc;
uint8_t buffer_src;
@ -3363,9 +3381,16 @@ uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota)
struct dp_tx_desc_s *tx_desc = NULL;
struct dp_tx_desc_s *head_desc = NULL;
struct dp_tx_desc_s *tail_desc = NULL;
uint32_t num_processed;
uint32_t count;
uint32_t num_processed = 0;
uint32_t count = 0;
bool force_break = false;
DP_HIST_INIT();
more_data:
/* Re-initialize local variables to be re-used */
head_desc = NULL;
tail_desc = NULL;
if (qdf_unlikely(hal_srng_access_start(soc->hal_soc, hal_srng))) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s %d : HAL RING Access Failed -- %pK",
@ -3373,9 +3398,6 @@ uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota)
return 0;
}
num_processed = 0;
count = 0;
/* Find head descriptor from completion ring */
while (qdf_likely(tx_comp_hal_desc =
hal_srng_dst_get_next(soc->hal_soc, hal_srng))) {
@ -3466,6 +3488,8 @@ uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota)
tx_desc->next = NULL;
tail_desc = tx_desc;
DP_HIST_PACKET_COUNT_INC(tx_desc->pdev->pdev_id);
/* Collect hw completion contents */
hal_tx_comp_desc_sync(tx_comp_hal_desc,
&tx_desc->comp, 1);
@ -3478,10 +3502,15 @@ uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota)
* Processed packet count is more than given quota
* stop to processing
*/
if ((num_processed >= quota))
if (num_processed >= quota) {
force_break = true;
break;
}
count++;
if (dp_tx_comp_loop_pkt_limit_hit(soc, count))
break;
}
hal_srng_access_end(soc->hal_soc, hal_srng);
@ -3490,6 +3519,17 @@ uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota)
if (head_desc)
dp_tx_comp_process_desc_list(soc, head_desc);
if (dp_tx_comp_enable_eol_data_check(soc)) {
if (!force_break &&
hal_srng_dst_peek_sync_locked(soc, hal_srng)) {
DP_STATS_INC(soc, tx.hp_oos2, 1);
if (!hif_exec_should_yield(soc->hif_handle,
int_ctx->dp_intr_id))
goto more_data;
}
}
DP_TX_HIST_STATS_PER_PDEV();
return num_processed;
}

View file

@ -177,7 +177,21 @@ qdf_nbuf_t dp_tx_non_std(struct cdp_vdev *vdev_handle,
enum ol_tx_spec tx_spec, qdf_nbuf_t msdu_list);
#endif
uint32_t dp_tx_comp_handler(struct dp_soc *soc, void *hal_srng, uint32_t quota);
/**
* dp_tx_comp_handler() - Tx completion handler
* @int_ctx: pointer to DP interrupt context
* @soc: core txrx main context
* @ring_id: completion ring id
* @quota: No. of packets/descriptors that can be serviced in one loop
*
* This function will collect hardware release ring element contents and
* handle descriptor contents. Based on contents, free packet or handle error
* conditions
*
* Return: Number of TX completions processed
*/
uint32_t dp_tx_comp_handler(struct dp_intr *int_ctx, struct dp_soc *soc,
void *hal_srng, uint32_t quota);
QDF_STATUS
dp_tx_prepare_send_me(struct dp_vdev *vdev, qdf_nbuf_t nbuf);

View file

@ -576,6 +576,34 @@ struct dp_rx_tid {
};
/**
* struct dp_intr_stats - DP Interrupt Stats for an interrupt context
* @num_tx_ring_masks: interrupts with tx_ring_mask set
* @num_rx_ring_masks: interrupts with rx_ring_mask set
* @num_rx_mon_ring_masks: interrupts with rx_mon_ring_mask set
* @num_rx_err_ring_masks: interrupts with rx_err_ring_mask set
* @num_rx_wbm_rel_ring_masks: interrupts with rx_wbm_rel_ring_mask set
* @num_reo_status_ring_masks: interrupts with reo_status_ring_mask set
* @num_rxdma2host_ring_masks: interrupts with rxdma2host_ring_mask set
* @num_host2rxdma_ring_masks: interrupts with host2rxdma_ring_mask set
* @num_host2rxdma_ring_masks: interrupts with host2rxdma_ring_mask set
* @num_masks: total number of times the interrupt was received
*
* Counter for individual masks are incremented only if there are any packets
* on that ring.
*/
struct dp_intr_stats {
uint32_t num_tx_ring_masks[MAX_TCL_DATA_RINGS];
uint32_t num_rx_ring_masks[MAX_REO_DEST_RINGS];
uint32_t num_rx_mon_ring_masks;
uint32_t num_rx_err_ring_masks;
uint32_t num_rx_wbm_rel_ring_masks;
uint32_t num_reo_status_ring_masks;
uint32_t num_rxdma2host_ring_masks;
uint32_t num_host2rxdma_ring_masks;
uint32_t num_masks;
};
/* per interrupt context */
struct dp_intr {
uint8_t tx_ring_mask; /* WBM Tx completion rings (0-2)
@ -594,6 +622,9 @@ struct dp_intr {
to get DMA ring handles */
qdf_lro_ctx_t lro_ctx;
uint8_t dp_intr_id;
/* Interrupt Stats for individual masks */
struct dp_intr_stats intr_stats;
};
#define REO_DESC_FREELIST_SIZE 64
@ -624,6 +655,10 @@ struct dp_soc_stats {
uint32_t dropped_fw_removed;
/* tx completion release_src != TQM or FW */
uint32_t invalid_release_source;
/* TX Comp loop packet limit hit */
uint32_t tx_comp_loop_pkt_limit_hit;
/* Head pointer Out of sync at the end of dp_tx_comp_handler */
uint32_t hp_oos2;
} tx;
/* SOC level RX stats */
@ -639,8 +674,13 @@ struct dp_soc_stats {
uint32_t rx_frag_err;
/* No of reinjected packets */
uint32_t reo_reinject;
/* Head pointer Out of sync */
/* Reap loop packet limit hit */
uint32_t reap_loop_pkt_limit_hit;
/* Head pointer Out of sync during reap loop*/
uint32_t hp_oos;
/* Head pointer Out of sync at the end of dp_rx_process */
uint32_t hp_oos2;
struct {
/* Invalid RBM error count */
uint32_t invalid_rbm;