qcacld-3.0: Add NAPI statistics to dumpstats

Currently NAPI stats are retrieved as a part of iwpriv getStats command.
The buffer available for this command is limited and NAPI stats get
truncated.

Add a new dumpStats parameter (9) to dump NAPI stats.
The following command will dump NAPI Stats into kmsg.
>iwpriv wlan0 dumpStats 9

Cleanup existing getStats

Change-Id: I0d804295d96a495b4afa576c8258f08c9c2b9bbb
CRs-Fixed: 1076563
This commit is contained in:
Mohit Khanna 2016-10-11 13:18:29 -07:00 • committed by Sandeep Puligilla
commit 3e2115b6e2
9 changed files with 164 additions and 380 deletions

View file

@ -3919,7 +3919,7 @@ ol_txrx_stats(uint8_t vdev_id, char *buffer, unsigned buf_len)
}
len = scnprintf(buffer, buf_len,
"\nTXRX stats:\n\nllQueue State : %s\n pause %u unpause %u\n overflow %u\n llQueue timer state : %s\n",
"\n\nTXRX stats:\nllQueue State : %s\npause %u unpause %u\noverflow %u\nllQueue timer state : %s",
((vdev->ll_pause.is_q_paused == false) ?
"UNPAUSED" : "PAUSED"),
vdev->ll_pause.q_pause_cnt,
@ -4383,44 +4383,21 @@ static void ol_txrx_ipa_uc_get_stat(struct cdp_pdev *ppdev)
#endif /* IPA_UC_OFFLOAD */
/**
* ol_txrx_display_stats_help() - print statistics help
* ol_txrx_display_stats() - Display OL TXRX display stats
* @value: Module id for which stats needs to be displayed
*
* Return: none
* Return: None
*/
static void ol_txrx_display_stats_help(void)
{
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"iwpriv wlan0 dumpStats [option] - dump statistics");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"iwpriv wlan0 clearStats [option] - clear statistics");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"options:");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
" 1 -- TXRX Layer statistics");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
" 2 -- Bandwidth compute timer stats");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
" 3 -- TSO statistics");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
" 4 -- Network queue statistics");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
" 5 -- Flow control statistics");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
" 6 -- Per Layer statistics");
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
" 7 -- Copy engine interrupt statistics");
}
static void ol_txrx_display_stats(uint16_t value)
static QDF_STATUS ol_txrx_display_stats(uint16_t value)
{
ol_txrx_pdev_handle pdev;
QDF_STATUS status = QDF_STATUS_SUCCESS;
pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (!pdev) {
QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR,
"%s: pdev is NULL", __func__);
return;
return QDF_STATUS_E_NULL_VALUE;
}
switch (value) {
@ -4457,14 +4434,22 @@ static void ol_txrx_display_stats(uint16_t value)
#endif
#endif
default:
ol_txrx_display_stats_help();
status = QDF_STATUS_E_INVAL;
break;
}
return status;
}
/**
* ol_txrx_clear_stats() - Clear OL TXRX stats
* @value: Module id for which stats needs to be cleared
*
* Return: None
*/
static void ol_txrx_clear_stats(uint16_t value)
{
ol_txrx_pdev_handle pdev;
QDF_STATUS status = QDF_STATUS_SUCCESS;
pdev = cds_get_context(QDF_MODULE_ID_TXRX);
if (!pdev) {
@ -4500,9 +4485,11 @@ static void ol_txrx_clear_stats(uint16_t value)
break;
#endif
default:
ol_txrx_display_stats_help();
status = QDF_STATUS_E_INVAL;
break;
}
return;
}
/**

View file

@ -322,7 +322,7 @@ extern spinlock_t hdd_context_lock;
#define WLAN_SAP_HDD_TX_FLOW_CONTROL_OS_Q_BLOCK_TIME 100
#define WLAN_HDD_TX_FLOW_CONTROL_MAX_24BAND_CH 14
#define NUM_TX_RX_HISTOGRAM 1024
#define NUM_TX_RX_HISTOGRAM 128
#define NUM_TX_RX_HISTOGRAM_MASK (NUM_TX_RX_HISTOGRAM - 1)
/**
@ -1984,7 +1984,7 @@ void hdd_clean_up_pre_cac_interface(hdd_context_t *hdd_ctx);
void wlan_hdd_txrx_pause_cb(uint8_t vdev_id,
enum netif_action_type action, enum netif_reason_type reason);
void hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value);
int hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value);
void wlan_hdd_deinit_tx_rx_histogram(hdd_context_t *hdd_ctx);
void wlan_hdd_display_tx_rx_histogram(hdd_context_t *pHddCtx);
void wlan_hdd_clear_tx_rx_histogram(hdd_context_t *pHddCtx);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -48,11 +48,7 @@ struct hdd_context_s;
int hdd_napi_enabled(int id);
int hdd_napi_create(void);
int hdd_napi_destroy(int force);
int hdd_napi_stats(char *buf,
int max,
char *indp,
struct qca_napi_data *napid);
int hdd_display_napi_stats(void);
/* the following triggers napi_enable/disable as required */
int hdd_napi_event(enum qca_napi_event event, void *data);
@ -91,8 +87,7 @@ static inline int hdd_napi_serialize(int is_on)
static inline int hdd_napi_enabled(int id) { return 0; }
static inline int hdd_napi_create(void) { return 0; }
static inline int hdd_napi_destroy(int force) { return 0; }
static inline int hdd_napi_stats(char *buf, int max, char *indp,
struct qca_napi_data *napid) { return 0; }
static inline int hdd_display_napi_stats(void) { return 0; }
static inline int hdd_napi_event(enum qca_napi_event event, void *data)
{
return 0;

View file

@ -301,6 +301,7 @@ typedef struct ccp_freq_chan_map_s {
extern int hdd_unregister_wext(struct net_device *dev);
extern int hdd_register_wext(struct net_device *dev);
extern int hdd_wlan_get_freq(uint32_t chan, uint32_t *freq);
extern void hdd_display_stats_help(void);
extern void hdd_wlan_get_version(hdd_context_t *hdd_ctx,
union iwreq_data *wrqu, char *extra);

View file

@ -3297,7 +3297,7 @@ static __iw_softap_setparam(struct net_device *dev,
case QCASAP_DUMP_STATS:
{
hdd_notice("QCASAP_DUMP_STATS val %d", set_value);
hdd_wlan_dump_stats(pHostapdAdapter, set_value);
ret = hdd_wlan_dump_stats(pHostapdAdapter, set_value);
break;
}
case QCASAP_CLEAR_STATS:

View file

@ -6102,303 +6102,6 @@ static int drv_cmd_get_linkspeed(hdd_adapter_t *adapter,
return ret;
}
#ifdef FEATURE_NAPI
/**
* hdd_parse_napi() - helper functions to drv_cmd_napi
* @str : source string to parse
* @cmd : pointer to cmd part after parsing
* @sub : pointer to subcmd part after parsing
* @aux : pointer to optional aux part after parsing
*
* Example:
* NAPI SCALE <n> +-- IN str
* | | +------ OUT aux
* | +------------ OUT subcmd
* +----------------- OUT cmd
*
* Return: ==0: success; !=0: failure
*/
static int hdd_parse_napi(char **str, char **cmd, char **sub, char **aux)
{
int rc;
char *token, *lcmd = NULL, *lsub = NULL, *laux = NULL;
NAPI_DEBUG("-->\n");
token = strsep(str, " \t");
if (NULL == token) {
hdd_err("cannot parse cmd");
goto parse_end;
}
lcmd = token;
token = strsep(str, " \t");
if (NULL == token) {
hdd_err("cannot parse subcmd");
goto parse_end;
}
lsub = token;
token = strsep(str, " \t");
if (NULL == token)
hdd_warn("cannot parse aux\n");
else
laux = token;
parse_end:
if ((NULL == lcmd) || (NULL == lsub))
rc = -EINVAL;
else {
rc = 0;
*cmd = lcmd;
*sub = lsub;
if (NULL != aux)
*aux = laux;
}
NAPI_DEBUG("<--[rc=%d]\n", rc);
return rc;
}
/**
* hdd_parse_stats() - print NAPI stats into a buffer
* @buf : buffer to write stats into
* @max : "size of buffer"
* @idp : NULL: all stats, otherwise, ptr to the NAPI instance
* @napid: binary structure to retrieve the stats from
*
* Return: number of bytes written into the buffer
*/
int hdd_napi_stats(char *buf,
int max,
char *indp,
struct qca_napi_data *napid)
{
int n = 0;
int i, j, k; /* NAPI, CPU, bucket indices */
int from, to;
struct qca_napi_info *napii;
struct qca_napi_stat *napis;
NAPI_DEBUG("-->\n");
if (NULL == napid)
return n;
if (NULL == indp) {
from = 0;
to = CE_COUNT_MAX;
} else {
if (0 > kstrtoint(indp, 10, &to)) {
from = 0;
to = CE_COUNT_MAX;
} else
from = to;
}
for (i = from; i < to; i++)
if (napid->ce_map & (0x01 << i)) {
napii = &(napid->napis[i]);
for (j = 0; j < NR_CPUS; j++) {
napis = &(napii->stats[j]);
n += scnprintf(buf + n, max - n,
"STATS: NAPI[%d] CPU: %d scheds: %d polls: %d completes: %d done: %d ",
i, j,
napis->napi_schedules,
napis->napi_polls,
napis->napi_completes,
napis->napi_workdone);
for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
n += scnprintf(
buf + n, max - n,
" %d",
napis->napi_budget_uses[k]);
}
n += scnprintf(buf+n, max - n, "\n");
}
}
NAPI_DEBUG("<--[n=%d]\n", n);
return n;
}
/**
* napi_set_scale() - sets the scale attribute in all NAPI entries
* @sc : scale to set
*
* Return: void
*/
static void napi_set_scale(uint8_t sc)
{
uint32_t i;
struct qca_napi_data *napi_data;
napi_data = hdd_napi_get_all();
if (likely(NULL != napi_data))
for (i = 0; i < CE_COUNT_MAX; i++)
if (napi_data->ce_map & (0x01 << i))
napi_data->napis[i].scale = sc;
return;
}
/**
* drv_cmd_napi() - processes NAPI commands
* @adapter : net_device
* @hdd_ctx : HDD context
* @command : command string from user command (including "NAPI")
* @command_len: length of command
* @priv_data : ifr_data
*
* Commands supported:
* NAPI ENABLE : enables NAPI administratively. Note that this may not
* enable NAPI functionally, as some other conditions
* may not have been satisfied yet
* NAPI DISABLE : reverse operation of "enable"
* NAPI STATUS : get global status of NAPI instances
* NAPI STATS [<n>] : get the stats for a given NAPI instance
* NAPI SCALE <n> : set the scale factor
*
* Return: 0: success; !0: failure
*/
static int drv_cmd_napi(hdd_adapter_t *adapter,
hdd_context_t *hdd_ctx,
uint8_t *command,
uint8_t command_len,
hdd_priv_data_t *priv_data)
{
int rc = 0;
int n, l;
char *cmd = NULL, *subcmd = NULL, *aux = NULL;
char *synopsis = "NAPI ENABLE\n"
"NAPI DISABLE\n"
"NAPI STATUS\n"
"NAPI STATS [<n>] -- if no <n> then all\n"
"NAPI SCALE <n> -- set the scale\n";
char *reply = NULL;
/* make a local copy, as strsep modifies the str in place */
char *str = NULL;
NAPI_DEBUG("-->\n");
/**
* NOTE TO MAINTAINER: from this point to the end of the function,
* please do not return anywhere in the code except the very end
* to avoid memory leakage (goto end_drv_napi instead)
* or make sure that reply+str is freed
*/
reply = kmalloc(MAX_USER_COMMAND_SIZE, GFP_KERNEL);
if (NULL == reply) {
hdd_err("could not allocate reply buffer");
rc = -ENOMEM;
goto end_drv_napi;
}
str = kmalloc(strlen(command) + 1, GFP_KERNEL);
if (NULL == str) {
hdd_err("could not allocate copy of input buffer");
rc = -ENOMEM;
goto end_drv_napi;
}
strlcpy(str, command, strlen(command) + 1);
hdd_debug("parsing command into cmd=0x%p sub=0x%p aux=0x%p\n",
cmd, subcmd, aux);
rc = hdd_parse_napi(&str, &cmd, &subcmd, &aux);
if (0 != rc) {
const char *msg = "unknown or badly formatted cmd\n%s";
l = QDF_MIN(MAX_USER_COMMAND_SIZE,
strlen(msg)+strlen(synopsis));
n = scnprintf(reply, l, msg, synopsis);
if (copy_to_user(priv_data->buf, reply,
QDF_MIN(priv_data->total_len, l)))
hdd_err("failed to copy data to user buffer");
hdd_debug("reply: %s", reply);
rc = -EINVAL;
} else {
hdd_debug("cmd=(%s) subcmd=(%s) aux=(%s)\n",
cmd, subcmd, aux);
if (!strcmp(subcmd, "ENABLE"))
hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)1);
else if (!strcmp(subcmd, "DISABLE"))
hdd_napi_event(NAPI_EVT_CMD_STATE, (void *)0);
else if (!strcmp(subcmd, "STATUS")) {
int n = 0;
uint32_t i;
struct qca_napi_data *napi_data;
napi_data = hdd_napi_get_all();
if (unlikely(NULL == napi_data))
goto status_end;
n += scnprintf(reply+n, MAX_USER_COMMAND_SIZE - n,
"NAPI state: 0x%08x map: 0x%08x\n",
napi_data->state,
napi_data->ce_map);
for (i = 0; i < CE_COUNT_MAX; i++)
if (napi_data->ce_map & (0x01 << i)) {
n += scnprintf(
reply + n,
MAX_USER_COMMAND_SIZE - n,
"#%d: id: %d, scale=%d\n",
i,
napi_data->napis[i].id,
napi_data->napis[i].scale);
}
status_end:
hdd_info("wlan: STATUS DATA:\n%s", reply);
if (copy_to_user(priv_data->buf, reply,
QDF_MIN(n, priv_data->total_len)))
rc = -EINVAL;
} else if (!strcmp(subcmd, "STATS")) {
int n = 0;
struct qca_napi_data *napi_data;
napi_data = hdd_napi_get_all();
if (NULL != napi_data) {
n = hdd_napi_stats(reply, MAX_USER_COMMAND_SIZE,
aux, napi_data);
NAPI_DEBUG("STATS: returns %d\n", n);
}
if (n > 0) {
if (copy_to_user(priv_data->buf, reply,
QDF_MIN(priv_data->total_len,
n)))
rc = -EINVAL;
hdd_info("wlan: STATS_DATA\n%s\n", reply);
} else
rc = -EINVAL;
} else if (!strcmp(subcmd, "SCALE")) {
if (NULL == aux) {
rc = -EINVAL;
hdd_err("wlan: SCALE cmd requires <n>");
} else {
uint8_t sc;
rc = kstrtou8(aux, 10, &sc);
if (rc) {
hdd_err("wlan: bad scale (%s)", aux);
rc = -EINVAL;
} else
napi_set_scale(sc);
}
} /* SCALE */
}
end_drv_napi:
if (NULL != str)
kfree(str);
if (NULL != reply)
kfree(reply);
NAPI_DEBUG("<--[rc=%d]\n", rc);
return rc;
}
#endif /* FEATURE_NAPI */
/**
* hdd_set_rx_filter() - set RX filter
* @adapter: Pointer to adapter
@ -7172,9 +6875,6 @@ static const hdd_drv_cmd_t hdd_drv_cmds[] = {
#endif
{"RSSI", drv_cmd_get_rssi},
{"LINKSPEED", drv_cmd_get_linkspeed},
#ifdef FEATURE_NAPI
{"NAPI", drv_cmd_napi},
#endif /* FEATURE_NAPI */
{"RXFILTER-REMOVE", drv_cmd_rx_filter_remove},
{"RXFILTER-ADD", drv_cmd_rx_filter_add},
{"SET_FCC_CHANNEL", drv_cmd_set_fcc_channel},

