File Index
Files and directories
Sign in
FILE

debugfs.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/wireless/ti/wlcore/debugfs.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * This file is part of wl1271
   4 *
   5 * Copyright (C) 2009 Nokia Corporation
   6 *
   7 * Contact: Luciano Coelho <luciano.coelho@nokia.com>
   8 */
   9
  10#include "debugfs.h"
  11
  12#include <linux/skbuff.h>
  13#include <linux/slab.h>
  14#include <linux/module.h>
  15#include <linux/pm_runtime.h>
  16
  17#include "wlcore.h"
  18#include "debug.h"
  19#include "acx.h"
  20#include "ps.h"
  21#include "io.h"
  22#include "tx.h"
  23#include "hw_ops.h"
  24
  25/* ms */
  26#define WL1271_DEBUGFS_STATS_LIFETIME 1000
  27
  28#define WLCORE_MAX_BLOCK_SIZE ((size_t)(4*PAGE_SIZE))
  29
  30/* debugfs macros idea from mac80211 */
  31int wl1271_format_buffer(char __user *userbuf, size_t count,
  32			 loff_t *ppos, char *fmt, ...)
  33{
  34	va_list args;
  35	char buf[DEBUGFS_FORMAT_BUFFER_SIZE];
  36	int res;
  37
  38	va_start(args, fmt);
  39	res = vscnprintf(buf, sizeof(buf), fmt, args);
  40	va_end(args);
  41
  42	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
  43}
  44EXPORT_SYMBOL_GPL(wl1271_format_buffer);
  45
  46void wl1271_debugfs_update_stats(struct wl1271 *wl)
  47{
  48	int ret;
  49
  50	mutex_lock(&wl->mutex);
  51
  52	if (unlikely(wl->state != WLCORE_STATE_ON))
  53		goto out;
  54
  55	ret = pm_runtime_resume_and_get(wl->dev);
  56	if (ret < 0)
  57		goto out;
  58
  59	if (!wl->plt &&
  60	    time_after(jiffies, wl->stats.fw_stats_update +
  61		       msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {
  62		wl1271_acx_statistics(wl, wl->stats.fw_stats);
  63		wl->stats.fw_stats_update = jiffies;
  64	}
  65
  66	pm_runtime_put_autosuspend(wl->dev);
  67
  68out:
  69	mutex_unlock(&wl->mutex);
  70}
  71EXPORT_SYMBOL_GPL(wl1271_debugfs_update_stats);
  72
  73DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count);
  74DEBUGFS_READONLY_FILE(excessive_retries, "%u",
  75		      wl->stats.excessive_retries);
  76
  77static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,
  78				 size_t count, loff_t *ppos)
  79{
  80	struct wl1271 *wl = file->private_data;
  81	u32 queue_len;
  82	char buf[20];
  83	int res;
  84
  85	queue_len = wl1271_tx_total_queue_count(wl);
  86
  87	res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);
  88	return simple_read_from_buffer(userbuf, count, ppos, buf, res);
  89}
  90
  91static const struct file_operations tx_queue_len_ops = {
  92	.read = tx_queue_len_read,
  93	.open = simple_open,
  94	.llseek = default_llseek,
  95};
  96
  97static void chip_op_handler(struct wl1271 *wl, unsigned long value,
  98			    void *arg)
  99{
 100	int ret;
 101	int (*chip_op) (struct wl1271 *wl);
 102
 103	if (!arg) {
 104		wl1271_warning("debugfs chip_op_handler with no callback");
 105		return;
 106	}
 107
 108	ret = pm_runtime_resume_and_get(wl->dev);
 109	if (ret < 0)
 110		return;
 111
 112	chip_op = arg;
 113	chip_op(wl);
 114
 115	pm_runtime_put_autosuspend(wl->dev);
 116}
 117
 118#define WL12XX_CONF_DEBUGFS(param, conf_sub_struct,			\
 119			    min_val, max_val, write_handler_locked,	\
 120			    write_handler_arg)				\
 121	static ssize_t param##_read(struct file *file,			\
 122				      char __user *user_buf,		\
 123				      size_t count, loff_t *ppos)	\
 124	{								\
 125	struct wl1271 *wl = file->private_data;				\
 126	return wl1271_format_buffer(user_buf, count,			\
 127				    ppos, "%d\n",			\
 128				    wl->conf.conf_sub_struct.param);	\
 129	}								\
 130									\
 131	static ssize_t param##_write(struct file *file,			\
 132				     const char __user *user_buf,	\
 133				     size_t count, loff_t *ppos)	\
 134	{								\
 135	struct wl1271 *wl = file->private_data;				\
 136	unsigned long value;						\
 137	int ret;							\
 138									\
 139	ret = kstrtoul_from_user(user_buf, count, 10, &value);		\
 140	if (ret < 0) {							\
 141		wl1271_warning("illegal value for " #param);		\
 142		return -EINVAL;						\
 143	}								\
 144									\
 145	if (value < min_val || value > max_val) {			\
 146		wl1271_warning(#param " is not in valid range");	\
 147		return -ERANGE;						\
 148	}								\
 149									\
 150	mutex_lock(&wl->mutex);						\
 151	wl->conf.conf_sub_struct.param = value;				\
 152									\
 153	write_handler_locked(wl, value, write_handler_arg);		\
 154									\
 155	mutex_unlock(&wl->mutex);					\
 156	return count;							\
 157	}								\
 158									\
 159	static const struct file_operations param##_ops = {		\
 160		.read = param##_read,					\
 161		.write = param##_write,					\
 162		.open = simple_open,					\
 163		.llseek = default_llseek,				\
 164	};
 165
 166WL12XX_CONF_DEBUGFS(irq_pkt_threshold, rx, 0, 65535,
 167		    chip_op_handler, wl1271_acx_init_rx_interrupt)
 168WL12XX_CONF_DEBUGFS(irq_blk_threshold, rx, 0, 65535,
 169		    chip_op_handler, wl1271_acx_init_rx_interrupt)
 170WL12XX_CONF_DEBUGFS(irq_timeout, rx, 0, 100,
 171		    chip_op_handler, wl1271_acx_init_rx_interrupt)
 172
 173static ssize_t gpio_power_read(struct file *file, char __user *user_buf,
 174			  size_t count, loff_t *ppos)
 175{
 176	struct wl1271 *wl = file->private_data;
 177	bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags);
 178
 179	int res;
 180	char buf[10];
 181
 182	res = scnprintf(buf, sizeof(buf), "%d\n", state);
 183
 184	return simple_read_from_buffer(user_buf, count, ppos, buf, res);
 185}
 186
 187static ssize_t gpio_power_write(struct file *file,
 188			   const char __user *user_buf,
 189			   size_t count, loff_t *ppos)
 190{
 191	struct wl1271 *wl = file->private_data;
 192	unsigned long value;
 193	int ret;
 194
 195	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 196	if (ret < 0) {
 197		wl1271_warning("illegal value in gpio_power");
 198		return -EINVAL;
 199	}
 200
 201	mutex_lock(&wl->mutex);
 202
 203	if (value)
 204		wl1271_power_on(wl);
 205	else
 206		wl1271_power_off(wl);
 207
 208	mutex_unlock(&wl->mutex);
 209	return count;
 210}
 211
 212static const struct file_operations gpio_power_ops = {
 213	.read = gpio_power_read,
 214	.write = gpio_power_write,
 215	.open = simple_open,
 216	.llseek = default_llseek,
 217};
 218
 219static ssize_t start_recovery_write(struct file *file,
 220				    const char __user *user_buf,
 221				    size_t count, loff_t *ppos)
 222{
 223	struct wl1271 *wl = file->private_data;
 224
 225	mutex_lock(&wl->mutex);
 226	wl12xx_queue_recovery_work(wl);
 227	mutex_unlock(&wl->mutex);
 228
 229	return count;
 230}
 231
 232static const struct file_operations start_recovery_ops = {
 233	.write = start_recovery_write,
 234	.open = simple_open,
 235	.llseek = default_llseek,
 236};
 237
 238static ssize_t dynamic_ps_timeout_read(struct file *file, char __user *user_buf,
 239			  size_t count, loff_t *ppos)
 240{
 241	struct wl1271 *wl = file->private_data;
 242
 243	return wl1271_format_buffer(user_buf, count,
 244				    ppos, "%d\n",
 245				    wl->conf.conn.dynamic_ps_timeout);
 246}
 247
 248static ssize_t dynamic_ps_timeout_write(struct file *file,
 249				    const char __user *user_buf,
 250				    size_t count, loff_t *ppos)
 251{
 252	struct wl1271 *wl = file->private_data;
 253	struct wl12xx_vif *wlvif;
 254	unsigned long value;
 255	int ret;
 256
 257	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 258	if (ret < 0) {
 259		wl1271_warning("illegal value in dynamic_ps");
 260		return -EINVAL;
 261	}
 262
 263	if (value < 1 || value > 65535) {
 264		wl1271_warning("dynamic_ps_timeout is not in valid range");
 265		return -ERANGE;
 266	}
 267
 268	mutex_lock(&wl->mutex);
 269
 270	wl->conf.conn.dynamic_ps_timeout = value;
 271
 272	if (unlikely(wl->state != WLCORE_STATE_ON))
 273		goto out;
 274
 275	ret = pm_runtime_resume_and_get(wl->dev);
 276	if (ret < 0)
 277		goto out;
 278
 279	/* In case we're already in PSM, trigger it again to set new timeout
 280	 * immediately without waiting for re-association
 281	 */
 282
 283	wl12xx_for_each_wlvif_sta(wl, wlvif) {
 284		if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
 285			wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE);
 286	}
 287
 288	pm_runtime_put_autosuspend(wl->dev);
 289
 290out:
 291	mutex_unlock(&wl->mutex);
 292	return count;
 293}
 294
 295static const struct file_operations dynamic_ps_timeout_ops = {
 296	.read = dynamic_ps_timeout_read,
 297	.write = dynamic_ps_timeout_write,
 298	.open = simple_open,
 299	.llseek = default_llseek,
 300};
 301
 302static ssize_t forced_ps_read(struct file *file, char __user *user_buf,
 303			  size_t count, loff_t *ppos)
 304{
 305	struct wl1271 *wl = file->private_data;
 306
 307	return wl1271_format_buffer(user_buf, count,
 308				    ppos, "%d\n",
 309				    wl->conf.conn.forced_ps);
 310}
 311
 312static ssize_t forced_ps_write(struct file *file,
 313				    const char __user *user_buf,
 314				    size_t count, loff_t *ppos)
 315{
 316	struct wl1271 *wl = file->private_data;
 317	struct wl12xx_vif *wlvif;
 318	unsigned long value;
 319	int ret, ps_mode;
 320
 321	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 322	if (ret < 0) {
 323		wl1271_warning("illegal value in forced_ps");
 324		return -EINVAL;
 325	}
 326
 327	if (value != 1 && value != 0) {
 328		wl1271_warning("forced_ps should be either 0 or 1");
 329		return -ERANGE;
 330	}
 331
 332	mutex_lock(&wl->mutex);
 333
 334	if (wl->conf.conn.forced_ps == value)
 335		goto out;
 336
 337	wl->conf.conn.forced_ps = value;
 338
 339	if (unlikely(wl->state != WLCORE_STATE_ON))
 340		goto out;
 341
 342	ret = pm_runtime_resume_and_get(wl->dev);
 343	if (ret < 0)
 344		goto out;
 345
 346	/* In case we're already in PSM, trigger it again to switch mode
 347	 * immediately without waiting for re-association
 348	 */
 349
 350	ps_mode = value ? STATION_POWER_SAVE_MODE : STATION_AUTO_PS_MODE;
 351
 352	wl12xx_for_each_wlvif_sta(wl, wlvif) {
 353		if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))
 354			wl1271_ps_set_mode(wl, wlvif, ps_mode);
 355	}
 356
 357	pm_runtime_put_autosuspend(wl->dev);
 358
 359out:
 360	mutex_unlock(&wl->mutex);
 361	return count;
 362}
 363
 364static const struct file_operations forced_ps_ops = {
 365	.read = forced_ps_read,
 366	.write = forced_ps_write,
 367	.open = simple_open,
 368	.llseek = default_llseek,
 369};
 370
 371static ssize_t split_scan_timeout_read(struct file *file, char __user *user_buf,
 372			  size_t count, loff_t *ppos)
 373{
 374	struct wl1271 *wl = file->private_data;
 375
 376	return wl1271_format_buffer(user_buf, count,
 377				    ppos, "%d\n",
 378				    wl->conf.scan.split_scan_timeout / 1000);
 379}
 380
 381static ssize_t split_scan_timeout_write(struct file *file,
 382				    const char __user *user_buf,
 383				    size_t count, loff_t *ppos)
 384{
 385	struct wl1271 *wl = file->private_data;
 386	unsigned long value;
 387	int ret;
 388
 389	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 390	if (ret < 0) {
 391		wl1271_warning("illegal value in split_scan_timeout");
 392		return -EINVAL;
 393	}
 394
 395	if (value == 0)
 396		wl1271_info("split scan will be disabled");
 397
 398	mutex_lock(&wl->mutex);
 399
 400	wl->conf.scan.split_scan_timeout = value * 1000;
 401
 402	mutex_unlock(&wl->mutex);
 403	return count;
 404}
 405
 406static const struct file_operations split_scan_timeout_ops = {
 407	.read = split_scan_timeout_read,
 408	.write = split_scan_timeout_write,
 409	.open = simple_open,
 410	.llseek = default_llseek,
 411};
 412
 413static ssize_t driver_state_read(struct file *file, char __user *user_buf,
 414				 size_t count, loff_t *ppos)
 415{
 416	struct wl1271 *wl = file->private_data;
 417	int res = 0;
 418	ssize_t ret;
 419	char *buf;
 420	struct wl12xx_vif *wlvif;
 421
 422#define DRIVER_STATE_BUF_LEN 1024
 423
 424	buf = kmalloc(DRIVER_STATE_BUF_LEN, GFP_KERNEL);
 425	if (!buf)
 426		return -ENOMEM;
 427
 428	mutex_lock(&wl->mutex);
 429
 430#define DRIVER_STATE_PRINT(x, fmt)   \
 431	(res += scnprintf(buf + res, DRIVER_STATE_BUF_LEN - res,\
 432			  #x " = " fmt "\n", wl->x))
 433
 434#define DRIVER_STATE_PRINT_GENERIC(x, fmt, args...)   \
 435	(res += scnprintf(buf + res, DRIVER_STATE_BUF_LEN - res,\
 436			  #x " = " fmt "\n", args))
 437
 438#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")
 439#define DRIVER_STATE_PRINT_INT(x)  DRIVER_STATE_PRINT(x, "%d")
 440#define DRIVER_STATE_PRINT_STR(x)  DRIVER_STATE_PRINT(x, "%s")
 441#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx")
 442#define DRIVER_STATE_PRINT_HEX(x)  DRIVER_STATE_PRINT(x, "0x%x")
 443
 444	wl12xx_for_each_wlvif_sta(wl, wlvif) {
 445		if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
 446			continue;
 447
 448		DRIVER_STATE_PRINT_GENERIC(channel, "%d (%s)", wlvif->channel,
 449					   wlvif->p2p ? "P2P-CL" : "STA");
 450	}
 451
 452	wl12xx_for_each_wlvif_ap(wl, wlvif)
 453		DRIVER_STATE_PRINT_GENERIC(channel, "%d (%s)", wlvif->channel,
 454					   wlvif->p2p ? "P2P-GO" : "AP");
 455
 456	DRIVER_STATE_PRINT_INT(tx_blocks_available);
 457	DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
 458	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]);
 459	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]);
 460	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]);
 461	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]);
 462	DRIVER_STATE_PRINT_INT(tx_frames_cnt);
 463	DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
 464	DRIVER_STATE_PRINT_INT(tx_queue_count[0]);
 465	DRIVER_STATE_PRINT_INT(tx_queue_count[1]);
 466	DRIVER_STATE_PRINT_INT(tx_queue_count[2]);
 467	DRIVER_STATE_PRINT_INT(tx_queue_count[3]);
 468	DRIVER_STATE_PRINT_INT(tx_packets_count);
 469	DRIVER_STATE_PRINT_INT(tx_results_count);
 470	DRIVER_STATE_PRINT_LHEX(flags);
 471	DRIVER_STATE_PRINT_INT(tx_blocks_freed);
 472	DRIVER_STATE_PRINT_INT(rx_counter);
 473	DRIVER_STATE_PRINT_INT(state);
 474	DRIVER_STATE_PRINT_INT(band);
 475	DRIVER_STATE_PRINT_INT(power_level);
 476	DRIVER_STATE_PRINT_INT(sg_enabled);
 477	DRIVER_STATE_PRINT_INT(enable_11a);
 478	DRIVER_STATE_PRINT_INT(noise);
 479	DRIVER_STATE_PRINT_LHEX(ap_fw_ps_map);
 480	DRIVER_STATE_PRINT_LHEX(ap_ps_map);
 481	DRIVER_STATE_PRINT_HEX(quirks);
 482	DRIVER_STATE_PRINT_HEX(irq);
 483	/* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */
 484	DRIVER_STATE_PRINT_HEX(hw_pg_ver);
 485	DRIVER_STATE_PRINT_HEX(irq_flags);
 486	DRIVER_STATE_PRINT_HEX(chip.id);
 487	DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
 488	DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str);
 489	DRIVER_STATE_PRINT_INT(recovery_count);
 490
 491#undef DRIVER_STATE_PRINT_INT
 492#undef DRIVER_STATE_PRINT_LONG
 493#undef DRIVER_STATE_PRINT_HEX
 494#undef DRIVER_STATE_PRINT_LHEX
 495#undef DRIVER_STATE_PRINT_STR
 496#undef DRIVER_STATE_PRINT
 497#undef DRIVER_STATE_BUF_LEN
 498
 499	mutex_unlock(&wl->mutex);
 500
 501	ret = simple_read_from_buffer(user_buf, count, ppos, buf, res);
 502	kfree(buf);
 503	return ret;
 504}
 505
 506static const struct file_operations driver_state_ops = {
 507	.read = driver_state_read,
 508	.open = simple_open,
 509	.llseek = default_llseek,
 510};
 511
 512static ssize_t vifs_state_read(struct file *file, char __user *user_buf,
 513				 size_t count, loff_t *ppos)
 514{
 515	struct wl1271 *wl = file->private_data;
 516	struct wl12xx_vif *wlvif;
 517	int ret, res = 0;
 518	const int buf_size = 4096;
 519	char *buf;
 520	char tmp_buf[64];
 521
 522	buf = kzalloc(buf_size, GFP_KERNEL);
 523	if (!buf)
 524		return -ENOMEM;
 525
 526	mutex_lock(&wl->mutex);
 527
 528#define VIF_STATE_PRINT(x, fmt)				\
 529	(res += scnprintf(buf + res, buf_size - res,	\
 530			  #x " = " fmt "\n", wlvif->x))
 531
 532#define VIF_STATE_PRINT_LONG(x)  VIF_STATE_PRINT(x, "%ld")
 533#define VIF_STATE_PRINT_INT(x)   VIF_STATE_PRINT(x, "%d")
 534#define VIF_STATE_PRINT_STR(x)   VIF_STATE_PRINT(x, "%s")
 535#define VIF_STATE_PRINT_LHEX(x)  VIF_STATE_PRINT(x, "0x%lx")
 536#define VIF_STATE_PRINT_LLHEX(x) VIF_STATE_PRINT(x, "0x%llx")
 537#define VIF_STATE_PRINT_HEX(x)   VIF_STATE_PRINT(x, "0x%x")
 538
 539#define VIF_STATE_PRINT_NSTR(x, len)				\
 540	do {							\
 541		memset(tmp_buf, 0, sizeof(tmp_buf));		\
 542		memcpy(tmp_buf, wlvif->x,			\
 543		       min_t(u8, len, sizeof(tmp_buf) - 1));	\
 544		res += scnprintf(buf + res, buf_size - res,	\
 545				 #x " = %s\n", tmp_buf);	\
 546	} while (0)
 547
 548	wl12xx_for_each_wlvif(wl, wlvif) {
 549		VIF_STATE_PRINT_INT(role_id);
 550		VIF_STATE_PRINT_INT(bss_type);
 551		VIF_STATE_PRINT_LHEX(flags);
 552		VIF_STATE_PRINT_INT(p2p);
 553		VIF_STATE_PRINT_INT(dev_role_id);
 554		VIF_STATE_PRINT_INT(dev_hlid);
 555
 556		if (wlvif->bss_type == BSS_TYPE_STA_BSS ||
 557		    wlvif->bss_type == BSS_TYPE_IBSS) {
 558			VIF_STATE_PRINT_INT(sta.hlid);
 559			VIF_STATE_PRINT_INT(sta.basic_rate_idx);
 560			VIF_STATE_PRINT_INT(sta.ap_rate_idx);
 561			VIF_STATE_PRINT_INT(sta.p2p_rate_idx);
 562			VIF_STATE_PRINT_INT(sta.qos);
 563		} else {
 564			VIF_STATE_PRINT_INT(ap.global_hlid);
 565			VIF_STATE_PRINT_INT(ap.bcast_hlid);
 566			VIF_STATE_PRINT_LHEX(ap.sta_hlid_map[0]);
 567			VIF_STATE_PRINT_INT(ap.mgmt_rate_idx);
 568			VIF_STATE_PRINT_INT(ap.bcast_rate_idx);
 569			VIF_STATE_PRINT_INT(ap.ucast_rate_idx[0]);
 570			VIF_STATE_PRINT_INT(ap.ucast_rate_idx[1]);
 571			VIF_STATE_PRINT_INT(ap.ucast_rate_idx[2]);
 572			VIF_STATE_PRINT_INT(ap.ucast_rate_idx[3]);
 573		}
 574		VIF_STATE_PRINT_INT(last_tx_hlid);
 575		VIF_STATE_PRINT_INT(tx_queue_count[0]);
 576		VIF_STATE_PRINT_INT(tx_queue_count[1]);
 577		VIF_STATE_PRINT_INT(tx_queue_count[2]);
 578		VIF_STATE_PRINT_INT(tx_queue_count[3]);
 579		VIF_STATE_PRINT_LHEX(links_map[0]);
 580		VIF_STATE_PRINT_NSTR(ssid, wlvif->ssid_len);
 581		VIF_STATE_PRINT_INT(band);
 582		VIF_STATE_PRINT_INT(channel);
 583		VIF_STATE_PRINT_HEX(bitrate_masks[0]);
 584		VIF_STATE_PRINT_HEX(bitrate_masks[1]);
 585		VIF_STATE_PRINT_HEX(basic_rate_set);
 586		VIF_STATE_PRINT_HEX(basic_rate);
 587		VIF_STATE_PRINT_HEX(rate_set);
 588		VIF_STATE_PRINT_INT(beacon_int);
 589		VIF_STATE_PRINT_INT(default_key);
 590		VIF_STATE_PRINT_INT(aid);
 591		VIF_STATE_PRINT_INT(psm_entry_retry);
 592		VIF_STATE_PRINT_INT(power_level);
 593		VIF_STATE_PRINT_INT(rssi_thold);
 594		VIF_STATE_PRINT_INT(last_rssi_event);
 595		VIF_STATE_PRINT_INT(ba_support);
 596		VIF_STATE_PRINT_INT(ba_allowed);
 597		VIF_STATE_PRINT_LLHEX(total_freed_pkts);
 598	}
 599
 600#undef VIF_STATE_PRINT_INT
 601#undef VIF_STATE_PRINT_LONG
 602#undef VIF_STATE_PRINT_HEX
 603#undef VIF_STATE_PRINT_LHEX
 604#undef VIF_STATE_PRINT_LLHEX
 605#undef VIF_STATE_PRINT_STR
 606#undef VIF_STATE_PRINT_NSTR
 607#undef VIF_STATE_PRINT
 608
 609	mutex_unlock(&wl->mutex);
 610
 611	ret = simple_read_from_buffer(user_buf, count, ppos, buf, res);
 612	kfree(buf);
 613	return ret;
 614}
 615
 616static const struct file_operations vifs_state_ops = {
 617	.read = vifs_state_read,
 618	.open = simple_open,
 619	.llseek = default_llseek,
 620};
 621
 622static ssize_t dtim_interval_read(struct file *file, char __user *user_buf,
 623				  size_t count, loff_t *ppos)
 624{
 625	struct wl1271 *wl = file->private_data;
 626	u8 value;
 627
 628	if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
 629	    wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
 630		value = wl->conf.conn.listen_interval;
 631	else
 632		value = 0;
 633
 634	return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
 635}
 636
 637static ssize_t dtim_interval_write(struct file *file,
 638				   const char __user *user_buf,
 639				   size_t count, loff_t *ppos)
 640{
 641	struct wl1271 *wl = file->private_data;
 642	unsigned long value;
 643	int ret;
 644
 645	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 646	if (ret < 0) {
 647		wl1271_warning("illegal value for dtim_interval");
 648		return -EINVAL;
 649	}
 650
 651	if (value < 1 || value > 10) {
 652		wl1271_warning("dtim value is not in valid range");
 653		return -ERANGE;
 654	}
 655
 656	mutex_lock(&wl->mutex);
 657
 658	wl->conf.conn.listen_interval = value;
 659	/* for some reason there are different event types for 1 and >1 */
 660	if (value == 1)
 661		wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
 662	else
 663		wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
 664
 665	/*
 666	 * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only
 667	 * take effect on the next time we enter psm.
 668	 */
 669	mutex_unlock(&wl->mutex);
 670	return count;
 671}
 672
 673static const struct file_operations dtim_interval_ops = {
 674	.read = dtim_interval_read,
 675	.write = dtim_interval_write,
 676	.open = simple_open,
 677	.llseek = default_llseek,
 678};
 679
 680
 681
 682static ssize_t suspend_dtim_interval_read(struct file *file,
 683					  char __user *user_buf,
 684					  size_t count, loff_t *ppos)
 685{
 686	struct wl1271 *wl = file->private_data;
 687	u8 value;
 688
 689	if (wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
 690	    wl->conf.conn.suspend_wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
 691		value = wl->conf.conn.suspend_listen_interval;
 692	else
 693		value = 0;
 694
 695	return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
 696}
 697
 698static ssize_t suspend_dtim_interval_write(struct file *file,
 699					   const char __user *user_buf,
 700					   size_t count, loff_t *ppos)
 701{
 702	struct wl1271 *wl = file->private_data;
 703	unsigned long value;
 704	int ret;
 705
 706	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 707	if (ret < 0) {
 708		wl1271_warning("illegal value for suspend_dtim_interval");
 709		return -EINVAL;
 710	}
 711
 712	if (value < 1 || value > 10) {
 713		wl1271_warning("suspend_dtim value is not in valid range");
 714		return -ERANGE;
 715	}
 716
 717	mutex_lock(&wl->mutex);
 718
 719	wl->conf.conn.suspend_listen_interval = value;
 720	/* for some reason there are different event types for 1 and >1 */
 721	if (value == 1)
 722		wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
 723	else
 724		wl->conf.conn.suspend_wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
 725
 726	mutex_unlock(&wl->mutex);
 727	return count;
 728}
 729
 730
 731static const struct file_operations suspend_dtim_interval_ops = {
 732	.read = suspend_dtim_interval_read,
 733	.write = suspend_dtim_interval_write,
 734	.open = simple_open,
 735	.llseek = default_llseek,
 736};
 737
 738static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
 739				    size_t count, loff_t *ppos)
 740{
 741	struct wl1271 *wl = file->private_data;
 742	u8 value;
 743
 744	if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_BEACON ||
 745	    wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_BEACONS)
 746		value = wl->conf.conn.listen_interval;
 747	else
 748		value = 0;
 749
 750	return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
 751}
 752
 753static ssize_t beacon_interval_write(struct file *file,
 754				     const char __user *user_buf,
 755				     size_t count, loff_t *ppos)
 756{
 757	struct wl1271 *wl = file->private_data;
 758	unsigned long value;
 759	int ret;
 760
 761	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 762	if (ret < 0) {
 763		wl1271_warning("illegal value for beacon_interval");
 764		return -EINVAL;
 765	}
 766
 767	if (value < 1 || value > 255) {
 768		wl1271_warning("beacon interval value is not in valid range");
 769		return -ERANGE;
 770	}
 771
 772	mutex_lock(&wl->mutex);
 773
 774	wl->conf.conn.listen_interval = value;
 775	/* for some reason there are different event types for 1 and >1 */
 776	if (value == 1)
 777		wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_BEACON;
 778	else
 779		wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_BEACONS;
 780
 781	/*
 782	 * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only
 783	 * take effect on the next time we enter psm.
 784	 */
 785	mutex_unlock(&wl->mutex);
 786	return count;
 787}
 788
 789static const struct file_operations beacon_interval_ops = {
 790	.read = beacon_interval_read,
 791	.write = beacon_interval_write,
 792	.open = simple_open,
 793	.llseek = default_llseek,
 794};
 795
 796static ssize_t rx_streaming_interval_write(struct file *file,
 797			   const char __user *user_buf,
 798			   size_t count, loff_t *ppos)
 799{
 800	struct wl1271 *wl = file->private_data;
 801	struct wl12xx_vif *wlvif;
 802	unsigned long value;
 803	int ret;
 804
 805	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 806	if (ret < 0) {
 807		wl1271_warning("illegal value in rx_streaming_interval!");
 808		return -EINVAL;
 809	}
 810
 811	/* valid values: 0, 10-100 */
 812	if (value && (value < 10 || value > 100)) {
 813		wl1271_warning("value is not in range!");
 814		return -ERANGE;
 815	}
 816
 817	mutex_lock(&wl->mutex);
 818
 819	wl->conf.rx_streaming.interval = value;
 820
 821	ret = pm_runtime_resume_and_get(wl->dev);
 822	if (ret < 0)
 823		goto out;
 824
 825	wl12xx_for_each_wlvif_sta(wl, wlvif) {
 826		wl1271_recalc_rx_streaming(wl, wlvif);
 827	}
 828
 829	pm_runtime_put_autosuspend(wl->dev);
 830out:
 831	mutex_unlock(&wl->mutex);
 832	return count;
 833}
 834
 835static ssize_t rx_streaming_interval_read(struct file *file,
 836			    char __user *userbuf,
 837			    size_t count, loff_t *ppos)
 838{
 839	struct wl1271 *wl = file->private_data;
 840	return wl1271_format_buffer(userbuf, count, ppos,
 841				    "%d\n", wl->conf.rx_streaming.interval);
 842}
 843
 844static const struct file_operations rx_streaming_interval_ops = {
 845	.read = rx_streaming_interval_read,
 846	.write = rx_streaming_interval_write,
 847	.open = simple_open,
 848	.llseek = default_llseek,
 849};
 850
 851static ssize_t rx_streaming_always_write(struct file *file,
 852			   const char __user *user_buf,
 853			   size_t count, loff_t *ppos)
 854{
 855	struct wl1271 *wl = file->private_data;
 856	struct wl12xx_vif *wlvif;
 857	unsigned long value;
 858	int ret;
 859
 860	ret = kstrtoul_from_user(user_buf, count, 10, &value);
 861	if (ret < 0) {
 862		wl1271_warning("illegal value in rx_streaming_write!");
 863		return -EINVAL;
 864	}
 865
 866	/* valid values: 0, 10-100 */
 867	if (!(value == 0 || value == 1)) {
 868		wl1271_warning("value is not in valid!");
 869		return -EINVAL;
 870	}
 871
 872	mutex_lock(&wl->mutex);
 873
 874	wl->conf.rx_streaming.always = value;
 875
 876	ret = pm_runtime_resume_and_get(wl->dev);
 877	if (ret < 0)
 878		goto out;
 879
 880	wl12xx_for_each_wlvif_sta(wl, wlvif) {
 881		wl1271_recalc_rx_streaming(wl, wlvif);
 882	}
 883
 884	pm_runtime_put_autosuspend(wl->dev);
 885out:
 886	mutex_unlock(&wl->mutex);
 887	return count;
 888}
 889
 890static ssize_t rx_streaming_always_read(struct file *file,
 891			    char __user *userbuf,
 892			    size_t count, loff_t *ppos)
 893{
 894	struct wl1271 *wl = file->private_data;
 895	return wl1271_format_buffer(userbuf, count, ppos,
 896				    "%d\n", wl->conf.rx_streaming.always);
 897}
 898
 899static const struct file_operations rx_streaming_always_ops = {
 900	.read = rx_streaming_always_read,
 901	.write = rx_streaming_always_write,
 902	.open = simple_open,
 903	.llseek = default_llseek,
 904};
 905
 906static ssize_t beacon_filtering_write(struct file *file,
 907				      const char __user *user_buf,
 908				      size_t count, loff_t *ppos)
 909{
 910	struct wl1271 *wl = file->private_data;
 911	struct wl12xx_vif *wlvif;
 912	unsigned long value;
 913	int ret;
 914
 915	ret = kstrtoul_from_user(user_buf, count, 0, &value);
 916	if (ret < 0) {
 917		wl1271_warning("illegal value for beacon_filtering!");
 918		return -EINVAL;
 919	}
 920
 921	mutex_lock(&wl->mutex);
 922
 923	ret = pm_runtime_resume_and_get(wl->dev);
 924	if (ret < 0)
 925		goto out;
 926
 927	wl12xx_for_each_wlvif(wl, wlvif) {
 928		ret = wl1271_acx_beacon_filter_opt(wl, wlvif, !!value);
 929	}
 930
 931	pm_runtime_put_autosuspend(wl->dev);
 932out:
 933	mutex_unlock(&wl->mutex);
 934	return count;
 935}
 936
 937static const struct file_operations beacon_filtering_ops = {
 938	.write = beacon_filtering_write,
 939	.open = simple_open,
 940	.llseek = default_llseek,
 941};
 942
 943static ssize_t fw_stats_raw_read(struct file *file,
 944				 char __user *userbuf,
 945				 size_t count, loff_t *ppos)
 946{
 947	struct wl1271 *wl = file->private_data;
 948
 949	wl1271_debugfs_update_stats(wl);
 950
 951	return simple_read_from_buffer(userbuf, count, ppos,
 952				       wl->stats.fw_stats,
 953				       wl->stats.fw_stats_len);
 954}
 955
 956static const struct file_operations fw_stats_raw_ops = {
 957	.read = fw_stats_raw_read,
 958	.open = simple_open,
 959	.llseek = default_llseek,
 960};
 961
 962static ssize_t sleep_auth_read(struct file *file, char __user *user_buf,
 963			       size_t count, loff_t *ppos)
 964{
 965	struct wl1271 *wl = file->private_data;
 966
 967	return wl1271_format_buffer(user_buf, count,
 968				    ppos, "%d\n",
 969				    wl->sleep_auth);
 970}
 971
 972static ssize_t sleep_auth_write(struct file *file,
 973				const char __user *user_buf,
 974				size_t count, loff_t *ppos)
 975{
 976	struct wl1271 *wl = file->private_data;
 977	unsigned long value;
 978	int ret;
 979
 980	ret = kstrtoul_from_user(user_buf, count, 0, &value);
 981	if (ret < 0) {
 982		wl1271_warning("illegal value in sleep_auth");
 983		return -EINVAL;
 984	}
 985
 986	if (value > WL1271_PSM_MAX) {
 987		wl1271_warning("sleep_auth must be between 0 and %d",
 988			       WL1271_PSM_MAX);
 989		return -ERANGE;
 990	}
 991
 992	mutex_lock(&wl->mutex);
 993
 994	wl->conf.conn.sta_sleep_auth = value;
 995
 996	if (unlikely(wl->state != WLCORE_STATE_ON)) {
 997		/* this will show up on "read" in case we are off */
 998		wl->sleep_auth = value;
 999		goto out;
1000	}
1001
1002	ret = pm_runtime_resume_and_get(wl->dev);
1003	if (ret < 0)
1004		goto out;
1005
1006	ret = wl1271_acx_sleep_auth(wl, value);
1007	if (ret < 0)
1008		goto out_sleep;
1009
1010out_sleep:
1011	pm_runtime_put_autosuspend(wl->dev);
1012out:
1013	mutex_unlock(&wl->mutex);
1014	return count;
1015}
1016
1017static const struct file_operations sleep_auth_ops = {
1018	.read = sleep_auth_read,
1019	.write = sleep_auth_write,
1020	.open = simple_open,
1021	.llseek = default_llseek,
1022};
1023
1024static ssize_t dev_mem_read(struct file *file,
1025	     char __user *user_buf, size_t count,
1026	     loff_t *ppos)
1027{
1028	struct wl1271 *wl = file->private_data;
1029	struct wlcore_partition_set part, old_part;
1030	size_t bytes = count;
1031	int ret;
1032	char *buf;
1033
1034	/* only requests of dword-aligned size and offset are supported */
1035	if (bytes % 4)
1036		return -EINVAL;
1037
1038	if (*ppos % 4)
1039		return -EINVAL;
1040
1041	/* function should return in reasonable time */
1042	bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
1043
1044	if (bytes == 0)
1045		return -EINVAL;
1046
1047	memset(&part, 0, sizeof(part));
1048	part.mem.start = *ppos;
1049	part.mem.size = bytes;
1050
1051	buf = kmalloc(bytes, GFP_KERNEL);
1052	if (!buf)
1053		return -ENOMEM;
1054
1055	mutex_lock(&wl->mutex);
1056
1057	if (unlikely(wl->state == WLCORE_STATE_OFF)) {
1058		ret = -EFAULT;
1059		goto skip_read;
1060	}
1061
1062	/*
1063	 * Don't fail if elp_wakeup returns an error, so the device's memory
1064	 * could be read even if the FW crashed
1065	 */
1066	pm_runtime_get_sync(wl->dev);
1067
1068	/* store current partition and switch partition */
1069	memcpy(&old_part, &wl->curr_part, sizeof(old_part));
1070	ret = wlcore_set_partition(wl, &part);
1071	if (ret < 0)
1072		goto part_err;
1073
1074	ret = wlcore_raw_read(wl, 0, buf, bytes, false);
1075	if (ret < 0)
1076		goto read_err;
1077
1078read_err:
1079	/* recover partition */
1080	ret = wlcore_set_partition(wl, &old_part);
1081	if (ret < 0)
1082		goto part_err;
1083
1084part_err:
1085	pm_runtime_put_autosuspend(wl->dev);
1086
1087skip_read:
1088	mutex_unlock(&wl->mutex);
1089
1090	if (ret == 0) {
1091		ret = copy_to_user(user_buf, buf, bytes);
1092		if (ret < bytes) {
1093			bytes -= ret;
1094			*ppos += bytes;
1095			ret = 0;
1096		} else {
1097			ret = -EFAULT;
1098		}
1099	}
1100
1101	kfree(buf);
1102
1103	return ((ret == 0) ? bytes : ret);
1104}
1105
1106static ssize_t dev_mem_write(struct file *file, const char __user *user_buf,
1107		size_t count, loff_t *ppos)
1108{
1109	struct wl1271 *wl = file->private_data;
1110	struct wlcore_partition_set part, old_part;
1111	size_t bytes = count;
1112	int ret;
1113	char *buf;
1114
1115	/* only requests of dword-aligned size and offset are supported */
1116	if (bytes % 4)
1117		return -EINVAL;
1118
1119	if (*ppos % 4)
1120		return -EINVAL;
1121
1122	/* function should return in reasonable time */
1123	bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE);
1124
1125	if (bytes == 0)
1126		return -EINVAL;
1127
1128	memset(&part, 0, sizeof(part));
1129	part.mem.start = *ppos;
1130	part.mem.size = bytes;
1131
1132	buf = memdup_user(user_buf, bytes);
1133	if (IS_ERR(buf))
1134		return PTR_ERR(buf);
1135
1136	mutex_lock(&wl->mutex);
1137
1138	if (unlikely(wl->state == WLCORE_STATE_OFF)) {
1139		ret = -EFAULT;
1140		goto skip_write;
1141	}
1142
1143	/*
1144	 * Don't fail if elp_wakeup returns an error, so the device's memory
1145	 * could be read even if the FW crashed
1146	 */
1147	pm_runtime_get_sync(wl->dev);
1148
1149	/* store current partition and switch partition */
1150	memcpy(&old_part, &wl->curr_part, sizeof(old_part));
1151	ret = wlcore_set_partition(wl, &part);
1152	if (ret < 0)
1153		goto part_err;
1154
1155	ret = wlcore_raw_write(wl, 0, buf, bytes, false);
1156	if (ret < 0)
1157		goto write_err;
1158
1159write_err:
1160	/* recover partition */
1161	ret = wlcore_set_partition(wl, &old_part);
1162	if (ret < 0)
1163		goto part_err;
1164
1165part_err:
1166	pm_runtime_put_autosuspend(wl->dev);
1167
1168skip_write:
1169	mutex_unlock(&wl->mutex);
1170
1171	if (ret == 0)
1172		*ppos += bytes;
1173
1174	kfree(buf);
1175
1176	return ((ret == 0) ? bytes : ret);
1177}
1178
1179static loff_t dev_mem_seek(struct file *file, loff_t offset, int orig)
1180{
1181	/* only requests of dword-aligned size and offset are supported */
1182	if (offset % 4)
1183		return -EINVAL;
1184
1185	return no_seek_end_llseek(file, offset, orig);
1186}
1187
1188static const struct file_operations dev_mem_ops = {
1189	.open = simple_open,
1190	.read = dev_mem_read,
1191	.write = dev_mem_write,
1192	.llseek = dev_mem_seek,
1193};
1194
1195static ssize_t fw_logger_read(struct file *file, char __user *user_buf,
1196			      size_t count, loff_t *ppos)
1197{
1198	struct wl1271 *wl = file->private_data;
1199
1200	return wl1271_format_buffer(user_buf, count,
1201					ppos, "%d\n",
1202					wl->conf.fwlog.output);
1203}
1204
1205static ssize_t fw_logger_write(struct file *file,
1206			       const char __user *user_buf,
1207			       size_t count, loff_t *ppos)
1208{
1209	struct wl1271 *wl = file->private_data;
1210	unsigned long value;
1211	int ret;
1212
1213	ret = kstrtoul_from_user(user_buf, count, 0, &value);
1214	if (ret < 0) {
1215		wl1271_warning("illegal value in fw_logger");
1216		return -EINVAL;
1217	}
1218
1219	if ((value > 2) || (value == 0)) {
1220		wl1271_warning("fw_logger value must be 1-UART 2-SDIO");
1221		return -ERANGE;
1222	}
1223
1224	if (wl->conf.fwlog.output == 0) {
1225		wl1271_warning("invalid operation - fw logger disabled by default, please change mode via wlconf");
1226		return -EINVAL;
1227	}
1228
1229	mutex_lock(&wl->mutex);
1230	ret = pm_runtime_resume_and_get(wl->dev);
1231	if (ret < 0) {
1232		count = ret;
1233		goto out;
1234	}
1235
1236	wl->conf.fwlog.output = value;
1237
1238	ret = wl12xx_cmd_config_fwlog(wl);
1239
1240	pm_runtime_put_autosuspend(wl->dev);
1241
1242out:
1243	mutex_unlock(&wl->mutex);
1244	return count;
1245}
1246
1247static const struct file_operations fw_logger_ops = {
1248	.open = simple_open,
1249	.read = fw_logger_read,
1250	.write = fw_logger_write,
1251	.llseek = default_llseek,
1252};
1253
1254static void wl1271_debugfs_add_files(struct wl1271 *wl,
1255				     struct dentry *rootdir)
1256{
1257	struct dentry *streaming;
1258
1259	DEBUGFS_ADD(tx_queue_len, rootdir);
1260	DEBUGFS_ADD(retry_count, rootdir);
1261	DEBUGFS_ADD(excessive_retries, rootdir);
1262
1263	DEBUGFS_ADD(gpio_power, rootdir);
1264	DEBUGFS_ADD(start_recovery, rootdir);
1265	DEBUGFS_ADD(driver_state, rootdir);
1266	DEBUGFS_ADD(vifs_state, rootdir);
1267	DEBUGFS_ADD(dtim_interval, rootdir);
1268	DEBUGFS_ADD(suspend_dtim_interval, rootdir);
1269	DEBUGFS_ADD(beacon_interval, rootdir);
1270	DEBUGFS_ADD(beacon_filtering, rootdir);
1271	DEBUGFS_ADD(dynamic_ps_timeout, rootdir);
1272	DEBUGFS_ADD(forced_ps, rootdir);
1273	DEBUGFS_ADD(split_scan_timeout, rootdir);
1274	DEBUGFS_ADD(irq_pkt_threshold, rootdir);
1275	DEBUGFS_ADD(irq_blk_threshold, rootdir);
1276	DEBUGFS_ADD(irq_timeout, rootdir);
1277	DEBUGFS_ADD(fw_stats_raw, rootdir);
1278	DEBUGFS_ADD(sleep_auth, rootdir);
1279	DEBUGFS_ADD(fw_logger, rootdir);
1280
1281	streaming = debugfs_create_dir("rx_streaming", rootdir);
1282
1283	DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming);
1284	DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming);
1285
1286	DEBUGFS_ADD_PREFIX(dev, mem, rootdir);
1287}
1288
1289void wl1271_debugfs_reset(struct wl1271 *wl)
1290{
1291	if (!wl->stats.fw_stats)
1292		return;
1293
1294	memset(wl->stats.fw_stats, 0, wl->stats.fw_stats_len);
1295	wl->stats.retry_count = 0;
1296	wl->stats.excessive_retries = 0;
1297}
1298
1299int wl1271_debugfs_init(struct wl1271 *wl)
1300{
1301	int ret;
1302	struct dentry *rootdir;
1303
1304	rootdir = debugfs_create_dir(KBUILD_MODNAME,
1305				     wl->hw->wiphy->debugfsdir);
1306
1307	wl->stats.fw_stats = kzalloc(wl->stats.fw_stats_len, GFP_KERNEL);
1308	if (!wl->stats.fw_stats) {
1309		ret = -ENOMEM;
1310		goto out_remove;
1311	}
1312
1313	wl->stats.fw_stats_update = jiffies;
1314
1315	wl1271_debugfs_add_files(wl, rootdir);
1316
1317	ret = wlcore_debugfs_init(wl, rootdir);
1318	if (ret < 0)
1319		goto out_exit;
1320
1321	goto out;
1322
1323out_exit:
1324	wl1271_debugfs_exit(wl);
1325
1326out_remove:
1327	debugfs_remove_recursive(rootdir);
1328
1329out:
1330	return ret;
1331}
1332
1333void wl1271_debugfs_exit(struct wl1271 *wl)
1334{
1335	kfree(wl->stats.fw_stats);
1336	wl->stats.fw_stats = NULL;
1337}
~/ Read-only file preview.