aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath10k/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath10k/debug.c')
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c115
1 files changed, 85 insertions, 30 deletions
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index 82a4c67f3672..fb0ade3adb07 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -21,6 +21,7 @@
#include <linux/utsname.h>
#include <linux/crc32.h>
#include <linux/firmware.h>
+#include <linux/devcoredump.h>
#include "core.h"
#include "debug.h"
@@ -40,6 +41,7 @@
*/
enum ath10k_fw_crash_dump_type {
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
+ ATH10K_FW_CRASH_DUMP_CE_DATA = 1,
ATH10K_FW_CRASH_DUMP_MAX,
};
@@ -235,7 +237,7 @@ static ssize_t ath10k_read_wmi_services(struct file *file,
{
struct ath10k *ar = file->private_data;
char *buf;
- unsigned int len = 0, buf_len = 4096;
+ size_t len = 0, buf_len = 4096;
const char *name;
ssize_t ret_cnt;
bool enabled;
@@ -399,6 +401,7 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
* prevent firmware from DoS-ing the host.
*/
ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
+ ath10k_fw_extd_stats_peers_free(&ar->debug.fw_stats.peers_extd);
ath10k_warn(ar, "dropping fw peer stats\n");
goto free;
}
@@ -409,10 +412,12 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
goto free;
}
+ if (!list_empty(&stats.peers))
+ list_splice_tail_init(&stats.peers_extd,
+ &ar->debug.fw_stats.peers_extd);
+
list_splice_tail_init(&stats.peers, &ar->debug.fw_stats.peers);
list_splice_tail_init(&stats.vdevs, &ar->debug.fw_stats.vdevs);
- list_splice_tail_init(&stats.peers_extd,
- &ar->debug.fw_stats.peers_extd);
}
complete(&ar->debug.fw_stats_complete);
@@ -524,7 +529,7 @@ static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
const char *buf = file->private_data;
- unsigned int len = strlen(buf);
+ size_t len = strlen(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -542,17 +547,16 @@ static ssize_t ath10k_debug_fw_reset_stats_read(struct file *file,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
- int ret, len, buf_len;
+ int ret;
+ size_t len = 0, buf_len = 500;
char *buf;
- buf_len = 500;
buf = kmalloc(buf_len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
spin_lock_bh(&ar->data_lock);
- len = 0;
len += scnprintf(buf + len, buf_len - len,
"fw_crash_counter\t\t%d\n", ar->stats.fw_crash_counter);
len += scnprintf(buf + len, buf_len - len,
@@ -691,7 +695,7 @@ static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
- unsigned int len;
+ size_t len;
char buf[50];
len = scnprintf(buf, sizeof(buf), "0x%08x\n", ar->chip_id);
@@ -721,17 +725,21 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
}
EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
-static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar,
+ bool mark_read)
{
struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+ struct ath10k_ce_crash_hdr *ce_hdr;
struct ath10k_dump_file_data *dump_data;
struct ath10k_tlv_dump_data *dump_tlv;
- int hdr_len = sizeof(*dump_data);
- unsigned int len, sofar = 0;
+ size_t hdr_len = sizeof(*dump_data);
+ size_t len, sofar = 0;
unsigned char *buf;
len = hdr_len;
len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+ len += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
+ CE_COUNT * sizeof(ce_hdr->entries[0]);
sofar += hdr_len;
@@ -790,19 +798,66 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
sizeof(crash_data->registers));
sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
- ar->debug.fw_crash_data->crashed_since_read = false;
+ dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
+ dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_CE_DATA);
+ dump_tlv->tlv_len = cpu_to_le32(sizeof(*ce_hdr) +
+ CE_COUNT * sizeof(ce_hdr->entries[0]));
+ ce_hdr = (struct ath10k_ce_crash_hdr *)(dump_tlv->tlv_data);
+ ce_hdr->ce_count = cpu_to_le32(CE_COUNT);
+ memset(ce_hdr->reserved, 0, sizeof(ce_hdr->reserved));
+ memcpy(ce_hdr->entries, crash_data->ce_crash_data,
+ CE_COUNT * sizeof(ce_hdr->entries[0]));
+ sofar += sizeof(*dump_tlv) + sizeof(*ce_hdr) +
+ CE_COUNT * sizeof(ce_hdr->entries[0]);
+
+ ar->debug.fw_crash_data->crashed_since_read = !mark_read;
spin_unlock_bh(&ar->data_lock);
return dump_data;
}
+int ath10k_debug_fw_devcoredump(struct ath10k *ar)
+{
+ struct ath10k_dump_file_data *dump;
+ void *dump_ptr;
+ u32 dump_len;
+
+ /* To keep the dump file available also for debugfs don't mark the
+ * file read, only debugfs should do that.
+ */
+ dump = ath10k_build_dump_file(ar, false);
+ if (!dump) {
+ ath10k_warn(ar, "no crash dump data found for devcoredump");
+ return -ENODATA;
+ }
+
+ /* Make a copy of the dump file for dev_coredumpv() as during the
+ * transition period we need to own the original file. Once
+ * fw_crash_dump debugfs file is removed no need to have a copy
+ * anymore.
+ */
+ dump_len = le32_to_cpu(dump->len);
+ dump_ptr = vzalloc(dump_len);
+
+ if (!dump_ptr)
+ return -ENOMEM;
+
+ memcpy(dump_ptr, dump, dump_len);
+
+ dev_coredumpv(ar->dev, dump_ptr, dump_len, GFP_KERNEL);
+
+ return 0;
+}
+
static int ath10k_fw_crash_dump_open(struct inode *inode, struct file *file)
{
struct ath10k *ar = inode->i_private;
struct ath10k_dump_file_data *dump;
- dump = ath10k_build_dump_file(ar);
+ ath10k_warn(ar, "fw_crash_dump debugfs file is deprecated, please use /sys/class/devcoredump instead.");
+
+ dump = ath10k_build_dump_file(ar, true);
if (!dump)
return -ENODATA;
@@ -844,7 +899,7 @@ static ssize_t ath10k_reg_addr_read(struct file *file,
{
struct ath10k *ar = file->private_data;
u8 buf[32];
- unsigned int len = 0;
+ size_t len = 0;
u32 reg_addr;
mutex_lock(&ar->conf_mutex);
@@ -892,7 +947,7 @@ static ssize_t ath10k_reg_value_read(struct file *file,
{
struct ath10k *ar = file->private_data;
u8 buf[48];
- unsigned int len;
+ size_t len;
u32 reg_addr, reg_val;
int ret;
@@ -1115,7 +1170,7 @@ static ssize_t ath10k_read_htt_stats_mask(struct file *file,
{
struct ath10k *ar = file->private_data;
char buf[32];
- unsigned int len;
+ size_t len;
len = scnprintf(buf, sizeof(buf), "%lu\n", ar->debug.htt_stats_mask);
@@ -1169,7 +1224,7 @@ static ssize_t ath10k_read_htt_max_amsdu_ampdu(struct file *file,
struct ath10k *ar = file->private_data;
char buf[64];
u8 amsdu, ampdu;
- unsigned int len;
+ size_t len;
mutex_lock(&ar->conf_mutex);
@@ -1229,7 +1284,7 @@ static ssize_t ath10k_read_fw_dbglog(struct file *file,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
- unsigned int len;
+ size_t len;
char buf[96];
len = scnprintf(buf, sizeof(buf), "0x%16llx %u\n",
@@ -1555,11 +1610,10 @@ static ssize_t ath10k_read_ani_enable(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
- int len = 0;
+ size_t len;
char buf[32];
- len = scnprintf(buf, sizeof(buf) - len, "%d\n",
- ar->ani_enabled);
+ len = scnprintf(buf, sizeof(buf), "%d\n", ar->ani_enabled);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1584,11 +1638,10 @@ static ssize_t ath10k_read_nf_cal_period(struct file *file,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
- unsigned int len;
+ size_t len;
char buf[32];
- len = scnprintf(buf, sizeof(buf), "%d\n",
- ar->debug.nf_cal_period);
+ len = scnprintf(buf, sizeof(buf), "%d\n", ar->debug.nf_cal_period);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1684,9 +1737,10 @@ void ath10k_debug_tpc_stats_process(struct ath10k *ar,
}
static void ath10k_tpc_stats_print(struct ath10k_tpc_stats *tpc_stats,
- unsigned int j, char *buf, unsigned int *len)
+ unsigned int j, char *buf, size_t *len)
{
- unsigned int i, buf_len;
+ int i;
+ size_t buf_len;
static const char table_str[][5] = { "CDD",
"STBC",
"TXBF" };
@@ -1726,7 +1780,8 @@ static void ath10k_tpc_stats_fill(struct ath10k *ar,
struct ath10k_tpc_stats *tpc_stats,
char *buf)
{
- unsigned int len, j, buf_len;
+ int j;
+ size_t len, buf_len;
len = 0;
buf_len = ATH10K_TPC_CONFIG_BUF_SIZE;
@@ -1860,7 +1915,7 @@ static ssize_t ath10k_tpc_stats_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos)
{
const char *buf = file->private_data;
- unsigned int len = strlen(buf);
+ size_t len = strlen(buf);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -2284,7 +2339,7 @@ static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
- unsigned int len = 0, buf_len = 4096;
+ size_t len = 0, buf_len = 4096;
ssize_t ret_cnt;
char *buf;
@@ -2500,7 +2555,7 @@ void ath10k_dbg_dump(struct ath10k *ar,
const void *buf, size_t len)
{
char linebuf[256];
- unsigned int linebuflen;
+ size_t linebuflen;
const void *ptr;
if (ath10k_debug_mask & mask) {