qcacmn: add periodic and host Tx/Rx stats support for WCN6450

Changes required to support periodic and host Tx/Rx stats for WCN6450.

Command to request and dump the host Tx/Rx stats,
iwpriv wlan0 txrx_stats <stats no> <mac_id>
mac_id: 0 - mac0(5 GHz), 1 - mac1(2 GHz)
        0 for single mac
stats no: 20 - TXRX_CLEAR_STATS
	  21 - TXRX_RX_RATE_STATS
	  22 - TXRX_TX_RATE_STATS
	  23 - TXRX_TX_HOST_STATS
	  24 - TXRX_RX_HOST_STATS
	  25 - TXRX_AST_STATS
	  26 - TXRX_SRNG_PTR_STATS
	  27 - TXRX_RX_MON_STATS
	  29 - TXRX_SOC_CFG_PARAMS
	  30 - TXRX_PDEV_CFG_PARAMS
	  31 - TXRX_NAPI_STATS
	  32 - TXRX_SOC_INTERRUPT_STATS
	  33 - TXRX_SOC_FSE_STATS

Change-Id: Ibda4d531c9074a24f8c39916b44d9e3c38f189ee
CRs-Fixed: 3485279
This commit is contained in:
Venkateswara Naralasetty
2023-07-11 14:38:52 +05:30
committed by Rahul Choudhary
parent 4e97268972
commit 51ddb93d21
7 changed files with 787 additions and 366 deletions

View File

