Commit f118a3e5 authored by Kalle Valo's avatar Kalle Valo

ath10k: add debugfs file to control firmware dbglog

Firmware dbglogs can be now enabled through fw_dbglog file. To enable all
possible log messages run:

echo 0xffffffff > /sys/kernel/debug/ieee80211/phy0/ath10k/fw_dbglog

And to put back firmare defaults use 0x0:

echo 0x0 > /sys/kernel/debug/ieee80211/phy0/ath10k/fw_dbglog
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
parent 869526b9
......@@ -272,6 +272,8 @@ struct ath10k_debug {
struct delayed_work htt_stats_dwork;
struct ath10k_dfs_stats dfs_stats;
struct ath_dfs_pool_stats dfs_pool_stats;
u32 fw_dbglog_mask;
};
enum ath10k_state {
......
......@@ -614,6 +614,61 @@ static const struct file_operations fops_htt_stats_mask = {
.llseek = default_llseek,
};
static ssize_t ath10k_read_fw_dbglog(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
unsigned int len;
char buf[32];
len = scnprintf(buf, sizeof(buf), "0x%08x\n",
ar->debug.fw_dbglog_mask);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
static ssize_t ath10k_write_fw_dbglog(struct file *file,
const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
unsigned long mask;
int ret;
ret = kstrtoul_from_user(user_buf, count, 0, &mask);
if (ret)
return ret;
mutex_lock(&ar->conf_mutex);
ar->debug.fw_dbglog_mask = mask;
if (ar->state == ATH10K_STATE_ON) {
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
if (ret) {
ath10k_warn("dbglog cfg failed from debugfs: %d\n",
ret);
goto exit;
}
}
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return ret;
}
static const struct file_operations fops_fw_dbglog = {
.read = ath10k_read_fw_dbglog,
.write = ath10k_write_fw_dbglog,
.open = simple_open,
.owner = THIS_MODULE,
.llseek = default_llseek,
};
int ath10k_debug_start(struct ath10k *ar)
{
int ret;
......@@ -625,6 +680,14 @@ int ath10k_debug_start(struct ath10k *ar)
/* continue normally anyway, this isn't serious */
ath10k_warn("failed to start htt stats workqueue: %d\n", ret);
if (ar->debug.fw_dbglog_mask) {
ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
if (ret)
/* not serious */
ath10k_warn("failed to enable dbglog during start: %d",
ret);
}
return 0;
}
......@@ -747,6 +810,9 @@ int ath10k_debug_create(struct ath10k *ar)
debugfs_create_file("htt_stats_mask", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_htt_stats_mask);
debugfs_create_file("fw_dbglog", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_fw_dbglog);
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
debugfs_create_file("dfs_simulate_radar", S_IWUSR,
ar->debug.debugfs_phy, ar,
......
......@@ -3502,3 +3502,40 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
type, delay_ms);
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
}
int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
{
struct wmi_dbglog_cfg_cmd *cmd;
struct sk_buff *skb;
u32 cfg;
skb = ath10k_wmi_alloc_skb(sizeof(*cmd));
if (!skb)
return -ENOMEM;
cmd = (struct wmi_dbglog_cfg_cmd *)skb->data;
if (module_enable) {
cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE,
ATH10K_DBGLOG_CFG_LOG_LVL);
} else {
/* set back defaults, all modules with WARN level */
cfg = SM(ATH10K_DBGLOG_LEVEL_WARN,
ATH10K_DBGLOG_CFG_LOG_LVL);
module_enable = ~0;
}
cmd->module_enable = __cpu_to_le32(module_enable);
cmd->module_valid = __cpu_to_le32(~0);
cmd->config_enable = __cpu_to_le32(cfg);
cmd->config_valid = __cpu_to_le32(ATH10K_DBGLOG_CFG_LOG_LVL_MASK);
ath10k_dbg(ATH10K_DBG_WMI,
"wmi dbglog cfg modules %08x %08x config %08x %08x\n",
__le32_to_cpu(cmd->module_enable),
__le32_to_cpu(cmd->module_valid),
__le32_to_cpu(cmd->config_enable),
__le32_to_cpu(cmd->config_valid));
return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
}
......@@ -4090,6 +4090,54 @@ struct wmi_force_fw_hang_cmd {
__le32 delay_ms;
} __packed;
enum ath10k_dbglog_level {
ATH10K_DBGLOG_LEVEL_VERBOSE = 0,
ATH10K_DBGLOG_LEVEL_INFO = 1,
ATH10K_DBGLOG_LEVEL_WARN = 2,
ATH10K_DBGLOG_LEVEL_ERR = 3,
};
/* VAP ids to enable dbglog */
#define ATH10K_DBGLOG_CFG_VAP_LOG_LSB 0
#define ATH10K_DBGLOG_CFG_VAP_LOG_MASK 0x0000ffff
/* to enable dbglog in the firmware */
#define ATH10K_DBGLOG_CFG_REPORTING_ENABLE_LSB 16
#define ATH10K_DBGLOG_CFG_REPORTING_ENABLE_MASK 0x00010000
/* timestamp resolution */
#define ATH10K_DBGLOG_CFG_RESOLUTION_LSB 17
#define ATH10K_DBGLOG_CFG_RESOLUTION_MASK 0x000E0000
/* number of queued messages before sending them to the host */
#define ATH10K_DBGLOG_CFG_REPORT_SIZE_LSB 20
#define ATH10K_DBGLOG_CFG_REPORT_SIZE_MASK 0x0ff00000
/*
* Log levels to enable. This defines the minimum level to enable, this is
* not a bitmask. See enum ath10k_dbglog_level for the values.
*/
#define ATH10K_DBGLOG_CFG_LOG_LVL_LSB 28
#define ATH10K_DBGLOG_CFG_LOG_LVL_MASK 0x70000000
/*
* Note: this is a cleaned up version of a struct firmware uses. For
* example, config_valid was hidden inside an array.
*/
struct wmi_dbglog_cfg_cmd {
/* bitmask to hold mod id config*/
__le32 module_enable;
/* see ATH10K_DBGLOG_CFG_ */
__le32 config_enable;
/* mask of module id bits to be changed */
__le32 module_valid;
/* mask of config bits to be changed, see ATH10K_DBGLOG_CFG_ */
__le32 config_valid;
} __packed;
#define ATH10K_RTS_MAX 2347
#define ATH10K_FRAGMT_THRESHOLD_MIN 540
#define ATH10K_FRAGMT_THRESHOLD_MAX 2346
......@@ -4167,5 +4215,6 @@ int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
int ath10k_wmi_force_fw_hang(struct ath10k *ar,
enum wmi_force_fw_hang_type type, u32 delay_ms);
int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
#endif /* _WMI_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment