1 /* 2 * Copyright (c) 2019 The Linux Foundation. All rights reserved. 3 * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for 6 * any purpose with or without fee is hereby granted, provided that the 7 * above copyright notice and this permission notice appear in all 8 * copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 11 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 12 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 13 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 16 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 17 * PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /** 21 * DOC: wlan_hdd_debugfs_config.c 22 * 23 * WLAN Host Device Driver implementation to update 24 * debugfs with ini configs 25 */ 26 27 #include "wlan_hdd_main.h" 28 #include "osif_psoc_sync.h" 29 #include "cfg_ucfg_api.h" 30 #include "wlan_hdd_debugfs_config.h" 31 32 #define DEBUGFS_CONFIG_BUF_SIZE (4096 * 8) 33 34 /** 35 * struct ini_config_buf - the buffer struct to save ini configs 36 * @len: buffer len 37 * @result: the pointer to buffer 38 */ 39 struct ini_config_buf { 40 ssize_t len; 41 uint8_t result[DEBUGFS_CONFIG_BUF_SIZE]; 42 }; 43 44 /** 45 * wlan_hdd_config_update() - Update userspace with local statistics buffer 46 * @buf: userspace buffer (to which data is being copied into) 47 * @count: max data that can be copied into buf 48 * @pos: offset (where data should be copied into) 49 * @ini_config: buffer structure for ini config info 50 * 51 * This function should copies ini configs into debugfs entry. 52 * 53 * Return: number of characters copied; 0 on no-copy 54 */ 55 static ssize_t wlan_hdd_config_update(char __user *buf, size_t count, 56 loff_t *pos, 57 struct ini_config_buf *ini_config) 58 { 59 ssize_t ret_cnt; 60 61 ret_cnt = simple_read_from_buffer(buf, count, pos, ini_config->result, 62 ini_config->len); 63 hdd_debug("ini config read req: count: %zu, pos: %lld", count, *pos); 64 65 return ret_cnt; 66 } 67 68 /** 69 * wlan_hdd_config_get() - Function to save ini config to buffer 70 * @hdd_ctx: hdd context used to register the debugfs file 71 * @ini_config: buffer structure for ini config info 72 * 73 * Return: Errno 74 */ 75 static int wlan_hdd_config_get(struct hdd_context *hdd_ctx, 76 struct ini_config_buf *ini_config) 77 { 78 QDF_STATUS status; 79 80 status = ucfg_cfg_ini_config_print(hdd_ctx->psoc, ini_config->result, 81 &ini_config->len, 82 DEBUGFS_CONFIG_BUF_SIZE); 83 return qdf_status_to_os_return(status); 84 } 85 86 /** 87 * __wlan_hdd_read_config_debugfs() - function to get ini conifg 88 * @file: file pointer 89 * @buf: buffer 90 * @count: count 91 * @pos: position pointer 92 * 93 * Return: Number of bytes read on success, error number otherwise 94 */ 95 static ssize_t __wlan_hdd_read_config_debugfs(struct file *file, 96 char __user *buf, size_t count, 97 loff_t *pos) 98 { 99 struct ini_config_buf *ini_config; 100 ssize_t err_size; 101 102 ini_config = (struct ini_config_buf *)file->private_data; 103 if (!ini_config) 104 return -ENOMEM; 105 106 err_size = wlan_hdd_config_update(buf, count, pos, ini_config); 107 108 return err_size; 109 } 110 111 /** 112 * wlan_hdd_read_config_debugfs() - wrapper function to get ini conifg 113 * @file: file pointer 114 * @buf: buffer 115 * @count: count 116 * @pos: position pointer 117 * 118 * Return: Number of bytes read on success, error number otherwise 119 */ 120 static ssize_t wlan_hdd_read_config_debugfs(struct file *file, 121 char __user *buf, size_t count, 122 loff_t *pos) 123 { 124 struct hdd_context *hdd_ctx = file_inode(file)->i_private; 125 struct osif_psoc_sync *psoc_sync; 126 ssize_t err_size; 127 128 err_size = wlan_hdd_validate_context(hdd_ctx); 129 if (err_size) 130 return err_size; 131 132 err_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), 133 &psoc_sync); 134 if (err_size) 135 return err_size; 136 137 err_size = __wlan_hdd_read_config_debugfs(file, buf, count, pos); 138 139 osif_psoc_sync_op_stop(psoc_sync); 140 141 return err_size; 142 } 143 144 /** 145 * __wlan_hdd_open_config_debugfs() - function to open config debugfs 146 * @inode: Pointer to inode structure 147 * @file: file pointer 148 * 149 * Return: Errno 150 */ 151 static int __wlan_hdd_open_config_debugfs(struct inode *inode, 152 struct file *file) 153 { 154 struct hdd_context *hdd_ctx = file_inode(file)->i_private; 155 struct ini_config_buf *ini_config; 156 ssize_t errno; 157 void *buf; 158 159 buf = qdf_mem_malloc(sizeof(*ini_config)); 160 if (!buf) 161 return -ENOMEM; 162 163 ini_config = (struct ini_config_buf *)buf; 164 hdd_nofl_debug("WLAN configuration written to debug log"); 165 ucfg_cfg_store_print(hdd_ctx->psoc); 166 errno = wlan_hdd_config_get(hdd_ctx, ini_config); 167 if (errno) { 168 qdf_mem_free(buf); 169 return errno; 170 } 171 172 file->private_data = buf; 173 return 0; 174 } 175 176 /** 177 * wlan_hdd_open_config_debugfs() - wrapper function to open config debugfs 178 * @inode: Pointer to inode structure 179 * @file: file pointer 180 * 181 * Return: Errno 182 */ 183 static int wlan_hdd_open_config_debugfs(struct inode *inode, struct file *file) 184 { 185 struct hdd_context *hdd_ctx = file_inode(file)->i_private; 186 struct osif_psoc_sync *psoc_sync; 187 ssize_t errno; 188 189 errno = wlan_hdd_validate_context(hdd_ctx); 190 if (errno) 191 return errno; 192 193 errno = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy), 194 &psoc_sync); 195 if (errno) 196 return errno; 197 198 errno = __wlan_hdd_open_config_debugfs(inode, file); 199 200 osif_psoc_sync_op_stop(psoc_sync); 201 return errno; 202 } 203 204 /** 205 * wlan_hdd_release_config_debugfs() - wrapper to release 206 * @inode: Pointer to inode structure 207 * @file: file pointer 208 * 209 * Return: Errno 210 */ 211 static int wlan_hdd_release_config_debugfs(struct inode *inode, 212 struct file *file) 213 { 214 qdf_mem_free(file->private_data); 215 file->private_data = NULL; 216 217 return 0; 218 } 219 220 static const struct file_operations fops_config_debugfs = { 221 .read = wlan_hdd_read_config_debugfs, 222 .open = wlan_hdd_open_config_debugfs, 223 .release = wlan_hdd_release_config_debugfs, 224 .owner = THIS_MODULE, 225 .llseek = default_llseek, 226 }; 227 228 int hdd_debugfs_ini_config_init(struct hdd_context *hdd_ctx) 229 { 230 if (!debugfs_create_file("ini_config", 0444, qdf_debugfs_get_root(), 231 hdd_ctx, &fops_config_debugfs)) 232 return -EINVAL; 233 234 return 0; 235 } 236 237 void hdd_debugfs_ini_config_deinit(struct hdd_context *hdd_ctx) 238 { 239 /* 240 * Config ini doesn't have a directory it is removed 241 * as part of qdf remove 242 */ 243 } 244