From a6a955d19fac0c089a119c49ea98bd3b4ccccb48 Mon Sep 17 00:00:00 2001 From: Jingxiang Ge Date: Tue, 25 Feb 2020 16:58:35 +0800 Subject: [PATCH] qcacld-3.0: Add debugfs for unit_test_host/unit_test_target These debugfs files are to replace wext cmd setUnitTestCmd /unit_test/wlan_suspend/wlan_resume. unit_test_host: /sys/kernel/debug/wlan_xx/unit_test_host wlan_xx is driver name unit_test_target: /sys/kernel/debug/wlan_xx/unit_test_target wlan_xx is adapter name wlan_suspend: /sys/kernel/debug/wlan_xx/wlan_suspend wlan_xx is adapter name wlan_resume: /sys/kernel/debug/wlan_xx/wlan_resume wlan_xx is adapter name Change-Id: I1ddf44b47a3f0d2e11ff74022dc1a26888da974c CRs-Fixed: 2631424 --- Kbuild | 5 + core/hdd/inc/wlan_hdd_debugfs_unit_test.h | 120 +++++ core/hdd/src/wlan_hdd_debugfs.c | 10 + core/hdd/src/wlan_hdd_debugfs_unit_test.c | 521 ++++++++++++++++++++++ core/hdd/src/wlan_hdd_main.c | 2 + core/hdd/src/wlan_hdd_unit_test.c | 114 +++++ core/hdd/src/wlan_hdd_unit_test.h | 45 ++ core/hdd/src/wlan_hdd_wext.c | 96 +--- 8 files changed, 819 insertions(+), 94 deletions(-) create mode 100644 core/hdd/inc/wlan_hdd_debugfs_unit_test.h create mode 100644 core/hdd/src/wlan_hdd_debugfs_unit_test.c create mode 100644 core/hdd/src/wlan_hdd_unit_test.c create mode 100644 core/hdd/src/wlan_hdd_unit_test.h diff --git a/Kbuild b/Kbuild index 6247d447b43e..5697e9859a4a 100644 --- a/Kbuild +++ b/Kbuild @@ -88,6 +88,10 @@ ifeq ($(CONFIG_WLAN_FEATURE_PERIODIC_STA_STATS), y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_periodic_sta_stats.o endif +ifeq ($(CONFIG_UNIT_TEST), y) +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_unit_test.o +endif + ifeq ($(CONFIG_WLAN_WEXT_SUPPORT_ENABLE), y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_wext.o \ $(HDD_SRC_DIR)/wlan_hdd_hostapd_wext.o @@ -114,6 +118,7 @@ HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_connect.o HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_offload.o HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_roam.o HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_config.o +HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_unit_test.o ifeq ($(CONFIG_WLAN_MWS_INFO_DEBUGFS), y) HDD_OBJS += $(HDD_SRC_DIR)/wlan_hdd_debugfs_coex.o endif diff --git a/core/hdd/inc/wlan_hdd_debugfs_unit_test.h b/core/hdd/inc/wlan_hdd_debugfs_unit_test.h new file mode 100644 index 000000000000..d2fac29d5bdf --- /dev/null +++ b/core/hdd/inc/wlan_hdd_debugfs_unit_test.h @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020 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_unit_test.h + * + * WLAN Host Device Driver implementation to create debugfs + * unit_test_host/unit_test_target/wlan_suspend/wlan_resume + */ + +#ifndef _WLAN_HDD_DEBUGFS_UNIT_TEST_H +#define _WLAN_HDD_DEBUGFS_UNIT_TEST_H + +#if defined(WLAN_DEBUGFS) && defined(WLAN_UNIT_TEST) +/** + * hdd_debugfs_unit_test_host_create() - API to create unit_test_target + * @hdd_ctx: hdd context + * + * this file is created per driver. + * file path: /sys/kernel/debug/wlan_xx/unit_test_host + * (wlan_xx is driver name) + * usage: + * echo 'all'>unit_test_host + * echo 'qdf_periodic_work'>unit_test_host + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_debugfs_unit_test_host_create(struct hdd_context *hdd_ctx); +#else +static inline int +wlan_hdd_debugfs_unit_test_host_create(struct hdd_context *hdd_ctx) +{ + return 0; +} +#endif + +#if defined(WLAN_DEBUGFS) && defined(WLAN_SUSPEND_RESUME_TEST) +/** + * wlan_hdd_debugfs_suspend_create() - API to create wlan_suspend + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/kernel/debug/wlan_xx/wlan_suspend + * (wlan_xx is adapter name) + * usage: + * echo [arg_0] [arg_1] > wlan_suspend + * arg_0 from enum wow_interface_pause + * arg_1 from enum wow_resume_trigger + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_debugfs_suspend_create(struct hdd_adapter *adapter); + +/** + * wlan_hdd_debugfs_resume_create() - API to create wlan_resume + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/kernel/debug/wlan_xx/wlan_resume + * (wlan_xx is adapter name) + * usage: + * echo > wlan_resume + * + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_debugfs_resume_create(struct hdd_adapter *adapter); +#else +static inline int +wlan_hdd_debugfs_suspend_create(struct hdd_adapter *adapter) +{ + return 0; +} + +static inline int +wlan_hdd_debugfs_resume_create(struct hdd_adapter *adapter) +{ + return 0; +} +#endif + +#ifdef WLAN_DEBUGFS +/** + * hdd_debugfs_unit_test_target_create() - API to create unit_test_target file + * @adapter: hdd adapter + * + * this file is created per adapter. + * file path: /sys/kernel/debug/wlan_xx/unit_test_target + * (wlan_xx is adapter name) + * usage: + * echo [module_id] [arg_num] [arg_0] [arg_xx] ... >unit_test_target + * echo '5' '2' '2' '1'>unit_test_target + * echo "5 2 2 1">unit_test_target //using one null space as delimiter + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_debugfs_unit_test_target_create(struct hdd_adapter *adapter); +#else +static inline int +wlan_hdd_debugfs_unit_test_target_create(struct hdd_adapter *adapter) +{ + return 0; +} +#endif /* WLAN_DEBUGFS */ +#endif /* _WLAN_HDD_DEBUGFS_UNIT_TEST_H */ diff --git a/core/hdd/src/wlan_hdd_debugfs.c b/core/hdd/src/wlan_hdd_debugfs.c index c7f369c3356f..98a76b482d19 100644 --- a/core/hdd/src/wlan_hdd_debugfs.c +++ b/core/hdd/src/wlan_hdd_debugfs.c @@ -34,6 +34,7 @@ #include #include #include +#include "wlan_hdd_debugfs_unit_test.h" #define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8 #define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512 @@ -552,6 +553,15 @@ QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter) if (wlan_hdd_create_ll_stats_file(adapter)) return QDF_STATUS_E_FAILURE; + if (wlan_hdd_debugfs_unit_test_target_create(adapter)) + return QDF_STATUS_E_FAILURE; + + if (wlan_hdd_debugfs_suspend_create(adapter)) + return QDF_STATUS_E_FAILURE; + + if (wlan_hdd_debugfs_resume_create(adapter)) + return QDF_STATUS_E_FAILURE; + return QDF_STATUS_SUCCESS; } diff --git a/core/hdd/src/wlan_hdd_debugfs_unit_test.c b/core/hdd/src/wlan_hdd_debugfs_unit_test.c new file mode 100644 index 000000000000..1e491ecb2bca --- /dev/null +++ b/core/hdd/src/wlan_hdd_debugfs_unit_test.c @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2020 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_unit_test.c + * + * WLAN Host Device Driver implementation to create debugfs + * unit_test_host/unit_test_target/wlan_suspend/wlan_resume + */ +#include "wlan_hdd_main.h" +#include "osif_psoc_sync.h" +#include "osif_vdev_sync.h" +#include "wlan_dsc_test.h" +#include "wlan_hdd_unit_test.h" +#include "wlan_hdd_debugfs_unit_test.h" +#include "wlan_module_ids.h" +#include "wma.h" +#include "wlan_hdd_power.h" + +#define MAX_USER_COMMAND_SIZE_UNIT_TEST_TARGET 256 + +#ifdef WLAN_UNIT_TEST +#define MAX_USER_COMMAND_SIZE_UNIT_TEST_HOST 32 + +/** + * __wlan_hdd_write_unit_test_host_debugfs() + * - host unit test debugfs handler + * + * @net_dev: net_device context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed or errno + */ +static ssize_t __wlan_hdd_write_unit_test_host_debugfs( + struct hdd_context *hdd_ctx, + const char __user *buf, size_t count, + loff_t *ppos) +{ + char name[MAX_USER_COMMAND_SIZE_UNIT_TEST_HOST + 1]; + int ret; + + if (count > MAX_USER_COMMAND_SIZE_UNIT_TEST_HOST) { + hdd_err_rl("Command length is larger than %d bytes", + MAX_USER_COMMAND_SIZE_UNIT_TEST_HOST); + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(name, buf, count)) + return -EFAULT; + /* default 'echo' cmd takes new line character to here*/ + if (name[count - 1] == '\n') + name[count - 1] = '\0'; + else + name[count] = '\0'; + + hdd_nofl_info("unit_test: count %zu name: %s", count, name); + + ret = wlan_hdd_unit_test(hdd_ctx, name); + if (ret != 0) + return ret; + + return count; +} + +/** + * wlan_hdd_write_unit_test_host_debugfs() + * - wrapper for __wlan_hdd_write_unit_test_host_debugfs + * + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: number of bytes processed or errno + */ +static ssize_t wlan_hdd_write_unit_test_host_debugfs( + struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct hdd_context *hdd_ctx = file_inode(file)->i_private; + struct osif_psoc_sync *psoc_sync; + ssize_t errno_size; + + errno_size = wlan_hdd_validate_context(hdd_ctx); + if (errno_size) + return errno_size; + + errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), + &psoc_sync); + if (errno_size) + return errno_size; + + errno_size = __wlan_hdd_write_unit_test_host_debugfs( + hdd_ctx, buf, count, ppos); + if (errno_size < 0) + hdd_err_rl("err_size %zd", errno_size); + + osif_psoc_sync_op_stop(psoc_sync); + return errno_size; +} + +static const struct file_operations fops_unit_test_host_debugfs = { + .write = wlan_hdd_write_unit_test_host_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int wlan_hdd_debugfs_unit_test_host_create(struct hdd_context *hdd_ctx) +{ + if (!debugfs_create_file("unit_test_host", 00400 | 00200, + qdf_debugfs_get_root(), + hdd_ctx, &fops_unit_test_host_debugfs)) + return -EINVAL; + + return 0; +} +#endif /* WLAN_UNIT_TEST */ + +#ifdef WLAN_SUSPEND_RESUME_TEST +#define MAX_USER_COMMAND_SIZE_SUSPEND 32 + +/** + * __wlan_hdd_write_suspend_debugfs() + * - suspend test debugfs handler + * + * @net_dev: net_device context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wlan_hdd_write_suspend_debugfs( + struct net_device *net_dev, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_USER_COMMAND_SIZE_SUSPEND + 1]; + char *sptr, *token; + int ret, pause_setting, resume_setting; + + if (hdd_validate_adapter(adapter)) { + hdd_err_rl("adapter validate fail"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (count > MAX_USER_COMMAND_SIZE_SUSPEND) { + hdd_err_rl("Command length is larger than %d bytes", + MAX_USER_COMMAND_SIZE_SUSPEND); + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(buf_local, buf, count)) + return -EFAULT; + + /* default 'echo' cmd takes new line character to here*/ + if (buf_local[count - 1] == '\n') + buf_local[count - 1] = '\0'; + else + buf_local[count] = '\0'; + sptr = buf_local; + hdd_nofl_info("unit_test: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get pause_setting */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &pause_setting)) + return -EINVAL; + + /* Get resume_setting */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &resume_setting)) + return -EINVAL; + + hdd_nofl_info("unit_test: pause_setting %d, resume_setting %d", + pause_setting, resume_setting); + ret = hdd_wlan_fake_apps_suspend(hdd_ctx->wiphy, net_dev, + pause_setting, resume_setting); + if (ret != 0) { + hdd_err_rl("suspend test failed"); + return -EINVAL; + } + + return count; +} + +/** + * wlan_hdd_write_suspend_debugfs() + * - wrapper for __wlan_hdd_write_suspend_debugfs + * + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: number of bytes processed or errno + */ +static ssize_t wlan_hdd_write_suspend_debugfs( + struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __wlan_hdd_write_suspend_debugfs( + net_dev, buf, count, ppos); + if (errno_size < 0) + hdd_err_rl("errno_size %zd", errno_size); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static const struct file_operations fops_suspend_debugfs = { + .write = wlan_hdd_write_suspend_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int wlan_hdd_debugfs_suspend_create(struct hdd_adapter *adapter) +{ + struct net_device *net_dev = adapter->dev; + + if (!debugfs_create_file("wlan_suspend", 00400 | 00200, + adapter->debugfs_phy, + net_dev, &fops_suspend_debugfs)) + return -EINVAL; + + return 0; +} + +/** + * __wlan_hdd_write_resume_debugfs() + * - resume test debugfs handler + * + * @net_dev: net_device context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wlan_hdd_write_resume_debugfs( + struct net_device *net_dev, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + int ret; + + if (hdd_validate_adapter(adapter)) { + hdd_err_rl("adapter validate fail"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + ret = hdd_wlan_fake_apps_resume(hdd_ctx->wiphy, net_dev); + if (ret != 0) { + hdd_err_rl("resume test failed"); + return -EINVAL; + } + + return count; +} + +/** + * wlan_hdd_write_resume_debugfs() + * - wrapper for __wlan_hdd_write_resume_debugfs + * + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: number of bytes processed or errno + */ +static ssize_t wlan_hdd_write_resume_debugfs( + struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __wlan_hdd_write_resume_debugfs( + net_dev, buf, count, ppos); + if (errno_size < 0) + hdd_err_rl("errno_size %zd", errno_size); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static const struct file_operations fops_resume_debugfs = { + .write = wlan_hdd_write_resume_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int wlan_hdd_debugfs_resume_create(struct hdd_adapter *adapter) +{ + struct net_device *net_dev = adapter->dev; + + if (!debugfs_create_file("wlan_resume", 00400 | 00200, + adapter->debugfs_phy, + net_dev, &fops_resume_debugfs)) + return -EINVAL; + + return 0; +} +#endif + +/** + * __wlan_hdd_write_unit_test_target_debugfs() + * - target unit test debugfs handler + * + * @net_dev: net_device context used to register the debugfs file + * @buf: text being written to the debugfs + * @count: size of @buf + * @ppos: (unused) offset into the virtual file system + * + * Return: number of bytes processed + */ +static ssize_t __wlan_hdd_write_unit_test_target_debugfs( + struct net_device *net_dev, + const char __user *buf, size_t count, + loff_t *ppos) +{ + struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(net_dev); + struct hdd_context *hdd_ctx; + char buf_local[MAX_USER_COMMAND_SIZE_UNIT_TEST_TARGET + 1]; + char *sptr, *token; + uint32_t apps_args[WMA_MAX_NUM_ARGS]; + int module_id, args_num, ret, i; + QDF_STATUS status; + + if (hdd_validate_adapter(adapter)) { + hdd_err_rl("adapter validate fail"); + return -EINVAL; + } + + hdd_ctx = WLAN_HDD_GET_CTX(adapter); + ret = wlan_hdd_validate_context(hdd_ctx); + if (ret != 0) + return ret; + + if (!wlan_hdd_validate_modules_state(hdd_ctx)) + return -EINVAL; + + if (count > MAX_USER_COMMAND_SIZE_UNIT_TEST_TARGET) { + hdd_err_rl("Command length is larger than %d bytes", + MAX_USER_COMMAND_SIZE_UNIT_TEST_TARGET); + return -EINVAL; + } + + /* Get command from user */ + if (copy_from_user(buf_local, buf, count)) + return -EFAULT; + /* default 'echo' cmd takes new line character to here*/ + if (buf_local[count - 1] == '\n') + buf_local[count - 1] = '\0'; + else + buf_local[count] = '\0'; + + sptr = buf_local; + hdd_nofl_info("unit_test: count %zu buf_local:(%s) net_devname %s", + count, buf_local, net_dev->name); + + /* Get module_id */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &module_id)) + return -EINVAL; + + /* Get args_num */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &args_num)) + return -EINVAL; + + if (module_id < WLAN_MODULE_ID_MIN || + module_id >= WLAN_MODULE_ID_MAX) { + hdd_err_rl("Invalid MODULE ID %d", module_id); + return -EINVAL; + } + if (args_num > WMA_MAX_NUM_ARGS) { + hdd_err_rl("Too many args %d", args_num); + return -EINVAL; + } + + for (i = 0; i < args_num; i++) { + token = strsep(&sptr, " "); + if (!token) { + hdd_err_rl("not enough args(%d), expected args_num:%d", + i, args_num); + return -EINVAL; + } + if (kstrtou32(token, 0, &apps_args[i])) + return -EINVAL; + } + + status = sme_send_unit_test_cmd(adapter->vdev_id, + module_id, + args_num, + &apps_args[0]); + if (status != QDF_STATUS_SUCCESS) { + hdd_err_rl("sme_send_unit_test_cmd returned %d", status); + return -EINVAL; + } + + return count; +} + +/** + * wlan_hdd_write_unit_test_target_debugfs() + * - wrapper for __wlan_hdd_write_unit_test_target_debugfs + * + * @file: file pointer + * @buf: buffer + * @count: count + * @ppos: position pointer + * + * Return: number of bytes processed or errno + */ +static ssize_t wlan_hdd_write_unit_test_target_debugfs( + struct file *file, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct net_device *net_dev = file_inode(file)->i_private; + struct osif_vdev_sync *vdev_sync; + ssize_t errno_size; + + errno_size = osif_vdev_sync_op_start(net_dev, &vdev_sync); + if (errno_size) + return errno_size; + + errno_size = __wlan_hdd_write_unit_test_target_debugfs( + net_dev, buf, count, ppos); + if (errno_size < 0) + hdd_err_rl("errno_size %zd", errno_size); + + osif_vdev_sync_op_stop(vdev_sync); + + return errno_size; +} + +static const struct file_operations fops_unit_test_target_debugfs = { + .write = wlan_hdd_write_unit_test_target_debugfs, + .owner = THIS_MODULE, + .llseek = default_llseek, +}; + +int wlan_hdd_debugfs_unit_test_target_create(struct hdd_adapter *adapter) +{ + struct net_device *net_dev = adapter->dev; + + if (!debugfs_create_file("unit_test_target", 00400 | 00200, + adapter->debugfs_phy, + net_dev, &fops_unit_test_target_debugfs)) + return -EINVAL; + + return 0; +} diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index dd8f25189421..0c64f46ca9d6 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -182,6 +182,7 @@ #include "cfg_nan_api.h" #include "wlan_hdd_btc_chain_mode.h" #include +#include "wlan_hdd_debugfs_unit_test.h" #ifdef MODULE #define WLAN_MODULE_NAME module_name(THIS_MODULE) @@ -13148,6 +13149,7 @@ int hdd_wlan_startup(struct hdd_context *hdd_ctx) hdd_set_idle_ps_config(hdd_ctx, is_imps_enabled); hdd_debugfs_mws_coex_info_init(hdd_ctx); hdd_debugfs_ini_config_init(hdd_ctx); + wlan_hdd_debugfs_unit_test_host_create(hdd_ctx); wlan_cfg80211_init_interop_issues_ap(hdd_ctx->pdev); hdd_exit(); diff --git a/core/hdd/src/wlan_hdd_unit_test.c b/core/hdd/src/wlan_hdd_unit_test.c new file mode 100644 index 000000000000..30081923bff3 --- /dev/null +++ b/core/hdd/src/wlan_hdd_unit_test.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2011-2020 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_unit_test.c + * + * config wlan_hdd_unit_test which will be used by wext and + * debugfs unit_test_host + */ +#include "wlan_hdd_main.h" +#include "qdf_delayed_work_test.h" +#include "qdf_hashtable_test.h" +#include "qdf_periodic_work_test.h" +#include "qdf_ptr_hash_test.h" +#include "qdf_slist_test.h" +#include "qdf_talloc_test.h" +#include "qdf_str.h" +#include "qdf_trace.h" +#include "qdf_tracker_test.h" +#include "qdf_types_test.h" +#include "wlan_dsc_test.h" +#include "wlan_hdd_unit_test.h" + +typedef uint32_t (*hdd_ut_callback)(void); + +struct hdd_ut_entry { + const hdd_ut_callback callback; + const char *name; +}; + +struct hdd_ut_entry hdd_ut_entries[] = { + { .name = "dsc", .callback = dsc_unit_test }, + { .name = "qdf_delayed_work", .callback = qdf_delayed_work_unit_test }, + { .name = "qdf_ht", .callback = qdf_ht_unit_test }, + { .name = "qdf_periodic_work", + .callback = qdf_periodic_work_unit_test }, + { .name = "qdf_ptr_hash", .callback = qdf_ptr_hash_unit_test }, + { .name = "qdf_slist", .callback = qdf_slist_unit_test }, + { .name = "qdf_talloc", .callback = qdf_talloc_unit_test }, + { .name = "qdf_tracker", .callback = qdf_tracker_unit_test }, + { .name = "qdf_types", .callback = qdf_types_unit_test }, +}; + +#define hdd_for_each_ut_entry(cursor) \ + for (cursor = hdd_ut_entries; \ + cursor < hdd_ut_entries + ARRAY_SIZE(hdd_ut_entries); \ + cursor++) + +static struct hdd_ut_entry *hdd_ut_lookup(const char *name) +{ + struct hdd_ut_entry *entry; + + hdd_for_each_ut_entry(entry) { + if (qdf_str_eq(entry->name, name)) + return entry; + } + + return NULL; +} + +static uint32_t hdd_ut_single(const struct hdd_ut_entry *entry) +{ + uint32_t errors; + + hdd_nofl_info("START: '%s'", entry->name); + + errors = entry->callback(); + if (errors) + hdd_nofl_err("FAIL: '%s' with %u errors", entry->name, errors); + else + hdd_nofl_info("PASS: '%s'", entry->name); + + return errors; +} + +int wlan_hdd_unit_test(struct hdd_context *hdd_ctx, const char *name) +{ + struct hdd_ut_entry *entry; + uint32_t errors = 0; + + hdd_nofl_info("Unit tests begin"); + + if (!name || !name[0] || qdf_str_eq(name, "all")) { + hdd_for_each_ut_entry(entry) + errors += hdd_ut_single(entry); + } else { + entry = hdd_ut_lookup(name); + if (entry) { + errors += hdd_ut_single(entry); + } else { + hdd_nofl_err("Unit test '%s' not found", name); + return -EINVAL; + } + } + + hdd_nofl_info("Unit tests complete"); + + return errors ? -EPERM : 0; +} diff --git a/core/hdd/src/wlan_hdd_unit_test.h b/core/hdd/src/wlan_hdd_unit_test.h new file mode 100644 index 000000000000..b20e1d204e94 --- /dev/null +++ b/core/hdd/src/wlan_hdd_unit_test.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 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_unit_test.h + * + * config wlan_hdd_unit_test + */ + +#ifndef _WLAN_HDD_UNIT_TEST_H +#define _WLAN_HDD_UNIT_TEST_H + +#ifdef WLAN_UNIT_TEST +/** + * wlan_hdd_unit_test() - API to begin unit test on host side + * @hdd_ctx: hdd context + * @name: test item name + * + * Return: 0 on success and errno on failure + */ +int wlan_hdd_unit_test(struct hdd_context *hdd_ctx, const char *name); +#else +static inline int +wlan_hdd_unit_test(struct hdd_context *hdd_ctx, const char *name) +{ + return -EOPNOTSUPP; +} +#endif + +#endif /* _WLAN_HDD_UNIT_TEST_H */ diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index a835005b3616..87c2d3e77d82 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -69,16 +69,6 @@ #include "qc_sap_ioctl.h" #include "sme_api.h" #include "wma_types.h" -#include "qdf_delayed_work_test.h" -#include "qdf_hashtable_test.h" -#include "qdf_periodic_work_test.h" -#include "qdf_ptr_hash_test.h" -#include "qdf_slist_test.h" -#include "qdf_talloc_test.h" -#include "qdf_str.h" -#include "qdf_trace.h" -#include "qdf_tracker_test.h" -#include "qdf_types_test.h" #include "wlan_hdd_assoc.h" #include "wlan_hdd_ioctl.h" #include "wlan_hdd_scan.h" @@ -121,6 +111,7 @@ #include "wlan_pmo_ucfg_api.h" #include "dp_txrx.h" #include "wlan_fwol_ucfg_api.h" +#include "wlan_hdd_unit_test.h" /* Private ioctls and their sub-ioctls */ #define WLAN_PRIV_SET_INT_GET_NONE (SIOCIWFIRSTPRIV + 0) @@ -5833,89 +5824,6 @@ static int iw_setnone_get_threeint(struct net_device *dev, return errno; } - -#ifdef WLAN_UNIT_TEST -typedef uint32_t (*hdd_ut_callback)(void); - -struct hdd_ut_entry { - const hdd_ut_callback callback; - const char *name; -}; - -struct hdd_ut_entry hdd_ut_entries[] = { - { .name = "dsc", .callback = dsc_unit_test }, - { .name = "qdf_delayed_work", .callback = qdf_delayed_work_unit_test }, - { .name = "qdf_ht", .callback = qdf_ht_unit_test }, - { .name = "qdf_periodic_work", - .callback = qdf_periodic_work_unit_test }, - { .name = "qdf_ptr_hash", .callback = qdf_ptr_hash_unit_test }, - { .name = "qdf_slist", .callback = qdf_slist_unit_test }, - { .name = "qdf_talloc", .callback = qdf_talloc_unit_test }, - { .name = "qdf_tracker", .callback = qdf_tracker_unit_test }, - { .name = "qdf_types", .callback = qdf_types_unit_test }, -}; - -#define hdd_for_each_ut_entry(cursor) \ - for (cursor = hdd_ut_entries; \ - cursor < hdd_ut_entries + ARRAY_SIZE(hdd_ut_entries); \ - cursor++) - -static struct hdd_ut_entry *hdd_ut_lookup(const char *name) -{ - struct hdd_ut_entry *entry; - - hdd_for_each_ut_entry(entry) { - if (qdf_str_eq(entry->name, name)) - return entry; - } - - return NULL; -} - -static uint32_t hdd_ut_single(const struct hdd_ut_entry *entry) -{ - uint32_t errors; - - hdd_nofl_info("START: '%s'", entry->name); - - errors = entry->callback(); - if (errors) - hdd_nofl_err("FAIL: '%s' with %u errors", entry->name, errors); - else - hdd_nofl_info("PASS: '%s'", entry->name); - - return errors; -} - -static int hdd_we_unit_test(struct hdd_context *hdd_ctx, const char *name) -{ - struct hdd_ut_entry *entry; - uint32_t errors = 0; - - hdd_nofl_info("Unit tests begin"); - - if (!name || !name[0] || qdf_str_eq(name, "all")) { - hdd_for_each_ut_entry(entry) - errors += hdd_ut_single(entry); - } else { - entry = hdd_ut_lookup(name); - if (entry) - errors += hdd_ut_single(entry); - else - hdd_nofl_err("Unit test '%s' not found", name); - } - - hdd_nofl_info("Unit tests complete"); - - return errors ? -EPERM : 0; -} -#else -static int hdd_we_unit_test(struct hdd_context *hdd_ctx, const char *name) -{ - return -EOPNOTSUPP; -} -#endif /* WLAN_UNIT_TEST */ - /** * iw_setchar_getnone() - Generic "set string" private ioctl handler * @dev: device upon which the ioctl was received @@ -6041,7 +5949,7 @@ static int __iw_setchar_getnone(struct net_device *dev, hdd_debug("Received WE_SET_AP_WPS_IE, won't process"); break; case WE_UNIT_TEST: - ret = hdd_we_unit_test(hdd_ctx, str_arg); + ret = wlan_hdd_unit_test(hdd_ctx, str_arg); break; default: {