1337 lines · 32.1 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * This file is part of wl1271 * * Copyright (C) 2009 Nokia Corporation * * Contact: Luciano Coelho <luciano.coelho@nokia.com> */ #include "debugfs.h" #include <linux/skbuff.h>#include <linux/slab.h>#include <linux/module.h>#include <linux/pm_runtime.h> #include "wlcore.h"#include "debug.h"#include "acx.h"#include "ps.h"#include "io.h"#include "tx.h"#include "hw_ops.h" /* ms */#define WL1271_DEBUGFS_STATS_LIFETIME 1000 #define WLCORE_MAX_BLOCK_SIZE ((size_t)(4*PAGE_SIZE)) /* debugfs macros idea from mac80211 */int wl1271_format_buffer(char __user *userbuf, size_t count,			 loff_t *ppos, char *fmt, ...){	va_list args;	char buf[DEBUGFS_FORMAT_BUFFER_SIZE];	int res; 	va_start(args, fmt);	res = vscnprintf(buf, sizeof(buf), fmt, args);	va_end(args); 	return simple_read_from_buffer(userbuf, count, ppos, buf, res);}EXPORT_SYMBOL_GPL(wl1271_format_buffer); void wl1271_debugfs_update_stats(struct wl1271 *wl){	int ret; 	mutex_lock(&wl->mutex); 	if (unlikely(wl->state != WLCORE_STATE_ON))		goto out; 	ret = pm_runtime_resume_and_get(wl->dev);	if (ret < 0)		goto out; 	if (!wl->plt &&	    time_after(jiffies, wl->stats.fw_stats_update +		       msecs_to_jiffies(WL1271_DEBUGFS_STATS_LIFETIME))) {		wl1271_acx_statistics(wl, wl->stats.fw_stats);		wl->stats.fw_stats_update = jiffies;	} 	pm_runtime_put_autosuspend(wl->dev); out:	mutex_unlock(&wl->mutex);}EXPORT_SYMBOL_GPL(wl1271_debugfs_update_stats); DEBUGFS_READONLY_FILE(retry_count, "%u", wl->stats.retry_count);DEBUGFS_READONLY_FILE(excessive_retries, "%u",		      wl->stats.excessive_retries); static ssize_t tx_queue_len_read(struct file *file, char __user *userbuf,				 size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data;	u32 queue_len;	char buf[20];	int res; 	queue_len = wl1271_tx_total_queue_count(wl); 	res = scnprintf(buf, sizeof(buf), "%u\n", queue_len);	return simple_read_from_buffer(userbuf, count, ppos, buf, res);} static const struct file_operations tx_queue_len_ops = {	.read = tx_queue_len_read,	.open = simple_open,	.llseek = default_llseek,}; static void chip_op_handler(struct wl1271 *wl, unsigned long value,			    void *arg){	int ret;	int (*chip_op) (struct wl1271 *wl); 	if (!arg) {		wl1271_warning("debugfs chip_op_handler with no callback");		return;	} 	ret = pm_runtime_resume_and_get(wl->dev);	if (ret < 0)		return; 	chip_op = arg;	chip_op(wl); 	pm_runtime_put_autosuspend(wl->dev);} #define WL12XX_CONF_DEBUGFS(param, conf_sub_struct,			\			    min_val, max_val, write_handler_locked,	\			    write_handler_arg)				\	static ssize_t param##_read(struct file *file,			\				      char __user *user_buf,		\				      size_t count, loff_t *ppos)	\	{								\	struct wl1271 *wl = file->private_data;				\	return wl1271_format_buffer(user_buf, count,			\				    ppos, "%d\n",			\				    wl->conf.conf_sub_struct.param);	\	}								\									\	static ssize_t param##_write(struct file *file,			\				     const char __user *user_buf,	\				     size_t count, loff_t *ppos)	\	{								\	struct wl1271 *wl = file->private_data;				\	unsigned long value;						\	int ret;							\									\	ret = kstrtoul_from_user(user_buf, count, 10, &value);		\	if (ret < 0) {							\		wl1271_warning("illegal value for " #param);		\		return -EINVAL;						\	}								\									\	if (value < min_val || value > max_val) {			\		wl1271_warning(#param " is not in valid range");	\		return -ERANGE;						\	}								\									\	mutex_lock(&wl->mutex);						\	wl->conf.conf_sub_struct.param = value;				\									\	write_handler_locked(wl, value, write_handler_arg);		\									\	mutex_unlock(&wl->mutex);					\	return count;							\	}								\									\	static const struct file_operations param##_ops = {		\		.read = param##_read,					\		.write = param##_write,					\		.open = simple_open,					\		.llseek = default_llseek,				\	}; WL12XX_CONF_DEBUGFS(irq_pkt_threshold, rx, 0, 65535,		    chip_op_handler, wl1271_acx_init_rx_interrupt)WL12XX_CONF_DEBUGFS(irq_blk_threshold, rx, 0, 65535,		    chip_op_handler, wl1271_acx_init_rx_interrupt)WL12XX_CONF_DEBUGFS(irq_timeout, rx, 0, 100,		    chip_op_handler, wl1271_acx_init_rx_interrupt) static ssize_t gpio_power_read(struct file *file, char __user *user_buf,			  size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data;	bool state = test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); 	int res;	char buf[10]; 	res = scnprintf(buf, sizeof(buf), "%d\n", state); 	return simple_read_from_buffer(user_buf, count, ppos, buf, res);} static ssize_t gpio_power_write(struct file *file,			   const char __user *user_buf,			   size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data;	unsigned long value;	int ret; 	ret = kstrtoul_from_user(user_buf, count, 10, &value);	if (ret < 0) {		wl1271_warning("illegal value in gpio_power");		return -EINVAL;	} 	mutex_lock(&wl->mutex); 	if (value)		wl1271_power_on(wl);	else		wl1271_power_off(wl); 	mutex_unlock(&wl->mutex);	return count;} static const struct file_operations gpio_power_ops = {	.read = gpio_power_read,	.write = gpio_power_write,	.open = simple_open,	.llseek = default_llseek,}; static ssize_t start_recovery_write(struct file *file,				    const char __user *user_buf,				    size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data; 	mutex_lock(&wl->mutex);	wl12xx_queue_recovery_work(wl);	mutex_unlock(&wl->mutex); 	return count;} static const struct file_operations start_recovery_ops = {	.write = start_recovery_write,	.open = simple_open,	.llseek = default_llseek,}; static ssize_t dynamic_ps_timeout_read(struct file *file, char __user *user_buf,			  size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data; 	return wl1271_format_buffer(user_buf, count,				    ppos, "%d\n",				    wl->conf.conn.dynamic_ps_timeout);} static ssize_t dynamic_ps_timeout_write(struct file *file,				    const char __user *user_buf,				    size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data;	struct wl12xx_vif *wlvif;	unsigned long value;	int ret; 	ret = kstrtoul_from_user(user_buf, count, 10, &value);	if (ret < 0) {		wl1271_warning("illegal value in dynamic_ps");		return -EINVAL;	} 	if (value < 1 || value > 65535) {		wl1271_warning("dynamic_ps_timeout is not in valid range");		return -ERANGE;	} 	mutex_lock(&wl->mutex); 	wl->conf.conn.dynamic_ps_timeout = value; 	if (unlikely(wl->state != WLCORE_STATE_ON))		goto out; 	ret = pm_runtime_resume_and_get(wl->dev);	if (ret < 0)		goto out; 	/* In case we're already in PSM, trigger it again to set new timeout	 * immediately without waiting for re-association	 */ 	wl12xx_for_each_wlvif_sta(wl, wlvif) {		if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))			wl1271_ps_set_mode(wl, wlvif, STATION_AUTO_PS_MODE);	} 	pm_runtime_put_autosuspend(wl->dev); out:	mutex_unlock(&wl->mutex);	return count;} static const struct file_operations dynamic_ps_timeout_ops = {	.read = dynamic_ps_timeout_read,	.write = dynamic_ps_timeout_write,	.open = simple_open,	.llseek = default_llseek,}; static ssize_t forced_ps_read(struct file *file, char __user *user_buf,			  size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data; 	return wl1271_format_buffer(user_buf, count,				    ppos, "%d\n",				    wl->conf.conn.forced_ps);} static ssize_t forced_ps_write(struct file *file,				    const char __user *user_buf,				    size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data;	struct wl12xx_vif *wlvif;	unsigned long value;	int ret, ps_mode; 	ret = kstrtoul_from_user(user_buf, count, 10, &value);	if (ret < 0) {		wl1271_warning("illegal value in forced_ps");		return -EINVAL;	} 	if (value != 1 && value != 0) {		wl1271_warning("forced_ps should be either 0 or 1");		return -ERANGE;	} 	mutex_lock(&wl->mutex); 	if (wl->conf.conn.forced_ps == value)		goto out; 	wl->conf.conn.forced_ps = value; 	if (unlikely(wl->state != WLCORE_STATE_ON))		goto out; 	ret = pm_runtime_resume_and_get(wl->dev);	if (ret < 0)		goto out; 	/* In case we're already in PSM, trigger it again to switch mode	 * immediately without waiting for re-association	 */ 	ps_mode = value ? STATION_POWER_SAVE_MODE : STATION_AUTO_PS_MODE; 	wl12xx_for_each_wlvif_sta(wl, wlvif) {		if (test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags))			wl1271_ps_set_mode(wl, wlvif, ps_mode);	} 	pm_runtime_put_autosuspend(wl->dev); out:	mutex_unlock(&wl->mutex);	return count;} static const struct file_operations forced_ps_ops = {	.read = forced_ps_read,	.write = forced_ps_write,	.open = simple_open,	.llseek = default_llseek,}; static ssize_t split_scan_timeout_read(struct file *file, char __user *user_buf,			  size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data; 	return wl1271_format_buffer(user_buf, count,				    ppos, "%d\n",				    wl->conf.scan.split_scan_timeout / 1000);} static ssize_t split_scan_timeout_write(struct file *file,				    const char __user *user_buf,				    size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data;	unsigned long value;	int ret; 	ret = kstrtoul_from_user(user_buf, count, 10, &value);	if (ret < 0) {		wl1271_warning("illegal value in split_scan_timeout");		return -EINVAL;	} 	if (value == 0)		wl1271_info("split scan will be disabled"); 	mutex_lock(&wl->mutex); 	wl->conf.scan.split_scan_timeout = value * 1000; 	mutex_unlock(&wl->mutex);	return count;} static const struct file_operations split_scan_timeout_ops = {	.read = split_scan_timeout_read,	.write = split_scan_timeout_write,	.open = simple_open,	.llseek = default_llseek,}; static ssize_t driver_state_read(struct file *file, char __user *user_buf,				 size_t count, loff_t *ppos){	struct wl1271 *wl = file->private_data;	int res = 0;	ssize_t ret;	char *buf;	struct wl12xx_vif *wlvif; #define DRIVER_STATE_BUF_LEN 1024 	buf = kmalloc(DRIVER_STATE_BUF_LEN, GFP_KERNEL);	if (!buf)		return -ENOMEM; 	mutex_lock(&wl->mutex); #define DRIVER_STATE_PRINT(x, fmt)   \	(res += scnprintf(buf + res, DRIVER_STATE_BUF_LEN - res,\			  #x " = " fmt "\n", wl->x)) #define DRIVER_STATE_PRINT_GENERIC(x, fmt, args...)   \	(res += scnprintf(buf + res, DRIVER_STATE_BUF_LEN - res,\			  #x " = " fmt "\n", args)) #define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")#define DRIVER_STATE_PRINT_INT(x)  DRIVER_STATE_PRINT(x, "%d")#define DRIVER_STATE_PRINT_STR(x)  DRIVER_STATE_PRINT(x, "%s")#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx")#define DRIVER_STATE_PRINT_HEX(x)  DRIVER_STATE_PRINT(x, "0x%x") 	wl12xx_for_each_wlvif_sta(wl, wlvif) {		if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))			continue; 		DRIVER_STATE_PRINT_GENERIC(channel, "%d (%s)", wlvif->channel,					   wlvif->p2p ? "P2P-CL" : "STA");	} 	wl12xx_for_each_wlvif_ap(wl, wlvif)		DRIVER_STATE_PRINT_GENERIC(channel, "%d (%s)", wlvif->channel,					   wlvif->p2p ? "P2P-GO" : "AP"); 	DRIVER_STATE_PRINT_INT(tx_blocks_available);	DRIVER_STATE_PRINT_INT(tx_allocated_blocks);	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[0]);	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[1]);	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[2]);	DRIVER_STATE_PRINT_INT(tx_allocated_pkts[3]);	DRIVER_STATE_PRINT_INT(tx_frames_cnt);	DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);	DRIVER_STATE_PRINT_INT(tx_queue_count[0]);	DRIVER_STATE_PRINT_INT(tx_queue_count[1]);	DRIVER_STATE_PRINT_INT(tx_queue_count[2]);	DRIVER_STATE_PRINT_INT(tx_queue_count[3]);	DRIVER_STATE_PRINT_INT(tx_packets_count);	DRIVER_STATE_PRINT_INT(tx_results_count);	DRIVER_STATE_PRINT_LHEX(flags);	DRIVER_STATE_PRINT_INT(tx_blocks_freed);	DRIVER_STATE_PRINT_INT(rx_counter);	DRIVER_STATE_PRINT_INT(state);	DRIVER_STATE_PRINT_INT(band);	DRIVER_STATE_PRINT_INT(power_level);	DRIVER_STATE_PRINT_INT(sg_enabled);	DRIVER_STATE_PRINT_INT(enable_11a);	DRIVER_STATE_PRINT_INT(noise);	DRIVER_STATE_PRINT_LHEX(ap_fw_ps_map);	DRIVER_STATE_PRINT_LHEX(ap_ps_map);	DRIVER_STATE_PRINT_HEX(quirks);	DRIVER_STATE_PRINT_HEX(irq);	/* TODO: ref_clock and tcxo_clock were moved to wl12xx priv */	DRIVER_STATE_PRINT_HEX(hw_pg_ver);	DRIVER_STATE_PRINT_HEX(irq_flags);	DRIVER_STATE_PRINT_HEX(chip.id);	DRIVER_STATE_PRINT_STR(chip.fw_ver_str);	DRIVER_STATE_PRINT_STR(chip.phy_fw_ver_str);	DRIVER_STATE_PRINT_INT(recovery_count); #undef DRIVER_STATE_PRINT_INT#undef DRIVER_STATE_PRINT_LONG#undef DRIVER_STATE_PRINT_HEX#undef DRIVER_STATE_PRINT_LHEX#undef DRIVER_STATE_PRINT_STR#undef DRIVER_STATE_PRINT#undef DRIVER_STATE_BUF_LEN 	mutex_unlock(&wl->mutex); 

Lines 1–500 of 1337.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t