@@ -104,6 +104,7 @@ struct mt76x02_dev {
u32 tx_hang_reset;
u8 tx_hang_check;
+ u8 beacon_hang_check;
u8 mcu_timeout;
struct mt76x02_calibration cal;
@@ -1040,12 +1040,26 @@ EXPORT_SYMBOL_GPL(mt76x02_update_channel);
static void mt76x02_check_mac_err(struct mt76x02_dev *dev)
{
- u32 val = mt76_rr(dev, 0x10f4);
+ if (dev->mt76.beacon_mask) {
+ if (mt76_rr(dev, MT_TX_STA_0) & MT_TX_STA_0_BEACONS) {
+ dev->beacon_hang_check = 0;
+ return;
+ }
- if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
- return;
+ if (++dev->beacon_hang_check < 10)
+ return;
+
+ dev->beacon_hang_check = 0;
+ } else {
+ u32 val = mt76_rr(dev, 0x10f4);
+ if (!(val & BIT(29)) || !(val & (BIT(7) | BIT(5))))
+ return;
+ }
+
+ dev_err(dev->mt76.dev, "MAC error detected\n");
- dev_err(dev->mt76.dev, "mac specific condition occurred\n");
+ mt76_wr(dev, MT_MAC_SYS_CTRL, 0);
+ mt76x02_wait_for_txrx_idle(&dev->mt76);
mt76_set(dev, MT_MAC_SYS_CTRL, MT_MAC_SYS_CTRL_RESET_CSR);
udelay(10);
@@ -1178,8 +1192,7 @@ void mt76x02_mac_work(struct work_struct *work)
dev->mt76.aggr_stats[idx++] += val >> 16;
}
- if (!dev->mt76.beacon_mask)
- mt76x02_check_mac_err(dev);
+ mt76x02_check_mac_err(dev);
if (dev->ed_monitor)
mt76x02_edcca_check(dev);
@@ -571,6 +571,8 @@
#define MT_RX_STAT_2_OVERFLOW_ERRORS GENMASK(31, 16)
#define MT_TX_STA_0 0x170c
+#define MT_TX_STA_0_BEACONS GENMASK(31, 16)
+
#define MT_TX_STA_1 0x1710
#define MT_TX_STA_2 0x1714
On AP mode devices, check beacon tx counters to detect MAC errors. When an error is detected, stop the MAC before resetting it Signed-off-by: Felix Fietkau <nbd@nbd.name> --- drivers/net/wireless/mediatek/mt76/mt76x02.h | 1 + .../net/wireless/mediatek/mt76/mt76x02_mac.c | 25 ++++++++++++++----- .../net/wireless/mediatek/mt76/mt76x02_regs.h | 2 ++ 3 files changed, 22 insertions(+), 6 deletions(-)