qcacmn: Add history to track the entries in rx rings
The rx rings are relatively of smaller size. Any duplicate entry sent by hardware cannot be back-tracked by just looking at the ring contents alone. Hence add a history to track the entries for the REO2SW, REO exception and SW2REO ring. Change-Id: I9b0b311950d60a9421378ce0fcc0535be450f713 CRs-Fixed: 2739181
Šī revīzija ir iekļauta:

revīziju iesūtīja
snandini

vecāks
bc798a3c5c
revīzija
9beeaa95a7
@@ -2242,6 +2242,24 @@ void dp_set_max_page_size(struct qdf_mem_multi_page_t *pages,
|
||||
}
|
||||
#endif /* MAX_ALLOC_PAGE_SIZE */
|
||||
|
||||
/**
|
||||
* dp_history_get_next_index() - get the next entry to record an entry
|
||||
* in the history.
|
||||
* @curr_idx: Current index where the last entry is written.
|
||||
* @max_entries: Max number of entries in the history
|
||||
*
|
||||
* This function assumes that the max number os entries is a power of 2.
|
||||
*
|
||||
* Returns: The index where the next entry is to be written.
|
||||
*/
|
||||
static inline uint32_t dp_history_get_next_index(qdf_atomic_t *curr_idx,
|
||||
uint32_t max_entries)
|
||||
{
|
||||
uint32_t idx = qdf_atomic_inc_return(curr_idx);
|
||||
|
||||
return idx & (max_entries - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* dp_rx_skip_tlvs() - Skip TLVs len + L2 hdr_offset, save in nbuf->cb
|
||||
* @nbuf: nbuf cb to be updated
|
||||
|
@@ -3827,6 +3827,63 @@ static QDF_STATUS dp_htt_ppdu_stats_attach(struct dp_pdev *pdev)
|
||||
return QDF_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY
|
||||
/**
|
||||
* dp_soc_rx_history_attach() - Attach the ring history record buffers
|
||||
* @soc: DP soc structure
|
||||
*
|
||||
* This function allocates the memory for recording the rx ring, rx error
|
||||
* ring and the reinject ring entries. There is no error returned in case
|
||||
* of allocation failure since the record function checks if the history is
|
||||
* initialized or not. We do not want to fail the driver load in case of
|
||||
* failure to allocate memory for debug history.
|
||||
*
|
||||
* Returns: None
|
||||
*/
|
||||
static void dp_soc_rx_history_attach(struct dp_soc *soc)
|
||||
{
|
||||
int i;
|
||||
uint32_t rx_ring_hist_size;
|
||||
uint32_t rx_err_ring_hist_size;
|
||||
uint32_t rx_reinject_hist_size;
|
||||
|
||||
rx_ring_hist_size = sizeof(*soc->rx_ring_history[i]);
|
||||
rx_err_ring_hist_size = sizeof(*soc->rx_err_ring_history);
|
||||
rx_reinject_hist_size = sizeof(*soc->rx_reinject_ring_history);
|
||||
|
||||
for (i = 0; i < MAX_REO_DEST_RINGS; i++) {
|
||||
soc->rx_ring_history[i] = qdf_mem_malloc(rx_ring_hist_size);
|
||||
qdf_atomic_init(&soc->rx_ring_history[i]->index);
|
||||
}
|
||||
|
||||
soc->rx_err_ring_history = qdf_mem_malloc(rx_err_ring_hist_size);
|
||||
qdf_atomic_init(&soc->rx_err_ring_history->index);
|
||||
|
||||
soc->rx_reinject_ring_history = qdf_mem_malloc(rx_reinject_hist_size);
|
||||
qdf_atomic_init(&soc->rx_reinject_ring_history->index);
|
||||
}
|
||||
|
||||
static void dp_soc_rx_history_detach(struct dp_soc *soc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_REO_DEST_RINGS; i++)
|
||||
qdf_mem_free(soc->rx_ring_history[i]);
|
||||
|
||||
qdf_mem_free(soc->rx_err_ring_history);
|
||||
qdf_mem_free(soc->rx_reinject_ring_history);
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void dp_soc_rx_history_attach(struct dp_soc *soc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void dp_soc_rx_history_detach(struct dp_soc *soc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* dp_pdev_attach_wifi3() - attach txrx pdev
|
||||
* @txrx_soc: Datapath SOC handle
|
||||
@@ -4327,6 +4384,7 @@ static void dp_soc_detach(struct cdp_soc_t *txrx_soc)
|
||||
dp_hw_link_desc_ring_free(soc);
|
||||
dp_hw_link_desc_pool_banks_free(soc, WLAN_INVALID_PDEV_ID);
|
||||
wlan_cfg_soc_detach(soc->wlan_cfg_ctx);
|
||||
dp_soc_rx_history_detach(soc);
|
||||
|
||||
qdf_mem_free(soc);
|
||||
}
|
||||
@@ -10922,6 +10980,7 @@ dp_soc_attach(struct cdp_ctrl_objmgr_psoc *ctrl_psoc,
|
||||
/* Reset wbm sg list and flags */
|
||||
dp_rx_wbm_sg_list_reset(soc);
|
||||
|
||||
dp_soc_rx_history_attach(soc);
|
||||
wlan_set_srng_cfg(&soc->wlan_srng_cfg);
|
||||
soc->wlan_cfg_ctx = wlan_cfg_soc_attach(soc->ctrl_psoc);
|
||||
if (!soc->wlan_cfg_ctx) {
|
||||
|
@@ -1948,6 +1948,49 @@ bool dp_rx_is_raw_frame_dropped(qdf_nbuf_t nbuf)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY
|
||||
/**
|
||||
* dp_rx_ring_record_entry() - Record an entry into the rx ring history.
|
||||
* @soc: Datapath soc structure
|
||||
* @ring_num: REO ring number
|
||||
* @ring_desc: REO ring descriptor
|
||||
*
|
||||
* Returns: None
|
||||
*/
|
||||
static inline void
|
||||
dp_rx_ring_record_entry(struct dp_soc *soc, uint8_t ring_num,
|
||||
hal_ring_desc_t ring_desc)
|
||||
{
|
||||
struct dp_buf_info_record *record;
|
||||
uint8_t rbm;
|
||||
struct hal_buf_info hbi;
|
||||
uint32_t idx;
|
||||
|
||||
if (qdf_unlikely(!&soc->rx_ring_history[ring_num]))
|
||||
return;
|
||||
|
||||
hal_rx_reo_buf_paddr_get(ring_desc, &hbi);
|
||||
rbm = hal_rx_ret_buf_manager_get(ring_desc);
|
||||
|
||||
idx = dp_history_get_next_index(&soc->rx_ring_history[ring_num]->index,
|
||||
DP_RX_HIST_MAX);
|
||||
|
||||
/* No NULL check needed for record since its an array */
|
||||
record = &soc->rx_ring_history[ring_num]->entry[idx];
|
||||
|
||||
record->timestamp = qdf_get_log_timestamp();
|
||||
record->hbi.paddr = hbi.paddr;
|
||||
record->hbi.sw_cookie = hbi.sw_cookie;
|
||||
record->hbi.rbm = rbm;
|
||||
}
|
||||
#else
|
||||
static inline void
|
||||
dp_rx_ring_record_entry(struct dp_soc *soc, uint8_t ring_num,
|
||||
hal_ring_desc_t ring_desc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dp_rx_process() - Brain of the Rx processing functionality
|
||||
* Called from the bottom half (tasklet/NET_RX_SOFTIRQ)
|
||||
@@ -2071,6 +2114,7 @@ more_data:
|
||||
qdf_assert(0);
|
||||
}
|
||||
|
||||
dp_rx_ring_record_entry(soc, reo_ring_num, ring_desc);
|
||||
rx_buf_cookie = HAL_RX_REO_BUF_COOKIE_GET(ring_desc);
|
||||
status = dp_rx_cookie_check_and_invalidate(ring_desc);
|
||||
if (qdf_unlikely(QDF_IS_STATUS_ERROR(status))) {
|
||||
|
@@ -1000,6 +1000,45 @@ dp_rx_defrag_nwifi_to_8023(struct dp_soc *soc,
|
||||
qdf_mem_free(rx_desc_info);
|
||||
}
|
||||
|
||||
#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY
|
||||
/**
|
||||
* dp_rx_reinject_ring_record_entry() - Record reinject ring history
|
||||
* @soc: Datapath soc structure
|
||||
* @paddr: paddr of the buffer reinjected to SW2REO ring
|
||||
* @sw_cookie: SW cookie of the buffer reinjected to SW2REO ring
|
||||
* @rbm: Return buffer manager of the buffer reinjected to SW2REO ring
|
||||
*
|
||||
* Returns: None
|
||||
*/
|
||||
static inline void
|
||||
dp_rx_reinject_ring_record_entry(struct dp_soc *soc, uint64_t paddr,
|
||||
uint32_t sw_cookie, uint8_t rbm)
|
||||
{
|
||||
struct dp_buf_info_record *record;
|
||||
uint32_t idx;
|
||||
|
||||
if (qdf_unlikely(soc->rx_reinject_ring_history))
|
||||
return;
|
||||
|
||||
idx = dp_history_get_next_index(&soc->rx_reinject_ring_history->index,
|
||||
DP_RX_REINJECT_HIST_MAX);
|
||||
|
||||
/* No NULL check needed for record since its an array */
|
||||
record = &soc->rx_reinject_ring_history->entry[idx];
|
||||
|
||||
record->timestamp = qdf_get_log_timestamp();
|
||||
record->hbi.paddr = paddr;
|
||||
record->hbi.sw_cookie = sw_cookie;
|
||||
record->hbi.rbm = rbm;
|
||||
}
|
||||
#else
|
||||
static inline void
|
||||
dp_rx_reinject_ring_record_entry(struct dp_soc *soc, uint64_t paddr,
|
||||
uint32_t sw_cookie, uint8_t rbm)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* dp_rx_defrag_reo_reinject(): Reinject the fragment chain back into REO
|
||||
* @peer: Pointer to the peer
|
||||
@@ -1136,6 +1175,7 @@ static QDF_STATUS dp_rx_defrag_reo_reinject(struct dp_peer *peer,
|
||||
return QDF_STATUS_E_FAILURE;
|
||||
}
|
||||
|
||||
dp_rx_reinject_ring_record_entry(soc, paddr, cookie, DP_DEFRAG_RBM);
|
||||
paddr = (uint64_t)buf_info.paddr;
|
||||
/* buf addr */
|
||||
hal_rxdma_buff_addr_info_set(ent_ring_desc, paddr,
|
||||
|
@@ -1436,6 +1436,45 @@ dp_rx_link_cookie_invalidate(hal_ring_desc_t ring_desc)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WLAN_FEATURE_DP_RX_RING_HISTORY
|
||||
/**
|
||||
* dp_rx_err_ring_record_entry() - Record rx err ring history
|
||||
* @soc: Datapath soc structure
|
||||
* @paddr: paddr of the buffer in RX err ring
|
||||
* @sw_cookie: SW cookie of the buffer in RX err ring
|
||||
* @rbm: Return buffer manager of the buffer in RX err ring
|
||||
*
|
||||
* Returns: None
|
||||
*/
|
||||
static inline void
|
||||
dp_rx_err_ring_record_entry(struct dp_soc *soc, uint64_t paddr,
|
||||
uint32_t sw_cookie, uint8_t rbm)
|
||||
{
|
||||
struct dp_buf_info_record *record;
|
||||
uint32_t idx;
|
||||
|
||||
if (qdf_unlikely(soc->rx_err_ring_history))
|
||||
return;
|
||||
|
||||
idx = dp_history_get_next_index(&soc->rx_err_ring_history->index,
|
||||
DP_RX_ERR_HIST_MAX);
|
||||
|
||||
/* No NULL check needed for record since its an array */
|
||||
record = &soc->rx_err_ring_history->entry[idx];
|
||||
|
||||
record->timestamp = qdf_get_log_timestamp();
|
||||
record->hbi.paddr = paddr;
|
||||
record->hbi.sw_cookie = sw_cookie;
|
||||
record->hbi.rbm = rbm;
|
||||
}
|
||||
#else
|
||||
static inline void
|
||||
dp_rx_err_ring_record_entry(struct dp_soc *soc, uint64_t paddr,
|
||||
uint32_t sw_cookie, uint8_t rbm)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t
|
||||
dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
|
||||
hal_ring_handle_t hal_ring_hdl, uint32_t quota)
|
||||
@@ -1519,7 +1558,9 @@ dp_rx_err_process(struct dp_intr *int_ctx, struct dp_soc *soc,
|
||||
link_desc_va = dp_rx_cookie_2_link_desc_va(soc, &hbi);
|
||||
hal_rx_msdu_list_get(soc->hal_soc, link_desc_va, &msdu_list,
|
||||
&num_msdus);
|
||||
|
||||
dp_rx_err_ring_record_entry(soc, msdu_list.paddr[0],
|
||||
msdu_list.sw_cookie[0],
|
||||
msdu_list.rbm[0]);
|
||||
if (qdf_unlikely((msdu_list.rbm[0] != DP_WBM2SW_RBM) &&
|
||||
(msdu_list.rbm[0] !=
|
||||
HAL_RX_BUF_RBM_WBM_IDLE_DESC_LIST) &&
|
||||
|
@@ -975,6 +975,61 @@ struct rx_buff_pool {
|
||||
bool is_initialized;
|
||||
};
|
||||
|
||||
/*
|
||||
* The logic for get current index of these history is dependent on this
|
||||
* value being power of 2.
|
||||
*/
|
||||
#define DP_RX_HIST_MAX 2048
|
||||
#define DP_RX_ERR_HIST_MAX 4096
|
||||
#define DP_RX_REINJECT_HIST_MAX 1024
|
||||
|
||||
QDF_COMPILE_TIME_ASSERT(rx_history_size,
|
||||
(DP_RX_HIST_MAX &
|
||||
(DP_RX_HIST_MAX - 1)) == 0);
|
||||
QDF_COMPILE_TIME_ASSERT(rx_err_history_size,
|
||||
(DP_RX_ERR_HIST_MAX &
|
||||
(DP_RX_ERR_HIST_MAX - 1)) == 0);
|
||||
QDF_COMPILE_TIME_ASSERT(rx_reinject_history_size,
|
||||
(DP_RX_REINJECT_HIST_MAX &
|
||||
(DP_RX_REINJECT_HIST_MAX - 1)) == 0);
|
||||
|
||||
/**
|
||||
* struct dp_buf_info_record - ring buffer info
|
||||
* @hbi: HW ring buffer info
|
||||
* @timestamp: timestamp when this entry was recorded
|
||||
*/
|
||||
struct dp_buf_info_record {
|
||||
struct hal_buf_info hbi;
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
/* struct dp_rx_history - rx ring hisotry
|
||||
* @index: Index where the last entry is written
|
||||
* @entry: history entries
|
||||
*/
|
||||
struct dp_rx_history {
|
||||
qdf_atomic_t index;
|
||||
struct dp_buf_info_record entry[DP_RX_HIST_MAX];
|
||||
};
|
||||
|
||||
/* struct dp_rx_err_history - rx err ring hisotry
|
||||
* @index: Index where the last entry is written
|
||||
* @entry: history entries
|
||||
*/
|
||||
struct dp_rx_err_history {
|
||||
qdf_atomic_t index;
|
||||
struct dp_buf_info_record entry[DP_RX_ERR_HIST_MAX];
|
||||
};
|
||||
|
||||
/* struct dp_rx_reinject_history - rx reinject ring hisotry
|
||||
* @index: Index where the last entry is written
|
||||
* @entry: history entries
|
||||
*/
|
||||
struct dp_rx_reinject_history {
|
||||
qdf_atomic_t index;
|
||||
struct dp_buf_info_record entry[DP_RX_REINJECT_HIST_MAX];
|
||||
};
|
||||
|
||||
/* SOC level structure for data path */
|
||||
struct dp_soc {
|
||||
/**
|
||||
@@ -1223,6 +1278,10 @@ struct dp_soc {
|
||||
TAILQ_HEAD(, dp_ast_entry) * bins;
|
||||
} ast_hash;
|
||||
|
||||
struct dp_rx_history *rx_ring_history[MAX_REO_DEST_RINGS];
|
||||
struct dp_rx_err_history *rx_err_ring_history;
|
||||
struct dp_rx_reinject_history *rx_reinject_ring_history;
|
||||
|
||||
qdf_spinlock_t ast_lock;
|
||||
/*Timer for AST entry ageout maintainance */
|
||||
qdf_timer_t ast_aging_timer;
|
||||
|
Atsaukties uz šo jaunā problēmā
Block a user