Merge https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
[linux-2.6-microblaze.git] / drivers / net / wireless / mediatek / mt76 / mt7915 / debugfs.c
index e96d1c3..280823f 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 **/
 
@@ -75,7 +79,11 @@ mt7915_radar_trigger(void *data, u64 val)
 {
        struct mt7915_dev *dev = data;
 
-       return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0);
+       if (val > MT_RX_SEL2)
+               return -EINVAL;
+
+       return mt76_connac_mcu_rdd_cmd(&dev->mt76, RDD_RADAR_EMULATE,
+                                      val, 0, 0);
 }
 
 DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
@@ -300,6 +308,53 @@ exit:
 }
 DEFINE_SHOW_ATTRIBUTE(mt7915_muru_stats);
 
+static int
+mt7915_rdd_monitor(struct seq_file *s, void *data)
+{
+       struct mt7915_dev *dev = dev_get_drvdata(s->private);
+       struct cfg80211_chan_def *chandef = &dev->rdd2_chandef;
+       const char *bw;
+       int ret = 0;
+
+       mutex_lock(&dev->mt76.mutex);
+
+       if (!cfg80211_chandef_valid(chandef)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (!dev->rdd2_phy) {
+               seq_puts(s, "not running\n");
+               goto out;
+       }
+
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_40:
+               bw = "40";
+               break;
+       case NL80211_CHAN_WIDTH_80:
+               bw = "80";
+               break;
+       case NL80211_CHAN_WIDTH_160:
+               bw = "160";
+               break;
+       case NL80211_CHAN_WIDTH_80P80:
+               bw = "80P80";
+               break;
+       default:
+               bw = "20";
+               break;
+       }
+
+       seq_printf(s, "channel %d (%d MHz) width %s MHz center1: %d MHz\n",
+                  chandef->chan->hw_value, chandef->chan->center_freq,
+                  bw, chandef->center_freq1);
+out:
+       mutex_unlock(&dev->mt76.mutex);
+
+       return ret;
+}
+
 static int
 mt7915_fw_debug_wm_set(void *data, u64 val)
 {
@@ -311,16 +366,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 +446,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)
 {
@@ -521,14 +650,14 @@ mt7915_tx_stats_show(struct seq_file *file, void *data)
 DEFINE_SHOW_ATTRIBUTE(mt7915_tx_stats);
 
 static void
-mt7915_hw_queue_read(struct seq_file *s, u32 base, u32 size,
+mt7915_hw_queue_read(struct seq_file *s, u32 size,
                     const struct hw_queue_map *map)
 {
        struct mt7915_phy *phy = s->private;
        struct mt7915_dev *dev = phy->dev;
        u32 i, val;
 
-       val = mt76_rr(dev, base + MT_FL_Q_EMPTY);
+       val = mt76_rr(dev, MT_FL_Q_EMPTY);
        for (i = 0; i < size; i++) {
                u32 ctrl, head, tail, queued;
 
@@ -536,13 +665,13 @@ mt7915_hw_queue_read(struct seq_file *s, u32 base, u32 size,
                        continue;
 
                ctrl = BIT(31) | (map[i].pid << 10) | (map[i].qid << 24);
-               mt76_wr(dev, base + MT_FL_Q0_CTRL, ctrl);
+               mt76_wr(dev, MT_FL_Q0_CTRL, ctrl);
 
-               head = mt76_get_field(dev, base + MT_FL_Q2_CTRL,
+               head = mt76_get_field(dev, MT_FL_Q2_CTRL,
                                      GENMASK(11, 0));
-               tail = mt76_get_field(dev, base + MT_FL_Q2_CTRL,
+               tail = mt76_get_field(dev, MT_FL_Q2_CTRL,
                                      GENMASK(27, 16));
-               queued = mt76_get_field(dev, base + MT_FL_Q3_CTRL,
+               queued = mt76_get_field(dev, MT_FL_Q3_CTRL,
                                        GENMASK(11, 0));
 
                seq_printf(s, "\t%s: ", map[i].name);
@@ -570,8 +699,8 @@ mt7915_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
                if (val & BIT(offs))
                        continue;
 
-               mt76_wr(dev, MT_PLE_BASE + MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
-               qlen = mt76_get_field(dev, MT_PLE_BASE + MT_FL_Q3_CTRL,
+               mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
+               qlen = mt76_get_field(dev, MT_FL_Q3_CTRL,
                                      GENMASK(11, 0));
                seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
                           sta->addr, msta->wcid.idx,
@@ -633,7 +762,7 @@ mt7915_hw_queues_show(struct seq_file *file, void *data)
                   val, head, tail);
 
        seq_puts(file, "PLE non-empty queue info:\n");
-       mt7915_hw_queue_read(file, MT_PLE_BASE, ARRAY_SIZE(ple_queue_map),
+       mt7915_hw_queue_read(file, ARRAY_SIZE(ple_queue_map),
                             &ple_queue_map[0]);
 
        /* iterate per-sta ple queue */
@@ -641,7 +770,7 @@ mt7915_hw_queues_show(struct seq_file *file, void *data)
                                          mt7915_sta_hw_queue_read, file);
        /* pse queue */
        seq_puts(file, "PSE non-empty queue info:\n");
-       mt7915_hw_queue_read(file, MT_PSE_BASE, ARRAY_SIZE(pse_queue_map),
+       mt7915_hw_queue_read(file, ARRAY_SIZE(pse_queue_map),
                             &pse_queue_map[0]);
 
        return 0;
@@ -757,6 +886,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,
@@ -773,11 +903,72 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
                                   &dev->hw_pattern);
                debugfs_create_file("radar_trigger", 0200, dir, dev,
                                    &fops_radar_trigger);
+               debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir,
+                                           mt7915_rdd_monitor);
        }
 
+       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 **/