From 9abd17fe45b6ae3faff67d3317b8f56a0bb06f13 Mon Sep 17 00:00:00 2001 From: tinlin Date: Wed, 14 Aug 2019 13:29:44 +0800 Subject: [PATCH] qcacld-3.0: Add debugfs for MIB statistics Define debugfs node in driver to export MIB counters to user app. Define macro WLAN_FEATURE_MIB_STATS for this feature that gets MIB statistics from fw. Change-Id: Icae8826309094d17e8f6d4503f617a3a7116d3c9 CRs-Fixed: 2548241 --- Kbuild | 4 + configs/default_defconfig | 1 + core/hdd/inc/wlan_hdd_debugfs_mibstat.h | 68 +++++ core/hdd/src/wlan_hdd_debugfs.c | 5 + core/hdd/src/wlan_hdd_debugfs_mibstat.c | 362 ++++++++++++++++++++++++ core/hdd/src/wlan_hdd_stats.c | 27 ++ core/hdd/src/wlan_hdd_stats.h | 10 + 7 files changed, 477 insertions(+) create mode 100644 core/hdd/inc/wlan_hdd_debugfs_mibstat.h create mode 100644 core/hdd/src/wlan_hdd_debugfs_mibstat.c diff --git a/Kbuild b/Kbuild index 6a6ef3775576..5584c0cf0f09 100644 --- a/Kbuild +++ b/Kbuild @@ -98,6 +98,9 @@ HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs.o ifeq ($(CONFIG_WLAN_FEATURE_LINK_LAYER_STATS), y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_llstat.o endif +ifeq ($(CONFIG_WLAN_FEATURE_MIB_STATS), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_mibstat.o +endif HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_csr.o HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_connect.o HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_offload.o @@ -2118,6 +2121,7 @@ cppflags-$(CONFIG_FEATURE_WLAN_LPHB) += -DFEATURE_WLAN_LPHB cppflags-$(CONFIG_QCA_SUPPORT_TX_THROTTLE) += -DQCA_SUPPORT_TX_THROTTLE cppflags-$(CONFIG_WMI_INTERFACE_EVENT_LOGGING) += -DWMI_INTERFACE_EVENT_LOGGING cppflags-$(CONFIG_WLAN_FEATURE_LINK_LAYER_STATS) += -DWLAN_FEATURE_LINK_LAYER_STATS +cppflags-$(CONFIG_WLAN_FEATURE_MIB_STATS) += -DWLAN_FEATURE_MIB_STATS cppflags-$(CONFIG_FEATURE_WLAN_EXTSCAN) += -DFEATURE_WLAN_EXTSCAN cppflags-$(CONFIG_160MHZ_SUPPORT) += -DCONFIG_160MHZ_SUPPORT cppflags-$(CONFIG_MCL) += -DCONFIG_MCL diff --git a/configs/default_defconfig b/configs/default_defconfig index 4cbadc873e99..d556deed2822 100644 --- a/configs/default_defconfig +++ b/configs/default_defconfig @@ -816,6 +816,7 @@ CONFIG_FEATURE_WLAN_LPHB := y CONFIG_QCA_SUPPORT_TX_THROTTLE := y CONFIG_WMI_INTERFACE_EVENT_LOGGING := y CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y +CONFIG_WLAN_FEATURE_MIB_STATS := y CONFIG_FEATURE_WLAN_EXTSCAN := n CONFIG_WMI_BCN_OFFLOAD := y CONFIG_160MHZ_SUPPORT := y diff --git a/core/hdd/inc/wlan_hdd_debugfs_mibstat.h b/core/hdd/inc/wlan_hdd_debugfs_mibstat.h new file mode 100644 index 000000000000..e42236cd3b75 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_debugfs_mibstat.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2019 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. + */ + +/** + * DOC: wlan_hdd_debugfs_mibstat.h + * + * WLAN Host Device Driver implementation to update + * debugfs with MIB statistics + */ + +#ifndef _WLAN_HDD_DEBUGFS_MIBSTAT_H +#define _WLAN_HDD_DEBUGFS_MIBSTAT_H + +#define DEBUGFS_MIBSTATS_BUF_SIZE 4096 + +#include + +#if defined(WLAN_FEATURE_MIB_STATS) && defined(WLAN_DEBUGFS) +/** + * hdd_debugfs_process_mib_stats() - Process mib stats from fw + * + * This function is used to store mib stats to global variable mib_stats. + * + * Return: None + */ +void hdd_debugfs_process_mib_stats(struct hdd_adapter *adapter, + struct stats_event *stats); + +/** + * wlan_hdd_create_mib_stats_file() - API to create MIB stats file + * @adapter: interface adapter pointer + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_create_mib_stats_file(struct hdd_adapter *adapter); + +/** + * wlan_hdd_destroy_mib_stats_lock() - API to destroy MIB stats lock + * + * Return: No return + */ +void wlan_hdd_destroy_mib_stats_lock(void); +#else +static inline int wlan_hdd_create_mib_stats_file(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline void wlan_hdd_destroy_mib_stats_lock(void) +{ +} +#endif +#endif /* #ifndef _WLAN_HDD_DEBUGFS_MIBSTAT_H */ diff --git a/core/hdd/src/wlan_hdd_debugfs.c b/core/hdd/src/wlan_hdd_debugfs.c index 05e6e16e65b4..41d5ede31a9b 100644 --- a/core/hdd/src/wlan_hdd_debugfs.c +++ b/core/hdd/src/wlan_hdd_debugfs.c @@ -33,6 +33,7 @@ #include #include #include +#include #define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8 #define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512 @@ -527,6 +528,9 @@ QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter) &fops_patterngen)) return QDF_STATUS_E_FAILURE; + if (wlan_hdd_create_mib_stats_file(adapter)) + return QDF_STATUS_E_FAILURE; + if (wlan_hdd_create_ll_stats_file(adapter)) return QDF_STATUS_E_FAILURE; @@ -544,5 +548,6 @@ QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter) void hdd_debugfs_exit(struct hdd_adapter *adapter) { debugfs_remove_recursive(adapter->debugfs_phy); + wlan_hdd_destroy_mib_stats_lock(); } #endif /* #ifdef WLAN_OPEN_SOURCE */ diff --git a/core/hdd/src/wlan_hdd_debugfs_mibstat.c b/core/hdd/src/wlan_hdd_debugfs_mibstat.c new file mode 100644 index 000000000000..de8169acc43c --- /dev/null +++ b/core/hdd/src/wlan_hdd_debugfs_mibstat.c @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2019 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. + */ + +/** + * DOC: wlan_hdd_debugfs_mibstat.c + * + * WLAN Host Device Driver implementation to update + * debugfs with MIB statistics + */ + +#include +#include "osif_sync.h" +#include +#include +#include + +struct mib_stats_buf { + ssize_t len; + uint8_t *result; +}; + +static struct mib_stats_buf mib_stats; + +qdf_mutex_t mibstats_lock; + +void hdd_debugfs_process_mib_stats(struct hdd_adapter *adapter, + struct stats_event *stats) +{ + ssize_t len = 0; + uint8_t *buffer; + + hdd_enter(); + + qdf_mutex_acquire(&mibstats_lock); + if (!mib_stats.result) { + qdf_mutex_release(&mibstats_lock); + hdd_err("MIB statistics buffer is NULL"); + return; + } + + buffer = mib_stats.result; + buffer += mib_stats.len; + + len = scnprintf(buffer, DEBUGFS_MIBSTATS_BUF_SIZE - mib_stats.len, + "dot11RTSSuccessCount %d " + "\ndot11RTSFailureCount %d " + "\ndot11QosFailedCount %d " + "\ndot11QosRetryCount %d " + "\ndot11QosTransmittedFrameCount %d " + "\ndot11QosMPDUsReceivedCount %d " + "\ndot11TransmittedAMPDUCount %d " + "\ndot11QosACKFailureCount %d", + stats->mib_stats->mib_mac_statistics.rts_success_cnt, + stats->mib_stats->mib_mac_statistics.rts_fail_cnt, + stats->mib_stats->mib_qos_counters.qos_failed_cnt, + stats->mib_stats->mib_qos_counters.qos_retry_cnt, + stats->mib_stats->mib_qos_counters.qos_tx_frame_cnt, + stats->mib_stats->mib_qos_counters.qos_mpdu_rx_cnt, + stats->mib_stats->mib_counters_group3.tx_ampdu_cnt, + stats->mib_stats-> + mib_qos_counters.tx_qos_ack_fail_cnt_up + ); + + buffer += len; + mib_stats.len += len; + qdf_mutex_release(&mibstats_lock); + + hdd_exit(); +} + +static inline void wlan_hdd_mibstats_free_buf(void) +{ + qdf_mutex_acquire(&mibstats_lock); + qdf_mem_free(mib_stats.result); + mib_stats.result = NULL; + mib_stats.len = 0; + qdf_mutex_release(&mibstats_lock); +} + +static int wlan_hdd_mibstats_alloc_buf(void) +{ + qdf_mutex_acquire(&mibstats_lock); + if (mib_stats.result) { + qdf_mutex_release(&mibstats_lock); + hdd_err("Buffer is already allocated"); + return 0; + } + mib_stats.len = 0; + mib_stats.result = qdf_mem_malloc(DEBUGFS_MIBSTATS_BUF_SIZE); + if (!mib_stats.result) { + qdf_mutex_release(&mibstats_lock); + return -EINVAL; + } + qdf_mutex_release(&mibstats_lock); + return 0; +} + +/** + * hdd_debugfs_mib_stats_update() - Update userspace with local stats buffer + * @buf: userspace buffer (to which data is being copied into) + * @count: max data that can be copied into buf in bytes + * @pos: offset (where data should be copied into) + * + * This function copies mib statistics buffer into debugfs + * entry. + * + * Return: number of characters copied; 0 on no-copy + */ +static ssize_t hdd_debugfs_mib_stats_update(char __user *buf, + size_t count, loff_t *pos) +{ + ssize_t ret_cnt; + + hdd_enter(); + qdf_mutex_acquire(&mibstats_lock); + if (!mib_stats.result) { + qdf_mutex_release(&mibstats_lock); + hdd_err("Trying to read from NULL buffer"); + return 0; + } + + ret_cnt = simple_read_from_buffer(buf, count, pos, + mib_stats.result, + mib_stats.len); + qdf_mutex_release(&mibstats_lock); + hdd_debug("mib stats read req: count: %zu, pos: %lld", count, *pos); + + hdd_exit(); + return ret_cnt; +} + +/** + * __wlan_hdd_release_mib_stats_debugfs() - Function to free private + * memory on release + * @net_dev: net_device context used to register the debugfs file + * + * Return: Errno + */ +static int __wlan_hdd_release_mib_stats_debugfs(struct net_device *net_dev) + +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(net_dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + wlan_hdd_mibstats_free_buf(); + + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_release_mib_stats_debugfs() - SSR wrapper function to free + * private memory on release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_release_mib_stats_debugfs(struct inode *inode, + struct file *file) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_release_mib_stats_debugfs(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +/** + * __wlan_hdd_read_mib_stats_debugfs() - mib_stats debugfs handler + * @net_dev: net_device context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @pos: (unused) offset into the virtual file system + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t __wlan_hdd_read_mib_stats_debugfs(struct net_device *net_dev, + char __user *buf, + size_t count, loff_t *pos) + +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + ssize_t ret; + + hdd_enter_dev(net_dev); + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + goto free_buf; + + if (*pos == 0) { + ret = wlan_hdd_get_mib_stats(adapter); + if (ret) + goto free_buf; + } + + /* All the events are received and buffer is populated */ + ret = hdd_debugfs_mib_stats_update(buf, count, pos); + hdd_debug("%zu characters written into debugfs", ret); + + hdd_exit(); + + return ret; + +free_buf: + wlan_hdd_mibstats_free_buf(); + + hdd_exit(); + + return ret; +} + +/** + * wlan_hdd_read_mib_stats_debugfs() - SSR wrapper function to read + * mib stats + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, error number otherwise + */ +static ssize_t wlan_hdd_read_mib_stats_debugfs(struct file *file, + char __user *buf, size_t count, + loff_t *pos) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + ssize_t err_size; + + err_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (err_size) + return err_size; + + err_size = __wlan_hdd_read_mib_stats_debugfs(net_dev, buf, + count, pos); + + osif_vdev_sync_op_stop(vdev_sync); + + return err_size; +} + +/** + * __wlan_hdd_open_mib_stats_debugfs() - Function to save private on open + * @net_dev: net_device context used to register the debugfs file + * + * Return: Errno + */ +static int __wlan_hdd_open_mib_stats_debugfs(struct net_device *net_dev) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int errno; + + hdd_enter_dev(net_dev); + + errno = hdd_validate_adapter(adapter); + if (errno) + return errno; + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + errno = wlan_hdd_validate_context(hdd_ctx); + if (errno) + return errno; + + errno = wlan_hdd_mibstats_alloc_buf(); + if (errno) + return errno; + + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_open_mib_stats_debugfs() - SSR wrapper to save private + * on open + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: Errno + */ +static int wlan_hdd_open_mib_stats_debugfs(struct inode *inode, + struct file *file) +{ + struct net_device *net_dev = inode->i_private; + struct osif_vdev_sync *vdev_sync; + int errno; + + errno = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno) + return errno; + + errno = __wlan_hdd_open_mib_stats_debugfs(net_dev); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno; +} + +static const struct file_operations fops_mib_stats = { + .read = wlan_hdd_read_mib_stats_debugfs, + .open = wlan_hdd_open_mib_stats_debugfs, + .release = wlan_hdd_release_mib_stats_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int wlan_hdd_create_mib_stats_file(struct hdd_adapter *adapter) +{ + if (!debugfs_create_file("mib_stats", 0444, adapter->debugfs_phy, + adapter->dev, &fops_mib_stats)) + return -EINVAL; + + if (QDF_IS_STATUS_ERROR(qdf_mutex_create( + &mibstats_lock))) { + hdd_err("mibstats lock init failed!"); + return QDF_STATUS_E_FAILURE; + } + + return 0; +} + +void wlan_hdd_destroy_mib_stats_lock(void) +{ + qdf_mutex_destroy(&mibstats_lock); +} diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index b19bf2357bff..adcd9de33b22 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -35,6 +35,7 @@ #include "wlan_hdd_hostapd.h" #include "wlan_osif_request_manager.h" #include "wlan_hdd_debugfs_llstat.h" +#include "wlan_hdd_debugfs_mibstat.h" #include "wlan_reg_services_api.h" #include #include "wlan_cp_stats_mc_ucfg_api.h" @@ -5266,6 +5267,32 @@ out: return status; } +#ifdef WLAN_FEATURE_MIB_STATS +QDF_STATUS wlan_hdd_get_mib_stats(struct hdd_adapter *adapter) +{ + int ret = 0; + struct stats_event *stats; + + if (!adapter) { + hdd_err("Invalid context, adapter"); + return QDF_STATUS_E_FAULT; + } + + stats = wlan_cfg80211_mc_cp_stats_get_mib_stats( + adapter->vdev, + &ret); + if (ret || !stats) { + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + return ret; + } + + hdd_debugfs_process_mib_stats(adapter, stats); + + wlan_cfg80211_mc_cp_stats_free_stats_event(stats); + return ret; +} +#endif + QDF_STATUS wlan_hdd_get_rssi(struct hdd_adapter *adapter, int8_t *rssi_value) { int ret = 0, i; diff --git a/core/hdd/src/wlan_hdd_stats.h b/core/hdd/src/wlan_hdd_stats.h index a6272db124c7..88a9b587e053 100644 --- a/core/hdd/src/wlan_hdd_stats.h +++ b/core/hdd/src/wlan_hdd_stats.h @@ -352,6 +352,16 @@ int wlan_hdd_get_rcpi(struct hdd_adapter *adapter, uint8_t *mac, int32_t *rcpi_value, enum rcpi_measurement_type measurement_type); +#ifdef WLAN_FEATURE_MIB_STATS +/** + * wlan_hdd_get_mib_stats() - Get the mib statistics + * @adapter: adapter upon which the measurement is requested + * + * Return: QDF_STATUS_SUCCESS on success, QDF_STATUS_E_** on error + */ +QDF_STATUS wlan_hdd_get_mib_stats(struct hdd_adapter *adapter); +#endif + /** * wlan_hdd_get_rssi() - Get the current RSSI * @adapter: adapter upon which the measurement is requested