From 3e2115b6e29b6848acc9665bc23f4d30b2ee6047 Mon Sep 17 00:00:00 2001 From: Mohit Khanna Date: Tue, 11 Oct 2016 13:18:29 -0700 Subject: [PATCH] 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 --- core/dp/txrx/ol_txrx.c | 51 ++---- core/hdd/inc/wlan_hdd_main.h | 4 +- core/hdd/inc/wlan_hdd_napi.h | 11 +- core/hdd/inc/wlan_hdd_wext.h | 1 + core/hdd/src/wlan_hdd_hostapd.c | 2 +- core/hdd/src/wlan_hdd_ioctl.c | 300 -------------------------------- core/hdd/src/wlan_hdd_main.c | 43 +++-- core/hdd/src/wlan_hdd_napi.c | 61 ++++++- core/hdd/src/wlan_hdd_wext.c | 71 +++++--- 9 files changed, 164 insertions(+), 380 deletions(-) diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index 5e6336be2b20..5a4d55a92cf1 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -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; } /** diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index ecbe851b629e..b9cf5eeab294 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -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); diff --git a/core/hdd/inc/wlan_hdd_napi.h b/core/hdd/inc/wlan_hdd_napi.h index 81f973405d1f..67f4b068f55b 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 @@ 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; diff --git a/core/hdd/inc/wlan_hdd_wext.h b/core/hdd/inc/wlan_hdd_wext.h index 80f1f376b671..b9b07961aa50 100644 --- a/core/hdd/inc/wlan_hdd_wext.h +++ b/core/hdd/inc/wlan_hdd_wext.h @@ -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); diff --git a/core/hdd/src/wlan_hdd_hostapd.c b/core/hdd/src/wlan_hdd_hostapd.c index 2d6bb6f22c54..5007fcb86e9f 100644 --- a/core/hdd/src/wlan_hdd_hostapd.c +++ b/core/hdd/src/wlan_hdd_hostapd.c @@ -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: diff --git a/core/hdd/src/wlan_hdd_ioctl.c b/core/hdd/src/wlan_hdd_ioctl.c index 4801faba7599..ec8d5b78eb47 100644 --- a/core/hdd/src/wlan_hdd_ioctl.c +++ b/core/hdd/src/wlan_hdd_ioctl.c @@ -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 +-- 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 [] : get the stats for a given NAPI instance - * NAPI SCALE : 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 [] -- if no then all\n" - "NAPI SCALE -- 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 "); - } 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}, diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index bb573a11f157..65a382556ed1 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -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( diff --git a/core/hdd/src/wlan_hdd_napi.c b/core/hdd/src/wlan_hdd_napi.c index ea72cca08f54..614d8b3ca30b 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 @@ 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; +} + diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 44a5071ef9f4..8592bf5734d4 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -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; }