mt76: mt7915: add support for passing chip/firmware debug data to user space
authorFelix Fietkau <nbd@nbd.name>
Sun, 26 Dec 2021 21:18:32 +0000 (22:18 +0100)
committerFelix Fietkau <nbd@nbd.name>
Thu, 3 Feb 2022 12:57:58 +0000 (13:57 +0100)
This can be used to assist in debugging driver or firmware tx/rx issues.
The data is streamed to user space using a relay file in debugfs

Signed-off-by: Felix Fietkau <nbd@nbd.name>
drivers/net/wireless/mediatek/mt76/mt7915/Kconfig
drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.c
drivers/net/wireless/mediatek/mt76/mt7915/mac.h
drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
drivers/net/wireless/mediatek/mt76/mt7915/regs.h

index b8b98cb..6dc4708 100644 (file)
@@ -4,6 +4,7 @@ config MT7915E
        select MT76_CONNAC_LIB
        depends on MAC80211
        depends on PCI
+       select RELAY
        help
          This adds support for MT7915-based wireless PCIe devices,
          which support concurrent dual-band operation at both 5GHz
index c59ef08..464d2b4 100644 (file)
@@ -1,9 +1,13 @@
 // SPDX-License-Identifier: ISC
 /* Copyright (C) 2020 MediaTek Inc. */
 
+#include <linux/relay.h>
 #include "mt7915.h"
 #include "eeprom.h"
 #include "mcu.h"
+#include "mac.h"
+
+#define FW_BIN_LOG_MAGIC       0x44e98caf
 
 /** global debugfs **/
 
@@ -311,16 +315,31 @@ mt7915_fw_debug_wm_set(void *data, u64 val)
                DEBUG_SPL,
                DEBUG_RPT_RX,
        } debug;
+       bool tx, rx, en;
        int ret;
 
        dev->fw_debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;
 
-       ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, dev->fw_debug_wm);
+       if (dev->fw_debug_bin)
+               val = 16;
+       else
+               val = dev->fw_debug_wm;
+
+       tx = dev->fw_debug_wm || (dev->fw_debug_bin & BIT(1));
+       rx = dev->fw_debug_wm || (dev->fw_debug_bin & BIT(2));
+       en = dev->fw_debug_wm || (dev->fw_debug_bin & BIT(0));
+
+       ret = mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, val);
        if (ret)
                return ret;
 
        for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) {
-               ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, !!dev->fw_debug_wm);
+               if (debug == DEBUG_RPT_RX)
+                       val = en && rx;
+               else
+                       val = en && tx;
+
+               ret = mt7915_mcu_fw_dbg_ctrl(dev, debug, val);
                if (ret)
                        return ret;
        }
@@ -376,6 +395,65 @@ mt7915_fw_debug_wa_get(void *data, u64 *val)
 DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get,
                         mt7915_fw_debug_wa_set, "%lld\n");
 
+static struct dentry *
+create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,
+                  struct rchan_buf *buf, int *is_global)
+{
+       struct dentry *f;
+
+       f = debugfs_create_file("fwlog_data", mode, parent, buf,
+                               &relay_file_operations);
+       if (IS_ERR(f))
+               return NULL;
+
+       *is_global = 1;
+
+       return f;
+}
+
+static int
+remove_buf_file_cb(struct dentry *f)
+{
+       debugfs_remove(f);
+
+       return 0;
+}
+
+static int
+mt7915_fw_debug_bin_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 mt7915_dev *dev = data;
+
+       if (!dev->relay_fwlog)
+               dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir,
+                                           1500, 512, &relay_cb, NULL);
+       if (!dev->relay_fwlog)
+               return -ENOMEM;
+
+       dev->fw_debug_bin = val;
+
+       relay_reset(dev->relay_fwlog);
+
+       return mt7915_fw_debug_wm_set(dev, dev->fw_debug_wm);
+}
+
+static int
+mt7915_fw_debug_bin_get(void *data, u64 *val)
+{
+       struct mt7915_dev *dev = data;
+
+       *val = dev->fw_debug_bin;
+
+       return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7915_fw_debug_bin_get,
+                        mt7915_fw_debug_bin_set, "%lld\n");
+
 static int
 mt7915_fw_util_wm_show(struct seq_file *file, void *data)
 {
@@ -757,6 +835,7 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
        debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
        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("fw_util_wm", 0400, dir, dev,
                            &mt7915_fw_util_wm_fops);
        debugfs_create_file("fw_util_wa", 0400, dir, dev,
@@ -775,9 +854,68 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
                                    &fops_radar_trigger);
        }
 
+       if (!ext_phy)
+               dev->debugfs_dir = dir;
+
        return 0;
 }
 
