blob: a7f3508d3569ad507ef5ffb32a53be9517429fba [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{
66 hdd_adapter_t *pAdapter;
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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -080077 pAdapter = (hdd_adapter_t *)file->private_data;
78 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->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
83 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
84 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) {
117 if (!hdd_exit_wowl(pAdapter)) {
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
143 if (!hdd_enter_wowl(pAdapter, 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{
186 hdd_adapter_t *pAdapter = (hdd_adapter_t *) 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
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800198 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->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
203 hdd_ctx = WLAN_HDD_GET_CTX(pAdapter);
204 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) {
241 hdd_del_wowl_ptrn_debugfs(pAdapter, pattern_idx);
242
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
264 hdd_add_wowl_ptrn_debugfs(pAdapter, pattern_idx, pattern_offset,
265 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{
305 hdd_adapter_t *pAdapter;
Jeff Johnson2a9711b2017-08-28 12:05:00 -0700306 struct hdd_context *pHddCtx;
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
321 pAdapter = (hdd_adapter_t *)file->private_data;
322 if ((NULL == pAdapter) || (WLAN_HDD_ADAPTER_MAGIC != pAdapter->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
327 pHddCtx = WLAN_HDD_GET_CTX(pAdapter);
328 ret = wlan_hdd_validate_context(pHddCtx);
329 if (0 != ret)
330 return ret;
331
Arun Khandavallica892f62017-05-26 14:25:50 +0530332 if (!wlan_hdd_validate_modules_state(pHddCtx))
333 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,
Srinivas Girigowdaa5bba7a2015-11-18 22:44:36 -0800395 &pAdapter->macAddressCurrent);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800396
397 /* Delete pattern */
398 status = sme_del_periodic_tx_ptrn(pHddCtx->hHal,
399 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 */
Srinivas Girigowda73bfe252017-03-06 16:14:41 -0800416 hdd_debug("device mode %d", pAdapter->device_mode);
Krunal Sonibe766b02016-03-10 13:00:44 -0800417 if ((QDF_STA_MODE == pAdapter->device_mode) &&
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800418 (!hdd_conn_is_connected(WLAN_HDD_GET_STATION_CTX_PTR(pAdapter)))) {
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,
Srinivas Girigowda31896552015-11-18 22:59:52 -0800457 &pAdapter->macAddressCurrent);
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 */
470 status = sme_add_periodic_tx_ptrn(pHddCtx->hHal,
471 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;
519 qdf_mem_free(stats->power_stats.debug_registers);
520}
521
522static void hdd_power_debugstats_cb(struct power_stats_response *response,
523 void *context)
524{
525 struct hdd_request *request;
526 struct power_stats_priv *priv;
527 uint32_t *debug_registers;
528 uint32_t debug_registers_len;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530529
530 ENTER();
Jeff Johnson52133112017-01-25 06:25:32 -0800531
532 request = hdd_request_get(context);
533 if (!request) {
534 hdd_err("Obsolete request");
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530535 return;
536 }
537
Jeff Johnson52133112017-01-25 06:25:32 -0800538 priv = hdd_request_priv(request);
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530539
Jeff Johnson52133112017-01-25 06:25:32 -0800540 /* copy fixed-sized data */
541 priv->power_stats = *response;
542
543 /* copy variable-size data */
544 if (response->num_debug_register) {
545 debug_registers_len = (sizeof(response->debug_registers[0]) *
546 response->num_debug_register);
547 debug_registers = qdf_mem_malloc(debug_registers_len);
548 priv->power_stats.debug_registers = debug_registers;
549 if (debug_registers) {
550 qdf_mem_copy(debug_registers,
551 response->debug_registers,
552 debug_registers_len);
553 } else {
554 hdd_err("Power stats memory alloc fails!");
555 priv->power_stats.num_debug_register = 0;
556 }
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530557 }
Jeff Johnson52133112017-01-25 06:25:32 -0800558 hdd_request_complete(request);
559 hdd_request_put(request);
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530560 EXIT();
561}
562
563/**
564 * __wlan_hdd_read_power_debugfs() - API to collect Chip power stats from FW
565 * @file: file pointer
566 * @buf: buffer
567 * @count: count
568 * @pos: position pointer
569 *
570 * Return: Number of bytes read on success, error number otherwise
571 */
572static ssize_t __wlan_hdd_read_power_debugfs(struct file *file,
573 char __user *buf,
574 size_t count, loff_t *pos)
575{
576 hdd_adapter_t *adapter;
Jeff Johnson2a9711b2017-08-28 12:05:00 -0700577 struct hdd_context *hdd_ctx;
Jeff Johnson52133112017-01-25 06:25:32 -0800578 QDF_STATUS status;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530579 struct power_stats_response *chip_power_stats;
580 ssize_t ret_cnt = 0;
Jeff Johnson52133112017-01-25 06:25:32 -0800581 int j;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530582 unsigned int len = 0;
Jeff Johnson52133112017-01-25 06:25:32 -0800583 char *power_debugfs_buf = NULL;
584 void *cookie;
585 struct hdd_request *request;
586 struct power_stats_priv *priv;
587 static const struct hdd_request_params params = {
588 .priv_size = sizeof(*priv),
589 .timeout_ms = WLAN_WAIT_TIME_STATS,
590 .dealloc = hdd_power_debugstats_dealloc,
591 };
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530592
593 ENTER();
594 adapter = (hdd_adapter_t *)file->private_data;
595 if ((!adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
596 hdd_err("Invalid adapter or adapter has invalid magic");
597 return -EINVAL;
598 }
599
600 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
601 ret_cnt = wlan_hdd_validate_context(hdd_ctx);
602 if (0 != ret_cnt)
603 return ret_cnt;
604
Arun Khandavallica892f62017-05-26 14:25:50 +0530605 if (!wlan_hdd_validate_modules_state(hdd_ctx))
606 return -EINVAL;
607
Jeff Johnson52133112017-01-25 06:25:32 -0800608 request = hdd_request_alloc(&params);
609 if (!request) {
610 hdd_err("Request allocation failure");
611 return -ENOMEM;
612 }
613 cookie = hdd_request_cookie(request);
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530614
Jeff Johnson52133112017-01-25 06:25:32 -0800615 status = sme_power_debug_stats_req(hdd_ctx->hHal,
616 hdd_power_debugstats_cb,
617 cookie);
618 if (QDF_IS_STATUS_ERROR(status)) {
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530619 hdd_err("chip power stats request failed");
Jeff Johnson52133112017-01-25 06:25:32 -0800620 ret_cnt = -EINVAL;
621 goto cleanup;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530622 }
623
Jeff Johnson52133112017-01-25 06:25:32 -0800624 ret_cnt = hdd_request_wait_for_response(request);
625 if (ret_cnt) {
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530626 hdd_err("Target response timed out Power stats");
Jeff Johnson52133112017-01-25 06:25:32 -0800627 ret_cnt = -ETIMEDOUT;
628 goto cleanup;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530629 }
630
Jeff Johnson52133112017-01-25 06:25:32 -0800631 priv = hdd_request_priv(request);
632 chip_power_stats = &priv->power_stats;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530633
634 power_debugfs_buf = qdf_mem_malloc(POWER_DEBUGFS_BUFFER_MAX_LEN);
635 if (!power_debugfs_buf) {
636 hdd_err("Power stats buffer alloc fails!");
Jeff Johnson52133112017-01-25 06:25:32 -0800637 ret_cnt = -EINVAL;
638 goto cleanup;
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530639 }
640
641 len += scnprintf(power_debugfs_buf, POWER_DEBUGFS_BUFFER_MAX_LEN,
642 "POWER DEBUG STATS\n=================\n"
643 "cumulative_sleep_time_ms: %d\n"
644 "cumulative_total_on_time_ms: %d\n"
645 "deep_sleep_enter_counter: %d\n"
646 "last_deep_sleep_enter_tstamp_ms: %d\n"
647 "debug_register_fmt: %d\n"
648 "num_debug_register: %d\n",
649 chip_power_stats->cumulative_sleep_time_ms,
650 chip_power_stats->cumulative_total_on_time_ms,
651 chip_power_stats->deep_sleep_enter_counter,
652 chip_power_stats->last_deep_sleep_enter_tstamp_ms,
653 chip_power_stats->debug_register_fmt,
654 chip_power_stats->num_debug_register);
655
656 for (j = 0; j < chip_power_stats->num_debug_register; j++) {
657 if ((POWER_DEBUGFS_BUFFER_MAX_LEN - len) > 0)
658 len += scnprintf(power_debugfs_buf + len,
659 POWER_DEBUGFS_BUFFER_MAX_LEN - len,
660 "debug_registers[%d]: 0x%x\n", j,
661 chip_power_stats->debug_registers[j]);
662 else
663 j = chip_power_stats->num_debug_register;
664 }
665
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530666 ret_cnt = simple_read_from_buffer(buf, count, pos,
Jeff Johnson52133112017-01-25 06:25:32 -0800667 power_debugfs_buf, len);
668
669 cleanup:
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530670 qdf_mem_free(power_debugfs_buf);
Jeff Johnson52133112017-01-25 06:25:32 -0800671 hdd_request_put(request);
672
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530673 return ret_cnt;
674}
675
676/**
677 * wlan_hdd_read_power_debugfs() - SSR wrapper function to read power debugfs
678 * @file: file pointer
679 * @buf: buffer
680 * @count: count
681 * @pos: position pointer
682 *
683 * Return: Number of bytes read on success, error number otherwise
684 */
685static ssize_t wlan_hdd_read_power_debugfs(struct file *file,
686 char __user *buf,
687 size_t count, loff_t *pos)
688{
689 int ret;
690
691 cds_ssr_protect(__func__);
692 ret = __wlan_hdd_read_power_debugfs(file, buf, count, pos);
693 cds_ssr_unprotect(__func__);
694
695 return ret;
696}
697
698/**
699 * __wlan_hdd_open_power_debugfs() - Function to save private on open
700 * @inode: Pointer to inode structure
701 * @file: file pointer
702 *
703 * Return: zero
704 */
705static int __wlan_hdd_open_power_debugfs(struct inode *inode, struct file *file)
706{
707 file->private_data = inode->i_private;
708 return 0;
709}
710
711
712/**
713 * wlan_hdd_open_power_debugfs() - SSR wrapper function to save private on open
714 * @inode: Pointer to inode structure
715 * @file: file pointer
716 *
717 * Return: zero
718 */
719static int wlan_hdd_open_power_debugfs(struct inode *inode, struct file *file)
720{
721 int ret;
722
723 cds_ssr_protect(__func__);
724 ret = __wlan_hdd_open_power_debugfs(inode, file);
725 cds_ssr_unprotect(__func__);
726
727 return ret;
728}
729#endif
730
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800731/**
732 * __wcnss_debugfs_open() - Generic debugfs open() handler
733 * @inode: inode of the debugfs file
734 * @file: file handle of the debugfs file
735 *
736 * Return: 0
737 */
738static int __wcnss_debugfs_open(struct inode *inode, struct file *file)
739{
740 hdd_adapter_t *adapter;
Jeff Johnson2a9711b2017-08-28 12:05:00 -0700741 struct hdd_context *hdd_ctx;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800742 int ret;
743
744 ENTER();
745
746 if (inode->i_private)
747 file->private_data = inode->i_private;
748
749 adapter = (hdd_adapter_t *)file->private_data;
750 if ((NULL == adapter) || (WLAN_HDD_ADAPTER_MAGIC != adapter->magic)) {
Srinivas Girigowda73bfe252017-03-06 16:14:41 -0800751 hdd_err("Invalid adapter or adapter has invalid magic");
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800752 return -EINVAL;
753 }
754
755 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
756 ret = wlan_hdd_validate_context(hdd_ctx);
757 if (0 != ret)
758 return ret;
Hanumantha Reddy Pothula2db50ed2015-11-23 10:48:33 +0530759 EXIT();
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800760 return 0;
761}
762
763/**
764 * wcnss_debugfs_open() - SSR wrapper for __wcnss_debugfs_open
765 * @inode: inode pointer
766 * @file: file pointer
767 *
768 * Return: 0 on success, error number otherwise
769 */
770static int wcnss_debugfs_open(struct inode *inode, struct file *file)
771{
772 int ret;
773
774 cds_ssr_protect(__func__);
775 ret = __wcnss_debugfs_open(inode, file);
776 cds_ssr_unprotect(__func__);
777
778 return ret;
779}
780
781static const struct file_operations fops_wowenable = {
782 .write = wcnss_wowenable_write,
783 .open = wcnss_debugfs_open,
784 .owner = THIS_MODULE,
785 .llseek = default_llseek,
786};
787
788static const struct file_operations fops_wowpattern = {
789 .write = wcnss_wowpattern_write,
790 .open = wcnss_debugfs_open,
791 .owner = THIS_MODULE,
792 .llseek = default_llseek,
793};
794
795static const struct file_operations fops_patterngen = {
796 .write = wcnss_patterngen_write,
797 .open = wcnss_debugfs_open,
798 .owner = THIS_MODULE,
799 .llseek = default_llseek,
800};
801
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530802#ifdef WLAN_POWER_DEBUGFS
803static const struct file_operations fops_powerdebugs = {
804 .read = wlan_hdd_read_power_debugfs,
805 .open = wlan_hdd_open_power_debugfs,
806 .owner = THIS_MODULE,
807 .llseek = default_llseek,
808};
809
810/**
811 * wlan_hdd_create_power_stats_file() - API to create power stats file
812 * @adapter: interface adapter pointer
813 *
814 * Return: QDF_STATUS
815 */
816static QDF_STATUS wlan_hdd_create_power_stats_file(hdd_adapter_t *adapter)
817{
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530818 if (!debugfs_create_file("power_stats", 00400 | 00040 | 00004,
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530819 adapter->debugfs_phy, adapter,
820 &fops_powerdebugs))
821 return QDF_STATUS_E_FAILURE;
822
823 return QDF_STATUS_SUCCESS;
824}
825
826#else
827static QDF_STATUS wlan_hdd_create_power_stats_file(hdd_adapter_t *adapter)
828{
829 return QDF_STATUS_SUCCESS;
830}
831#endif
832
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800833/**
834 * hdd_debugfs_init() - Initialize debugfs interface
Rajeev Kumardca5f812016-02-04 17:28:06 -0800835 * @adapter: interface adapter pointer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800836 *
837 * Register support for the debugfs files supported by the driver.
838 *
839 * NB: The current implementation only supports debugfs operations
840 * on the primary interface, i.e. wlan0
841 *
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530842 * Return: QDF_STATUS_SUCCESS if all files registered,
843 * QDF_STATUS_E_FAILURE on failure
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800844 */
Rajeev Kumardca5f812016-02-04 17:28:06 -0800845QDF_STATUS hdd_debugfs_init(hdd_adapter_t *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800846{
Rajeev Kumardca5f812016-02-04 17:28:06 -0800847 struct net_device *dev = adapter->dev;
848 adapter->debugfs_phy = debugfs_create_dir(dev->name, 0);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800849
Rajeev Kumardca5f812016-02-04 17:28:06 -0800850 if (NULL == adapter->debugfs_phy)
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530851 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800852
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530853 if (NULL == debugfs_create_file("wow_enable", 00400 | 00200,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800854 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800855 &fops_wowenable))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530856 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800857
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530858 if (NULL == debugfs_create_file("wow_pattern", 00400 | 00200,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800859 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800860 &fops_wowpattern))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530861 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800862
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530863 if (NULL == debugfs_create_file("pattern_gen", 00400 | 00200,
Rajeev Kumardca5f812016-02-04 17:28:06 -0800864 adapter->debugfs_phy, adapter,
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800865 &fops_patterngen))
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530866 return QDF_STATUS_E_FAILURE;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800867
Sridhar Selvarajdc400d22016-10-18 17:18:03 +0530868 if (QDF_STATUS_SUCCESS != wlan_hdd_create_power_stats_file(adapter))
869 return QDF_STATUS_E_FAILURE;
870
Krishna Kumaar Natarajanc7e2bb72017-03-10 10:38:46 -0800871 if (0 != wlan_hdd_create_ll_stats_file(adapter))
872 return QDF_STATUS_E_FAILURE;
873
Anurag Chouhanfb54ab02016-02-18 18:00:46 +0530874 return QDF_STATUS_SUCCESS;
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800875}
876
877/**
878 * hdd_debugfs_exit() - Shutdown debugfs interface
Rajeev Kumardca5f812016-02-04 17:28:06 -0800879 * @adapter: interface adapter pointer
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800880 *
881 * Unregister support for the debugfs files supported by the driver.
882 *
883 * Return: None
884 */
Rajeev Kumardca5f812016-02-04 17:28:06 -0800885void hdd_debugfs_exit(hdd_adapter_t *adapter)
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800886{
Arunk Khandavalli0ecf8c82017-06-29 15:48:53 +0530887 debugfs_remove_recursive(adapter->debugfs_phy);
Prakash Dhavali7090c5f2015-11-02 17:55:19 -0800888}
889#endif /* #ifdef WLAN_OPEN_SOURCE */