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
diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c
index 5e6336b..5a4d55a 100644
--- a/core/dp/txrx/ol_txrx.c
+++ b/core/dp/txrx/ol_txrx.c
@@ -3919,7 +3919,7 @@
}
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 @@
#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 @@
#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 @@
break;
#endif
default:
- ol_txrx_display_stats_help();
+ status = QDF_STATUS_E_INVAL;
break;
}
+
+ return;
}
/**
diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h
index ecbe851..b9cf5ee 100644
--- a/core/hdd/inc/wlan_hdd_main.h
+++ b/core/hdd/inc/wlan_hdd_main.h
@@ -322,7 +322,7 @@
#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 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);
diff --git a/core/hdd/inc/wlan_hdd_napi.h b/core/hdd/inc/wlan_hdd_napi.h
index 81f9734..67f4b06 100644
--- a/core/hdd/inc/wlan_hdd_napi.h
+++ b/core/hdd/inc/wlan_hdd_napi.h
@@ -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 @@
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_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;
diff --git a/core/hdd/inc/wlan_hdd_wext.h b/core/hdd/inc/wlan_hdd_wext.h
index 80f1f37..b9b0796 100644
--- a/core/hdd/inc/wlan_hdd_wext.h
+++ b/core/hdd/inc/wlan_hdd_wext.h
@@ -301,6 +301,7 @@
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);
diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c
index 2d6bb6f..5007fcb 100644
--- a/core/hdd/src/wlan_hdd_hostapd.c
+++ b/core/hdd/src/wlan_hdd_hostapd.c
@@ -3297,7 +3297,7 @@
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:
diff --git a/core/hdd/src/wlan_hdd_ioctl.c b/core/hdd/src/wlan_hdd_ioctl.c
index 4801fab..ec8d5b7 100644
--- a/core/hdd/src/wlan_hdd_ioctl.c
+++ b/core/hdd/src/wlan_hdd_ioctl.c
@@ -6102,303 +6102,6 @@
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 @@
#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},
diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c
index bb573a1..65a3825 100644
--- a/core/hdd/src/wlan_hdd_main.c
+++ b/core/hdd/src/wlan_hdd_main.c
@@ -6150,17 +6150,24 @@
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 @@
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 @@
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 @@
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(
diff --git a/core/hdd/src/wlan_hdd_napi.c b/core/hdd/src/wlan_hdd_napi.c
index ea72cca..614d8b3 100644
--- a/core/hdd/src/wlan_hdd_napi.c
+++ b/core/hdd/src/wlan_hdd_napi.c
@@ -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 @@
{
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;
+}
+
diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c
index 44a5071..8592bf5 100644
--- a/core/hdd/src/wlan_hdd_wext.c
+++ b/core/hdd/src/wlan_hdd_wext.c
@@ -2931,14 +2931,14 @@
}
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 @@
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 @@
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 @@
*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 @@
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 @@
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;
}