@@ -1645,6 +1645,50 @@ static inline void ce_update_wrt_idx_offset(struct hif_softc *scn,
else
QDF_BUG(0);
}
/*
* hif_ce_print_ring_stats() - Print ce ring statistics
*
* @hif_ctx: hif context
*
* Returns: None
*/
void hif_ce_print_ring_stats(struct hif_opaque_softc *hif_ctx)
{
struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
struct CE_state *ce_state;
int i;
for (i = 0; i < scn->ce_count; i++) {
ce_state = scn->ce_id_to_state[i];
if (!ce_state)
continue;
if (ce_state->src_ring) {
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
"ce%d:SW: sw_index %u write_index %u",
ce_state->src_ring->sw_index,
ce_state->src_ring->write_index);
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
"ce%d:HW: read_index %u write_index %u",
CE_SRC_RING_READ_IDX_GET_FROM_REGISTER(scn, ce_state->ctrl_addr),
CE_SRC_RING_WRITE_IDX_GET_FROM_REGISTER(scn, ce_state->ctrl_addr));
}
if (ce_state->dest_ring) {
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
"ce%d:SW: sw_index %u write_index %u",
ce_state->dest_ring->sw_index,
ce_state->dest_ring->write_index);
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
"ce%d:HW: read_index %u write_index %u",
CE_DEST_RING_READ_IDX_GET_FROM_REGISTER(scn, ce_state->ctrl_addr),
CE_DEST_RING_WRITE_IDX_GET_FROM_REGISTER(scn, ce_state->ctrl_addr));
}
}
}
#endif
/**

View File

@@ -197,6 +197,7 @@ void hif_event_history_deinit(struct hif_opaque_softc *hif_ctx, uint8_t id)
}
#endif /* WLAN_FEATURE_DP_EVENT_HISTORY */
#ifndef QCA_WIFI_WCN6450
/**
* hif_print_napi_latency_stats() - print NAPI scheduling latency stats
* @hif_state: hif context
@@ -301,6 +302,97 @@ static void hif_get_poll_times_hist_str(struct qca_napi_stat *stats, char *buf,
"%u|", stats->poll_time_buckets[i]);
}
void hif_print_napi_stats(struct hif_opaque_softc *hif_ctx)
{
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
struct hif_exec_context *hif_ext_group;
struct qca_napi_stat *napi_stats;
int i, j;
/*
* Max value of uint_32 (poll_time_bucket) = 4294967295
* Thus we need 10 chars + 1 space =11 chars for each bucket value.
* +1 space for '\0'.
*/
char hist_str[(QCA_NAPI_NUM_BUCKETS * 11) + 1] = {'\0'};
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
"NAPI[#]CPU[#] |scheds |polls |comps |dones |t-lim |max(us)|hist(500us buckets)");
for (i = 0;
(i < hif_state->hif_num_extgroup && hif_state->hif_ext_group[i]);
i++) {
hif_ext_group = hif_state->hif_ext_group[i];
for (j = 0; j < num_possible_cpus(); j++) {
napi_stats = &hif_ext_group->stats[j];
if (!napi_stats->napi_schedules)
continue;
hif_get_poll_times_hist_str(napi_stats,
hist_str,
sizeof(hist_str));
QDF_TRACE(QDF_MODULE_ID_HIF,
QDF_TRACE_LEVEL_INFO_HIGH,
"NAPI[%d]CPU[%d]: %7u %7u %7u %7u %7u %7llu %s",
i, j,
napi_stats->napi_schedules,
napi_stats->napi_polls,
napi_stats->napi_completes,
napi_stats->napi_workdone,
napi_stats->time_limit_reached,
qdf_do_div(napi_stats->napi_max_poll_time,
1000),
hist_str);
}
}
hif_print_napi_latency_stats(hif_state);
}
qdf_export_symbol(hif_print_napi_stats);
#else
static inline
void hif_get_poll_times_hist_str(struct qca_napi_stat *stats, char *buf,
uint8_t buf_len)
{
}
void hif_print_napi_stats(struct hif_opaque_softc *hif_ctx)
{
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
struct hif_exec_context *hif_ext_group;
struct qca_napi_stat *napi_stats;
int i, j;
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
"NAPI[#ctx]CPU[#] |schedules |polls |completes |workdone");
for (i = 0; i < hif_state->hif_num_extgroup; i++) {
if (hif_state->hif_ext_group[i]) {
hif_ext_group = hif_state->hif_ext_group[i];
for (j = 0; j < num_possible_cpus(); j++) {
napi_stats = &(hif_ext_group->stats[j]);
if (napi_stats->napi_schedules != 0)
QDF_TRACE(QDF_MODULE_ID_HIF,
QDF_TRACE_LEVEL_FATAL,
"NAPI[%2d]CPU[%d]: "
"%7d %7d %7d %7d ",
i, j,
napi_stats->napi_schedules,
napi_stats->napi_polls,
napi_stats->napi_completes,
napi_stats->napi_workdone);
}
}
}
hif_print_napi_latency_stats(hif_state);
}
qdf_export_symbol(hif_print_napi_stats);
#endif /* WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT */
#endif /* QCA_WIFI_WCN6450 */
#ifdef WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT
/**
* hif_exec_fill_poll_time_histogram() - fills poll time histogram for a NAPI
* @hif_ext_group: hif_ext_group of type NAPI
@@ -393,63 +485,7 @@ void hif_exec_update_service_start_time(struct hif_exec_context *hif_ext_group)
hif_ext_group->poll_start_time = qdf_time_sched_clock();
}
void hif_print_napi_stats(struct hif_opaque_softc *hif_ctx)
{
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
struct hif_exec_context *hif_ext_group;
struct qca_napi_stat *napi_stats;
int i, j;
/*
* Max value of uint_32 (poll_time_bucket) = 4294967295
* Thus we need 10 chars + 1 space =11 chars for each bucket value.
* +1 space for '\0'.
*/
char hist_str[(QCA_NAPI_NUM_BUCKETS * 11) + 1] = {'\0'};
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
"NAPI[#]CPU[#] |scheds |polls |comps |dones |t-lim |max(us)|hist(500us buckets)");
for (i = 0;
(i < hif_state->hif_num_extgroup && hif_state->hif_ext_group[i]);
i++) {
hif_ext_group = hif_state->hif_ext_group[i];
for (j = 0; j < num_possible_cpus(); j++) {
napi_stats = &hif_ext_group->stats[j];
if (!napi_stats->napi_schedules)
continue;
hif_get_poll_times_hist_str(napi_stats,
hist_str,
sizeof(hist_str));
QDF_TRACE(QDF_MODULE_ID_HIF,
QDF_TRACE_LEVEL_INFO_HIGH,
"NAPI[%d]CPU[%d]: %7u %7u %7u %7u %7u %7llu %s",
i, j,
napi_stats->napi_schedules,
napi_stats->napi_polls,
napi_stats->napi_completes,
napi_stats->napi_workdone,
napi_stats->time_limit_reached,
qdf_do_div(napi_stats->napi_max_poll_time,
1000),
hist_str);
}
}
hif_print_napi_latency_stats(hif_state);
}
qdf_export_symbol(hif_print_napi_stats);
#else
static inline
void hif_get_poll_times_hist_str(struct qca_napi_stat *stats, char *buf,
uint8_t buf_len)
{
}
static inline
void hif_exec_update_service_start_time(struct hif_exec_context *hif_ext_group)
{
@@ -459,39 +495,6 @@ static inline
void hif_exec_fill_poll_time_histogram(struct hif_exec_context *hif_ext_group)
{
}
void hif_print_napi_stats(struct hif_opaque_softc *hif_ctx)
{
struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_ctx);
struct hif_exec_context *hif_ext_group;
struct qca_napi_stat *napi_stats;
int i, j;
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
"NAPI[#ctx]CPU[#] |schedules |polls |completes |workdone");
for (i = 0; i < hif_state->hif_num_extgroup; i++) {
if (hif_state->hif_ext_group[i]) {
hif_ext_group = hif_state->hif_ext_group[i];
for (j = 0; j < num_possible_cpus(); j++) {
napi_stats = &(hif_ext_group->stats[j]);
if (napi_stats->napi_schedules != 0)
QDF_TRACE(QDF_MODULE_ID_HIF,
QDF_TRACE_LEVEL_FATAL,
"NAPI[%2d]CPU[%d]: "
"%7d %7d %7d %7d ",
i, j,
napi_stats->napi_schedules,
napi_stats->napi_polls,
napi_stats->napi_completes,
napi_stats->napi_workdone);
}
}
}
hif_print_napi_latency_stats(hif_state);
}
qdf_export_symbol(hif_print_napi_stats);
#endif /* WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT */
static void hif_exec_tasklet_schedule(struct hif_exec_context *ctx)