+static void
+mt7915_debugfs_write_fwlog(struct mt7915_dev *dev, const void *hdr, int hdrlen,
+                        const void *data, int len)
+{
+       static DEFINE_SPINLOCK(lock);
+       unsigned long flags;
+       void *dest;
+
+       spin_lock_irqsave(&lock, flags);
+       dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4);
+       if (dest) {
+               *(u32 *)dest = hdrlen + len;
+               dest += 4;
+
+               if (hdrlen) {
+                       memcpy(dest, hdr, hdrlen);
+                       dest += hdrlen;
+               }
+
+               memcpy(dest, data, len);
+               relay_flush(dev->relay_fwlog);
+       }
+       spin_unlock_irqrestore(&lock, flags);
+}
+
+void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len)
+{
+       struct {
+               __le32 magic;
+               __le32 timestamp;
+               __le16 msg_type;
+               __le16 len;
+       } hdr = {
+               .magic = cpu_to_le32(FW_BIN_LOG_MAGIC),
+               .msg_type = PKT_TYPE_RX_FW_MONITOR,
+       };
+
+       if (!dev->relay_fwlog)
+               return;
+
+       hdr.timestamp = mt76_rr(dev, MT_LPON_FRCR(0));
+       hdr.len = *(__le16 *)data;
+       mt7915_debugfs_write_fwlog(dev, &hdr, sizeof(hdr), data, len);
+}
+
+bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len)
+{
+       if (get_unaligned_le32(data) != FW_BIN_LOG_MAGIC)
+               return false;
+
+       if (dev->relay_fwlog)
+               mt7915_debugfs_write_fwlog(dev, NULL, 0, data, len);
+
+       return true;
+}
+
 #ifdef CONFIG_MAC80211_DEBUGFS
 /** per-station debugfs **/
 
index e0200f8..08ec8ce 100644 (file)
@@ -1691,6 +1691,9 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
                for (rxd += 2; rxd + 8 <= end; rxd += 8)
                    mt7915_mac_add_txs(dev, rxd);
                return false;
+       case PKT_TYPE_RX_FW_MONITOR:
+               mt7915_debugfs_rx_fw_monitor(dev, data, len);
+               return false;
        default:
                return true;
        }
@@ -1722,6 +1725,9 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
                    mt7915_mac_add_txs(dev, rxd);
                dev_kfree_skb(skb);
                break;
+       case PKT_TYPE_RX_FW_MONITOR:
+               mt7915_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
+               break;
        case PKT_TYPE_NORMAL:
                if (!mt7915_mac_fill_rx(dev, skb)) {
                        mt76_rx(&dev->mt76, q, skb);
index d79f0a5..5add1dd 100644 (file)
@@ -23,6 +23,7 @@ enum rx_pkt_type {
        PKT_TYPE_RETRIEVE,
        PKT_TYPE_TXRX_NOTIFY,
        PKT_TYPE_RX_EVENT,
+       PKT_TYPE_RX_FW_MONITOR = 0x0c,
 };
 
 /* RXD DW1 */
index 74cdfd3..66f8daf 100644 (file)
@@ -368,9 +368,13 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
        struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data;
        const char *data = (char *)&rxd[1];
        const char *type;
+       int len = skb->len - sizeof(*rxd);
 
        switch (rxd->s2d_index) {
        case 0:
+               if (mt7915_debugfs_rx_log(dev, data, len))
+                       return;
+
                type = "WM";
                break;
        case 2:
@@ -381,8 +385,7 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
                break;
        }
 
-       wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type,
-                  (int)(skb->len - sizeof(*rxd)), data);
+       wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data);
 }
 
 static void
index f1568f9..e8ff686 100644 (file)
@@ -50,6 +50,7 @@ static const u32 mt7915_offs[] = {
        [AGG_ATCR3]             = 0x0f4,
        [LPON_UTTR0]            = 0x080,
        [LPON_UTTR1]            = 0x084,
+       [LPON_FRCR]             = 0x314,
        [MIB_SDR3]              = 0x014,
        [MIB_SDR4]              = 0x018,
        [MIB_SDR5]              = 0x01c,
@@ -121,6 +122,7 @@ static const u32 mt7916_offs[] = {
        [AGG_ATCR3]             = 0x080,
        [LPON_UTTR0]            = 0x360,
        [LPON_UTTR1]            = 0x364,
+       [LPON_FRCR]             = 0x37c,
        [MIB_SDR3]              = 0x698,
        [MIB_SDR4]              = 0x788,
        [MIB_SDR5]              = 0x780,
index 5adde02..cd7ee71 100644 (file)
@@ -291,6 +291,10 @@ struct mt7915_dev {
        bool ibf;
        u8 fw_debug_wm;
        u8 fw_debug_wa;
+       u8 fw_debug_bin;
+
+       struct dentry *debugfs_dir;
+       struct rchan *relay_fwlog;
 
        void *cal;
 
@@ -537,6 +541,8 @@ void mt7915_update_channel(struct mt76_phy *mphy);
 int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enable);
 int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms);
 int mt7915_init_debugfs(struct mt7915_phy *phy);
+void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len);
+bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len);
 #ifdef CONFIG_MAC80211_DEBUGFS
 void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                            struct ieee80211_sta *sta, struct dentry *dir);
index aa19e59..6a0f681 100644 (file)
@@ -50,6 +50,7 @@ enum offs_rev {
        AGG_ATCR3,
        LPON_UTTR0,
        LPON_UTTR1,
+       LPON_FRCR,
        MIB_SDR3,
        MIB_SDR4,
        MIB_SDR5,
@@ -238,6 +239,7 @@ enum offs_rev {
 
 #define MT_LPON_UTTR0(_band)           MT_WF_LPON(_band, __OFFS(LPON_UTTR0))
 #define MT_LPON_UTTR1(_band)           MT_WF_LPON(_band, __OFFS(LPON_UTTR1))
+#define MT_LPON_FRCR(_band)            MT_WF_LPON(_band, __OFFS(LPON_FRCR))
 
 #define MT_LPON_TCR(_band, n)          MT_WF_LPON(_band, 0x0a8 +       \
                                                   (((n) * 4) << 1))