blob: 79208dadcf631b8bcde78efd0521a64e6f4d7d6b [file] [log] [blame]
Rajeev Kumar Sirasanagandla197d4172018-02-15 19:03:29 +05301/*
2 * Copyright (c) 2018 The Linux Foundation. All rights reserved.
3 *
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 * DOC: wlan_hdd_debugfs_csr.c
24 *
25 * WLAN Host Device Driver implementation to update
26 * debugfs with roaming related information
27 */
28
29#include <wlan_hdd_debugfs_csr.h>
30#include <wlan_hdd_main.h>
31#include <cds_sched.h>
32#include <wma_api.h>
33#include "qwlan_version.h"
34#include "wmi_unified_param.h"
35#include "wlan_hdd_debugfs.h"
36
37ssize_t
38wlan_hdd_current_time_info_debugfs(uint8_t *buf, ssize_t buf_avail_len)
39{
40 ssize_t length;
41 char time_buffer[HDD_TIME_STRING_LEN];
42 int ret_val;
43
44 qdf_get_time_of_the_day_in_hr_min_sec_usec(time_buffer,
45 sizeof(time_buffer));
46 ret_val = scnprintf(buf, buf_avail_len,
47 "\nTime at which this file generated = %s\n",
48 time_buffer);
49 if (ret_val < 0)
50 return 0;
51 length = ret_val;
52
53 return length;
54}
55
56/**
57 * wlan_hdd_debugfs_update_csr() - Function to update internal debugfs buffer
58 * and write into user-space buffer
59 * @hdd_ctx: hdd context
60 * @adapter: adapter
61 * @id: used to identify file for which this info has to be read
62 * @buf: output buffer to write
63 * @buf_avail_len: length of the available buffer
64 *
65 * Return: Number of bytes read on success, zero otherwise
66 */
67static ssize_t
68wlan_hdd_debugfs_update_csr(struct hdd_context *hdd_ctx,
69 struct hdd_adapter *adapter,
70 enum hdd_debugfs_file_id id,
71 uint8_t *buf,
72 ssize_t buf_avail_len)
73{
74 ssize_t len = 0;
75
76 switch (id) {
77 case HDD_DEBUFS_FILE_ID_CONNECT_INFO:
78 /* populate connect info */
Rajeev Kumar Sirasanagandla4c8edc02018-03-12 08:44:51 +053079 len = wlan_hdd_debugfs_update_connect_info(hdd_ctx, adapter,
80 buf, buf_avail_len);
Rajeev Kumar Sirasanagandla197d4172018-02-15 19:03:29 +053081 break;
82 case HDD_DEBUFS_FILE_ID_ROAM_SCAN_STATS_INFO:
83 /* populate roam scan stats info */
84 break;
85 case HDD_DEBUFS_FILE_ID_OFFLOAD_INFO:
86 /* populate offload info */
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +053087 len = wlan_hdd_debugfs_update_filters_info(hdd_ctx, adapter,
88 buf, buf_avail_len);
Rajeev Kumar Sirasanagandla197d4172018-02-15 19:03:29 +053089 break;
90 default:
91 hdd_err("Failed to fetch stats, unknown stats type");
92 }
93
94 return len;
95}
96
97/**
98 * __wlan_hdd_read_debugfs_csr() - Function to read debug stats
99 * @file: file pointer
100 * @buf: buffer
101 * @count: count
102 * @pos: position pointer
103 *
104 * Return: Number of bytes read on success, zero otherwise
105 */
106static ssize_t
107__wlan_hdd_read_debugfs_csr(struct file *file, char __user *buf,
108 size_t count, loff_t *pos)
109{
110 struct wlan_hdd_debugfs_buffer_info *info;
111 struct hdd_adapter *adapter;
112 struct hdd_context *hdd_ctx;
113 int ret;
114 ssize_t length;
115
116 hdd_enter();
117
118 info = file->private_data;
119 if (!info || !info->data) {
120 hdd_err("No valid private data");
121 return 0;
122 }
123
124 adapter = info->adapter;
125 if ((!adapter) || (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) {
126 hdd_err("Invalid adapter or adapter has invalid magic");
127 return 0;
128 }
129
130 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
131 ret = wlan_hdd_validate_context(hdd_ctx);
132 if (ret)
133 return 0;
134
135 if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) {
136 hdd_err("Interface is not enabled");
137 return 0;
138 }
139
140 if (*pos == 0) {
141 info->length = wlan_hdd_debugfs_update_csr(hdd_ctx, adapter,
142 info->id,
143 info->data,
144 info->max_buf_len);
145 }
146
147 length = simple_read_from_buffer(buf, count, pos,
148 info->data, info->length);
149 hdd_debug("length written = %zu, count: %zu, pos: %lld",
150 length, count, *pos);
151
152 hdd_exit();
153 return length;
154}
155
156/**
157 * wlan_hdd_read_debugfs_csr() - SSR wrapper function to read stats
158 * @file: file pointer
159 * @buf: buffer
160 * @count: count
161 * @pos: position pointer
162 *
163 * Return: Number of bytes read on success, zero otherwise
164 */
165static ssize_t
166wlan_hdd_read_debugfs_csr(struct file *file, char __user *buf,
167 size_t count, loff_t *pos)
168{
169 int ret;
170
171 cds_ssr_protect(__func__);
172 ret = __wlan_hdd_read_debugfs_csr(file, buf, count, pos);
173 cds_ssr_unprotect(__func__);
174
175 return ret;
176}
177
178/**
179 * __wlan_hdd_open_debugfs_csr() - Allocates memory for private data
180 * @inode: Pointer to inode structure
181 * @file: file pointer
182 *
183 * Return: zero
184 */
185static int __wlan_hdd_open_debugfs_csr(struct inode *inode,
186 struct file *file)
187{
188 struct wlan_hdd_debugfs_buffer_info *info;
189 struct hdd_debugfs_file_info *csr;
190 struct hdd_adapter *adapter = NULL;
191 struct hdd_context *hdd_ctx;
192 int ret;
193
194 hdd_enter();
195
196 csr = inode->i_private;
197 if (!csr) {
198 hdd_err("No private data");
199 return -EINVAL;
200 }
201
202 adapter = qdf_container_of(csr, struct hdd_adapter,
203 csr_file[csr->id]);
204 if (!adapter || (adapter->magic != WLAN_HDD_ADAPTER_MAGIC)) {
205 hdd_err("Invalid adapter or adapter has invalid magic");
206 return -EINVAL;
207 }
208
209 hdd_ctx = WLAN_HDD_GET_CTX(adapter);
210 ret = wlan_hdd_validate_context(hdd_ctx);
211 if (ret)
212 return -EINVAL;
213
214 if (!test_bit(DEVICE_IFACE_OPENED, &adapter->event_flags)) {
215 hdd_err("Interface is not enabled");
216 return -EINVAL;
217 }
218
219 info = qdf_mem_malloc(sizeof(*info));
220 if (!info) {
221 hdd_err("Not enough memory for file private data");
222 return -ENOMEM;
223 }
224
225 info->data = qdf_mem_malloc(csr->buf_max_size);
226 if (!info->data) {
227 hdd_err("roam stats debugfs buffer allocation failed");
228 qdf_mem_free(info);
229 return -ENOMEM;
230 }
231 info->length = 0;
232 info->max_buf_len = csr->buf_max_size;
233 info->id = csr->id;
234 info->adapter = adapter;
235
236 file->private_data = info;
237 hdd_exit();
238
239 return 0;
240}
241
242/**
243 * wlan_hdd_open_debugfs_csr() - SSR wrapper function to allocate memory for
244 * private data on file open
245 * @inode: Pointer to inode structure
246 * @file: file pointer
247 *
248 * Return: zero
249 */
250static int wlan_hdd_open_debugfs_csr(struct inode *inode,
251 struct file *file)
252{
253 int ret;
254
255 cds_ssr_protect(__func__);
256
257 hdd_debugfs_thread_increment();
258 ret = __wlan_hdd_open_debugfs_csr(inode, file);
259 if (ret)
260 hdd_debugfs_thread_decrement();
261
262 cds_ssr_unprotect(__func__);
263
264 return ret;
265}
266
267/**
268 * __wlan_hdd_release_debugfs_csr() - Function to free private memory on
269 * release
270 * @inode: Pointer to inode structure
271 * @file: file pointer
272 *
273 * Return: zero
274 */
275static int __wlan_hdd_release_debugfs_csr(struct inode *inode,
276 struct file *file)
277{
278 struct wlan_hdd_debugfs_buffer_info *info = file->private_data;
279
280 hdd_enter();
281
282 if (!info)
283 return 0;
284
285 file->private_data = NULL;
286 qdf_mem_free(info->data);
287 qdf_mem_free(info);
288
289 hdd_exit();
290
291 return 0;
292}
293
294/**
295 * wlan_hdd_release_debugfs_csr() - SSR wrapper function to free
296 * private data on release
297 * @inode: Pointer to inode structure
298 * @file: file pointer
299 *
300 * Return: zero
301 */
302static int wlan_hdd_release_debugfs_csr(struct inode *inode, struct file *file)
303{
304 int ret;
305
306 cds_ssr_protect(__func__);
307 ret = __wlan_hdd_release_debugfs_csr(inode, file);
308 hdd_debugfs_thread_decrement();
309 cds_ssr_unprotect(__func__);
310
311 return ret;
312}
313
314static const struct file_operations fops_csr_debugfs = {
315 .read = wlan_hdd_read_debugfs_csr,
316 .open = wlan_hdd_open_debugfs_csr,
317 .release = wlan_hdd_release_debugfs_csr,
318 .owner = THIS_MODULE,
319 .llseek = default_llseek,
320};
321
322void wlan_hdd_debugfs_csr_init(struct hdd_adapter *adapter)
323{
Rajeev Kumar Sirasanagandla4c8edc02018-03-12 08:44:51 +0530324 struct hdd_debugfs_file_info *csr;
325 const uint32_t max_len = HDD_DEBUGFS_FILE_NAME_MAX;
326
Rajeev Kumar Sirasanagandla197d4172018-02-15 19:03:29 +0530327 /*
328 * Create debufs diagnostic files for connect, offload info
329 * and roam info and store in csr_file member of adapter
330 */
Rajeev Kumar Sirasanagandla4c8edc02018-03-12 08:44:51 +0530331
332 csr = &adapter->csr_file[HDD_DEBUFS_FILE_ID_CONNECT_INFO];
333 if (!csr->entry) {
334 strlcpy(csr->name, "connect_info", max_len);
335 csr->id = HDD_DEBUFS_FILE_ID_CONNECT_INFO;
336 csr->buf_max_size = DEBUGFS_CONNECT_INFO_BUF_SIZE;
337 csr->entry = debugfs_create_file(csr->name, 0444,
338 adapter->debugfs_phy,
339 csr, &fops_csr_debugfs);
340 if (!csr->entry)
341 hdd_err("Failed to create debugfs file: %s",
342 csr->name);
343 }
Rajeev Kumar Sirasanagandla85f8b022018-03-12 12:52:59 +0530344
345 csr = &adapter->csr_file[HDD_DEBUFS_FILE_ID_OFFLOAD_INFO];
346 if (!csr->entry) {
347 strlcpy(csr->name, "offload_info", max_len);
348 csr->id = HDD_DEBUFS_FILE_ID_OFFLOAD_INFO;
349 csr->buf_max_size = DEBUGFS_OFFLOAD_INFO_BUF_SIZE;
350 csr->entry = debugfs_create_file(csr->name, 0444,
351 adapter->debugfs_phy,
352 csr, &fops_csr_debugfs);
353 if (!csr->entry)
354 hdd_err("Failed to create generic_info debugfs file");
355 }
Rajeev Kumar Sirasanagandla197d4172018-02-15 19:03:29 +0530356}
357
358void wlan_hdd_debugfs_csr_deinit(struct hdd_adapter *adapter)
359{
360 uint32_t i;
361 struct dentry *entry;
362
363 for (i = 0; i < HDD_DEBUGFS_FILE_ID_MAX; i++) {
364 entry = adapter->csr_file[i].entry;
365 if (!entry)
366 continue;
367
368 adapter->csr_file[i].entry = NULL;
369 debugfs_remove(entry);
370 entry = NULL;
371 }
372}