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:
Om Prakash Tripathi
2017-08-03 10:21:24 +05:30
父節點 fbeb4bb9fa
當前提交 121268292f
共有 4 個文件被更改,包括 118 次插入39 次删除

查看文件

@@ -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 */