View file

@ -6150,17 +6150,24 @@ void wlan_hdd_display_tx_rx_histogram(hdd_context_t *hdd_ctx)
hdd_err("index, total_rx, interval_rx, total_tx, interval_tx, bus_bw_level, RX TP Level, TX TP Level");
for (i = 0; i < NUM_TX_RX_HISTOGRAM; i++) {
hdd_err("%d: %llu, %llu, %llu, %llu, %s, %s, %s",
i, hdd_ctx->hdd_txrx_hist[i].total_rx,
hdd_ctx->hdd_txrx_hist[i].interval_rx,
hdd_ctx->hdd_txrx_hist[i].total_tx,
hdd_ctx->hdd_txrx_hist[i].interval_tx,
convert_level_to_string(
hdd_ctx->hdd_txrx_hist[i].next_vote_level),
convert_level_to_string(
hdd_ctx->hdd_txrx_hist[i].next_rx_level),
convert_level_to_string(
hdd_ctx->hdd_txrx_hist[i].next_tx_level));
/* using hdd_log to avoid printing function name */
if (hdd_ctx->hdd_txrx_hist[i].total_rx != 0 ||
hdd_ctx->hdd_txrx_hist[i].total_tx != 0)
hdd_log(QDF_TRACE_LEVEL_ERROR,
"%d: %llu, %llu, %llu, %llu, %s, %s, %s",
i, hdd_ctx->hdd_txrx_hist[i].total_rx,
hdd_ctx->hdd_txrx_hist[i].interval_rx,
hdd_ctx->hdd_txrx_hist[i].total_tx,
hdd_ctx->hdd_txrx_hist[i].interval_tx,
convert_level_to_string(
hdd_ctx->hdd_txrx_hist[i].
next_vote_level),
convert_level_to_string(
hdd_ctx->hdd_txrx_hist[i].
next_rx_level),
convert_level_to_string(
hdd_ctx->hdd_txrx_hist[i].
next_tx_level));
}
return;
}
@ -6197,7 +6204,7 @@ void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx)
while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) {
adapter = adapter_node->pAdapter;
hdd_err("\nNetif queue operation statistics:");
hdd_err("Netif queue operation statistics:");
hdd_err("Session_id %d device mode %d",
adapter->sessionId, adapter->device_mode);
hdd_err("Current pause_map value %x", adapter->pause_map);
@ -6223,7 +6230,9 @@ void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx)
if (adapter->pause_map & (1 << i))
pause_delta = delta;
hdd_err("%s: %d: %d: %ums",
/* using hdd_log to avoid printing function name */
hdd_log(QDF_TRACE_LEVEL_ERROR,
"%s: %d: %d: %ums",
hdd_reason_type_to_string(i),
adapter->queue_oper_stats[i].pause_count,
adapter->queue_oper_stats[i].unpause_count,
@ -6232,14 +6241,18 @@ void wlan_hdd_display_netif_queue_history(hdd_context_t *hdd_ctx)
pause_delta));
}
hdd_err("\nNetif queue operation history:");
hdd_err("Netif queue operation history:");
hdd_err("Total entries: %d current index %d",
WLAN_HDD_MAX_HISTORY_ENTRY, adapter->history_index);
hdd_err("index: time: action_type: reason_type: pause_map");
for (i = 0; i < WLAN_HDD_MAX_HISTORY_ENTRY; i++) {
hdd_err("%d: %u: %s: %s: %x",
/* using hdd_log to avoid printing function name */
if (adapter->queue_oper_history[i].time == 0)
continue;
hdd_log(QDF_TRACE_LEVEL_ERROR,
"%d: %u: %s: %s: %x",
i, qdf_system_ticks_to_msecs(
adapter->queue_oper_history[i].time),
hdd_action_type_to_string(

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2016 The Linux Foundation. All rights reserved.
* Copyright (c) 2015-2017 The Linux Foundation. All rights reserved.
*
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
*
@ -373,3 +373,62 @@ int hdd_napi_poll(struct napi_struct *napi, int budget)
{
return hif_napi_poll(cds_get_context(QDF_MODULE_ID_HIF), napi, budget);
}
/**
* hdd_display_napi_stats() - print NAPI stats
*
* Return: == 0: success; !=0: failure
*/
int hdd_display_napi_stats(void)
{
int i, j, k, n; /* NAPI, CPU, bucket indices, bucket buf write index*/
int max;
struct qca_napi_data *napid;
struct qca_napi_info *napii;
struct qca_napi_stat *napis;
/*
* Expecting each NAPI bucket item to need at max 5 numerals + space for
* formatting. For example "10000 " Thus the array needs to have
* (5 + 1) * QCA_NAPI_NUM_BUCKETS bytes of space. Leaving one space at
* the end of the "buf" arrary for end of string char.
*/
char buf[6 * QCA_NAPI_NUM_BUCKETS + 1] = {'\0'};
napid = hdd_napi_get_all();
if (NULL == napid) {
hdd_err("%s unable to retrieve napi structure", __func__);
return -EFAULT;
}
qdf_print("[NAPI -- STATS]: scheds polls comps done time-lim pkt-lim napi-buckets(%d)", QCA_NAPI_NUM_BUCKETS);
for (i = 0; i < CE_COUNT_MAX; i++)
if (napid->ce_map & (0x01 << i)) {
napii = &(napid->napis[i]);
for (j = 0; j < NR_CPUS; j++) {
napis = &(napii->stats[j]);
n = 0;
max = sizeof(buf);
for (k = 0; k < QCA_NAPI_NUM_BUCKETS; k++) {
n += scnprintf(
buf + n, max - n,
" %d",
napis->napi_budget_uses[k]);
}
if (napis->napi_schedules != 0)
qdf_print("NAPI[%2d]CPU[%2d]: %7d %7d %7d %7d %8d %7d %s",
i, j,
napis->napi_schedules,
napis->napi_polls,
napis->napi_completes,
napis->napi_workdone,
napis->time_limit_reached,
napis->rxpkt_thresh_reached,
buf);
}
}
hif_napi_stats(napid);
return 0;
}

View file

@ -2931,14 +2931,14 @@ void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length,
}
len = scnprintf(buffer, buf_len,
"\nTransmit"
"\ncalled %u, dropped %u,"
"\n dropped BK %u, BE %u, VI %u, VO %u"
"\n classified BK %u, BE %u, VI %u, VO %u"
"\ncompleted %u,"
"\n\nReceive Total"
"\n packets %u, dropped %u, delivered %u, refused %u"
"\nTransmit[%lu] - "
"called %u, dropped %u,"
"\n[dropped] BK %u, BE %u, VI %u, VO %u"
"\n[classified] BK %u, BE %u, VI %u, VO %u"
"\n\nReceive[%lu] - "
"packets %u, dropped %u, delivered %u, refused %u"
"\n",
qdf_system_ticks(),
pStats->txXmitCalled,
pStats->txXmitDropped,
@ -2951,21 +2951,22 @@ void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length,
pStats->txXmitClassifiedAC[SME_AC_BE],
pStats->txXmitClassifiedAC[SME_AC_VI],
pStats->txXmitClassifiedAC[SME_AC_VO],
pStats->txCompleted,
qdf_system_ticks(),
total_rx_pkt, total_rx_dropped, total_rx_delv, total_rx_refused
);
for (i = 0; i < NUM_CPUS; i++) {
if (pStats->rxPackets[i] == 0)
continue;
len += scnprintf(buffer + len, buf_len - len,
"\nReceive CPU: %d"
"\n packets %u, dropped %u, delivered %u, refused %u",
"Rx CPU[%d]:"
"packets %u, dropped %u, delivered %u, refused %u\n",
i, pStats->rxPackets[i], pStats->rxDropped[i],
pStats->rxDelivered[i], pStats->rxRefused[i]);
}
len += scnprintf(buffer + len, buf_len - len,
"\n\nTX_FLOW"
"\nTX_FLOW"
"\nCurrent status: %s"
"\ntx-flow timer start count %u"
"\npause count %u, unpause count %u",
@ -2976,10 +2977,6 @@ void hdd_wlan_get_stats(hdd_adapter_t *pAdapter, uint16_t *length,
len += cdp_stats(cds_get_context(QDF_MODULE_ID_SOC),
pAdapter->sessionId, &buffer[len], (buf_len - len));
len += hdd_napi_stats(buffer + len, buf_len - len,
NULL, hdd_napi_get_all());
*length = len + 1;
}
@ -3092,20 +3089,41 @@ void hdd_wlan_list_fw_profile(uint16_t *length,
*length = len + 1;
}
/**
* hdd_display_stats_help() - print statistics help
*
* Return: none
*/
void hdd_display_stats_help(void)
{
hdd_err("iwpriv wlan0 dumpStats [option] - dump statistics");
hdd_err("iwpriv wlan0 clearStats [option] - clear statistics");
hdd_err("options:");
hdd_err(" 1 -- TXRX Layer statistics");
hdd_err(" 2 -- Bandwidth compute timer stats");
hdd_err(" 3 -- TSO statistics");
hdd_err(" 4 -- Network queue statistics");
hdd_err(" 5 -- Flow control statistics");
hdd_err(" 6 -- Per Layer statistics");
hdd_err(" 7 -- Copy engine interrupt statistics");
hdd_err(" 8 -- LRO statistics");
hdd_err(" 9 -- NAPI statistics");
}
/**
* hdd_wlan_dump_stats() - display dump Stats
* @adapter: adapter handle
* @value: value from user
*
* Return: none
* Return: 0 => success, error code on failure
*/
void hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value)
int hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value)
{
int ret = 0;
QDF_STATUS status;
hdd_context_t *hdd_ctx = WLAN_HDD_GET_CTX(adapter);
switch (value) {
case WLAN_TXRX_HIST_STATS:
wlan_hdd_display_tx_rx_histogram(hdd_ctx);
break;
@ -3117,11 +3135,22 @@ void hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value)
break;
case WLAN_LRO_STATS:
hdd_lro_display_stats(hdd_ctx);
case WLAN_NAPI_STATS:
if (hdd_display_napi_stats()) {
hdd_err("error displaying napi stats");
ret = EFAULT;
}
break;
default:
cdp_display_stats(cds_get_context(QDF_MODULE_ID_SOC), value);
status = cdp_display_stats(cds_get_context(QDF_MODULE_ID_SOC),
value);
if (status == QDF_STATUS_E_INVAL) {
hdd_display_stats_help();
ret = EINVAL;
}
break;
}
return ret;
}
/**
@ -8369,7 +8398,7 @@ static int __iw_setint_getnone(struct net_device *dev,
case WE_DUMP_STATS:
{
hdd_notice("WE_DUMP_STATS val %d", set_value);
hdd_wlan_dump_stats(pAdapter, set_value);
ret = hdd_wlan_dump_stats(pAdapter, set_value);
break;
}