View File

@@ -749,7 +749,7 @@ inline void hif_napi_enable_irq(struct hif_opaque_softc *hif, int id)
hif_irq_enable(scn, NAPI_ID2PIPE(id));
}
#ifdef HIF_LATENCY_PROFILE_ENABLE
#if defined(QCA_WIFI_WCN6450) && defined(HIF_LATENCY_PROFILE_ENABLE)
/*
* hif_napi_latency_profile_start() - update the schedule start timestamp
*
@@ -807,6 +807,42 @@ static void hif_napi_latency_profile_measure(struct qca_napi_info *napi_info)
else
napi_info->sched_latency_stats[7]++;
}
static void hif_print_napi_latency_stats(struct qca_napi_info *napii, int ce_id)
{
int i;
int64_t cur_tstamp;
const char time_str[HIF_SCHED_LATENCY_BUCKETS][15] = {
"0-2 ms",
"3-10 ms",
"11-20 ms",
"21-50 ms",
"51-100 ms",
"101-250 ms",
"251-500 ms",
"> 500 ms"
};
cur_tstamp = qdf_ktime_to_ms(qdf_ktime_get());
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
"Current timestamp: %lld", cur_tstamp);
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
"ce id %d Last serviced timestamp: %lld",
ce_id, napii->tstamp);
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
"Latency Bucket | Time elapsed");
for (i = 0; i < HIF_SCHED_LATENCY_BUCKETS; i++)
QDF_TRACE(QDF_MODULE_ID_HIF,
QDF_TRACE_LEVEL_INFO_HIGH,
"%s | %lld",
time_str[i],
napii->sched_latency_stats[i]);
}
#else
static inline void
hif_napi_latency_profile_start(struct hif_softc *scn, int ce_id)
@@ -817,8 +853,14 @@ static inline void
hif_napi_latency_profile_measure(struct qca_napi_info *napi_info)
{
}
static inline void
hif_print_napi_latency_stats(struct qca_napi_info *napii, int ce_id)
{
}
#endif
#ifdef QCA_WIFI_WCN6450
#ifdef WLAN_FEATURE_RX_SOFTIRQ_TIME_LIMIT
/**
* hif_napi_update_service_start_time() - Update NAPI poll start time
@@ -868,6 +910,137 @@ static void hif_napi_fill_poll_time_histogram(struct qca_napi_info *napi_info)
++napi_stat->poll_time_buckets[bucket];
}
/*
* hif_get_poll_times_hist_str() - Get HIF poll times histogram string
* @stats: NAPI stats to get poll time buckets
* @buf: buffer to fill histogram string
* @buf_len: length of the buffer
*
* Return: void
*/
static void hif_get_poll_times_hist_str(struct qca_napi_stat *stats, char *buf,
uint8_t buf_len)
{
int i;
int str_index = 0;
for (i = 0; i < QCA_NAPI_NUM_BUCKETS; i++)
str_index += qdf_scnprintf(buf + str_index, buf_len - str_index,
"%u|", stats->poll_time_buckets[i]);
}
void hif_print_napi_stats(struct hif_opaque_softc *hif_ctx)
{
struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
struct qca_napi_info *napii;
struct qca_napi_stat *napi_stats;
int ce_id, cpu;
/*
* Max value of uint_32 (poll_time_bucket) = 4294967295
* Thus we need 10 chars + 1 space =11 chars for each bucket value.
* +1 space for '\0'.
*/
char hist_str[(QCA_NAPI_NUM_BUCKETS * 11) + 1] = {'\0'};
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_INFO_HIGH,
"NAPI[#]CPU[#] |scheds |polls |comps |dones |t-lim |max(us)|hist(500us buckets)");
for (ce_id = 0; ce_id < CE_COUNT_MAX; ce_id++) {
if (!hif_napi_enabled(hif_ctx, ce_id))
continue;
napii = scn->napi_data.napis[ce_id];
if (napii) {
for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
napi_stats = &napii->stats[cpu];
hif_get_poll_times_hist_str(napi_stats,
hist_str,
sizeof(hist_str));
if (napi_stats->napi_schedules != 0)
QDF_TRACE(QDF_MODULE_ID_HIF,
QDF_TRACE_LEVEL_INFO_HIGH,
"NAPI[%d]CPU[%d]: %7u %7u %7u %7u %7u %7llu %s",
ce_id, cpu,
napi_stats->napi_schedules,
napi_stats->napi_polls,
napi_stats->napi_completes,
napi_stats->napi_workdone,
qdf_do_div(napi_stats->napi_max_poll_time, 1000),
hist_str);
}
hif_print_napi_latency_stats(napii, ce_id);
}
}
}
#else
static inline void
hif_napi_update_service_start_time(struct qca_napi_info *napi_info)
{
}
static inline void
hif_napi_fill_poll_time_histogram(struct qca_napi_info *napi_info)
{
}
void hif_print_napi_stats(struct hif_opaque_softc *hif_ctx)
{
struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
struct qca_napi_info *napii;
struct qca_napi_stat *napi_stats;
int ce_id, cpu;
QDF_TRACE(QDF_MODULE_ID_HIF, QDF_TRACE_LEVEL_FATAL,
"NAPI[#ctx]CPU[#] |schedules |polls |completes |workdone");
for (ce_id = 0; ce_id < CE_COUNT_MAX; ce_id++) {
if (!hif_napi_enabled(hif_ctx, ce_id))
continue;
napii = scn->napi_data.napis[ce_id];
if (napii) {
for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
napi_stats = &napii->stats[cpu];
if (napi_stats->napi_schedules != 0)
QDF_TRACE(QDF_MODULE_ID_HIF,
QDF_TRACE_LEVEL_FATAL,
"NAPI[%2d]CPU[%d]: "
"%7d %7d %7d %7d ",
ce_id, cpu,
napi_stats->napi_schedules,
napi_stats->napi_polls,
napi_stats->napi_completes,
napi_stats->napi_workdone);
}
hif_print_napi_latency_stats(napii, ce_id);
}
}
}
#endif
void hif_clear_napi_stats(struct hif_opaque_softc *hif_ctx)
{
struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx);
struct qca_napi_info *napii;
int ce_id;
for (ce_id = 0; ce_id < CE_COUNT_MAX; ce_id++) {
if (!hif_napi_enabled(hif_ctx, ce_id))
continue;
napii = scn->napi_data.napis[ce_id];
if (napii)
qdf_mem_set(napii->sched_latency_stats,
sizeof(napii->sched_latency_stats), 0);
}
}
#else
static inline void
hif_napi_update_service_start_time(struct qca_napi_info *napi_info)