developer | 66e89bc | 2024-04-23 14:50:01 +0800 | [diff] [blame^] | 1 | From a5d6a71a81b1bd7daadd810a601615a293beea80 Mon Sep 17 00:00:00 2001 |
| 2 | From: Benjamin Lin <benjamin-jw.lin@mediatek.com> |
| 3 | Date: Thu, 11 Jan 2024 08:55:13 +0800 |
| 4 | Subject: [PATCH 082/116] mtk: wifi: mt76: mt7992: add support to enable index |
| 5 | FW log for ConsysPlanet |
| 6 | |
| 7 | Add support to enable and record index FW log, which is the input for ConsysPlanet, via mt76-test command. |
| 8 | |
| 9 | Usage: |
| 10 | 1. Foreground logging |
| 11 | 1) Start: mt76-test phy0 idxlog |
| 12 | 2) Stop: Ctrl + C |
| 13 | 2. Background logging |
| 14 | 1) Start: mt76-test phy0 idxlog & |
| 15 | 2) Stop: killall mt76-test |
| 16 | 3. Logging with FW Parser |
| 17 | 1) Start Ethernet recording of FW Parser. |
| 18 | 2) Start: mt76-test phy0 idxlog <PC's IP Address> |
| 19 | 3) Stop: Ctrl + C |
| 20 | 4) Stop FW Parser. |
| 21 | |
| 22 | Log Files |
| 23 | - FW Log: FW text message |
| 24 | - Location: /tmp/log/clog_(timestamp)/WIFI_FW_(timestamp).clog |
| 25 | - Driver Log: log message printed at driver layer |
| 26 | - Location: /tmp/log/clog_(timestamp)/WIFI_KERNEL_(timestamp).clog |
| 27 | |
| 28 | CR-Id: WCNCR00298425 |
| 29 | Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com> |
| 30 | Change-Id: I5d72c844e920cdcbaed4c65f734de8f041e6f384 |
| 31 | --- |
| 32 | mt7996/debugfs.c | 90 +++++++++++++++++-- |
| 33 | mt7996/mac.c | 10 ++- |
| 34 | mt7996/mcu.c | 34 +++++++- |
| 35 | mt7996/mcu.h | 4 +- |
| 36 | mt7996/mt7996.h | 3 + |
| 37 | tools/fwlog.c | 218 ++++++++++++++++++++++++++++++++++------------ |
| 38 | tools/main.c | 2 + |
| 39 | tools/mt76-test.h | 3 + |
| 40 | 8 files changed, 295 insertions(+), 69 deletions(-) |
| 41 | |
| 42 | diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c |
| 43 | index e26de48c6..837758611 100644 |
| 44 | --- a/mt7996/debugfs.c |
| 45 | +++ b/mt7996/debugfs.c |
| 46 | @@ -430,8 +430,8 @@ create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode, |
| 47 | { |
| 48 | struct dentry *f; |
| 49 | |
| 50 | - f = debugfs_create_file("fwlog_data", mode, parent, buf, |
| 51 | - &relay_file_operations); |
| 52 | + f = debugfs_create_file(filename[0] == 'f' ? "fwlog_data" : "idxlog_data", |
| 53 | + mode, parent, buf, &relay_file_operations); |
| 54 | if (IS_ERR(f)) |
| 55 | return NULL; |
| 56 | |
| 57 | @@ -522,6 +522,53 @@ mt7996_fw_debug_bin_get(void *data, u64 *val) |
| 58 | DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7996_fw_debug_bin_get, |
| 59 | mt7996_fw_debug_bin_set, "%lld\n"); |
| 60 | |
| 61 | +static int |
| 62 | +mt7996_idxlog_enable_get(void *data, u64 *val) |
| 63 | +{ |
| 64 | + struct mt7996_dev *dev = data; |
| 65 | + |
| 66 | + *val = dev->idxlog_enable; |
| 67 | + |
| 68 | + return 0; |
| 69 | +} |
| 70 | + |
| 71 | +static int |
| 72 | +mt7996_idxlog_enable_set(void *data, u64 val) |
| 73 | +{ |
| 74 | + static struct rchan_callbacks relay_cb = { |
| 75 | + .create_buf_file = create_buf_file_cb, |
| 76 | + .remove_buf_file = remove_buf_file_cb, |
| 77 | + }; |
| 78 | + struct mt7996_dev *dev = data; |
| 79 | + |
| 80 | + if (dev->idxlog_enable == !!val) |
| 81 | + return 0; |
| 82 | + |
| 83 | + if (!dev->relay_idxlog) { |
| 84 | + dev->relay_idxlog = relay_open("idxlog_data", dev->debugfs_dir, |
| 85 | + 1500, 512, &relay_cb, NULL); |
| 86 | + if (!dev->relay_idxlog) |
| 87 | + return -ENOMEM; |
| 88 | + } |
| 89 | + |
| 90 | + dev->idxlog_enable = !!val; |
| 91 | + |
| 92 | + if (val) { |
| 93 | + int ret = mt7996_mcu_fw_time_sync(&dev->mt76); |
| 94 | + if (ret) |
| 95 | + return ret; |
| 96 | + |
| 97 | + /* Reset relay channel only when it is not being written to. */ |
| 98 | + relay_reset(dev->relay_idxlog); |
| 99 | + } |
| 100 | + |
| 101 | + return mt7996_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, |
| 102 | + val ? MCU_FW_LOG_RELAY_IDX : 0); |
| 103 | +} |
| 104 | + |
| 105 | +DEFINE_DEBUGFS_ATTRIBUTE(fops_idxlog_enable, mt7996_idxlog_enable_get, |
| 106 | + mt7996_idxlog_enable_set, "%llu\n"); |
| 107 | + |
| 108 | static int |
| 109 | mt7996_fw_util_wa_show(struct seq_file *file, void *data) |
| 110 | { |
| 111 | @@ -1042,6 +1089,7 @@ int mt7996_init_debugfs(struct mt7996_phy *phy) |
| 112 | debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm); |
| 113 | debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa); |
| 114 | debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin); |
| 115 | + debugfs_create_file("idxlog_enable", 0600, dir, dev, &fops_idxlog_enable); |
| 116 | /* TODO: wm fw cpu utilization */ |
| 117 | debugfs_create_file("fw_util_wa", 0400, dir, dev, |
| 118 | &mt7996_fw_util_wa_fops); |
| 119 | @@ -1108,6 +1156,32 @@ mt7996_debugfs_write_fwlog(struct mt7996_dev *dev, const void *hdr, int hdrlen, |
| 120 | spin_unlock_irqrestore(&lock, flags); |
| 121 | } |
| 122 | |
| 123 | +static void |
| 124 | +mt7996_debugfs_write_idxlog(struct mt7996_dev *dev, const void *data, int len) |
| 125 | +{ |
| 126 | + static DEFINE_SPINLOCK(lock); |
| 127 | + unsigned long flags; |
| 128 | + void *dest; |
| 129 | + |
| 130 | + if (!dev->relay_idxlog) |
| 131 | + return; |
| 132 | + |
| 133 | + spin_lock_irqsave(&lock, flags); |
| 134 | + |
| 135 | + dest = relay_reserve(dev->relay_idxlog, len + 4); |
| 136 | + if (!dest) |
| 137 | + dev_err(dev->mt76.dev, "Failed to reserve slot in %s\n", |
| 138 | + dev->relay_idxlog->base_filename); |
| 139 | + else { |
| 140 | + *(u32 *)dest = len; |
| 141 | + dest += 4; |
| 142 | + memcpy(dest, data, len); |
| 143 | + relay_flush(dev->relay_idxlog); |
| 144 | + } |
| 145 | + |
| 146 | + spin_unlock_irqrestore(&lock, flags); |
| 147 | +} |
| 148 | + |
| 149 | void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len) |
| 150 | { |
| 151 | struct { |
| 152 | @@ -1132,11 +1206,15 @@ void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int |
| 153 | |
| 154 | bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len) |
| 155 | { |
| 156 | - if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC) |
| 157 | - return false; |
| 158 | + bool is_fwlog = get_unaligned_le32(data) == FW_BIN_LOG_MAGIC; |
| 159 | |
| 160 | - if (dev->relay_fwlog) |
| 161 | - mt7996_debugfs_write_fwlog(dev, NULL, 0, data, len); |
| 162 | + if (is_fwlog) { |
| 163 | + if (dev->relay_fwlog) |
| 164 | + mt7996_debugfs_write_fwlog(dev, NULL, 0, data, len); |
| 165 | + } else if (dev->relay_idxlog) |
| 166 | + mt7996_debugfs_write_idxlog(dev, data, len); |
| 167 | + else |
| 168 | + return false; |
| 169 | |
| 170 | return true; |
| 171 | } |
| 172 | diff --git a/mt7996/mac.c b/mt7996/mac.c |
| 173 | index e3758ff13..8c444423b 100644 |
| 174 | --- a/mt7996/mac.c |
| 175 | +++ b/mt7996/mac.c |
| 176 | @@ -2279,11 +2279,9 @@ void mt7996_mac_work(struct work_struct *work) |
| 177 | mutex_lock(&mdev->mutex); |
| 178 | |
| 179 | mt76_update_survey(mphy); |
| 180 | - if (++mphy->mac_work_count == 5) { |
| 181 | + if (++mphy->mac_work_count % 5 == 0) { |
| 182 | int i; |
| 183 | |
| 184 | - mphy->mac_work_count = 0; |
| 185 | - |
| 186 | mt7996_mac_update_stats(phy); |
| 187 | |
| 188 | /* Update DEV-wise information only in |
| 189 | @@ -2302,6 +2300,12 @@ void mt7996_mac_work(struct work_struct *work) |
| 190 | if (mt7996_mcu_wa_cmd(phy->dev, MCU_WA_PARAM_CMD(QUERY), MCU_WA_PARAM_BSS_ACQ_PKT_CNT, |
| 191 | BSS_ACQ_PKT_CNT_BSS_BITMAP_ALL | BSS_ACQ_PKT_CNT_READ_CLR, 0)) |
| 192 | dev_err(mdev->dev, "Failed to query per-AC-queue packet counts.\n"); |
| 193 | + |
| 194 | + if (mphy->mac_work_count == 100) { |
| 195 | + if (phy->dev->idxlog_enable && mt7996_mcu_fw_time_sync(mdev)) |
| 196 | + dev_err(mdev->dev, "Failed to synchronize time with FW.\n"); |
| 197 | + mphy->mac_work_count = 0; |
| 198 | + } |
| 199 | } else if (mt7996_band_valid(phy->dev, i) && |
| 200 | test_bit(MT76_STATE_RUNNING, &mdev->phys[i]->state)) |
| 201 | break; |
| 202 | diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
| 203 | index 6fb9f81f0..3a376c9ac 100644 |
| 204 | --- a/mt7996/mcu.c |
| 205 | +++ b/mt7996/mcu.c |
| 206 | @@ -400,6 +400,7 @@ static void |
| 207 | mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb) |
| 208 | { |
| 209 | #define UNI_EVENT_FW_LOG_FORMAT 0 |
| 210 | +#define UNI_EVENT_FW_LOG_MEMORY 1 |
| 211 | struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; |
| 212 | const char *data = (char *)&rxd[1] + 4, *type; |
| 213 | struct tlv *tlv = (struct tlv *)data; |
| 214 | @@ -411,7 +412,8 @@ mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb) |
| 215 | goto out; |
| 216 | } |
| 217 | |
| 218 | - if (le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_FORMAT) |
| 219 | + if (le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_FORMAT && |
| 220 | + le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_MEMORY) |
| 221 | return; |
| 222 | |
| 223 | data += sizeof(*tlv) + 4; |
| 224 | @@ -3184,6 +3186,36 @@ int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level) |
| 225 | sizeof(data), false); |
| 226 | } |
| 227 | |
| 228 | +int mt7996_mcu_fw_time_sync(struct mt76_dev *dev) |
| 229 | +{ |
| 230 | + struct { |
| 231 | + u8 _rsv[4]; |
| 232 | + |
| 233 | + __le16 tag; |
| 234 | + __le16 len; |
| 235 | + __le32 sec; |
| 236 | + __le32 usec; |
| 237 | + } data = { |
| 238 | + .tag = cpu_to_le16(UNI_WSYS_CONFIG_FW_TIME_SYNC), |
| 239 | + .len = cpu_to_le16(sizeof(data) - 4), |
| 240 | + }; |
| 241 | + struct timespec64 ts; |
| 242 | + struct tm tm; |
| 243 | + |
| 244 | + ktime_get_real_ts64(&ts); |
| 245 | + data.sec = cpu_to_le32((u32)ts.tv_sec); |
| 246 | + data.usec = cpu_to_le32((u32)(ts.tv_nsec / 1000)); |
| 247 | + |
| 248 | + /* Dump synchronized time for ConsysPlanet to parse. */ |
| 249 | + time64_to_tm(ts.tv_sec, 0, &tm); |
| 250 | + dev_info(dev->dev, "%ld-%02d-%02d %02d:%02d:%02d.%ld UTC\n", |
| 251 | + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, |
| 252 | + tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec / 1000); |
| 253 | + |
| 254 | + return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(WSYS_CONFIG), &data, |
| 255 | + sizeof(data), true); |
| 256 | +} |
| 257 | + |
| 258 | static int mt7996_mcu_set_mwds(struct mt7996_dev *dev, bool enabled) |
| 259 | { |
| 260 | struct { |
| 261 | diff --git a/mt7996/mcu.h b/mt7996/mcu.h |
| 262 | index d24874a4b..814072e3a 100644 |
| 263 | --- a/mt7996/mcu.h |
| 264 | +++ b/mt7996/mcu.h |
| 265 | @@ -357,7 +357,8 @@ enum { |
| 266 | MCU_FW_LOG_WM, |
| 267 | MCU_FW_LOG_WA, |
| 268 | MCU_FW_LOG_TO_HOST, |
| 269 | - MCU_FW_LOG_RELAY = 16 |
| 270 | + MCU_FW_LOG_RELAY = 16, |
| 271 | + MCU_FW_LOG_RELAY_IDX = 40 |
| 272 | }; |
| 273 | |
| 274 | enum { |
| 275 | @@ -950,6 +951,7 @@ enum { |
| 276 | UNI_WSYS_CONFIG_FW_LOG_CTRL, |
| 277 | UNI_WSYS_CONFIG_FW_DBG_CTRL, |
| 278 | UNI_CMD_CERT_CFG = 6, |
| 279 | + UNI_WSYS_CONFIG_FW_TIME_SYNC, /* UNI_CMD_FW_TIME_SYNC in FW */ |
| 280 | }; |
| 281 | |
| 282 | enum { |
| 283 | diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| 284 | index 69bcf78f5..d03d3d94c 100644 |
| 285 | --- a/mt7996/mt7996.h |
| 286 | +++ b/mt7996/mt7996.h |
| 287 | @@ -591,9 +591,11 @@ struct mt7996_dev { |
| 288 | u8 fw_debug_bin; |
| 289 | u16 fw_debug_seq; |
| 290 | bool fw_debug_muru_disable; |
| 291 | + bool idxlog_enable; |
| 292 | |
| 293 | struct dentry *debugfs_dir; |
| 294 | struct rchan *relay_fwlog; |
| 295 | + struct rchan *relay_idxlog; |
| 296 | |
| 297 | void *cal; |
| 298 | u32 cur_prek_offset; |
| 299 | @@ -845,6 +847,7 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3); |
| 300 | int mt7996_mcu_red_config(struct mt7996_dev *dev, bool enable); |
| 301 | int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl); |
| 302 | int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level); |
| 303 | +int mt7996_mcu_fw_time_sync(struct mt76_dev *dev); |
| 304 | int mt7996_mcu_trigger_assert(struct mt7996_dev *dev); |
| 305 | void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb); |
| 306 | void mt7996_mcu_exit(struct mt7996_dev *dev); |
| 307 | diff --git a/tools/fwlog.c b/tools/fwlog.c |
| 308 | index 3c6a61d71..0e2de2dc2 100644 |
| 309 | --- a/tools/fwlog.c |
| 310 | +++ b/tools/fwlog.c |
| 311 | @@ -29,10 +29,9 @@ static const char *debugfs_path(const char *phyname, const char *file) |
| 312 | static int mt76_set_fwlog_en(const char *phyname, bool en, char *val) |
| 313 | { |
| 314 | FILE *f = fopen(debugfs_path(phyname, "fw_debug_bin"), "w"); |
| 315 | - |
| 316 | if (!f) { |
| 317 | - fprintf(stderr, "Could not open fw_debug_bin file\n"); |
| 318 | - return 1; |
| 319 | + perror("fopen"); |
| 320 | + return -1; |
| 321 | } |
| 322 | |
| 323 | if (en && val) |
| 324 | @@ -47,6 +46,21 @@ static int mt76_set_fwlog_en(const char *phyname, bool en, char *val) |
| 325 | return 0; |
| 326 | } |
| 327 | |
| 328 | +static int mt76_set_idxlog_enable(const char *phyname, bool enable) |
| 329 | +{ |
| 330 | + FILE *f = fopen(debugfs_path(phyname, "idxlog_enable"), "w"); |
| 331 | + if (!f) { |
| 332 | + perror("fopen"); |
| 333 | + return -1; |
| 334 | + } |
| 335 | + |
| 336 | + fprintf(f, "%hhu", enable); |
| 337 | + |
| 338 | + fclose(f); |
| 339 | + |
| 340 | + return 0; |
| 341 | +} |
| 342 | + |
| 343 | int read_retry(int fd, void *buf, int len) |
| 344 | { |
| 345 | int out_len = 0; |
| 346 | @@ -80,105 +94,193 @@ static void handle_signal(int sig) |
| 347 | done = true; |
| 348 | } |
| 349 | |
| 350 | -int mt76_fwlog(const char *phyname, int argc, char **argv) |
| 351 | +static int mt76_log_socket(struct sockaddr_in *remote, char *ip) |
| 352 | { |
| 353 | -#define BUF_SIZE 1504 |
| 354 | struct sockaddr_in local = { |
| 355 | .sin_family = AF_INET, |
| 356 | .sin_addr.s_addr = INADDR_ANY, |
| 357 | }; |
| 358 | - struct sockaddr_in remote = { |
| 359 | - .sin_family = AF_INET, |
| 360 | - .sin_port = htons(55688), |
| 361 | - }; |
| 362 | - char *buf = calloc(BUF_SIZE, sizeof(char)); |
| 363 | - int ret = 0; |
| 364 | - /* int yes = 1; */ |
| 365 | - int s, fd; |
| 366 | - |
| 367 | - if (argc < 1) { |
| 368 | - fprintf(stderr, "need destination address\n"); |
| 369 | - return 1; |
| 370 | - } |
| 371 | + int s, ret; |
| 372 | |
| 373 | - if (!inet_aton(argv[0], &remote.sin_addr)) { |
| 374 | - fprintf(stderr, "invalid destination address\n"); |
| 375 | - return 1; |
| 376 | + remote->sin_family = AF_INET; |
| 377 | + remote->sin_port = htons(55688); |
| 378 | + if (!inet_aton(ip, &remote->sin_addr)) { |
| 379 | + fprintf(stderr, "Invalid destination IP address: %s\n", ip); |
| 380 | + return -EINVAL; |
| 381 | } |
| 382 | |
| 383 | s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
| 384 | if (s < 0) { |
| 385 | perror("socket"); |
| 386 | - return 1; |
| 387 | + return s; |
| 388 | } |
| 389 | |
| 390 | - /* setsockopt(s, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)); */ |
| 391 | - if (bind(s, (struct sockaddr *)&local, sizeof(local)) < 0) { |
| 392 | + ret = bind(s, (struct sockaddr *)&local, sizeof(local)); |
| 393 | + if (ret) { |
| 394 | perror("bind"); |
| 395 | - return 1; |
| 396 | + close(s); |
| 397 | + return ret; |
| 398 | } |
| 399 | |
| 400 | - if (mt76_set_fwlog_en(phyname, true, argv[1])) |
| 401 | - return 1; |
| 402 | + return s; |
| 403 | +} |
| 404 | + |
| 405 | +static int mt76_log_relay(int in_fd, int out_fd, struct sockaddr_in *remote) |
| 406 | +{ |
| 407 | + char *buf = malloc(FWLOG_BUF_SIZE); |
| 408 | + int ret = 0; |
| 409 | |
| 410 | - fd = open(debugfs_path(phyname, "fwlog_data"), O_RDONLY); |
| 411 | - if (fd < 0) { |
| 412 | - fprintf(stderr, "Could not open fwlog_data file: %s\n", strerror(errno)); |
| 413 | - ret = 1; |
| 414 | - goto out; |
| 415 | + if (!buf) { |
| 416 | + perror("malloc"); |
| 417 | + return -ENOMEM; |
| 418 | } |
| 419 | |
| 420 | signal(SIGTERM, handle_signal); |
| 421 | signal(SIGINT, handle_signal); |
| 422 | signal(SIGQUIT, handle_signal); |
| 423 | |
| 424 | - while (1) { |
| 425 | + while (!done) { |
| 426 | struct pollfd pfd = { |
| 427 | - .fd = fd, |
| 428 | - .events = POLLIN | POLLHUP | POLLERR, |
| 429 | + .fd = in_fd, |
| 430 | + .events = POLLIN, |
| 431 | }; |
| 432 | uint32_t len; |
| 433 | - int r; |
| 434 | - |
| 435 | - if (done) |
| 436 | - break; |
| 437 | + int rc; |
| 438 | |
| 439 | poll(&pfd, 1, -1); |
| 440 | |
| 441 | - r = read_retry(fd, &len, sizeof(len)); |
| 442 | - if (r < 0) |
| 443 | + rc = read_retry(in_fd, &len, sizeof(len)); |
| 444 | + if (rc < 0) { |
| 445 | + if (!done) { |
| 446 | + fprintf(stderr, "Failed to read relay file.\n"); |
| 447 | + ret = -1; |
| 448 | + } |
| 449 | break; |
| 450 | - |
| 451 | - if (!r) |
| 452 | + } |
| 453 | + if (!rc) |
| 454 | continue; |
| 455 | |
| 456 | - if (len > BUF_SIZE) { |
| 457 | - fprintf(stderr, "Length error: %d > %d\n", len, BUF_SIZE); |
| 458 | - ret = 1; |
| 459 | + if (len > FWLOG_BUF_SIZE) { |
| 460 | + fprintf(stderr, "Log size was too large: %u bytes\n", len); |
| 461 | + ret = -ENOMEM; |
| 462 | break; |
| 463 | } |
| 464 | |
| 465 | - if (done) |
| 466 | + rc = read_retry(in_fd, buf, len); |
| 467 | + if (rc < 0) { |
| 468 | + if (!done) { |
| 469 | + fprintf(stderr, "Failed to read relay file.\n"); |
| 470 | + ret = -1; |
| 471 | + } |
| 472 | break; |
| 473 | - |
| 474 | - r = read_retry(fd, buf, len); |
| 475 | - if (done) |
| 476 | + } |
| 477 | + if (rc != len) { |
| 478 | + fprintf(stderr, "Expected log size: %u bytes\n", len); |
| 479 | + fprintf(stderr, "Read log size: %u bytes\n", rc); |
| 480 | + ret = -EIO; |
| 481 | break; |
| 482 | + } |
| 483 | |
| 484 | - if (r != len) { |
| 485 | - fprintf(stderr, "Short read: %d < %d\n", r, len); |
| 486 | - ret = 1; |
| 487 | + if (remote) |
| 488 | + rc = sendto(out_fd, buf, len, 0, (struct sockaddr *)remote, sizeof(*remote)); |
| 489 | + else |
| 490 | + rc = write(out_fd, buf, len); |
| 491 | + if (rc < 0) { |
| 492 | + perror("sendto/write"); |
| 493 | + ret = -1; |
| 494 | break; |
| 495 | } |
| 496 | + } |
| 497 | + |
| 498 | + free(buf); |
| 499 | + |
| 500 | + return ret; |
| 501 | +} |
| 502 | + |
| 503 | +int mt76_fwlog(const char *phyname, int argc, char **argv) |
| 504 | +{ |
| 505 | + struct sockaddr_in remote; |
| 506 | + int in_fd, out_fd, ret; |
| 507 | + |
| 508 | + if (argc < 1) { |
| 509 | + fprintf(stderr, "need destination address\n"); |
| 510 | + return -EINVAL; |
| 511 | + } |
| 512 | + |
| 513 | + out_fd = mt76_log_socket(&remote, argv[0]); |
| 514 | + if (out_fd < 0) |
| 515 | + return out_fd; |
| 516 | + |
| 517 | + ret = mt76_set_fwlog_en(phyname, true, argv[1]); |
| 518 | + if (ret) |
| 519 | + goto close; |
| 520 | |
| 521 | - /* send buf */ |
| 522 | - sendto(s, buf, len, 0, (struct sockaddr *)&remote, sizeof(remote)); |
| 523 | + in_fd = open(debugfs_path(phyname, "fwlog_data"), O_RDONLY); |
| 524 | + if (in_fd < 0) { |
| 525 | + perror("open"); |
| 526 | + goto disable; |
| 527 | } |
| 528 | |
| 529 | - close(fd); |
| 530 | + if (mt76_log_relay(in_fd, out_fd, &remote)) |
| 531 | + fprintf(stderr, "Failed to relay FW log.\n"); |
| 532 | |
| 533 | -out: |
| 534 | - mt76_set_fwlog_en(phyname, false, NULL); |
| 535 | + close(in_fd); |
| 536 | +disable: |
| 537 | + ret = mt76_set_fwlog_en(phyname, false, NULL); |
| 538 | +close: |
| 539 | + close(out_fd); |
| 540 | + |
| 541 | + return ret; |
| 542 | +} |
| 543 | + |
| 544 | +int mt76_idxlog(const char *phyname, int argc, char **argv) |
| 545 | +{ |
| 546 | +#define IDXLOG_FILE_PATH "/tmp/log/WIFI_FW.clog" |
| 547 | + struct sockaddr_in remote; |
| 548 | + int in_fd, out_fd, ret; |
| 549 | + |
| 550 | + if (argc) { |
| 551 | + out_fd = mt76_log_socket(&remote, argv[0]); |
| 552 | + if (out_fd < 0) |
| 553 | + return out_fd; |
| 554 | + } else { |
| 555 | + out_fd = open(IDXLOG_FILE_PATH, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR); |
| 556 | + if (out_fd < 0) { |
| 557 | + perror("open"); |
| 558 | + return -1; |
| 559 | + } |
| 560 | + } |
| 561 | + |
| 562 | + ret = mt76_set_idxlog_enable(phyname, true); |
| 563 | + if (ret) |
| 564 | + goto close; |
| 565 | + |
| 566 | + in_fd = open(debugfs_path(phyname, "idxlog_data"), O_RDONLY); |
| 567 | + if (in_fd < 0) { |
| 568 | + perror("open"); |
| 569 | + goto disable; |
| 570 | + } |
| 571 | + |
| 572 | + if (mt76_log_relay(in_fd, out_fd, argc ? &remote : NULL)) |
| 573 | + fprintf(stderr, "Failed to relay index log.\n"); |
| 574 | + |
| 575 | + close(in_fd); |
| 576 | +disable: |
| 577 | + ret = mt76_set_idxlog_enable(phyname, false); |
| 578 | +close: |
| 579 | + close(out_fd); |
| 580 | + |
| 581 | + if (argc) |
| 582 | + system("timestamp=$(date +\"%y%m%d_%H%M%S\");" |
| 583 | + "clog_dir=/tmp/log/clog_${timestamp};" |
| 584 | + "mkdir ${clog_dir};" |
| 585 | + "dmesg > ${clog_dir}/WIFI_KERNEL_${timestamp}.clog"); |
| 586 | + else |
| 587 | + system("timestamp=$(date +\"%y%m%d_%H%M%S\");" |
| 588 | + "clog_dir=/tmp/log/clog_${timestamp};" |
| 589 | + "mkdir ${clog_dir};" |
| 590 | + "mv /tmp/log/WIFI_FW.clog ${clog_dir}/WIFI_FW_${timestamp}.clog;" |
| 591 | + "dmesg > ${clog_dir}/WIFI_KERNEL_${timestamp}.clog"); |
| 592 | |
| 593 | return ret; |
| 594 | } |
| 595 | diff --git a/tools/main.c b/tools/main.c |
| 596 | index 699a9eea6..e9e255679 100644 |
| 597 | --- a/tools/main.c |
| 598 | +++ b/tools/main.c |
| 599 | @@ -198,6 +198,8 @@ int main(int argc, char **argv) |
| 600 | ret = mt76_eeprom(phy, argc, argv); |
| 601 | else if (!strcmp(cmd, "fwlog")) |
| 602 | ret = mt76_fwlog(phyname, argc, argv); |
| 603 | + else if (!strcmp(cmd, "idxlog")) |
| 604 | + ret = mt76_idxlog(phyname, argc, argv); |
| 605 | else |
| 606 | usage(); |
| 607 | |
| 608 | diff --git a/tools/mt76-test.h b/tools/mt76-test.h |
| 609 | index d2fafa862..b9d508c5c 100644 |
| 610 | --- a/tools/mt76-test.h |
| 611 | +++ b/tools/mt76-test.h |
| 612 | @@ -22,6 +22,8 @@ |
| 613 | #define EEPROM_FILE_PATH_FMT "/tmp/mt76-test-%s" |
| 614 | #define EEPROM_PART_SIZE 20480 |
| 615 | |
| 616 | +#define FWLOG_BUF_SIZE 1504 |
| 617 | + |
| 618 | struct nl_msg; |
| 619 | struct nlattr; |
| 620 | |
| 621 | @@ -61,5 +63,6 @@ extern unsigned char *eeprom_data; |
| 622 | void usage(void); |
| 623 | int mt76_eeprom(int phy, int argc, char **argv); |
| 624 | int mt76_fwlog(const char *phyname, int argc, char **argv); |
| 625 | +int mt76_idxlog(const char *phyname, int argc, char **argv); |
| 626 | |
| 627 | #endif |
| 628 | -- |
| 629 | 2.39.2 |
| 630 | |