mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-26 20:38:12 +00:00
wifi: mt76: mt7603: improve stuck beacon handling
[ Upstream commit3176205933
] Before preparing the new beacon, check the queue status, flush out all previous beacons and buffered multicast packets, then (if necessary) try to recover more gracefully from a stuck beacon condition by making a less invasive attempt at getting the MAC un-stuck. Fixes:c8846e1015
("mt76: add driver for MT7603E and MT7628/7688") Signed-off-by: Felix Fietkau <nbd@nbd.name> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
c2fd48179c
commit
2b12aebbd3
2 changed files with 62 additions and 23 deletions
|
@ -9,6 +9,23 @@ struct beacon_bc_data {
|
|||
int count[MT7603_MAX_INTERFACES];
|
||||
};
|
||||
|
||||
static void
|
||||
mt7603_mac_stuck_beacon_recovery(struct mt7603_dev *dev)
|
||||
{
|
||||
if (dev->beacon_check % 5 != 4)
|
||||
return;
|
||||
|
||||
mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN);
|
||||
mt76_set(dev, MT_SCH_4, MT_SCH_4_RESET);
|
||||
mt76_clear(dev, MT_SCH_4, MT_SCH_4_RESET);
|
||||
mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_EN);
|
||||
|
||||
mt76_set(dev, MT_WF_CFG_OFF_WOCCR, MT_WF_CFG_OFF_WOCCR_TMAC_GC_DIS);
|
||||
mt76_set(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE);
|
||||
mt76_clear(dev, MT_ARB_SCR, MT_ARB_SCR_TX_DISABLE);
|
||||
mt76_clear(dev, MT_WF_CFG_OFF_WOCCR, MT_WF_CFG_OFF_WOCCR_TMAC_GC_DIS);
|
||||
}
|
||||
|
||||
static void
|
||||
mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
|
@ -16,6 +33,8 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
|||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
|
||||
struct sk_buff *skb = NULL;
|
||||
u32 om_idx = mvif->idx;
|
||||
u32 val;
|
||||
|
||||
if (!(mdev->beacon_mask & BIT(mvif->idx)))
|
||||
return;
|
||||
|
@ -24,20 +43,33 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
|||
if (!skb)
|
||||
return;
|
||||
|
||||
if (om_idx)
|
||||
om_idx |= 0x10;
|
||||
val = MT_DMA_FQCR0_BUSY | MT_DMA_FQCR0_MODE |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_BSS, om_idx) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8);
|
||||
|
||||
spin_lock_bh(&dev->ps_lock);
|
||||
|
||||
mt76_wr(dev, MT_DMA_FQCR0, val |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, MT_TX_HW_QUEUE_BCN));
|
||||
if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) {
|
||||
dev->beacon_check = MT7603_WATCHDOG_TIMEOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mt76_wr(dev, MT_DMA_FQCR0, val |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, MT_TX_HW_QUEUE_BMC));
|
||||
if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) {
|
||||
dev->beacon_check = MT7603_WATCHDOG_TIMEOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mt76_tx_queue_skb(dev, dev->mphy.q_tx[MT_TXQ_BEACON],
|
||||
MT_TXQ_BEACON, skb, &mvif->sta.wcid, NULL);
|
||||
|
||||
spin_lock_bh(&dev->ps_lock);
|
||||
mt76_wr(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_WCID, mvif->sta.wcid.idx) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_TARGET_QID,
|
||||
dev->mphy.q_tx[MT_TXQ_CAB]->hw_idx) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_DEST_PORT_ID, 3) |
|
||||
FIELD_PREP(MT_DMA_FQCR0_DEST_QUEUE_ID, 8));
|
||||
|
||||
if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000))
|
||||
dev->beacon_check = MT7603_WATCHDOG_TIMEOUT;
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&dev->ps_lock);
|
||||
}
|
||||
|
||||
|
@ -81,6 +113,18 @@ void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t)
|
|||
data.dev = dev;
|
||||
__skb_queue_head_init(&data.q);
|
||||
|
||||
/* Flush all previous CAB queue packets and beacons */
|
||||
mt76_wr(dev, MT_WF_ARB_CAB_FLUSH, GENMASK(30, 16) | BIT(0));
|
||||
|
||||
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_CAB], false);
|
||||
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BEACON], false);
|
||||
|
||||
if (dev->mphy.q_tx[MT_TXQ_BEACON]->queued > 0)
|
||||
dev->beacon_check++;
|
||||
else
|
||||
dev->beacon_check = 0;
|
||||
mt7603_mac_stuck_beacon_recovery(dev);
|
||||
|
||||
q = dev->mphy.q_tx[MT_TXQ_BEACON];
|
||||
spin_lock(&q->lock);
|
||||
ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev),
|
||||
|
@ -89,14 +133,9 @@ void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t)
|
|||
mt76_queue_kick(dev, q);
|
||||
spin_unlock(&q->lock);
|
||||
|
||||
/* Flush all previous CAB queue packets */
|
||||
mt76_wr(dev, MT_WF_ARB_CAB_FLUSH, GENMASK(30, 16) | BIT(0));
|
||||
|
||||
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_CAB], false);
|
||||
|
||||
mt76_csa_check(mdev);
|
||||
if (mdev->csa_complete)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
q = dev->mphy.q_tx[MT_TXQ_CAB];
|
||||
do {
|
||||
|
@ -108,7 +147,7 @@ void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t)
|
|||
skb_queue_len(&data.q) < 8);
|
||||
|
||||
if (skb_queue_empty(&data.q))
|
||||
goto out;
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(data.tail); i++) {
|
||||
if (!data.tail[i])
|
||||
|
@ -136,11 +175,6 @@ void mt7603_pre_tbtt_tasklet(struct tasklet_struct *t)
|
|||
MT_WF_ARB_CAB_START_BSSn(0) |
|
||||
(MT_WF_ARB_CAB_START_BSS0n(1) *
|
||||
((1 << (MT7603_MAX_INTERFACES - 1)) - 1)));
|
||||
|
||||
out:
|
||||
mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[MT_TXQ_BEACON], false);
|
||||
if (dev->mphy.q_tx[MT_TXQ_BEACON]->queued > hweight8(mdev->beacon_mask))
|
||||
dev->beacon_check++;
|
||||
}
|
||||
|
||||
void mt7603_beacon_set_timer(struct mt7603_dev *dev, int idx, int intval)
|
||||
|
|
|
@ -462,6 +462,11 @@ enum {
|
|||
#define MT_WF_SEC_BASE 0x21a00
|
||||
#define MT_WF_SEC(ofs) (MT_WF_SEC_BASE + (ofs))
|
||||
|
||||
#define MT_WF_CFG_OFF_BASE 0x21e00
|
||||
#define MT_WF_CFG_OFF(ofs) (MT_WF_CFG_OFF_BASE + (ofs))
|
||||
#define MT_WF_CFG_OFF_WOCCR MT_WF_CFG_OFF(0x004)
|
||||
#define MT_WF_CFG_OFF_WOCCR_TMAC_GC_DIS BIT(4)
|
||||
|
||||
#define MT_SEC_SCR MT_WF_SEC(0x004)
|
||||
#define MT_SEC_SCR_MASK_ORDER GENMASK(1, 0)
|
||||
|
||||
|
|
Loading…
Reference in a new issue