mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
mt76: mt7915: add support for passing chip/firmware debug data to user space
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>
This commit is contained in:
@@ -4,6 +4,7 @@ config MT7915E
|
|||||||
select MT76_CONNAC_LIB
|
select MT76_CONNAC_LIB
|
||||||
depends on MAC80211
|
depends on MAC80211
|
||||||
depends on PCI
|
depends on PCI
|
||||||
|
select RELAY
|
||||||
help
|
help
|
||||||
This adds support for MT7915-based wireless PCIe devices,
|
This adds support for MT7915-based wireless PCIe devices,
|
||||||
which support concurrent dual-band operation at both 5GHz
|
which support concurrent dual-band operation at both 5GHz
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
// SPDX-License-Identifier: ISC
|
// SPDX-License-Identifier: ISC
|
||||||
/* Copyright (C) 2020 MediaTek Inc. */
|
/* Copyright (C) 2020 MediaTek Inc. */
|
||||||
|
|
||||||
|
#include <linux/relay.h>
|
||||||
#include "mt7915.h"
|
#include "mt7915.h"
|
||||||
#include "eeprom.h"
|
#include "eeprom.h"
|
||||||
#include "mcu.h"
|
#include "mcu.h"
|
||||||
|
#include "mac.h"
|
||||||
|
|
||||||
|
#define FW_BIN_LOG_MAGIC 0x44e98caf
|
||||||
|
|
||||||
/** global debugfs **/
|
/** global debugfs **/
|
||||||
|
|
||||||
@@ -311,16 +315,31 @@ mt7915_fw_debug_wm_set(void *data, u64 val)
|
|||||||
DEBUG_SPL,
|
DEBUG_SPL,
|
||||||
DEBUG_RPT_RX,
|
DEBUG_RPT_RX,
|
||||||
} debug;
|
} debug;
|
||||||
|
bool tx, rx, en;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
dev->fw_debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
for (debug = DEBUG_TXCMD; debug <= DEBUG_RPT_RX; debug++) {
|
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)
|
if (ret)
|
||||||
return 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,
|
DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_wa, mt7915_fw_debug_wa_get,
|
||||||
mt7915_fw_debug_wa_set, "%lld\n");
|
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
|
static int
|
||||||
mt7915_fw_util_wm_show(struct seq_file *file, void *data)
|
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("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_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_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,
|
debugfs_create_file("fw_util_wm", 0400, dir, dev,
|
||||||
&mt7915_fw_util_wm_fops);
|
&mt7915_fw_util_wm_fops);
|
||||||
debugfs_create_file("fw_util_wa", 0400, dir, dev,
|
debugfs_create_file("fw_util_wa", 0400, dir, dev,
|
||||||
@@ -775,9 +854,68 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
|
|||||||
&fops_radar_trigger);
|
&fops_radar_trigger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ext_phy)
|
||||||
|
dev->debugfs_dir = dir;
|
||||||
|
|
||||||
return 0;
|
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
|
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||||
/** per-station debugfs **/
|
/** per-station debugfs **/
|
||||||
|
|
||||||
|
|||||||
@@ -1691,6 +1691,9 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
|
|||||||
for (rxd += 2; rxd + 8 <= end; rxd += 8)
|
for (rxd += 2; rxd + 8 <= end; rxd += 8)
|
||||||
mt7915_mac_add_txs(dev, rxd);
|
mt7915_mac_add_txs(dev, rxd);
|
||||||
return false;
|
return false;
|
||||||
|
case PKT_TYPE_RX_FW_MONITOR:
|
||||||
|
mt7915_debugfs_rx_fw_monitor(dev, data, len);
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
return true;
|
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);
|
mt7915_mac_add_txs(dev, rxd);
|
||||||
dev_kfree_skb(skb);
|
dev_kfree_skb(skb);
|
||||||
break;
|
break;
|
||||||
|
case PKT_TYPE_RX_FW_MONITOR:
|
||||||
|
mt7915_debugfs_rx_fw_monitor(dev, skb->data, skb->len);
|
||||||
|
break;
|
||||||
case PKT_TYPE_NORMAL:
|
case PKT_TYPE_NORMAL:
|
||||||
if (!mt7915_mac_fill_rx(dev, skb)) {
|
if (!mt7915_mac_fill_rx(dev, skb)) {
|
||||||
mt76_rx(&dev->mt76, q, skb);
|
mt76_rx(&dev->mt76, q, skb);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ enum rx_pkt_type {
|
|||||||
PKT_TYPE_RETRIEVE,
|
PKT_TYPE_RETRIEVE,
|
||||||
PKT_TYPE_TXRX_NOTIFY,
|
PKT_TYPE_TXRX_NOTIFY,
|
||||||
PKT_TYPE_RX_EVENT,
|
PKT_TYPE_RX_EVENT,
|
||||||
|
PKT_TYPE_RX_FW_MONITOR = 0x0c,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RXD DW1 */
|
/* RXD DW1 */
|
||||||
|
|||||||
@@ -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;
|
struct mt7915_mcu_rxd *rxd = (struct mt7915_mcu_rxd *)skb->data;
|
||||||
const char *data = (char *)&rxd[1];
|
const char *data = (char *)&rxd[1];
|
||||||
const char *type;
|
const char *type;
|
||||||
|
int len = skb->len - sizeof(*rxd);
|
||||||
|
|
||||||
switch (rxd->s2d_index) {
|
switch (rxd->s2d_index) {
|
||||||
case 0:
|
case 0:
|
||||||
|
if (mt7915_debugfs_rx_log(dev, data, len))
|
||||||
|
return;
|
||||||
|
|
||||||
type = "WM";
|
type = "WM";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
@@ -381,8 +385,7 @@ mt7915_mcu_rx_log_message(struct mt7915_dev *dev, struct sk_buff *skb)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type,
|
wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data);
|
||||||
(int)(skb->len - sizeof(*rxd)), data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ static const u32 mt7915_offs[] = {
|
|||||||
[AGG_ATCR3] = 0x0f4,
|
[AGG_ATCR3] = 0x0f4,
|
||||||
[LPON_UTTR0] = 0x080,
|
[LPON_UTTR0] = 0x080,
|
||||||
[LPON_UTTR1] = 0x084,
|
[LPON_UTTR1] = 0x084,
|
||||||
|
[LPON_FRCR] = 0x314,
|
||||||
[MIB_SDR3] = 0x014,
|
[MIB_SDR3] = 0x014,
|
||||||
[MIB_SDR4] = 0x018,
|
[MIB_SDR4] = 0x018,
|
||||||
[MIB_SDR5] = 0x01c,
|
[MIB_SDR5] = 0x01c,
|
||||||
@@ -121,6 +122,7 @@ static const u32 mt7916_offs[] = {
|
|||||||
[AGG_ATCR3] = 0x080,
|
[AGG_ATCR3] = 0x080,
|
||||||
[LPON_UTTR0] = 0x360,
|
[LPON_UTTR0] = 0x360,
|
||||||
[LPON_UTTR1] = 0x364,
|
[LPON_UTTR1] = 0x364,
|
||||||
|
[LPON_FRCR] = 0x37c,
|
||||||
[MIB_SDR3] = 0x698,
|
[MIB_SDR3] = 0x698,
|
||||||
[MIB_SDR4] = 0x788,
|
[MIB_SDR4] = 0x788,
|
||||||
[MIB_SDR5] = 0x780,
|
[MIB_SDR5] = 0x780,
|
||||||
|
|||||||
@@ -291,6 +291,10 @@ struct mt7915_dev {
|
|||||||
bool ibf;
|
bool ibf;
|
||||||
u8 fw_debug_wm;
|
u8 fw_debug_wm;
|
||||||
u8 fw_debug_wa;
|
u8 fw_debug_wa;
|
||||||
|
u8 fw_debug_bin;
|
||||||
|
|
||||||
|
struct dentry *debugfs_dir;
|
||||||
|
struct rchan *relay_fwlog;
|
||||||
|
|
||||||
void *cal;
|
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_set(struct mt7915_dev *dev, bool enable);
|
||||||
int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms);
|
int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms);
|
||||||
int mt7915_init_debugfs(struct mt7915_phy *phy);
|
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
|
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||||
void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
struct ieee80211_sta *sta, struct dentry *dir);
|
struct ieee80211_sta *sta, struct dentry *dir);
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ enum offs_rev {
|
|||||||
AGG_ATCR3,
|
AGG_ATCR3,
|
||||||
LPON_UTTR0,
|
LPON_UTTR0,
|
||||||
LPON_UTTR1,
|
LPON_UTTR1,
|
||||||
|
LPON_FRCR,
|
||||||
MIB_SDR3,
|
MIB_SDR3,
|
||||||
MIB_SDR4,
|
MIB_SDR4,
|
||||||
MIB_SDR5,
|
MIB_SDR5,
|
||||||
@@ -238,6 +239,7 @@ enum offs_rev {
|
|||||||
|
|
||||||
#define MT_LPON_UTTR0(_band) MT_WF_LPON(_band, __OFFS(LPON_UTTR0))
|
#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_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 + \
|
#define MT_LPON_TCR(_band, n) MT_WF_LPON(_band, 0x0a8 + \
|
||||||
(((n) * 4) << 1))
|
(((n) * 4) << 1))
|
||||||
|
|||||||
Reference in New Issue
Block a user