blob: 7131fd67cfb3ae94503fde43c92e9faa7b3c0ad2 [file] [log] [blame]
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08001/*
Jeff Johnson52133112017-01-25 06:25:32 -08002 * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
Prakash Dhavali7090c5f2015-11-02 17:55:19 -08003 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28/**
29 * DOC: wlan_hdd_debugfs.c
30 *
31 * This driver currently supports the following debugfs files:
32 * wlan_wcnss/wow_enable to enable/disable WoWL.
33 * wlan_wcnss/wow_pattern to configure WoWL patterns.
34 * wlan_wcnss/pattern_gen to configure periodic TX patterns.
35 */
36
37#ifdef WLAN_OPEN_SOURCE
38#include <wlan_hdd_includes.h>
Jeff Johnson510779e2016-10-05 15:51:12 -070039#include <wlan_hdd_debugfs.h>
Jeff Johnson52133112017-01-25 06:25:32 -080040#include <wlan_hdd_request_manager.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080041#include <wlan_hdd_wowl.h>
42#include <cds_sched.h>
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -080043#include <wlan_hdd_debugfs_llstat.h>
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080044
45#define MAX_USER_COMMAND_SIZE_WOWL_ENABLE 8
46#define MAX_USER_COMMAND_SIZE_WOWL_PATTERN 512
47#define MAX_USER_COMMAND_SIZE_FRAME 4096
48
Sridhar Selvarajdc400d22016-10-18 17:18:03 +053049#ifdef WLAN_POWER_DEBUGFS
50#define POWER_DEBUGFS_BUFFER_MAX_LEN 4096
51#endif
52
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080053/**
54 * __wcnss_wowenable_write() - wow_enable debugfs handler
55 * @file: debugfs file handle
56 * @buf: text being written to the debugfs
57 * @count: size of @buf
58 * @ppos: (unused) offset into the virtual file system
59 *
60 * Return: number of bytes processed
61 */
62static ssize_t __wcnss_wowenable_write(struct file *file,
63 const char __user *buf, size_t count,
64 loff_t *ppos)
65{
Jeff Johnsond900b9d2017-10-02 13:29:49 -070066 struct hdd_adapter *adapter;
Jeff Johnson2a9711b2017-08-28 12:05:00 -070067 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080068 char cmd[MAX_USER_COMMAND_SIZE_WOWL_ENABLE + 1];
69 char *sptr, *token;
70 uint8_t wow_enable = 0;
71 uint8_t wow_mp = 0;
72 uint8_t wow_pbm = 0;
73 int ret;
74
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +053075 ENTER();
76
Jeff Johnsond900b9d2017-10-02 13:29:49 -070077 adapter = (struct hdd_adapter *)file->private_data;
78 if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -080079 hdd_err("Invalid adapter or adapter has invalid magic");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080080 return -EINVAL;
81 }
82
Jeff Johnsond900b9d2017-10-02 13:29:49 -070083 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080084 ret = wlan_hdd_validate_context(hdd_ctx);
85 if (0 != ret)
86 return ret;
87
Arun Khandavallica892f62017-05-26 14:25:50 +053088 if (!wlan_hdd_validate_modules_state(hdd_ctx))
89 return -EINVAL;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080090
91 if (!sme_is_feature_supported_by_fw(WOW)) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -070092 hdd_err("Wake-on-Wireless feature is not supported in firmware!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080093 return -EINVAL;
94 }
95
96 if (count > MAX_USER_COMMAND_SIZE_WOWL_ENABLE) {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -080097 hdd_err("Command length is larger than %d bytes",
Jeff Johnson85c0abf2016-08-05 12:28:24 -070098 MAX_USER_COMMAND_SIZE_WOWL_ENABLE);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080099 return -EINVAL;
100 }
101
102 /* Get command from user */
103 if (copy_from_user(cmd, buf, count))
104 return -EFAULT;
105 cmd[count] = '\0';
106 sptr = cmd;
107
108 /* Get enable or disable wow */
109 token = strsep(&sptr, " ");
110 if (!token)
111 return -EINVAL;
112 if (kstrtou8(token, 0, &wow_enable))
113 return -EINVAL;
114
115 /* Disable wow */
116 if (!wow_enable) {
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700117 if (!hdd_exit_wowl(adapter)) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700118 hdd_err("hdd_exit_wowl failed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800119 return -EFAULT;
120 }
121
122 return count;
123 }
124
125 /* Get enable or disable magic packet mode */
126 token = strsep(&sptr, " ");
127 if (!token)
128 return -EINVAL;
129 if (kstrtou8(token, 0, &wow_mp))
130 return -EINVAL;
131 if (wow_mp > 1)
132 wow_mp = 1;
133
134 /* Get enable or disable pattern byte matching mode */
135 token = strsep(&sptr, " ");
136 if (!token)
137 return -EINVAL;
138 if (kstrtou8(token, 0, &wow_pbm))
139 return -EINVAL;
140 if (wow_pbm > 1)
141 wow_pbm = 1;
142
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700143 if (!hdd_enter_wowl(adapter, wow_mp, wow_pbm)) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700144 hdd_err("hdd_enter_wowl failed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800145 return -EFAULT;
146 }
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530147 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800148 return count;
149}
150
151/**
152 * wcnss_wowenable_write() - SSR wrapper for wcnss_wowenable_write
153 * @file: file pointer
154 * @buf: buffer
155 * @count: count
156 * @ppos: position pointer
157 *
158 * Return: 0 on success, error number otherwise
159 */
160static ssize_t wcnss_wowenable_write(struct file *file,
161 const char __user *buf,
162 size_t count, loff_t *ppos)
163{
164 ssize_t ret;
165
166 cds_ssr_protect(__func__);
167 ret = __wcnss_wowenable_write(file, buf, count, ppos);
168 cds_ssr_unprotect(__func__);
169
170 return ret;
171}
172
173/**
174 * __wcnss_wowpattern_write() - wow_pattern debugfs handler
175 * @file: debugfs file handle
176 * @buf: text being written to the debugfs
177 * @count: size of @buf
178 * @ppos: (unused) offset into the virtual file system
179 *
180 * Return: number of bytes processed
181 */
182static ssize_t __wcnss_wowpattern_write(struct file *file,
183 const char __user *buf, size_t count,
184 loff_t *ppos)
185{
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700186 struct hdd_adapter *adapter = (struct hdd_adapter *) file->private_data;
Jeff Johnson2a9711b2017-08-28 12:05:00 -0700187 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800188 char cmd[MAX_USER_COMMAND_SIZE_WOWL_PATTERN + 1];
189 char *sptr, *token;
190 uint8_t pattern_idx = 0;
191 uint8_t pattern_offset = 0;
192 char *pattern_buf;
193 char *pattern_mask;
194 int ret;
195
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530196 ENTER();
197
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700198 if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -0800199 hdd_err("Invalid adapter or adapter has invalid magic");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800200 return -EINVAL;
201 }
202
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700203 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800204 ret = wlan_hdd_validate_context(hdd_ctx);
205 if (0 != ret)
206 return ret;
207
Arun Khandavallica892f62017-05-26 14:25:50 +0530208 if (!wlan_hdd_validate_modules_state(hdd_ctx))
209 return -EINVAL;
210
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800211 if (!sme_is_feature_supported_by_fw(WOW)) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700212 hdd_err("Wake-on-Wireless feature is not supported in firmware!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800213 return -EINVAL;
214 }
215
216 if (count > MAX_USER_COMMAND_SIZE_WOWL_PATTERN) {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -0800217 hdd_err("Command length is larger than %d bytes",
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700218 MAX_USER_COMMAND_SIZE_WOWL_PATTERN);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800219 return -EINVAL;
220 }
221
222 /* Get command from user */
223 if (copy_from_user(cmd, buf, count))
224 return -EFAULT;
225 cmd[count] = '\0';
226 sptr = cmd;
227
228 /* Get pattern idx */
229 token = strsep(&sptr, " ");
230 if (!token)
231 return -EINVAL;
232
233 if (kstrtou8(token, 0, &pattern_idx))
234 return -EINVAL;
235
236 /* Get pattern offset */
237 token = strsep(&sptr, " ");
238
239 /* Delete pattern if no further argument */
240 if (!token) {
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700241 hdd_del_wowl_ptrn_debugfs(adapter, pattern_idx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800242
243 return count;
244 }
245
246 if (kstrtou8(token, 0, &pattern_offset))
247 return -EINVAL;
248
249 /* Get pattern */
250 token = strsep(&sptr, " ");
251 if (!token)
252 return -EINVAL;
253
254 pattern_buf = token;
255
256 /* Get pattern mask */
257 token = strsep(&sptr, " ");
258 if (!token)
259 return -EINVAL;
260
261 pattern_mask = token;
262 pattern_mask[strlen(pattern_mask) - 1] = '\0';
263
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700264 hdd_add_wowl_ptrn_debugfs(adapter, pattern_idx, pattern_offset,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800265 pattern_buf, pattern_mask);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530266 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800267 return count;
268}
269
270/**
271 * wcnss_wowpattern_write() - SSR wrapper for __wcnss_wowpattern_write
272 * @file: file pointer
273 * @buf: buffer
274 * @count: count
275 * @ppos: position pointer
276 *
277 * Return: 0 on success, error number otherwise
278 */
279static ssize_t wcnss_wowpattern_write(struct file *file,
280 const char __user *buf,
281 size_t count, loff_t *ppos)
282{
283 ssize_t ret;
284
285 cds_ssr_protect(__func__);
286 ret = __wcnss_wowpattern_write(file, buf, count, ppos);
287 cds_ssr_unprotect(__func__);
288
289 return ret;
290}
291
292/**
293 * wcnss_patterngen_write() - pattern_gen debugfs handler
294 * @file: debugfs file handle
295 * @buf: text being written to the debugfs
296 * @count: size of @buf
297 * @ppos: (unused) offset into the virtual file system
298 *
299 * Return: number of bytes processed
300 */
301static ssize_t __wcnss_patterngen_write(struct file *file,
302 const char __user *buf, size_t count,
303 loff_t *ppos)
304{
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700305 struct hdd_adapter *adapter;
Jeff Johnson8d5e82b2017-09-03 09:14:51 -0700306 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800307 tSirAddPeriodicTxPtrn *addPeriodicTxPtrnParams;
308 tSirDelPeriodicTxPtrn *delPeriodicTxPtrnParams;
309
310 char *cmd, *sptr, *token;
311 uint8_t pattern_idx = 0;
312 uint8_t pattern_duration = 0;
313 char *pattern_buf;
314 uint16_t pattern_len = 0;
315 uint16_t i = 0;
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530316 QDF_STATUS status;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800317 int ret;
318
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530319 ENTER();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800320
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700321 adapter = (struct hdd_adapter *)file->private_data;
322 if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -0800323 hdd_err("Invalid adapter or adapter has invalid magic");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800324 return -EINVAL;
325 }
326
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700327 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
Jeff Johnson8d5e82b2017-09-03 09:14:51 -0700328 ret = wlan_hdd_validate_context(hdd_ctx);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800329 if (0 != ret)
330 return ret;
331
Jeff Johnson8d5e82b2017-09-03 09:14:51 -0700332 if (!wlan_hdd_validate_modules_state(hdd_ctx))
Arun Khandavallica892f62017-05-26 14:25:50 +0530333 return -EINVAL;
334
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800335 if (!sme_is_feature_supported_by_fw(WLAN_PERIODIC_TX_PTRN)) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700336 hdd_err("Periodic Tx Pattern Offload feature is not supported in firmware!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800337 return -EINVAL;
338 }
339
340 /* Get command from user */
341 if (count <= MAX_USER_COMMAND_SIZE_FRAME)
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530342 cmd = qdf_mem_malloc(count + 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800343 else {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -0800344 hdd_err("Command length is larger than %d bytes",
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700345 MAX_USER_COMMAND_SIZE_FRAME);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800346
347 return -EINVAL;
348 }
349
350 if (!cmd) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700351 hdd_err("Memory allocation for cmd failed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800352 return -ENOMEM;
353 }
354
355 if (copy_from_user(cmd, buf, count)) {
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530356 qdf_mem_free(cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800357 return -EFAULT;
358 }
359 cmd[count] = '\0';
360 sptr = cmd;
361
362 /* Get pattern idx */
363 token = strsep(&sptr, " ");
364 if (!token)
365 goto failure;
366 if (kstrtou8(token, 0, &pattern_idx))
367 goto failure;
368
369 if (pattern_idx > (MAXNUM_PERIODIC_TX_PTRNS - 1)) {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -0800370 hdd_err("Pattern index: %d is not in the range (0 ~ %d)",
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700371 pattern_idx, MAXNUM_PERIODIC_TX_PTRNS - 1);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800372
373 goto failure;
374 }
375
376 /* Get pattern duration */
377 token = strsep(&sptr, " ");
378 if (!token)
379 goto failure;
380 if (kstrtou8(token, 0, &pattern_duration))
381 goto failure;
382
383 /* Delete pattern using index if duration is 0 */
384 if (!pattern_duration) {
385 delPeriodicTxPtrnParams =
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530386 qdf_mem_malloc(sizeof(tSirDelPeriodicTxPtrn));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800387 if (!delPeriodicTxPtrnParams) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700388 hdd_err("Memory allocation failed!");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530389 qdf_mem_free(cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800390 return -ENOMEM;
391 }
392 delPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
393 delPeriodicTxPtrnParams->ucPatternIdBitmap = 1 << pattern_idx;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530394 qdf_copy_macaddr(&delPeriodicTxPtrnParams->mac_address,
Jeff Johnson1e851a12017-10-28 14:36:12 -0700395 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800396
397 /* Delete pattern */
Jeff Johnson8d5e82b2017-09-03 09:14:51 -0700398 status = sme_del_periodic_tx_ptrn(hdd_ctx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800399 delPeriodicTxPtrnParams);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530400 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700401 hdd_err("sme_del_periodic_tx_ptrn() failed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800402
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530403 qdf_mem_free(delPeriodicTxPtrnParams);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800404 goto failure;
405 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530406 qdf_mem_free(cmd);
407 qdf_mem_free(delPeriodicTxPtrnParams);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800408 return count;
409 }
410
411 /*
412 * In SAP mode allow configuration without any connection check
413 * In STA mode check if it's in connected state before adding
414 * patterns
415 */
Jeff Johnsond900b9d2017-10-02 13:29:49 -0700416 hdd_debug("device mode %d", adapter->device_mode);
417 if ((QDF_STA_MODE == adapter->device_mode) &&
418 (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(adapter)))) {
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530419 hdd_err("Not in Connected state!");
420 goto failure;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800421 }
422
423 /* Get pattern */
424 token = strsep(&sptr, " ");
425 if (!token)
426 goto failure;
427
428 pattern_buf = token;
429 pattern_buf[strlen(pattern_buf) - 1] = '\0';
430 pattern_len = strlen(pattern_buf);
431
432 /* Since the pattern is a hex string, 2 characters represent 1 byte. */
433 if (pattern_len % 2) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700434 hdd_err("Malformed pattern!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800435
436 goto failure;
437 } else
438 pattern_len >>= 1;
439
440 if (pattern_len < 14 || pattern_len > PERIODIC_TX_PTRN_MAX_SIZE) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700441 hdd_err("Not an 802.3 frame!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800442
443 goto failure;
444 }
445
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530446 addPeriodicTxPtrnParams = qdf_mem_malloc(sizeof(tSirAddPeriodicTxPtrn));
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800447 if (!addPeriodicTxPtrnParams) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700448 hdd_err("Memory allocation failed!");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530449 qdf_mem_free(cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800450 return -ENOMEM;
451 }
452
453 addPeriodicTxPtrnParams->ucPtrnId = pattern_idx;
454 addPeriodicTxPtrnParams->usPtrnIntervalMs = pattern_duration * 500;
455 addPeriodicTxPtrnParams->ucPtrnSize = pattern_len;
Anurag Chouhanc5548422016-02-24 18:33:27 +0530456 qdf_copy_macaddr(&addPeriodicTxPtrnParams->mac_address,
Jeff Johnson1e851a12017-10-28 14:36:12 -0700457 &adapter->mac_addr);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800458
459 /* Extract the pattern */
460 for (i = 0; i < addPeriodicTxPtrnParams->ucPtrnSize; i++) {
461 addPeriodicTxPtrnParams->ucPattern[i] =
462 (hex_to_bin(pattern_buf[0]) << 4) +
463 hex_to_bin(pattern_buf[1]);
464
465 /* Skip to next byte */
466 pattern_buf += 2;
467 }
468
469 /* Add pattern */
Jeff Johnson8d5e82b2017-09-03 09:14:51 -0700470 status = sme_add_periodic_tx_ptrn(hdd_ctx->hHal,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800471 addPeriodicTxPtrnParams);
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530472 if (QDF_STATUS_SUCCESS != status) {
Jeff Johnson85c0abf2016-08-05 12:28:24 -0700473 hdd_err("sme_add_periodic_tx_ptrn() failed!");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800474
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530475 qdf_mem_free(addPeriodicTxPtrnParams);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800476 goto failure;
477 }
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530478 qdf_mem_free(cmd);
479 qdf_mem_free(addPeriodicTxPtrnParams);
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530480 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800481 return count;
482
483failure:
Rajeev Kumarb08f39c2016-02-04 17:50:54 -0800484 hdd_err("Invalid input. Input format is: ptrn_idx duration pattern");
Anurag Chouhan600c3a02016-03-01 10:33:54 +0530485 qdf_mem_free(cmd);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800486 return -EINVAL;
487}
488
489/**
490 * wcnss_patterngen_write() - SSR wrapper for __wcnss_patterngen_write
491 * @file: file pointer
492 * @buf: buffer
493 * @count: count
494 * @ppos: position pointer
495 *
496 * Return: 0 on success, error number otherwise
497 */
498static ssize_t wcnss_patterngen_write(struct file *file,
499 const char __user *buf,
500 size_t count, loff_t *ppos)
501{
502 ssize_t ret;
503
504 cds_ssr_protect(__func__);
505 ret = __wcnss_patterngen_write(file, buf, count, ppos);
506 cds_ssr_unprotect(__func__);
507
508 return ret;
509}
510
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530511#ifdef WLAN_POWER_DEBUGFS
Jeff Johnson52133112017-01-25 06:25:32 -0800512struct power_stats_priv {
513 struct power_stats_response power_stats;
514};
515
516static void hdd_power_debugstats_dealloc(void *priv)
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530517{
Jeff Johnson52133112017-01-25 06:25:32 -0800518 struct power_stats_priv *stats = priv;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -0700519
Jeff Johnson52133112017-01-25 06:25:32 -0800520 qdf_mem_free(stats->power_stats.debug_registers);
521}
522
523static void hdd_power_debugstats_cb(struct power_stats_response *response,
524 void *context)
525{
526 struct hdd_request *request;
527 struct power_stats_priv *priv;
528 uint32_t *debug_registers;
529 uint32_t debug_registers_len;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530530
531 ENTER();
Jeff Johnson52133112017-01-25 06:25:32 -0800532
533 request = hdd_request_get(context);
534 if (!request) {
535 hdd_err("Obsolete request");
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530536 return;
537 }
538
Jeff Johnson52133112017-01-25 06:25:32 -0800539 priv = hdd_request_priv(request);
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530540
Jeff Johnson52133112017-01-25 06:25:32 -0800541 /* copy fixed-sized data */
542 priv->power_stats = *response;
543
544 /* copy variable-size data */
545 if (response->num_debug_register) {
546 debug_registers_len = (sizeof(response->debug_registers[0]) *
547 response->num_debug_register);
548 debug_registers = qdf_mem_malloc(debug_registers_len);
549 priv->power_stats.debug_registers = debug_registers;
550 if (debug_registers) {
551 qdf_mem_copy(debug_registers,
552 response->debug_registers,
553 debug_registers_len);
554 } else {
555 hdd_err("Power stats memory alloc fails!");
556 priv->power_stats.num_debug_register = 0;
557 }
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530558 }
Jeff Johnson52133112017-01-25 06:25:32 -0800559 hdd_request_complete(request);
560 hdd_request_put(request);
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530561 EXIT();
562}
563
564/**
565 * __wlan_hdd_read_power_debugfs() - API to collect Chip power stats from FW
566 * @file: file pointer
567 * @buf: buffer
568 * @count: count
569 * @pos: position pointer
570 *
571 * Return: Number of bytes read on success, error number otherwise
572 */
573static ssize_t __wlan_hdd_read_power_debugfs(struct file *file,
574 char __user *buf,
575 size_t count, loff_t *pos)
576{
Jeff Johnsonf0a3c612017-08-29 14:38:18 -0700577 struct hdd_adapter *adapter;
Jeff Johnson2a9711b2017-08-28 12:05:00 -0700578 struct hdd_context *hdd_ctx;
Jeff Johnson52133112017-01-25 06:25:32 -0800579 QDF_STATUS status;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530580 struct power_stats_response *chip_power_stats;
581 ssize_t ret_cnt = 0;
Jeff Johnson52133112017-01-25 06:25:32 -0800582 int j;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530583 unsigned int len = 0;
Jeff Johnson52133112017-01-25 06:25:32 -0800584 char *power_debugfs_buf = NULL;
585 void *cookie;
586 struct hdd_request *request;
587 struct power_stats_priv *priv;
588 static const struct hdd_request_params params = {
589 .priv_size = sizeof(*priv),
590 .timeout_ms = WLAN_WAIT_TIME_STATS,
591 .dealloc = hdd_power_debugstats_dealloc,
592 };
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530593
594 ENTER();
Jeff Johnsonf0a3c612017-08-29 14:38:18 -0700595 adapter = (struct hdd_adapter *)file->private_data;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530596 if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
597 hdd_err("Invalid adapter or adapter has invalid magic");
598 return -EINVAL;
599 }
600
601 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
602 ret_cnt = wlan_hdd_validate_context(hdd_ctx);
603 if (0 != ret_cnt)
604 return ret_cnt;
605
Arun Khandavallica892f62017-05-26 14:25:50 +0530606 if (!wlan_hdd_validate_modules_state(hdd_ctx))
607 return -EINVAL;
608
Jeff Johnson52133112017-01-25 06:25:32 -0800609 request = hdd_request_alloc(&params);
610 if (!request) {
611 hdd_err("Request allocation failure");
612 return -ENOMEM;
613 }
614 cookie = hdd_request_cookie(request);
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530615
Jeff Johnson52133112017-01-25 06:25:32 -0800616 status = sme_power_debug_stats_req(hdd_ctx->hHal,
617 hdd_power_debugstats_cb,
618 cookie);
619 if (QDF_IS_STATUS_ERROR(status)) {
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530620 hdd_err("chip power stats request failed");
Jeff Johnson52133112017-01-25 06:25:32 -0800621 ret_cnt = -EINVAL;
622 goto cleanup;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530623 }
624
Jeff Johnson52133112017-01-25 06:25:32 -0800625 ret_cnt = hdd_request_wait_for_response(request);
626 if (ret_cnt) {
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530627 hdd_err("Target response timed out Power stats");
Jeff Johnson52133112017-01-25 06:25:32 -0800628 ret_cnt = -ETIMEDOUT;
629 goto cleanup;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530630 }
631
Jeff Johnson52133112017-01-25 06:25:32 -0800632 priv = hdd_request_priv(request);
633 chip_power_stats = &priv->power_stats;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530634
635 power_debugfs_buf = qdf_mem_malloc(POWER_DEBUGFS_BUFFER_MAX_LEN);
636 if (!power_debugfs_buf) {
637 hdd_err("Power stats buffer alloc fails!");
Jeff Johnson52133112017-01-25 06:25:32 -0800638 ret_cnt = -EINVAL;
639 goto cleanup;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530640 }
641
642 len += scnprintf(power_debugfs_buf, POWER_DEBUGFS_BUFFER_MAX_LEN,
643 "POWER DEBUG STATS\n=================\n"
644 "cumulative_sleep_time_ms: %d\n"
645 "cumulative_total_on_time_ms: %d\n"
646 "deep_sleep_enter_counter: %d\n"
647 "last_deep_sleep_enter_tstamp_ms: %d\n"
648 "debug_register_fmt: %d\n"
649 "num_debug_register: %d\n",
650 chip_power_stats->cumulative_sleep_time_ms,
651 chip_power_stats->cumulative_total_on_time_ms,
652 chip_power_stats->deep_sleep_enter_counter,
653 chip_power_stats->last_deep_sleep_enter_tstamp_ms,
654 chip_power_stats->debug_register_fmt,
655 chip_power_stats->num_debug_register);
656
657 for (j = 0; j < chip_power_stats->num_debug_register; j++) {
658 if ((POWER_DEBUGFS_BUFFER_MAX_LEN - len) > 0)
659 len += scnprintf(power_debugfs_buf + len,
660 POWER_DEBUGFS_BUFFER_MAX_LEN - len,
661 "debug_registers[%d]: 0x%x\n", j,
662 chip_power_stats->debug_registers[j]);
663 else
664 j = chip_power_stats->num_debug_register;
665 }
666
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530667 ret_cnt = simple_read_from_buffer(buf, count, pos,
Jeff Johnson52133112017-01-25 06:25:32 -0800668 power_debugfs_buf, len);
669
670 cleanup:
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530671 qdf_mem_free(power_debugfs_buf);
Jeff Johnson52133112017-01-25 06:25:32 -0800672 hdd_request_put(request);
673
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530674 return ret_cnt;
675}
676
677/**
678 * wlan_hdd_read_power_debugfs() - SSR wrapper function to read power debugfs
679 * @file: file pointer
680 * @buf: buffer
681 * @count: count
682 * @pos: position pointer
683 *
684 * Return: Number of bytes read on success, error number otherwise
685 */
686static ssize_t wlan_hdd_read_power_debugfs(struct file *file,
687 char __user *buf,
688 size_t count, loff_t *pos)
689{
690 int ret;
691
692 cds_ssr_protect(__func__);
693 ret = __wlan_hdd_read_power_debugfs(file, buf, count, pos);
694 cds_ssr_unprotect(__func__);
695
696 return ret;
697}
698
699/**
700 * __wlan_hdd_open_power_debugfs() - Function to save private on open
701 * @inode: Pointer to inode structure
702 * @file: file pointer
703 *
704 * Return: zero
705 */
706static int __wlan_hdd_open_power_debugfs(struct inode *inode, struct file *file)
707{
708 file->private_data = inode->i_private;
709 return 0;
710}
711
712
713/**
714 * wlan_hdd_open_power_debugfs() - SSR wrapper function to save private on open
715 * @inode: Pointer to inode structure
716 * @file: file pointer
717 *
718 * Return: zero
719 */
720static int wlan_hdd_open_power_debugfs(struct inode *inode, struct file *file)
721{
722 int ret;
723
724 cds_ssr_protect(__func__);
725 ret = __wlan_hdd_open_power_debugfs(inode, file);
726 cds_ssr_unprotect(__func__);
727
728 return ret;
729}
730#endif
731
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800732/**
733 * __wcnss_debugfs_open() - Generic debugfs open() handler
734 * @inode: inode of the debugfs file
735 * @file: file handle of the debugfs file
736 *
737 * Return: 0
738 */
739static int __wcnss_debugfs_open(struct inode *inode, struct file *file)
740{
Jeff Johnsonf0a3c612017-08-29 14:38:18 -0700741 struct hdd_adapter *adapter;
Jeff Johnson2a9711b2017-08-28 12:05:00 -0700742 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800743 int ret;
744
745 ENTER();
746
747 if (inode->i_private)
748 file->private_data = inode->i_private;
749
Jeff Johnsonf0a3c612017-08-29 14:38:18 -0700750 adapter = (struct hdd_adapter *)file->private_data;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800751 if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -0800752 hdd_err("Invalid adapter or adapter has invalid magic");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800753 return -EINVAL;
754 }
755
756 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
757 ret = wlan_hdd_validate_context(hdd_ctx);
758 if (0 != ret)
759 return ret;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530760 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800761 return 0;
762}
763
764/**
765 * wcnss_debugfs_open() - SSR wrapper for __wcnss_debugfs_open
766 * @inode: inode pointer
767 * @file: file pointer
768 *
769 * Return: 0 on success, error number otherwise
770 */
771static int wcnss_debugfs_open(struct inode *inode, struct file *file)
772{
773 int ret;
774
775 cds_ssr_protect(__func__);
776 ret = __wcnss_debugfs_open(inode, file);
777 cds_ssr_unprotect(__func__);
778
779 return ret;
780}
781
782static const struct file_operations fops_wowenable = {
783 .write = wcnss_wowenable_write,
784 .open = wcnss_debugfs_open,
785 .owner = THIS_MODULE,
786 .llseek = default_llseek,
787};
788
789static const struct file_operations fops_wowpattern = {
790 .write = wcnss_wowpattern_write,
791 .open = wcnss_debugfs_open,
792 .owner = THIS_MODULE,
793 .llseek = default_llseek,
794};
795
796static const struct file_operations fops_patterngen = {
797 .write = wcnss_patterngen_write,
798 .open = wcnss_debugfs_open,
799 .owner = THIS_MODULE,
800 .llseek = default_llseek,
801};
802
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530803#ifdef WLAN_POWER_DEBUGFS
804static const struct file_operations fops_powerdebugs = {
805 .read = wlan_hdd_read_power_debugfs,
806 .open = wlan_hdd_open_power_debugfs,
807 .owner = THIS_MODULE,
808 .llseek = default_llseek,
809};
810
811/**
812 * wlan_hdd_create_power_stats_file() - API to create power stats file
813 * @adapter: interface adapter pointer
814 *
815 * Return: QDF_STATUS
816 */
Jeff Johnsonf0a3c612017-08-29 14:38:18 -0700817static QDF_STATUS wlan_hdd_create_power_stats_file(struct hdd_adapter *adapter)
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530818{
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530819 if (!debugfs_create_file("power_stats", 00400 | 00040 | 00004,
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530820 adapter->debugfs_phy, adapter,
821 &fops_powerdebugs))
822 return QDF_STATUS_E_FAILURE;
823
824 return QDF_STATUS_SUCCESS;
825}
826
827#else
Jeff Johnsonf0a3c612017-08-29 14:38:18 -0700828static QDF_STATUS wlan_hdd_create_power_stats_file(struct hdd_adapter *adapter)
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530829{
830 return QDF_STATUS_SUCCESS;
831}
832#endif
833
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800834/**
835 * hdd_debugfs_init() - Initialize debugfs interface
Rajeev Kumardca5f812016-02-04 17:28:06 -0800836 * @adapter: interface adapter pointer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800837 *
838 * Register support for the debugfs files supported by the driver.
839 *
840 * NB: The current implementation only supports debugfs operations
841 * on the primary interface, i.e. wlan0
842 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530843 * Return: QDF_STATUS_SUCCESS if all files registered,
844 * QDF_STATUS_E_FAILURE on failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800845 */
Jeff Johnsonf0a3c612017-08-29 14:38:18 -0700846QDF_STATUS hdd_debugfs_init(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800847{
Rajeev Kumardca5f812016-02-04 17:28:06 -0800848 struct net_device *dev = adapter->dev;
Jeff Johnson4f7f7c62017-10-05 08:53:41 -0700849
Rajeev Kumardca5f812016-02-04 17:28:06 -0800850 adapter->debugfs_phy = debugfs_create_dir(dev->name, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800851
Rajeev Kumardca5f812016-02-04 17:28:06 -0800852 if (NULL == adapter->debugfs_phy)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530853 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800854
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530855 if (NULL == debugfs_create_file("wow_enable", 00400 | 00200,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800856 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800857 &fops_wowenable))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530858 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800859
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530860 if (NULL == debugfs_create_file("wow_pattern", 00400 | 00200,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800861 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800862 &fops_wowpattern))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530863 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800864
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530865 if (NULL == debugfs_create_file("pattern_gen", 00400 | 00200,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800866 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800867 &fops_patterngen))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530868 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800869
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530870 if (QDF_STATUS_SUCCESS != wlan_hdd_create_power_stats_file(adapter))
871 return QDF_STATUS_E_FAILURE;
872
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800873 if (0 != wlan_hdd_create_ll_stats_file(adapter))
874 return QDF_STATUS_E_FAILURE;
875
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530876 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800877}
878
879/**
880 * hdd_debugfs_exit() - Shutdown debugfs interface
Rajeev Kumardca5f812016-02-04 17:28:06 -0800881 * @adapter: interface adapter pointer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800882 *
883 * Unregister support for the debugfs files supported by the driver.
884 *
885 * Return: None
886 */
Jeff Johnsonf0a3c612017-08-29 14:38:18 -0700887void hdd_debugfs_exit(struct hdd_adapter *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888{
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530889 debugfs_remove_recursive(adapter->debugfs_phy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800890}
891#endif /* #ifdef WLAN_OPEN_SOURCE */