From 197d4177339d5e62b2e78b5900985351c705f6dd Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Sirasanagandla Date: Thu, 15 Feb 2018 19:03:29 +0530 Subject: [PATCH] qcacld-3.0: Add debugfs framework support for CSR Add debugfs framework support to get connect, scan, roam scan statistics and offload info from debugfs. Change-Id: I86bdd7e449488d2bcda1b2eaaeb07aac7465770b CRs-Fixed: 2203626 --- Kbuild | 1 + core/hdd/inc/wlan_hdd_assoc.h | 2 + core/hdd/inc/wlan_hdd_debugfs.h | 122 +++++++++- core/hdd/inc/wlan_hdd_debugfs_csr.h | 123 ++++++++++ core/hdd/inc/wlan_hdd_main.h | 7 + core/hdd/src/wlan_hdd_debugfs.c | 45 ++++ core/hdd/src/wlan_hdd_debugfs_csr.c | 340 ++++++++++++++++++++++++++++ core/hdd/src/wlan_hdd_driver_ops.c | 7 + core/hdd/src/wlan_hdd_main.c | 22 +- 9 files changed, 663 insertions(+), 6 deletions(-) create mode 100644 core/hdd/inc/wlan_hdd_debugfs_csr.h create mode 100644 core/hdd/src/wlan_hdd_debugfs_csr.c diff --git a/Kbuild b/Kbuild index f55013afad..7434f3ede3 100755 --- a/Kbuild +++ b/Kbuild @@ -70,6 +70,7 @@ ifeq ($(CONFIG_WLAN_DEBUGFS), y) 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 +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_csr.o endif endif diff --git a/core/hdd/inc/wlan_hdd_assoc.h b/core/hdd/inc/wlan_hdd_assoc.h index 8a27418d59..6d2aef5191 100644 --- a/core/hdd/inc/wlan_hdd_assoc.h +++ b/core/hdd/inc/wlan_hdd_assoc.h @@ -31,6 +31,8 @@ #include #include +#define HDD_TIME_STRING_LEN 24 + /* Preprocessor Definitions and Constants */ #ifdef FEATURE_WLAN_TDLS #define HDD_MAX_NUM_TDLS_STA 8 diff --git a/core/hdd/inc/wlan_hdd_debugfs.h b/core/hdd/inc/wlan_hdd_debugfs.h index 01cf805416..daa4795e58 100644 --- a/core/hdd/inc/wlan_hdd_debugfs.h +++ b/core/hdd/inc/wlan_hdd_debugfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved. + * Copyright (c) 2013-2018 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 @@ -20,8 +20,77 @@ #define _WLAN_HDD_DEBUGFS_H #ifdef WLAN_DEBUGFS + +#define HDD_DEBUGFS_FILE_NAME_MAX 24 + +/** + * enum hdd_debugfs_file_id - Debugfs file Identifier + * @HDD_DEBUFS_FILE_ID_CONNECT_INFO: connect_info file id + * @HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO: roam_scan_stats file id + * @HDD_DEBUFS_FILE_ID_OFFLOAD_INFO: offload_info file id + * @HDD_DEBUGFS_FILE_ID_MAX: maximum id of csr debugfs file + */ +enum hdd_debugfs_file_id { + HDD_DEBUFS_FILE_ID_CONNECT_INFO = 0, + HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO = 1, + HDD_DEBUFS_FILE_ID_OFFLOAD_INFO = 2, + + HDD_DEBUGFS_FILE_ID_MAX, +}; + +/** + * struct hdd_debugfs_file_info - Debugfs file info + * @name: name of debugfs file + * @id: id from enum hdd_debugfs_file_id used to identify file + * @buf_max_size: max size of buffer from which debugfs file is updated + * @entry: dentry pointer to debugfs file + */ +struct hdd_debugfs_file_info { + uint8_t name[HDD_DEBUGFS_FILE_NAME_MAX]; + enum hdd_debugfs_file_id id; + ssize_t buf_max_size; + struct dentry *entry; +}; + QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter); void hdd_debugfs_exit(struct hdd_adapter *adapter); + +/** + * hdd_wait_for_debugfs_threads_completion() - Wait for debugfs threads + * completion before proceeding further to stop modules + * + * Return: true if there is no debugfs open + * false if there is at least one debugfs open + */ +bool hdd_wait_for_debugfs_threads_completion(void); + +/** + * hdd_return_debugfs_threads_count() - Return active debugfs threads + * + * Return: total number of active debugfs threads in driver + */ +int hdd_return_debugfs_threads_count(void); + +/** + * hdd_debugfs_thread_increment() - Increment debugfs thread count + * + * This function is used to increment and keep track of debugfs thread count. + * This is invoked for every file open operation. + * + * Return: None + */ +void hdd_debugfs_thread_increment(void); + +/** + * hdd_debugfs_thread_decrement() - Decrement debugfs thread count + * + * This function is used to decrement and keep track of debugfs thread count. + * This is invoked for every file release operation. + * + * Return: None + */ +void hdd_debugfs_thread_decrement(void); + #else static inline QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter) { @@ -31,5 +100,56 @@ static inline QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter) static inline void hdd_debugfs_exit(struct hdd_adapter *adapter) { } + +/** + * hdd_wait_for_debugfs_threads_completion() - Wait for debugfs threads + * completion before proceeding further to stop modules + * + * Return: true if there is no debugfs open + * false if there is at least one debugfs open + */ +static inline +bool hdd_wait_for_debugfs_threads_completion(void) +{ + return true; +} + +/** + * hdd_return_debugfs_threads_count() - Return active debugfs threads + * + * Return: total number of active debugfs threads in driver + */ +static inline +int hdd_return_debugfs_threads_count(void) +{ + return 0; +} + +/** + * hdd_debugfs_thread_increment() - Increment debugfs thread count + * + * This function is used to increment and keep track of debugfs thread count. + * This is invoked for every file open operation. + * + * Return: None + */ +static inline +void hdd_debugfs_thread_increment(void) +{ +} + +/** + * hdd_debugfs_thread_decrement() - Decrement debugfs thread count + * + * This function is used to decrement and keep track of debugfs thread count. + * This is invoked for every file release operation. + * + * Return: None + */ +static inline +void hdd_debugfs_thread_decrement(void) +{ +} + #endif /* #ifdef WLAN_DEBUGFS */ #endif /* #ifndef _WLAN_HDD_DEBUGFS_H */ diff --git a/core/hdd/inc/wlan_hdd_debugfs_csr.h b/core/hdd/inc/wlan_hdd_debugfs_csr.h new file mode 100644 index 0000000000..60a7dbe3d0 --- /dev/null +++ b/core/hdd/inc/wlan_hdd_debugfs_csr.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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. + */ + +/* + * This file was originally distributed by Qualcomm Atheros, Inc. + * under proprietary terms before Copyright ownership was assigned + * to the Linux Foundation. + */ + +/** + * DOC: wlan_hdd_debugfs_csr.h + * + * WLAN Host Device Driver implementation to update + * debugfs with connect, scan and roam information + */ + +#ifndef _WLAN_HDD_DEBUGFS_CSR_H +#define _WLAN_HDD_DEBUGFS_CSR_H + +#include + +#ifdef WLAN_DEBUGFS + +/** + * struct wlan_hdd_debugfs_buffer_info - Debugfs buffer info + * @length: current length of the debugfs buffer + * @max_buf_len: maximum buffer length of the debugfs buffer + * @id: id from enum hdd_debugfs_file_id used to identify file + * @data: start of debugfs buffer from which file read starts + * @adapter: pointer to adapter + * + * This structure is used to hold the debugfs buffer details and is stored in + * private data of file argument in file open operation. + */ +struct wlan_hdd_debugfs_buffer_info { + ssize_t length; + ssize_t max_buf_len; + enum hdd_debugfs_file_id id; + uint8_t *data; + struct hdd_adapter *adapter; +}; + +/** + * wlan_hdd_debugfs_csr_init() - Create wifi diagnostic debugfs files + * @adapter: pointer to adapter for which debugfs files are to be created + * + * Return: None + */ +void wlan_hdd_debugfs_csr_init(struct hdd_adapter *adapter); + +/** + * wlan_hdd_debugfs_csr_deinit() - Remove wifi diagnostic debugfs files + * @adapter: pointer to adapter for which debugfs files are to be removed + * + * Return: None + */ +void wlan_hdd_debugfs_csr_deinit(struct hdd_adapter *adapter); + +/** + * wlan_hdd_current_time_info_debugfs() - API to get time into user buffer + * @buf: output buffer to hold current time when queried + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +ssize_t +wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len); + +#else +/** + * wlan_hdd_debugfs_csr_init() - Create wifi diagnostic debugfs files + * @adapter: pointer to adapter for which debugfs files are to be created + * + * Return: None + */ +static inline void wlan_hdd_debugfs_csr_init(struct hdd_adapter *adapter) +{ +} + +/** + * wlan_hdd_debugfs_csr_deinit() - Remove wifi diagnostic debugfs files + * @adapter: pointer to adapter for which debugfs files are to be removed + * + * Return: None + */ +static inline void wlan_hdd_debugfs_csr_deinit(struct hdd_adapter *adapter) +{ +} + +/** + * wlan_hdd_current_time_info_debugfs() - API to get time into user buffer + * @buf: output buffer to hold current time when queried + * @buf_avail_len: available buffer length + * + * Return: No.of bytes copied + */ +static inline ssize_t +wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len) +{ + return 0; +} + +#endif + +#endif /* _WLAN_HDD_DEBUGFS_CSR_H */ diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index 265ef675a2..c02df39ae3 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -63,6 +63,7 @@ #include "wlan_hdd_tdls.h" #include "wlan_hdd_tsf.h" #include "wlan_hdd_cfg80211.h" +#include "wlan_hdd_debugfs.h" #include #include "sap_api.h" #include @@ -254,6 +255,8 @@ enum hdd_driver_flags { #define WLAN_WAIT_TIME_APF 1000 +#define WLAN_WAIT_TIME_FW_ROAM_STATS 1000 + /* Maximum time(ms) to wait for RSO CMD status event */ #define WAIT_TIME_RSO_CMD_STATUS 2000 @@ -1470,6 +1473,10 @@ struct hdd_adapter { #ifdef FEATURE_WLAN_APF struct hdd_apf_context apf_context; #endif /* FEATURE_WLAN_APF */ + +#ifdef WLAN_DEBUGFS + struct hdd_debugfs_file_info csr_file[HDD_DEBUGFS_FILE_ID_MAX]; +#endif /* WLAN_DEBUGFS */ }; #define WLAN_HDD_GET_STATION_CTX_PTR(adapter) (&(adapter)->session.station) diff --git a/core/hdd/src/wlan_hdd_debugfs.c b/core/hdd/src/wlan_hdd_debugfs.c index db1ea4d1c3..c451da836a 100644 --- a/core/hdd/src/wlan_hdd_debugfs.c +++ b/core/hdd/src/wlan_hdd_debugfs.c @@ -41,6 +41,51 @@ #define POWER_DEBUGFS_BUFFER_MAX_LEN 4096 #endif +#define MAX_DEBUGFS_WAIT_ITERATIONS 20 +#define DEBUGFS_WAIT_SLEEP_TIME 100 + +static qdf_atomic_t debugfs_thread_count; + +void hdd_debugfs_thread_increment(void) +{ + qdf_atomic_inc(&debugfs_thread_count); +} + +void hdd_debugfs_thread_decrement(void) +{ + qdf_atomic_dec(&debugfs_thread_count); +} + +int hdd_return_debugfs_threads_count(void) +{ + return qdf_atomic_read(&debugfs_thread_count); +} + +bool hdd_wait_for_debugfs_threads_completion(void) +{ + int count = MAX_DEBUGFS_WAIT_ITERATIONS; + int r; + + while (count) { + r = hdd_return_debugfs_threads_count(); + if (!r) + break; + + if (--count) { + hdd_debug("Waiting for %d debugfs threads to exit", r); + qdf_sleep(DEBUGFS_WAIT_SLEEP_TIME); + } + } + + /* at least one debugfs thread is executing */ + if (!count) { + hdd_err("Timed-out waiting for debugfs threads"); + return false; + } + + return true; +} + /** * __wcnss_wowpattern_write() - wow_pattern debugfs handler * @file: debugfs file handle diff --git a/core/hdd/src/wlan_hdd_debugfs_csr.c b/core/hdd/src/wlan_hdd_debugfs_csr.c new file mode 100644 index 0000000000..eb6f976432 --- /dev/null +++ b/core/hdd/src/wlan_hdd_debugfs_csr.c @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2018 The Linux Foundation. All rights reserved. + * + * Previously licensed under the ISC license by Qualcomm Atheros, Inc. + * + * + * 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_csr.c + * + * WLAN Host Device Driver implementation to update + * debugfs with roaming related information + */ + +#include +#include +#include +#include +#include "qwlan_version.h" +#include "wmi_unified_param.h" +#include "wlan_hdd_debugfs.h" + +ssize_t +wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len) +{ + ssize_t length; + char time_buffer[HDD_TIME_STRING_LEN]; + int ret_val; + + qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buffer, + sizeof(time_buffer)); + ret_val = scnprintf(buf, buf_avail_len, + "\nTime at which this file generated = %s\n", + time_buffer); + if (ret_val < 0) + return 0; + length = ret_val; + + return length; +} + +/** + * wlan_hdd_debugfs_update_csr() - Function to update internal debugfs buffer + * and write into user-space buffer + * @hdd_ctx: hdd context + * @adapter: adapter + * @id: used to identify file for which this info has to be read + * @buf: output buffer to write + * @buf_avail_len: length of the available buffer + * + * Return: Number of bytes read on success, zero otherwise + */ +static ssize_t +wlan_hdd_debugfs_update_csr(struct hdd_context *hdd_ctx, + struct hdd_adapter *adapter, + enum hdd_debugfs_file_id id, + uint8_t *buf, + ssize_t buf_avail_len) +{ + ssize_t len = 0; + + switch (id) { + case HDD_DEBUFS_FILE_ID_CONNECT_INFO: + /* populate connect info */ + break; + case HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO: + /* populate roam scan stats info */ + break; + case HDD_DEBUFS_FILE_ID_OFFLOAD_INFO: + /* populate offload info */ + break; + default: + hdd_err("Failed to fetch stats, unknown stats type"); + } + + return len; +} + +/** + * __wlan_hdd_read_debugfs_csr() - Function to read debug stats + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, zero otherwise + */ +static ssize_t +__wlan_hdd_read_debugfs_csr(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + struct wlan_hdd_debugfs_buffer_info *info; + struct hdd_adapter *adapter; + struct hdd_context *hdd_ctx; + int ret; + ssize_t length; + + hdd_enter(); + + info = file->private_data; + if (!info || !info->data) { + hdd_err("No valid private data"); + return 0; + } + + adapter = info->adapter; + if ((!adapter) || (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return 0; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return 0; + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return 0; + } + + if (*pos == 0) { + info->length = wlan_hdd_debugfs_update_csr(hdd_ctx, adapter, + info->id, + info->data, + info->max_buf_len); + } + + length = simple_read_from_buffer(buf, count, pos, + info->data, info->length); + hdd_debug("length written = %zu, count: %zu, pos: %lld", + length, count, *pos); + + hdd_exit(); + return length; +} + +/** + * wlan_hdd_read_debugfs_csr() - SSR wrapper function to read stats + * @file: file pointer + * @buf: buffer + * @count: count + * @pos: position pointer + * + * Return: Number of bytes read on success, zero otherwise + */ +static ssize_t +wlan_hdd_read_debugfs_csr(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_read_debugfs_csr(file, buf, count, pos); + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_open_debugfs_csr() - Allocates memory for private data + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int __wlan_hdd_open_debugfs_csr(struct inode *inode, + struct file *file) +{ + struct wlan_hdd_debugfs_buffer_info *info; + struct hdd_debugfs_file_info *csr; + struct hdd_adapter *adapter = NULL; + struct hdd_context *hdd_ctx; + int ret; + + hdd_enter(); + + csr = inode->i_private; + if (!csr) { + hdd_err("No private data"); + return -EINVAL; + } + + adapter = qdf_container_of(csr, struct hdd_adapter, + csr_file[csr->id]); + if (!adapter || (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) { + hdd_err("Invalid adapter or adapter has invalid magic"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret) + return -EINVAL; + + if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) { + hdd_err("Interface is not enabled"); + return -EINVAL; + } + + info = qdf_mem_malloc(sizeof(*info)); + if (!info) { + hdd_err("Not enough memory for file private data"); + return -ENOMEM; + } + + info->data = qdf_mem_malloc(csr->buf_max_size); + if (!info->data) { + hdd_err("roam stats debugfs buffer allocation failed"); + qdf_mem_free(info); + return -ENOMEM; + } + info->length = 0; + info->max_buf_len = csr->buf_max_size; + info->id = csr->id; + info->adapter = adapter; + + file->private_data = info; + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_open_debugfs_csr() - SSR wrapper function to allocate memory for + * private data on file open + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int wlan_hdd_open_debugfs_csr(struct inode *inode, + struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + + hdd_debugfs_thread_increment(); + ret = __wlan_hdd_open_debugfs_csr(inode, file); + if (ret) + hdd_debugfs_thread_decrement(); + + cds_ssr_unprotect(__func__); + + return ret; +} + +/** + * __wlan_hdd_release_debugfs_csr() - Function to free private memory on + * release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int __wlan_hdd_release_debugfs_csr(struct inode *inode, + struct file *file) +{ + struct wlan_hdd_debugfs_buffer_info *info = file->private_data; + + hdd_enter(); + + if (!info) + return 0; + + file->private_data = NULL; + qdf_mem_free(info->data); + qdf_mem_free(info); + + hdd_exit(); + + return 0; +} + +/** + * wlan_hdd_release_debugfs_csr() - SSR wrapper function to free + * private data on release + * @inode: Pointer to inode structure + * @file: file pointer + * + * Return: zero + */ +static int wlan_hdd_release_debugfs_csr(struct inode *inode, struct file *file) +{ + int ret; + + cds_ssr_protect(__func__); + ret = __wlan_hdd_release_debugfs_csr(inode, file); + hdd_debugfs_thread_decrement(); + cds_ssr_unprotect(__func__); + + return ret; +} + +static const struct file_operations fops_csr_debugfs = { + .read = wlan_hdd_read_debugfs_csr, + .open = wlan_hdd_open_debugfs_csr, + .release = wlan_hdd_release_debugfs_csr, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +void wlan_hdd_debugfs_csr_init(struct hdd_adapter *adapter) +{ + /* + * Create debufs diagnostic files for connect, offload info + * and roam info and store in csr_file member of adapter + */ +} + +void wlan_hdd_debugfs_csr_deinit(struct hdd_adapter *adapter) +{ + uint32_t i; + struct dentry *entry; + + for (i = 0; i < HDD_DEBUGFS_FILE_ID_MAX; i++) { + entry = adapter->csr_file[i].entry; + if (!entry) + continue; + + adapter->csr_file[i].entry = NULL; + debugfs_remove(entry); + entry = NULL; + } +} diff --git a/core/hdd/src/wlan_hdd_driver_ops.c b/core/hdd/src/wlan_hdd_driver_ops.c index 67bed532f3..94f4071d21 100644 --- a/core/hdd/src/wlan_hdd_driver_ops.c +++ b/core/hdd/src/wlan_hdd_driver_ops.c @@ -39,6 +39,7 @@ #include "pld_common.h" #include "wlan_hdd_driver_ops.h" #include "wlan_ipa_ucfg_api.h" +#include "wlan_hdd_debugfs.h" #ifdef MODULE #define WLAN_MODULE_NAME module_name(THIS_MODULE) @@ -494,6 +495,9 @@ static void wlan_hdd_remove(struct device *dev) if (!cds_wait_for_external_threads_completion(__func__)) hdd_warn("External threads are still active attempting driver unload anyway"); + if (!hdd_wait_for_debugfs_threads_completion()) + hdd_warn("Debugfs threads are still active attempting driver unload anyway"); + mutex_lock(&hdd_init_deinit_lock); hdd_start_driver_ops_timer(eHDD_DRV_OP_REMOVE); if (QDF_IS_EPPING_ENABLED(cds_get_conparam())) { @@ -596,6 +600,9 @@ static void wlan_hdd_shutdown(void) if (!cds_wait_for_external_threads_completion(__func__)) hdd_err("Host is not ready for SSR, attempting anyway"); + if (!hdd_wait_for_debugfs_threads_completion()) + hdd_err("Debufs threads are still pending, attempting SSR anyway"); + if (!QDF_IS_EPPING_ENABLED(cds_get_conparam())) { hif_disable_isr(hif_ctx); hdd_wlan_shutdown(); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index c0172aa700..c63884c4af 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -91,6 +91,7 @@ #include "wlan_hdd_ocb.h" #include "wlan_hdd_nan.h" #include "wlan_hdd_debugfs.h" +#include "wlan_hdd_debugfs_csr.h" #include "wlan_hdd_driver_ops.h" #include "epping_main.h" #include "wlan_hdd_data_stall_detection.h" @@ -4327,6 +4328,8 @@ static void hdd_cleanup_adapter(struct hdd_context *hdd_ctx, struct hdd_adapter qdf_mutex_destroy(&adapter->disconnection_status_lock); hdd_apf_context_destroy(adapter); + wlan_hdd_debugfs_csr_deinit(adapter); + hdd_debugfs_exit(adapter); /* @@ -4994,6 +4997,9 @@ struct hdd_adapter *hdd_open_adapter(struct hdd_context *hdd_ctx, uint8_t sessio hdd_info("%s interface created. iftype: %d", netdev_name(adapter->dev), session_type); + if (adapter->device_mode == QDF_STA_MODE) + wlan_hdd_debugfs_csr_init(adapter); + return adapter; err_free_netdev: @@ -5380,7 +5386,6 @@ QDF_STATUS hdd_stop_adapter_ext(struct hdd_context *hdd_ctx, } hdd_exit(); - return QDF_STATUS_SUCCESS; } @@ -9245,6 +9250,7 @@ int hdd_start_station_adapter(struct hdd_adapter *adapter) hdd_tx_flow_control_is_pause); hdd_exit(); + return 0; } @@ -10926,6 +10932,7 @@ int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode) bool is_recovery_stop = cds_is_driver_recovering(); int ret = 0; int active_threads; + int debugfs_threads; struct target_psoc_info *tgt_hdl; hdd_enter(); @@ -10943,11 +10950,16 @@ int hdd_wlan_stop_modules(struct hdd_context *hdd_ctx, bool ftm_mode) cds_set_module_stop_in_progress(true); active_threads = cds_return_external_threads_count(); - if (active_threads > 0 || hdd_ctx->is_wiphy_suspended) { - hdd_warn("External threads %d wiphy suspend %d", - active_threads, hdd_ctx->is_wiphy_suspended); + debugfs_threads = hdd_return_debugfs_threads_count(); - cds_print_external_threads(); + if (active_threads > 0 || debugfs_threads > 0 || + hdd_ctx->is_wiphy_suspended) { + hdd_warn("External threads %d, Debugfs threads %d, wiphy suspend %d", + active_threads, debugfs_threads, + hdd_ctx->is_wiphy_suspended); + + if (active_threads) + cds_print_external_threads(); if (IS_IDLE_STOP && !ftm_mode) { mutex_unlock(&hdd_ctx->iface_change_lock);