summaryrefslogtreecommitdiff
path: root/drivers/net/wireless/realtek/rtw89/debug.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/realtek/rtw89/debug.c')
-rw-r--r--drivers/net/wireless/realtek/rtw89/debug.c125
1 files changed, 124 insertions, 1 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/debug.c b/drivers/net/wireless/realtek/rtw89/debug.c
index afdfb9647fc1..3dc7981c510f 100644
--- a/drivers/net/wireless/realtek/rtw89/debug.c
+++ b/drivers/net/wireless/realtek/rtw89/debug.c
@@ -86,6 +86,7 @@ struct rtw89_debugfs {
struct rtw89_debugfs_priv stations;
struct rtw89_debugfs_priv disable_dm;
struct rtw89_debugfs_priv mlo_mode;
+ struct rtw89_debugfs_priv beacon_info;
};
struct rtw89_debugfs_iter_data {
@@ -3562,6 +3563,58 @@ static int rtw89_dbg_trigger_ctrl_error(struct rtw89_dev *rtwdev)
return 0;
}
+static int rtw89_dbg_trigger_mac_error_ax(struct rtw89_dev *rtwdev)
+{
+ u16 val16;
+ u8 val8;
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ val8 = rtw89_read8(rtwdev, R_AX_CMAC_FUNC_EN);
+ rtw89_write8(rtwdev, R_AX_CMAC_FUNC_EN, val8 & ~B_AX_TMAC_EN);
+ mdelay(1);
+ rtw89_write8(rtwdev, R_AX_CMAC_FUNC_EN, val8);
+
+ val16 = rtw89_read16(rtwdev, R_AX_PTCL_IMR0);
+ rtw89_write16(rtwdev, R_AX_PTCL_IMR0, val16 | B_AX_F2PCMD_EMPTY_ERR_INT_EN);
+ rtw89_write16(rtwdev, R_AX_PTCL_IMR0, val16);
+
+ return 0;
+}
+
+static int rtw89_dbg_trigger_mac_error_be(struct rtw89_dev *rtwdev)
+{
+ int ret;
+
+ ret = rtw89_mac_check_mac_en(rtwdev, RTW89_MAC_0, RTW89_CMAC_SEL);
+ if (ret)
+ return ret;
+
+ rtw89_write32_set(rtwdev, R_BE_CMAC_FW_TRIGGER_IDCT_ISR,
+ B_BE_CMAC_FW_TRIG_IDCT | B_BE_CMAC_FW_ERR_IDCT_IMR);
+
+ return 0;
+}
+
+static int rtw89_dbg_trigger_mac_error(struct rtw89_dev *rtwdev)
+{
+ const struct rtw89_chip_info *chip = rtwdev->chip;
+
+ rtw89_leave_ps_mode(rtwdev);
+
+ switch (chip->chip_gen) {
+ case RTW89_CHIP_AX:
+ return rtw89_dbg_trigger_mac_error_ax(rtwdev);
+ case RTW89_CHIP_BE:
+ return rtw89_dbg_trigger_mac_error_be(rtwdev);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static ssize_t
rtw89_debug_priv_fw_crash_get(struct rtw89_dev *rtwdev,
struct rtw89_debugfs_priv *debugfs_priv,
@@ -3577,6 +3630,7 @@ rtw89_debug_priv_fw_crash_get(struct rtw89_dev *rtwdev,
enum rtw89_dbg_crash_simulation_type {
RTW89_DBG_SIM_CPU_EXCEPTION = 1,
RTW89_DBG_SIM_CTRL_ERROR = 2,
+ RTW89_DBG_SIM_MAC_ERROR = 3,
};
static ssize_t
@@ -3585,6 +3639,7 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev,
const char *buf, size_t count)
{
int (*sim)(struct rtw89_dev *rtwdev);
+ bool announce = true;
u8 crash_type;
int ret;
@@ -3603,11 +3658,19 @@ rtw89_debug_priv_fw_crash_set(struct rtw89_dev *rtwdev,
case RTW89_DBG_SIM_CTRL_ERROR:
sim = rtw89_dbg_trigger_ctrl_error;
break;
+ case RTW89_DBG_SIM_MAC_ERROR:
+ sim = rtw89_dbg_trigger_mac_error;
+
+ /* Driver SER flow won't get involved; only FW will. */
+ announce = false;
+ break;
default:
return -EINVAL;
}
- set_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags);
+ if (announce)
+ set_bit(RTW89_FLAG_CRASH_SIMULATING, rtwdev->flags);
+
ret = sim(rtwdev);
if (ret)
@@ -4298,6 +4361,64 @@ rtw89_debug_priv_mlo_mode_set(struct rtw89_dev *rtwdev,
return count;
}
+static ssize_t
+rtw89_debug_priv_beacon_info_get(struct rtw89_dev *rtwdev,
+ struct rtw89_debugfs_priv *debugfs_priv,
+ char *buf, size_t bufsz)
+{
+ struct rtw89_pkt_stat *pkt_stat = &rtwdev->phystat.last_pkt_stat;
+ struct rtw89_beacon_track_info *bcn_track = &rtwdev->bcn_track;
+ struct rtw89_beacon_stat *bcn_stat = &rtwdev->phystat.bcn_stat;
+ struct rtw89_beacon_dist *bcn_dist = &bcn_stat->bcn_dist;
+ u16 upper, lower = bcn_stat->tbtt_tu_min;
+ char *p = buf, *end = buf + bufsz;
+ u16 *drift = bcn_stat->drift;
+ u8 bcn_num = bcn_stat->num;
+ u8 count;
+ u8 i;
+
+ p += scnprintf(p, end - p, "[Beacon info]\n");
+ p += scnprintf(p, end - p, "count: %u\n", pkt_stat->beacon_nr);
+ p += scnprintf(p, end - p, "interval: %u\n", bcn_track->beacon_int);
+ p += scnprintf(p, end - p, "dtim: %u\n", bcn_track->dtim);
+ p += scnprintf(p, end - p, "raw rssi: %lu\n",
+ ewma_rssi_read(&rtwdev->phystat.bcn_rssi));
+ p += scnprintf(p, end - p, "hw rate: %u\n", pkt_stat->beacon_rate);
+ p += scnprintf(p, end - p, "length: %u\n", pkt_stat->beacon_len);
+
+ p += scnprintf(p, end - p, "\n[Distribution]\n");
+ p += scnprintf(p, end - p, "tbtt\n");
+ for (i = 0; i < RTW89_BCN_TRACK_MAX_BIN_NUM; i++) {
+ upper = lower + RTW89_BCN_TRACK_BIN_WIDTH - 1;
+ if (i == RTW89_BCN_TRACK_MAX_BIN_NUM - 1)
+ upper = max(upper, bcn_stat->tbtt_tu_max);
+
+ p += scnprintf(p, end - p, "%02u - %02u: %u\n",
+ lower, upper, bcn_dist->bins[i]);
+
+ lower = upper + 1;
+ }
+
+ p += scnprintf(p, end - p, "\ndrift\n");
+
+ for (i = 0; i < bcn_num; i += count) {
+ count = 1;
+ while (i + count < bcn_num && drift[i] == drift[i + count])
+ count++;
+
+ p += scnprintf(p, end - p, "%u: %u\n", drift[i], count);
+ }
+ p += scnprintf(p, end - p, "\nlower bound: %u\n", bcn_dist->lower_bound);
+ p += scnprintf(p, end - p, "upper bound: %u\n", bcn_dist->upper_bound);
+ p += scnprintf(p, end - p, "outlier count: %u\n", bcn_dist->outlier_count);
+
+ p += scnprintf(p, end - p, "\n[Tracking]\n");
+ p += scnprintf(p, end - p, "tbtt offset: %u\n", bcn_track->tbtt_offset);
+ p += scnprintf(p, end - p, "bcn timeout: %u\n", bcn_track->bcn_timeout);
+
+ return p - buf;
+}
+
#define rtw89_debug_priv_get(name, opts...) \
{ \
.cb_read = rtw89_debug_priv_ ##name## _get, \
@@ -4356,6 +4477,7 @@ static const struct rtw89_debugfs rtw89_debugfs_templ = {
.stations = rtw89_debug_priv_get(stations, RLOCK),
.disable_dm = rtw89_debug_priv_set_and_get(disable_dm, RWLOCK),
.mlo_mode = rtw89_debug_priv_set_and_get(mlo_mode, RWLOCK),
+ .beacon_info = rtw89_debug_priv_get(beacon_info),
};
#define rtw89_debugfs_add(name, mode, fopname, parent) \
@@ -4401,6 +4523,7 @@ void rtw89_debugfs_add_sec1(struct rtw89_dev *rtwdev, struct dentry *debugfs_top
rtw89_debugfs_add_r(stations);
rtw89_debugfs_add_rw(disable_dm);
rtw89_debugfs_add_rw(mlo_mode);
+ rtw89_debugfs_add_r(beacon_info);
}
void rtw89_debugfs_init(struct rtw89_dev *rtwdev)