blob: 4bcbcfd07424f8c4a4430e022bdd808bbb7567d6 [file] [log] [blame]
From f7b0d9f73cb5e6b66e8d0c275df0932e0e637aa5 Mon Sep 17 00:00:00 2001
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Date: Thu, 11 Jan 2024 08:55:13 +0800
Subject: [PATCH 2027/2027] mtk: wifi: mt76: mt7992: add support to enable
index FW log for ConsysPlanet
Add support to enable and record index FW log, which is the input for ConsysPlanet, via mt76-test command.
Usage:
1. Foreground logging
1) Start: mt76-test phy0 idxlog
2) Stop: Ctrl + C
2. Background logging
1) Start: mt76-test phy0 idxlog &
2) Stop: killall mt76-test
3. Logging with FW Parser
1) Start Ethernet recording of FW Parser.
2) Start: mt76-test phy0 idxlog <PC's IP Address>
3) Stop: Ctrl + C
4) Stop FW Parser.
Log Files
- FW Log: FW text message
- Location: /tmp/log/clog_(timestamp)/WIFI_FW_(timestamp).clog
- Driver Log: log message printed at driver layer
- Location: /tmp/log/clog_(timestamp)/WIFI_KERNEL_(timestamp).clog
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
---
mt7996/debugfs.c | 90 +++++++++++++++++--
mt7996/mac.c | 10 ++-
mt7996/mcu.c | 34 +++++++-
mt7996/mcu.h | 4 +-
mt7996/mt7996.h | 3 +
tools/fwlog.c | 218 ++++++++++++++++++++++++++++++++++------------
tools/main.c | 2 +
tools/mt76-test.h | 3 +
8 files changed, 295 insertions(+), 69 deletions(-)
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
index 6ccf0827..c236ec98 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
@@ -425,8 +425,8 @@ create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,
{
struct dentry *f;
- f = debugfs_create_file("fwlog_data", mode, parent, buf,
- &relay_file_operations);
+ f = debugfs_create_file(filename[0] == 'f' ? "fwlog_data" : "idxlog_data",
+ mode, parent, buf, &relay_file_operations);
if (IS_ERR(f))
return NULL;
@@ -517,6 +517,53 @@ mt7996_fw_debug_bin_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7996_fw_debug_bin_get,
mt7996_fw_debug_bin_set, "%lld\n");
+static int
+mt7996_idxlog_enable_get(void *data, u64 *val)
+{
+ struct mt7996_dev *dev = data;
+
+ *val = dev->idxlog_enable;
+
+ return 0;
+}
+
+static int
+mt7996_idxlog_enable_set(void *data, u64 val)
+{
+ static struct rchan_callbacks relay_cb = {
+ .create_buf_file = create_buf_file_cb,
+ .remove_buf_file = remove_buf_file_cb,
+ };
+ struct mt7996_dev *dev = data;
+
+ if (dev->idxlog_enable == !!val)
+ return 0;
+
+ if (!dev->relay_idxlog) {
+ dev->relay_idxlog = relay_open("idxlog_data", dev->debugfs_dir,
+ 1500, 512, &relay_cb, NULL);
+ if (!dev->relay_idxlog)
+ return -ENOMEM;
+ }
+
+ dev->idxlog_enable = !!val;
+
+ if (val) {
+ int ret = mt7996_mcu_fw_time_sync(&dev->mt76);
+ if (ret)
+ return ret;
+
+ /* Reset relay channel only when it is not being written to. */
+ relay_reset(dev->relay_idxlog);
+ }
+
+ return mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM,
+ val ? MCU_FW_LOG_RELAY_IDX : 0);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_idxlog_enable, mt7996_idxlog_enable_get,
+ mt7996_idxlog_enable_set, "%llu\n");
+
static int
mt7996_fw_util_wa_show(struct seq_file *file, void *data)
{
@@ -1037,6 +1084,7 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
+ debugfs_create_file("idxlog_enable", 0600, dir, dev, &fops_idxlog_enable);
/* TODO: wm fw cpu utilization */
debugfs_create_file("fw_util_wa", 0400, dir, dev,
&mt7996_fw_util_wa_fops);
@@ -1103,6 +1151,32 @@ mt7996_debugfs_write_fwlog(struct mt7996_dev *dev, const void *hdr, int hdrlen,
spin_unlock_irqrestore(&lock, flags);
}
+static void
+mt7996_debugfs_write_idxlog(struct mt7996_dev *dev, const void *data, int len)
+{
+ static DEFINE_SPINLOCK(lock);
+ unsigned long flags;
+ void *dest;
+
+ if (!dev->relay_idxlog)
+ return;
+
+ spin_lock_irqsave(&lock, flags);
+
+ dest = relay_reserve(dev->relay_idxlog, len + 4);
+ if (!dest)
+ dev_err(dev->mt76.dev, "Failed to reserve slot in %s\n",
+ dev->relay_idxlog->base_filename);
+ else {
+ *(u32 *)dest = len;
+ dest += 4;
+ memcpy(dest, data, len);
+ relay_flush(dev->relay_idxlog);
+ }
+
+ spin_unlock_irqrestore(&lock, flags);
+}
+
void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len)
{
struct {
@@ -1127,11 +1201,15 @@ void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int
bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len)
{
- if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC)
- return false;
+ bool is_fwlog = get_unaligned_le32(data) == FW_BIN_LOG_MAGIC;
- if (dev->relay_fwlog)
- mt7996_debugfs_write_fwlog(dev, NULL, 0, data, len);
+ if (is_fwlog) {
+ if (dev->relay_fwlog)
+ mt7996_debugfs_write_fwlog(dev, NULL, 0, data, len);
+ } else if (dev->relay_idxlog)
+ mt7996_debugfs_write_idxlog(dev, data, len);
+ else
+ return false;
return true;
}
diff --git a/mt7996/mac.c b/mt7996/mac.c
index 7f72ec08..aecc1809 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -2271,11 +2271,9 @@ void mt7996_mac_work(struct work_struct *work)
mutex_lock(&mdev->mutex);
mt76_update_survey(mphy);
- if (++mphy->mac_work_count == 5) {
+ if (++mphy->mac_work_count % 5 == 0) {
int i;
- mphy->mac_work_count = 0;
-
mt7996_mac_update_stats(phy);
/* Update DEV-wise information only in
@@ -2294,6 +2292,12 @@ void mt7996_mac_work(struct work_struct *work)
if (mt7996_mcu_wa_cmd(phy->dev, MCU_WA_PARAM_CMD(QUERY), MCU_WA_PARAM_BSS_ACQ_PKT_CNT,
BSS_ACQ_PKT_CNT_BSS_BITMAP_ALL | BSS_ACQ_PKT_CNT_READ_CLR, 0))
dev_err(mdev->dev, "Failed to query per-AC-queue packet counts.\n");
+
+ if (mphy->mac_work_count == 100) {
+ if (phy->dev->idxlog_enable && mt7996_mcu_fw_time_sync(mdev))
+ dev_err(mdev->dev, "Failed to synchronize time with FW.\n");
+ mphy->mac_work_count = 0;
+ }
} else if (mt7996_band_valid(phy->dev, i) &&
test_bit(MT76_STATE_RUNNING, &mdev->phys[i]->state))
break;
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
index 9e04ea2b..0cb4cfa5 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -397,6 +397,7 @@ static void
mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb)
{
#define UNI_EVENT_FW_LOG_FORMAT 0
+#define UNI_EVENT_FW_LOG_MEMORY 1
struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
const char *data = (char *)&rxd[1] + 4, *type;
struct tlv *tlv = (struct tlv *)data;
@@ -408,7 +409,8 @@ mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb)
goto out;
}
- if (le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_FORMAT)
+ if (le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_FORMAT &&
+ le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_MEMORY)
return;
data += sizeof(*tlv) + 4;
@@ -3444,6 +3446,36 @@ int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level)
sizeof(data), false);
}
+int mt7996_mcu_fw_time_sync(struct mt76_dev *dev)
+{
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+ __le32 sec;
+ __le32 usec;
+ } data = {
+ .tag = cpu_to_le16(UNI_WSYS_CONFIG_FW_TIME_SYNC),
+ .len = cpu_to_le16(sizeof(data) - 4),
+ };
+ struct timespec64 ts;
+ struct tm tm;
+
+ ktime_get_real_ts64(&ts);
+ data.sec = cpu_to_le32((u32)ts.tv_sec);
+ data.usec = cpu_to_le32((u32)(ts.tv_nsec / 1000));
+
+ /* Dump synchronized time for ConsysPlanet to parse. */
+ time64_to_tm(ts.tv_sec, 0, &tm);
+ dev_info(dev->dev, "%ld-%02d-%02d %02d:%02d:%02d.%ld UTC\n",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec / 1000);
+
+ return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(WSYS_CONFIG), &data,
+ sizeof(data), true);
+}
+
static int mt7996_mcu_set_mwds(struct mt7996_dev *dev, bool enabled)
{
struct {
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
index 7721a01b..826cf204 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -357,7 +357,8 @@ enum {
MCU_FW_LOG_WM,
MCU_FW_LOG_WA,
MCU_FW_LOG_TO_HOST,
- MCU_FW_LOG_RELAY = 16
+ MCU_FW_LOG_RELAY = 16,
+ MCU_FW_LOG_RELAY_IDX = 40
};
enum {
@@ -949,6 +950,7 @@ enum {
UNI_WSYS_CONFIG_FW_LOG_CTRL,
UNI_WSYS_CONFIG_FW_DBG_CTRL,
UNI_CMD_CERT_CFG = 6,
+ UNI_WSYS_CONFIG_FW_TIME_SYNC, /* UNI_CMD_FW_TIME_SYNC in FW */
};
enum {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
index 0c3d2164..60d2ed16 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -639,9 +639,11 @@ struct mt7996_dev {
u8 fw_debug_bin;
u16 fw_debug_seq;
bool fw_debug_muru_disable;
+ bool idxlog_enable;
struct dentry *debugfs_dir;
struct rchan *relay_fwlog;
+ struct rchan *relay_idxlog;
void *cal;
u32 cur_prek_offset;
@@ -893,6 +895,7 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
int mt7996_mcu_red_config(struct mt7996_dev *dev, bool enable);
int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl);
int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
+int mt7996_mcu_fw_time_sync(struct mt76_dev *dev);
int mt7996_mcu_trigger_assert(struct mt7996_dev *dev);
void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
diff --git a/tools/fwlog.c b/tools/fwlog.c
index 3c6a61d7..0e2de2dc 100644
--- a/tools/fwlog.c
+++ b/tools/fwlog.c
@@ -29,10 +29,9 @@ static const char *debugfs_path(const char *phyname, const char *file)
static int mt76_set_fwlog_en(const char *phyname, bool en, char *val)
{
FILE *f = fopen(debugfs_path(phyname, "fw_debug_bin"), "w");
-
if (!f) {
- fprintf(stderr, "Could not open fw_debug_bin file\n");
- return 1;
+ perror("fopen");
+ return -1;
}
if (en && val)
@@ -47,6 +46,21 @@ static int mt76_set_fwlog_en(const char *phyname, bool en, char *val)
return 0;
}
+static int mt76_set_idxlog_enable(const char *phyname, bool enable)
+{
+ FILE *f = fopen(debugfs_path(phyname, "idxlog_enable"), "w");
+ if (!f) {
+ perror("fopen");
+ return -1;
+ }
+
+ fprintf(f, "%hhu", enable);
+
+ fclose(f);
+
+ return 0;
+}
+
int read_retry(int fd, void *buf, int len)
{
int out_len = 0;
@@ -80,105 +94,193 @@ static void handle_signal(int sig)
done = true;
}
-int mt76_fwlog(const char *phyname, int argc, char **argv)
+static int mt76_log_socket(struct sockaddr_in *remote, char *ip)
{
-#define BUF_SIZE 1504
struct sockaddr_in local = {
.sin_family = AF_INET,
.sin_addr.s_addr = INADDR_ANY,
};
- struct sockaddr_in remote = {
- .sin_family = AF_INET,
- .sin_port = htons(55688),
- };
- char *buf = calloc(BUF_SIZE, sizeof(char));
- int ret = 0;
- /* int yes = 1; */
- int s, fd;
-
- if (argc < 1) {
- fprintf(stderr, "need destination address\n");
- return 1;
- }
+ int s, ret;
- if (!inet_aton(argv[0], &remote.sin_addr)) {
- fprintf(stderr, "invalid destination address\n");
- return 1;
+ remote->sin_family = AF_INET;
+ remote->sin_port = htons(55688);
+ if (!inet_aton(ip, &remote->sin_addr)) {
+ fprintf(stderr, "Invalid destination IP address: %s\n", ip);
+ return -EINVAL;
}
s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (s < 0) {
perror("socket");
- return 1;
+ return s;
}
- /* setsockopt(s, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)); */
- if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0) {
+ ret = bind(s, (struct sockaddr *)&local, sizeof(local));
+ if (ret) {
perror("bind");
- return 1;
+ close(s);
+ return ret;
}
- if (mt76_set_fwlog_en(phyname, true, argv[1]))
- return 1;
+ return s;
+}
+
+static int mt76_log_relay(int in_fd, int out_fd, struct sockaddr_in *remote)
+{
+ char *buf = malloc(FWLOG_BUF_SIZE);
+ int ret = 0;
- fd = open(debugfs_path(phyname, "fwlog_data"), O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "Could not open fwlog_data file: %s\n", strerror(errno));
- ret = 1;
- goto out;
+ if (!buf) {
+ perror("malloc");
+ return -ENOMEM;
}
signal(SIGTERM, handle_signal);
signal(SIGINT, handle_signal);
signal(SIGQUIT, handle_signal);
- while (1) {
+ while (!done) {
struct pollfd pfd = {
- .fd = fd,
- .events = POLLIN | POLLHUP | POLLERR,
+ .fd = in_fd,
+ .events = POLLIN,
};
uint32_t len;
- int r;
-
- if (done)
- break;
+ int rc;
poll(&pfd, 1, -1);
- r = read_retry(fd, &len, sizeof(len));
- if (r < 0)
+ rc = read_retry(in_fd, &len, sizeof(len));
+ if (rc < 0) {
+ if (!done) {
+ fprintf(stderr, "Failed to read relay file.\n");
+ ret = -1;
+ }
break;
-
- if (!r)
+ }
+ if (!rc)
continue;
- if (len > BUF_SIZE) {
- fprintf(stderr, "Length error: %d > %d\n", len, BUF_SIZE);
- ret = 1;
+ if (len > FWLOG_BUF_SIZE) {
+ fprintf(stderr, "Log size was too large: %u bytes\n", len);
+ ret = -ENOMEM;
break;
}
- if (done)
+ rc = read_retry(in_fd, buf, len);
+ if (rc < 0) {
+ if (!done) {
+ fprintf(stderr, "Failed to read relay file.\n");
+ ret = -1;
+ }
break;
-
- r = read_retry(fd, buf, len);
- if (done)
+ }
+ if (rc != len) {
+ fprintf(stderr, "Expected log size: %u bytes\n", len);
+ fprintf(stderr, "Read log size: %u bytes\n", rc);
+ ret = -EIO;
break;
+ }
- if (r != len) {
- fprintf(stderr, "Short read: %d < %d\n", r, len);
- ret = 1;
+ if (remote)
+ rc = sendto(out_fd, buf, len, 0, (struct sockaddr *)remote, sizeof(*remote));
+ else
+ rc = write(out_fd, buf, len);
+ if (rc < 0) {
+ perror("sendto/write");
+ ret = -1;
break;
}
+ }
+
+ free(buf);
+
+ return ret;
+}
+
+int mt76_fwlog(const char *phyname, int argc, char **argv)
+{
+ struct sockaddr_in remote;
+ int in_fd, out_fd, ret;
+
+ if (argc < 1) {
+ fprintf(stderr, "need destination address\n");
+ return -EINVAL;
+ }
+
+ out_fd = mt76_log_socket(&remote, argv[0]);
+ if (out_fd < 0)
+ return out_fd;
+
+ ret = mt76_set_fwlog_en(phyname, true, argv[1]);
+ if (ret)
+ goto close;
- /* send buf */
- sendto(s, buf, len, 0, (struct sockaddr *)&remote, sizeof(remote));
+ in_fd = open(debugfs_path(phyname, "fwlog_data"), O_RDONLY);
+ if (in_fd < 0) {
+ perror("open");
+ goto disable;
}
- close(fd);
+ if (mt76_log_relay(in_fd, out_fd, &remote))
+ fprintf(stderr, "Failed to relay FW log.\n");
-out:
- mt76_set_fwlog_en(phyname, false, NULL);
+ close(in_fd);
+disable:
+ ret = mt76_set_fwlog_en(phyname, false, NULL);
+close:
+ close(out_fd);
+
+ return ret;
+}
+
+int mt76_idxlog(const char *phyname, int argc, char **argv)
+{
+#define IDXLOG_FILE_PATH "/tmp/log/WIFI_FW.clog"
+ struct sockaddr_in remote;
+ int in_fd, out_fd, ret;
+
+ if (argc) {
+ out_fd = mt76_log_socket(&remote, argv[0]);
+ if (out_fd < 0)
+ return out_fd;
+ } else {
+ out_fd = open(IDXLOG_FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR);
+ if (out_fd < 0) {
+ perror("open");
+ return -1;
+ }
+ }
+
+ ret = mt76_set_idxlog_enable(phyname, true);
+ if (ret)
+ goto close;
+
+ in_fd = open(debugfs_path(phyname, "idxlog_data"), O_RDONLY);
+ if (in_fd < 0) {
+ perror("open");
+ goto disable;
+ }
+
+ if (mt76_log_relay(in_fd, out_fd, argc ? &remote : NULL))
+ fprintf(stderr, "Failed to relay index log.\n");
+
+ close(in_fd);
+disable:
+ ret = mt76_set_idxlog_enable(phyname, false);
+close:
+ close(out_fd);
+
+ if (argc)
+ system("timestamp=$(date +\"%y%m%d_%H%M%S\");"
+ "clog_dir=/tmp/log/clog_${timestamp};"
+ "mkdir ${clog_dir};"
+ "dmesg > ${clog_dir}/WIFI_KERNEL_${timestamp}.clog");
+ else
+ system("timestamp=$(date +\"%y%m%d_%H%M%S\");"
+ "clog_dir=/tmp/log/clog_${timestamp};"
+ "mkdir ${clog_dir};"
+ "mv /tmp/log/WIFI_FW.clog ${clog_dir}/WIFI_FW_${timestamp}.clog;"
+ "dmesg > ${clog_dir}/WIFI_KERNEL_${timestamp}.clog");
return ret;
}
diff --git a/tools/main.c b/tools/main.c
index 699a9eea..e9e25567 100644
--- a/tools/main.c
+++ b/tools/main.c
@@ -198,6 +198,8 @@ int main(int argc, char **argv)
ret = mt76_eeprom(phy, argc, argv);
else if (!strcmp(cmd, "fwlog"))
ret = mt76_fwlog(phyname, argc, argv);
+ else if (!strcmp(cmd, "idxlog"))
+ ret = mt76_idxlog(phyname, argc, argv);
else
usage();
diff --git a/tools/mt76-test.h b/tools/mt76-test.h
index d2fafa86..b9d508c5 100644
--- a/tools/mt76-test.h
+++ b/tools/mt76-test.h
@@ -22,6 +22,8 @@
#define EEPROM_FILE_PATH_FMT "/tmp/mt76-test-%s"
#define EEPROM_PART_SIZE 20480
+#define FWLOG_BUF_SIZE 1504
+
struct nl_msg;
struct nlattr;
@@ -61,5 +63,6 @@ extern unsigned char *eeprom_data;
void usage(void);
int mt76_eeprom(int phy, int argc, char **argv);
int mt76_fwlog(const char *phyname, int argc, char **argv);
+int mt76_idxlog(const char *phyname, int argc, char **argv);
#endif
--
2.18.0