qcacmn: Add support for back to back htt stats
In existing implementation when previous stats handling is under process and a new stats event is received, new stats event is dropped. Add support to queue any received stats message and process it later in work queue context. Change-Id: I7895a2f7ac49456c49374ce209da97c2148f43a2 CRs-Fixed: 2076552
This commit is contained in:
@@ -1035,7 +1035,7 @@ fail0:
|
||||
|
||||
/**
|
||||
* dp_process_htt_stat_msg(): Process the list of buffers of HTT EXT stats
|
||||
* @soc: DP SOC handle
|
||||
* @htt_stats: htt stats info
|
||||
*
|
||||
* The FW sends the HTT EXT STATS as a stream of T2H messages. Each T2H message
|
||||
* contains sub messages which are identified by a TLV header.
|
||||
@@ -1053,7 +1053,7 @@ fail0:
|
||||
*
|
||||
* return: void
|
||||
*/
|
||||
static inline void dp_process_htt_stat_msg(struct dp_soc *soc)
|
||||
static inline void dp_process_htt_stat_msg(struct htt_stats_context *htt_stats)
|
||||
{
|
||||
htt_tlv_tag_t tlv_type = 0xff;
|
||||
qdf_nbuf_t htt_msg = NULL;
|
||||
@@ -1065,12 +1065,13 @@ static inline void dp_process_htt_stat_msg(struct dp_soc *soc)
|
||||
uint32_t *tlv_start;
|
||||
|
||||
/* Process node in the HTT message queue */
|
||||
while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats_msg)) != NULL) {
|
||||
while ((htt_msg = qdf_nbuf_queue_remove(&htt_stats->msg))
|
||||
!= NULL) {
|
||||
msg_word = (uint32_t *) qdf_nbuf_data(htt_msg);
|
||||
/* read 5th word */
|
||||
msg_word = msg_word + 4;
|
||||
msg_remain_len = qdf_min(soc->htt_msg_len,
|
||||
(uint32_t)DP_EXT_MSG_LENGTH);
|
||||
msg_remain_len = qdf_min(htt_stats->msg_len,
|
||||
(uint32_t) DP_EXT_MSG_LENGTH);
|
||||
|
||||
/* Keep processing the node till node length is 0 */
|
||||
while (msg_remain_len) {
|
||||
@@ -1151,19 +1152,17 @@ static inline void dp_process_htt_stat_msg(struct dp_soc *soc)
|
||||
}
|
||||
}
|
||||
|
||||
if (soc->htt_msg_len >= DP_EXT_MSG_LENGTH) {
|
||||
soc->htt_msg_len -= DP_EXT_MSG_LENGTH;
|
||||
if (htt_stats->msg_len >= DP_EXT_MSG_LENGTH) {
|
||||
htt_stats->msg_len -= DP_EXT_MSG_LENGTH;
|
||||
}
|
||||
|
||||
qdf_nbuf_free(htt_msg);
|
||||
}
|
||||
soc->htt_msg_len = 0;
|
||||
return;
|
||||
|
||||
error:
|
||||
qdf_nbuf_free(htt_msg);
|
||||
soc->htt_msg_len = 0;
|
||||
while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats_msg))
|
||||
while ((htt_msg = qdf_nbuf_queue_remove(&htt_stats->msg))
|
||||
!= NULL)
|
||||
qdf_nbuf_free(htt_msg);
|
||||
}
|
||||
@@ -1171,10 +1170,58 @@ error:
|
||||
void htt_t2h_stats_handler(void *context)
|
||||
{
|
||||
struct dp_soc *soc = (struct dp_soc *)context;
|
||||
struct htt_stats_context htt_stats;
|
||||
uint32_t length;
|
||||
uint32_t *msg_word;
|
||||
qdf_nbuf_t htt_msg = NULL;
|
||||
uint8_t done;
|
||||
uint8_t rem_stats;
|
||||
|
||||
if (soc && qdf_atomic_read(&soc->cmn_init_done))
|
||||
dp_process_htt_stat_msg(soc);
|
||||
if (!soc || !qdf_atomic_read(&soc->cmn_init_done)) {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
|
||||
"soc: 0x%p, init_done: %d", soc,
|
||||
qdf_atomic_read(&soc->cmn_init_done));
|
||||
return;
|
||||
}
|
||||
|
||||
qdf_mem_zero(&htt_stats, sizeof(htt_stats));
|
||||
qdf_nbuf_queue_init(&htt_stats.msg);
|
||||
|
||||
/* pull one completed stats from soc->htt_stats_msg and process */
|
||||
qdf_spin_lock_bh(&soc->htt_stats.lock);
|
||||
if (!soc->htt_stats.num_stats) {
|
||||
qdf_spin_unlock_bh(&soc->htt_stats.lock);
|
||||
return;
|
||||
}
|
||||
while ((htt_msg = qdf_nbuf_queue_remove(&soc->htt_stats.msg)) != NULL) {
|
||||
msg_word = (uint32_t *) qdf_nbuf_data(htt_msg);
|
||||
msg_word = msg_word + HTT_T2H_EXT_STATS_TLV_START_OFFSET;
|
||||
length = HTT_T2H_EXT_STATS_CONF_TLV_LENGTH_GET(*msg_word);
|
||||
done = HTT_T2H_EXT_STATS_CONF_TLV_DONE_GET(*msg_word);
|
||||
qdf_nbuf_queue_add(&htt_stats.msg, htt_msg);
|
||||
/*
|
||||
* HTT EXT stats response comes as stream of TLVs which span over
|
||||
* multiple T2H messages.
|
||||
* The first message will carry length of the response.
|
||||
* For rest of the messages length will be zero.
|
||||
*/
|
||||
if (length)
|
||||
htt_stats.msg_len = length;
|
||||
/*
|
||||
* Done bit signifies that this is the last T2H buffer in the
|
||||
* stream of HTT EXT STATS message
|
||||
*/
|
||||
if (done)
|
||||
break;
|
||||
}
|
||||
rem_stats = --soc->htt_stats.num_stats;
|
||||
qdf_spin_unlock_bh(&soc->htt_stats.lock);
|
||||
|
||||
dp_process_htt_stat_msg(&htt_stats);
|
||||
|
||||
/* If there are more stats to process, schedule stats work again */
|
||||
if (rem_stats)
|
||||
qdf_sched_work(0, &soc->htt_stats.work);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1187,15 +1234,12 @@ void htt_t2h_stats_handler(void *context)
|
||||
static inline void dp_txrx_fw_stats_handler(struct dp_soc *soc,
|
||||
qdf_nbuf_t htt_t2h_msg)
|
||||
{
|
||||
uint32_t length;
|
||||
uint8_t done;
|
||||
qdf_nbuf_t msg_copy;
|
||||
uint32_t *msg_word;
|
||||
|
||||
msg_word = (uint32_t *) qdf_nbuf_data(htt_t2h_msg);
|
||||
msg_word = msg_word + 3;
|
||||
done = 0;
|
||||
length = HTT_T2H_EXT_STATS_CONF_TLV_LENGTH_GET(*msg_word);
|
||||
done = HTT_T2H_EXT_STATS_CONF_TLV_DONE_GET(*msg_word);
|
||||
|
||||
/*
|
||||
@@ -1203,14 +1247,7 @@ static inline void dp_txrx_fw_stats_handler(struct dp_soc *soc,
|
||||
* multiple T2H messages.
|
||||
* The first message will carry length of the response.
|
||||
* For rest of the messages length will be zero.
|
||||
*/
|
||||
if (soc->htt_msg_len && length)
|
||||
goto error;
|
||||
|
||||
if (length)
|
||||
soc->htt_msg_len = length;
|
||||
|
||||
/*
|
||||
*
|
||||
* Clone the T2H message buffer and store it in a list to process
|
||||
* it later.
|
||||
*
|
||||
@@ -1222,26 +1259,31 @@ static inline void dp_txrx_fw_stats_handler(struct dp_soc *soc,
|
||||
if (!msg_copy) {
|
||||
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_INFO,
|
||||
"T2H messge clone failed for HTT EXT STATS");
|
||||
soc->htt_msg_len = 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
qdf_nbuf_queue_add(&soc->htt_stats_msg, msg_copy);
|
||||
|
||||
qdf_spin_lock_bh(&soc->htt_stats.lock);
|
||||
qdf_nbuf_queue_add(&soc->htt_stats.msg, msg_copy);
|
||||
/*
|
||||
* Done bit signifies that this is the last T2H buffer in the stream of
|
||||
* HTT EXT STATS message
|
||||
*/
|
||||
if (done)
|
||||
qdf_sched_work(0, &soc->htt_stats_work);
|
||||
if (done) {
|
||||
soc->htt_stats.num_stats++;
|
||||
qdf_sched_work(0, &soc->htt_stats.work);
|
||||
}
|
||||
qdf_spin_unlock_bh(&soc->htt_stats.lock);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
while ((msg_copy = qdf_nbuf_queue_remove(&soc->htt_stats_msg))
|
||||
qdf_spin_lock_bh(&soc->htt_stats.lock);
|
||||
while ((msg_copy = qdf_nbuf_queue_remove(&soc->htt_stats.msg))
|
||||
!= NULL) {
|
||||
qdf_nbuf_free(msg_copy);
|
||||
}
|
||||
soc->htt_stats.num_stats = 0;
|
||||
qdf_spin_unlock_bh(&soc->htt_stats.lock);
|
||||
return;
|
||||
|
||||
}
|
||||
|
@@ -46,6 +46,8 @@
|
||||
|
||||
#define DP_HTT_HTC_PKT_MISCLIST_SIZE 256
|
||||
|
||||
#define HTT_T2H_EXT_STATS_TLV_START_OFFSET 3
|
||||
|
||||
struct dp_htt_htc_pkt {
|
||||
void *soc_ctxt;
|
||||
qdf_dma_addr_t nbuf_paddr;
|
||||
@@ -157,4 +159,16 @@ int htt_h2t_rx_ring_cfg(void *htt_soc, int pdev_id, void *hal_srng,
|
||||
*/
|
||||
void htt_t2h_stats_handler(void *context);
|
||||
|
||||
/**
|
||||
* struct htt_stats_context - htt stats information
|
||||
* @soc: Size of each descriptor in the pool
|
||||
* @msg: T2H Ext stats message queue
|
||||
* @msg_len: T2H Ext stats message length
|
||||
*/
|
||||
struct htt_stats_context {
|
||||
struct dp_soc *soc;
|
||||
qdf_nbuf_queue_t msg;
|
||||
uint32_t msg_len;
|
||||
};
|
||||
|
||||
#endif /* _DP_HTT_H_ */
|
||||
|
@@ -1763,7 +1763,7 @@ static int dp_soc_cmn_setup(struct dp_soc *soc)
|
||||
hal_reo_setup(soc->hal_soc, &reo_params);
|
||||
|
||||
qdf_atomic_set(&soc->cmn_init_done, 1);
|
||||
qdf_nbuf_queue_init(&soc->htt_stats_msg);
|
||||
qdf_nbuf_queue_init(&soc->htt_stats.msg);
|
||||
return 0;
|
||||
fail1:
|
||||
/*
|
||||
@@ -2356,8 +2356,11 @@ static void dp_soc_detach_wifi3(void *txrx_soc)
|
||||
|
||||
qdf_atomic_set(&soc->cmn_init_done, 0);
|
||||
|
||||
qdf_flush_work(0, &soc->htt_stats_work);
|
||||
qdf_disable_work(0, &soc->htt_stats_work);
|
||||
qdf_flush_work(0, &soc->htt_stats.work);
|
||||
qdf_disable_work(0, &soc->htt_stats.work);
|
||||
|
||||
/* Free pending htt stats messages */
|
||||
qdf_nbuf_queue_free(&soc->htt_stats.msg);
|
||||
|
||||
for (i = 0; i < MAX_PDEV_CNT; i++) {
|
||||
if (soc->pdev_list[i])
|
||||
@@ -2418,7 +2421,10 @@ static void dp_soc_detach_wifi3(void *txrx_soc)
|
||||
dp_srng_cleanup(soc, &soc->reo_cmd_ring, REO_CMD, 0);
|
||||
dp_srng_cleanup(soc, &soc->reo_status_ring, REO_STATUS, 0);
|
||||
|
||||
qdf_spinlock_destroy(&soc->rx.reo_cmd_lock);
|
||||
qdf_spinlock_destroy(&soc->peer_ref_mutex);
|
||||
qdf_spinlock_destroy(&soc->htt_stats.lock);
|
||||
|
||||
htt_soc_detach(soc->htt_handle);
|
||||
|
||||
dp_reo_cmdlist_destroy(soc);
|
||||
@@ -2591,7 +2597,7 @@ static int dp_soc_attach_target_wifi3(struct cdp_soc_t *cdp_soc)
|
||||
DP_STATS_INIT(soc);
|
||||
|
||||
/* initialize work queue for stats processing */
|
||||
qdf_create_work(0, &soc->htt_stats_work, htt_t2h_stats_handler, soc);
|
||||
qdf_create_work(0, &soc->htt_stats.work, htt_t2h_stats_handler, soc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -5072,6 +5078,11 @@ void *dp_soc_attach_wifi3(void *osif_soc, void *hif_handle,
|
||||
|
||||
/* fill the tx/rx cpu ring map*/
|
||||
dp_soc_set_txrx_ring_map(soc);
|
||||
|
||||
qdf_spinlock_create(&soc->htt_stats.lock);
|
||||
/* initialize work queue for stats processing */
|
||||
qdf_create_work(0, &soc->htt_stats.work, htt_t2h_stats_handler, soc);
|
||||
|
||||
return (void *)soc;
|
||||
|
||||
fail2:
|
||||
|
@@ -533,6 +533,21 @@ struct dp_ast_entry {
|
||||
TAILQ_ENTRY(dp_ast_entry) hash_list_elem;
|
||||
};
|
||||
|
||||
/* SOC level htt stats */
|
||||
struct htt_t2h_stats {
|
||||
/* lock to protect htt_stats_msg update */
|
||||
qdf_spinlock_t lock;
|
||||
|
||||
/* work queue to process htt stats */
|
||||
qdf_work_t work;
|
||||
|
||||
/* T2H Ext stats message queue */
|
||||
qdf_nbuf_queue_t msg;
|
||||
|
||||
/* number of completed stats in htt_stats_msg */
|
||||
uint32_t num_stats;
|
||||
};
|
||||
|
||||
/* SOC level structure for data path */
|
||||
struct dp_soc {
|
||||
/* Common base structure - Should be the first member */
|
||||
@@ -758,12 +773,9 @@ struct dp_soc {
|
||||
u_int16_t pdev_bs_inact_interval;
|
||||
/* Inactivity timer */
|
||||
#endif /* QCA_SUPPORT_SON */
|
||||
/* T2H Ext stats message queue */
|
||||
qdf_nbuf_queue_t htt_stats_msg;
|
||||
/* T2H Ext stats message length */
|
||||
uint32_t htt_msg_len;
|
||||
/* work queue to process htt stats */
|
||||
qdf_work_t htt_stats_work;
|
||||
|
||||
/* htt stats */
|
||||
struct htt_t2h_stats htt_stats;
|
||||
|
||||
#ifdef IPA_OFFLOAD
|
||||
/* IPA uC datapath offload Wlan Tx resources */
|
||||
|
Reference in New Issue
Block a user