blob: 5cc9218e3f371bfc03c4202aa7fabac38b3b17f7 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**************************************************************************
*/
/*
* nss_wifili_stats.c
* NSS wifili statistics APIs
*/
#include "nss_tx_rx_common.h"
#include "nss_core.h"
#include "nss_wifili_if.h"
#include "nss_wifili_stats.h"
#include "nss_wifili_strings.h"
/*
* Declare atomic notifier data structure for statistics.
*/
ATOMIC_NOTIFIER_HEAD(nss_wifili_stats_notifier);
/*
* Statistics structures
* The structure will hold the statistics for 3 SOCs.
*/
struct nss_wifili_soc_stats soc_stats[NSS_WIFILI_MAX_SOC_NUM];
/*
* nss_wifili_stats_read()
* Read wifili statistics
*/
static ssize_t nss_wifili_stats_read(struct file *fp, char __user *ubuf, size_t sz, loff_t *ppos)
{
uint32_t i;
/*
* max output lines = ((#stats + eight blank lines) * #WIFILI #STATS) + start/end tag + 3 blank
* + Number of Extra outputlines for future reference to add new stats
*/
uint32_t max_pdev = 0;
uint32_t max_output_lines;
size_t size_al = 0;
size_t size_wr = 0;
ssize_t bytes_read = 0;
char *lbuf = NULL;
uint32_t soc_idx;
struct nss_wifili_stats *stats_wifili = NULL;
/*
* Max number of pdev depends on type of soc (Internal/Attached).
*/
for (soc_idx = 0; soc_idx < NSS_WIFILI_MAX_SOC_NUM; soc_idx++) {
max_pdev += soc_stats[soc_idx].soc_maxpdev;
}
/*
* Max pdev cannot be null.
*/
if (unlikely(max_pdev == 0)) {
nss_warning("Cannot have max pdev zero ");
return 0;
}
max_output_lines = (((NSS_WIFILI_STATS_MAX + 9) * max_pdev) +
NSS_WIFILI_STATS_WBM_MAX + NSS_STATS_EXTRA_OUTPUT_LINES);
size_al = NSS_STATS_MAX_STR_LENGTH * max_output_lines;
lbuf = kzalloc(size_al, GFP_KERNEL);
if (unlikely(lbuf == NULL)) {
nss_warning("Could not allocate memory for local statistics buffer");
return 0;
}
size_wr += nss_stats_banner(lbuf, size_wr, size_al, "wifili", NSS_STATS_SINGLE_CORE);
for (soc_idx = 0; soc_idx < NSS_WIFILI_MAX_SOC_NUM; soc_idx++) {
stats_wifili = &(soc_stats[soc_idx].stats_wifili);
for (i = 0; i < soc_stats[soc_idx].soc_maxpdev; i++) {
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "txrx", i
, nss_wifili_strings_stats_txrx
, stats_wifili->stats_txrx[i]
, NSS_WIFILI_STATS_TXRX_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr
, size_al - size_wr, "\n");
/*
* Filling TCL ring stats
*/
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "tcl ring", i
, nss_wifili_strings_stats_tcl
, stats_wifili->stats_tcl_ring[i]
, NSS_WIFILI_STATS_TCL_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr
, size_al - size_wr, "\n");
/*
* Filling TCL comp stats
*/
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "tcl comp", i
, nss_wifili_strings_stats_tx_comp
, stats_wifili->stats_tx_comp[i]
, NSS_WIFILI_STATS_TX_DESC_FREE_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr
, size_al - size_wr, "\n");
/*
* Filling reo ring stats
*/
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "reo ring", i
, nss_wifili_strings_stats_reo
, stats_wifili->stats_reo[i]
, NSS_WIFILI_STATS_REO_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr
, size_al - size_wr, "\n");
/*
* Filling TX SW Pool
*/
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "tx sw pool", i
, nss_wifili_strings_stats_txsw_pool
, stats_wifili->stats_tx_desc[i]
, NSS_WIFILI_STATS_TX_DESC_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr
, size_al - size_wr, "\n");
/*
* Filling TX EXt SW Pool
*/
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "tx ext sw pool", i
, nss_wifili_strings_stats_ext_txsw_pool
, stats_wifili->stats_ext_tx_desc[i]
, NSS_WIFILI_STATS_EXT_TX_DESC_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr
, size_al - size_wr, "\n");
/*
* Filling rxdma pool stats
*/
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "rxdma pool", i
, nss_wifili_strings_stats_rxdma_pool
, stats_wifili->stats_rx_desc[i]
, NSS_WIFILI_STATS_RX_DESC_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr
, size_al - size_wr, "\n");
/*
* Filling rxdma ring stats
*/
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "rxdma ring", i
, nss_wifili_strings_stats_rxdma_ring
, stats_wifili->stats_rxdma[i]
, NSS_WIFILI_STATS_RXDMA_DESC_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr
, size_al - size_wr, "\n");
}
/*
* Filling wbm ring stats
*/
spin_lock_bh(&nss_top_main.stats_lock);
size_wr += nss_stats_print("wifili", "wbm ring"
, NSS_STATS_SINGLE_INSTANCE
, nss_wifili_strings_stats_wbm
, stats_wifili->stats_wbm
, NSS_WIFILI_STATS_WBM_MAX
, lbuf, size_wr, size_al);
spin_unlock_bh(&nss_top_main.stats_lock);
size_wr += scnprintf(lbuf + size_wr, size_al - size_wr, "\n");
}
bytes_read = simple_read_from_buffer(ubuf, sz, ppos, lbuf, strlen(lbuf));
kfree(lbuf);
return bytes_read;
}
/*
* wifili_stats_ops
*/
NSS_STATS_DECLARE_FILE_OPERATIONS(wifili);
/*
* nss_wifili_stats_dentry_create()
* Create wifili statistics debug entry.
*/
void nss_wifili_stats_dentry_create(void)
{
nss_stats_create_dentry("wifili", &nss_wifili_stats_ops);
}
/*
* nss_wifili_stats_sync()
* Handle the syncing of WIFI stats.
*/
void nss_wifili_stats_sync(struct nss_ctx_instance *nss_ctx,
struct nss_wifili_stats_sync_msg *wlsoc_stats, uint16_t interface)
{
struct nss_top_instance *nss_top = nss_ctx->nss_top;
struct nss_wifili_soc_stats *nwss = NULL;
struct nss_wifili_stats *stats = NULL;
struct nss_wifili_device_stats *devstats = &wlsoc_stats->stats;
uint32_t index;
/*
* Max number of pdev depends on type of soc (Internal/Attached).
*/
switch (interface) {
case NSS_WIFILI_INTERNAL_INTERFACE:
nwss = &soc_stats[0];
nwss->soc_maxpdev = NSS_WIFILI_MAX_PDEV_NUM_MSG;
break;
case NSS_WIFILI_EXTERNAL_INTERFACE0:
nwss = &soc_stats[1];
nwss->soc_maxpdev = NSS_WIFILI_SOC_ATTACHED_MAX_PDEV_NUM;
break;
case NSS_WIFILI_EXTERNAL_INTERFACE1:
nwss = &soc_stats[2];
nwss->soc_maxpdev = NSS_WIFILI_SOC_ATTACHED_MAX_PDEV_NUM;
break;
default:
nss_warning("%px: Invalid wifili interface\n", nss_ctx);
return;
}
/*
* Wifili statistics structure.
*/
stats = &(nwss->stats_wifili);
spin_lock_bh(&nss_top->stats_lock);
for (index = 0; index < nwss->soc_maxpdev; index++) {
/*
* Rx stats
*/
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_MSDU_ERROR] +=
devstats->rx_data_stats[index].rx_msdu_err;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_INV_PEER_RCV] +=
(devstats->rx_data_stats[index].rx_inv_peer +
devstats->rx_data_stats[index].rx_scatter_inv_peer);
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_WDS_SRCPORT_EXCEPTION] +=
devstats->rx_data_stats[index].rx_wds_learn_send;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_WDS_SRCPORT_EXCEPTION_FAIL] +=
devstats->rx_data_stats[index].rx_wds_learn_send_fail;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_DELIVERD] +=
devstats->rx_data_stats[index].rx_deliver_cnt;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_DELIVER_DROPPED] +=
devstats->rx_data_stats[index].rx_deliver_cnt_fail;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_INTRA_BSS_UCAST] +=
devstats->rx_data_stats[index].rx_intra_bss_ucast_send;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_INTRA_BSS_UCAST_FAIL] +=
devstats->rx_data_stats[index].rx_intra_bss_ucast_send_fail;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_INTRA_BSS_MCAST] +=
devstats->rx_data_stats[index].rx_intra_bss_mcast_send;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_INTRA_BSS_MCAST_FAIL] +=
devstats->rx_data_stats[index].rx_intra_bss_mcast_send_fail;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_SG_RCV_SEND] +=
devstats->rx_data_stats[index].rx_sg_recv_send;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_SG_RCV_FAIL] +=
devstats->rx_data_stats[index].rx_sg_recv_fail;
stats->stats_txrx[index][NSS_STATS_WIFILI_RX_MCAST_ECHO] +=
devstats->rx_data_stats[index].rx_me_pkts;
stats->stats_txrx[index][NSS_STATS_WIFILI_RX_INV_TID] +=
devstats->rx_data_stats[index].rx_inv_tid;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_FRAG_INV_SC] +=
devstats->rx_data_stats[index].rx_frag_inv_sc;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_FRAG_INV_FC] +=
devstats->rx_data_stats[index].rx_frag_inv_fc;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_FRAG_NON_FRAG] +=
devstats->rx_data_stats[index].rx_non_frag_err;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_FRAG_RETRY] +=
devstats->rx_data_stats[index].rx_repeat_fragno;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_FRAG_OOO] +=
devstats->rx_data_stats[index].rx_ooo_frag;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_FRAG_OOO_SEQ] +=
devstats->rx_data_stats[index].rx_ooo_frag_seq;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_FRAG_ALL_FRAG_RCV] +=
devstats->rx_data_stats[index].rx_all_frag_rcv;
stats->stats_txrx[index][NSS_WIFILI_STATS_RX_FRAG_DELIVER] +=
devstats->rx_data_stats[index].rx_frag_deliver;
/*
* Tx stats
*/
stats->stats_txrx[index][NSS_WIFILI_STATS_TX_ENQUEUE] +=
devstats->tx_data_stats[index].tx_enqueue_cnt;
stats->stats_txrx[index][NSS_WIFILI_STATS_TX_ENQUEUE_DROP] +=
devstats->tx_data_stats[index].tx_enqueue_dropped;
stats->stats_txrx[index][NSS_WIFILI_STATS_TX_DEQUEUE] +=
devstats->tx_data_stats[index].tx_dequeue_cnt;
stats->stats_txrx[index][NSS_WIFILI_STATS_TX_HW_ENQUEUE_FAIL] +=
devstats->tx_data_stats[index].tx_send_fail_cnt;
stats->stats_txrx[index][NSS_WIFILI_STATS_TX_SENT_COUNT] +=
devstats->tx_data_stats[index].tx_processed_pkt;
}
/*
* update the tcl ring stats
*/
for (index = 0; index < NSS_WIFILI_MAX_TCL_DATA_RINGS_MSG; index++) {
stats->stats_tcl_ring[index][NSS_WIFILI_STATS_TCL_NO_HW_DESC] +=
devstats->tcl_stats[index].tcl_no_hw_desc;
stats->stats_tcl_ring[index][NSS_WIFILI_STATS_TCL_RING_FULL] +=
devstats->tcl_stats[index].tcl_ring_full;
stats->stats_tcl_ring[index][NSS_WIFILI_STATS_TCL_RING_SENT] +=
devstats->tcl_stats[index].tcl_ring_sent;
}
/*
* update the tcl comp stats
*/
for (index = 0; index < NSS_WIFILI_MAX_TCL_DATA_RINGS_MSG; index++) {
stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_DESC_FREE_INV_BUFSRC] +=
devstats->txcomp_stats[index].invalid_bufsrc;
stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_DESC_FREE_INV_COOKIE] +=
devstats->txcomp_stats[index].invalid_cookie;
stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_DESC_FREE_HW_RING_EMPTY] +=
devstats->txcomp_stats[index].hw_ring_empty;
stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_DESC_FREE_REAPED] +=
devstats->txcomp_stats[index].ring_reaped;
stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_CAPTURE_ENQUEUE] +=
devstats->txcomp_stats[index].tx_cap_enqueue_count;
stats->stats_tx_comp[index][NSS_WIFILI_STATS_TX_CAPTURE_ENQUEUE_FAIL] +=
devstats->txcomp_stats[index].tx_cap_enqueue_fail_count;
}
/*
* update reo ring stats
*/
for (index = 0; index < NSS_WIFILI_MAX_REO_DATA_RINGS_MSG; index++) {
stats->stats_reo[index][NSS_WIFILI_STATS_REO_ERROR] +=
devstats->rxreo_stats[index].ring_error;
stats->stats_reo[index][NSS_WIFILI_STATS_REO_REAPED] +=
devstats->rxreo_stats[index].ring_reaped;
stats->stats_reo[index][NSS_WIFILI_STATS_REO_INV_COOKIE] +=
devstats->rxreo_stats[index].invalid_cookie;
stats->stats_reo[index][NSS_WIFILI_STATS_REO_FRAG_RCV] +=
devstats->rxreo_stats[index].defrag_reaped;
}
/*
* update tx sw pool
*/
for (index = 0; index < NSS_WIFILI_MAX_TXDESC_POOLS_MSG; index++) {
stats->stats_tx_desc[index][NSS_WIFILI_STATS_TX_DESC_IN_USE] =
devstats->tx_sw_pool_stats[index].desc_alloc;
stats->stats_tx_desc[index][NSS_WIFILI_STATS_TX_DESC_ALLOC_FAIL] +=
devstats->tx_sw_pool_stats[index].desc_alloc_fail;
stats->stats_tx_desc[index][NSS_WIFILI_STATS_TX_DESC_ALREADY_ALLOCATED] +=
devstats->tx_sw_pool_stats[index].desc_already_allocated;
stats->stats_tx_desc[index][NSS_WIFILI_STATS_TX_DESC_INVALID_FREE] +=
devstats->tx_sw_pool_stats[index].desc_invalid_free;
stats->stats_tx_desc[index][NSS_WIFILI_STATS_TX_DESC_FREE_SRC_FW] +=
devstats->tx_sw_pool_stats[index].tx_rel_src_fw;
stats->stats_tx_desc[index][NSS_WIFILI_STATS_TX_DESC_FREE_COMPLETION] +=
devstats->tx_sw_pool_stats[index].tx_rel_tx_desc;
stats->stats_tx_desc[index][NSS_WIFILI_STATS_TX_DESC_NO_PB] +=
devstats->tx_sw_pool_stats[index].tx_rel_no_pb;
stats->stats_tx_desc[index][NSS_WIFILI_STATS_TX_QUEUELIMIT_DROP] +=
devstats->tx_sw_pool_stats[index].tx_queue_limit_drop;
}
/*
* update ext tx desc pool stats
*/
for (index = 0; index < NSS_WIFILI_MAX_TX_EXT_DESC_POOLS_MSG; index++) {
stats->stats_ext_tx_desc[index][NSS_WIFILI_STATS_EXT_TX_DESC_IN_USE] =
devstats->tx_ext_sw_pool_stats[index].desc_alloc;
stats->stats_ext_tx_desc[index][NSS_WIFILI_STATS_EXT_TX_DESC_ALLOC_FAIL] +=
devstats->tx_ext_sw_pool_stats[index].desc_alloc_fail;
stats->stats_ext_tx_desc[index][NSS_WIFILI_STATS_EXT_TX_DESC_ALREADY_ALLOCATED] +=
devstats->tx_ext_sw_pool_stats[index].desc_already_allocated;
stats->stats_ext_tx_desc[index][NSS_WIFILI_STATS_EXT_TX_DESC_INVALID_FREE] +=
devstats->tx_ext_sw_pool_stats[index].desc_invalid_free;
}
/*
* update rx desc pool stats
*/
for (index = 0; index < nwss->soc_maxpdev; index++) {
stats->stats_rx_desc[index][NSS_WIFILI_STATS_RX_DESC_NO_PB] +=
devstats->rx_sw_pool_stats[index].rx_no_pb;
stats->stats_rx_desc[index][NSS_WIFILI_STATS_RX_DESC_ALLOC_FAIL] +=
devstats->rx_sw_pool_stats[index].desc_alloc_fail;
stats->stats_rx_desc[index][NSS_WIFILI_STATS_RX_DESC_IN_USE] =
devstats->rx_sw_pool_stats[index].desc_alloc;
}
/*
* update rx dma ring stats
*/
for (index = 0; index < nwss->soc_maxpdev; index++) {
stats->stats_rxdma[index][NSS_WIFILI_STATS_RXDMA_DESC_UNAVAILABLE] +=
devstats->rxdma_stats[index].rx_hw_desc_unavailable;
stats->stats_rxdma[index][NSS_WIFILI_STATS_RXDMA_BUF_REPLENISHED] +=
devstats->rxdma_stats[index].rx_buf_replenished;
}
/*
* update wbm ring stats
*/
stats->stats_wbm[NSS_WIFILI_STATS_WBM_IE_LOCAL_ALLOC_FAIL] += devstats->rxwbm_stats.invalid_buf_mgr;
stats->stats_wbm[NSS_WIFILI_STATS_WBM_SRC_DMA] += devstats->rxwbm_stats.err_src_rxdma;
stats->stats_wbm[NSS_WIFILI_STATS_WBM_SRC_DMA_CODE_INV] += devstats->rxwbm_stats.err_src_rxdma_code_inv;
stats->stats_wbm[NSS_WIFILI_STATS_WBM_SRC_REO] += devstats->rxwbm_stats.err_src_reo;
stats->stats_wbm[NSS_WIFILI_STATS_WBM_SRC_REO_CODE_NULLQ] += devstats->rxwbm_stats.err_src_reo_code_nullq;
stats->stats_wbm[NSS_WIFILI_STATS_WBM_SRC_REO_CODE_INV] += devstats->rxwbm_stats.err_src_reo_code_inv;
stats->stats_wbm[NSS_WIFILI_STATS_WBM_SRC_INV] += devstats->rxwbm_stats.err_src_invalid;
spin_unlock_bh(&nss_top->stats_lock);
return;
}
/*
* nss_wifili_stats_notify()
* Sends notifications to the registered modules.
*
* Leverage NSS-FW statistics timing to update Netlink.
*/
void nss_wifili_stats_notify(struct nss_ctx_instance *nss_ctx, uint32_t if_num)
{
struct nss_wifili_stats_notification *wifili_stats;
uint32_t index = 0;
wifili_stats = kzalloc(sizeof(struct nss_wifili_stats_notification), GFP_ATOMIC);
if (!wifili_stats) {
nss_warning("%px: Failed to allocate memory for wifili stats\n", nss_ctx);
return;
}
wifili_stats->core_id = nss_ctx->id;
switch (if_num) {
case NSS_WIFILI_INTERNAL_INTERFACE:
index = 0;
break;
case NSS_WIFILI_EXTERNAL_INTERFACE0:
index = 1;
break;
case NSS_WIFILI_EXTERNAL_INTERFACE1:
index = 2;
break;
default:
nss_warning("%px: Invalid wifili interface\n", nss_ctx);
goto done;
}
wifili_stats->if_num = if_num;
memcpy(&wifili_stats->stats, &soc_stats[index].stats_wifili, sizeof(wifili_stats->stats));
atomic_notifier_call_chain(&nss_wifili_stats_notifier, NSS_STATS_EVENT_NOTIFY, (void *)wifili_stats);
done:
kfree(wifili_stats);
return;
}
/*
* nss_wifili_stats_register_notifier()
* Registers statistics notifier.
*/
int nss_wifili_stats_register_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_register(&nss_wifili_stats_notifier, nb);
}
EXPORT_SYMBOL(nss_wifili_stats_register_notifier);
/*
* nss_wifili_stats_unregister_notifier()
* Deregisters statistics notifier.
*/
int nss_wifili_stats_unregister_notifier(struct notifier_block *nb)
{
return atomic_notifier_chain_unregister(&nss_wifili_stats_notifier, nb);
}
EXPORT_SYMBOL(nss_wifili_stats_unregister_notifier);