Commit fd6c2dfa authored by Felix Fietkau's avatar Felix Fietkau
Browse files

mt76: mt76x02: fix handling MCU timeouts during hw restart



If a MCU timeout occurs before a hw restart completes, another hw restart
is scheduled, and the station state gets corrupted.
To speed up dealing with that, do not issue any MCU commands after the first
timeout, and defer handling timeouts until the reset has completed.
Also ignore errors in MCU commands during start/config to avoid making user
space fail on this condition. If it happens, another restart is scheduled
quickly, and that usually recovers the hardware properly.

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 5bb4e125
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -275,6 +275,7 @@ enum {
	MT76_STATE_RUNNING,
	MT76_STATE_MCU_RUNNING,
	MT76_SCANNING,
	MT76_RESTART,
	MT76_RESET,
	MT76_MCU_RESET,
	MT76_REMOVED,
+2 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@ static void mt76x0e_stop_hw(struct mt76x02_dev *dev)
{
	cancel_delayed_work_sync(&dev->cal_work);
	cancel_delayed_work_sync(&dev->mt76.mac_work);
	clear_bit(MT76_RESTART, &dev->mphy.state);

	if (!mt76_poll(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_TX_DMA_BUSY,
		       0, 1000))
@@ -83,6 +84,7 @@ static const struct ieee80211_ops mt76x0e_ops = {
	.set_coverage_class = mt76x02_set_coverage_class,
	.set_rts_threshold = mt76x02_set_rts_threshold,
	.get_antenna = mt76_get_antenna,
	.reconfig_complete = mt76x02_reconfig_complete,
};

static int mt76x0e_register_device(struct mt76x02_dev *dev)
+2 −0
Original line number Diff line number Diff line
@@ -187,6 +187,8 @@ void mt76x02_sta_ps(struct mt76_dev *dev, struct ieee80211_sta *sta, bool ps);
void mt76x02_bss_info_changed(struct ieee80211_hw *hw,
			      struct ieee80211_vif *vif,
			      struct ieee80211_bss_conf *info, u32 changed);
void mt76x02_reconfig_complete(struct ieee80211_hw *hw,
			       enum ieee80211_reconfig_type reconfig_type);

struct beacon_bc_data {
	struct mt76x02_dev *dev;
+3 −0
Original line number Diff line number Diff line
@@ -20,6 +20,9 @@ int mt76x02_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
	int ret;
	u8 seq;

	if (mt76_is_mmio(&dev->mt76) && dev->mcu_timeout)
		return -EIO;

	skb = mt76x02_mcu_msg_alloc(data, len);
	if (!skb)
		return -ENOMEM;
+16 −0
Original line number Diff line number Diff line
@@ -520,6 +520,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
	}

	if (restart) {
		set_bit(MT76_RESTART, &dev->mphy.state);
		mt76x02_mcu_function_select(dev, Q_SELECT, 1);
		ieee80211_restart_hw(dev->mt76.hw);
	} else {
@@ -528,8 +529,23 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
	}
}

void mt76x02_reconfig_complete(struct ieee80211_hw *hw,
			       enum ieee80211_reconfig_type reconfig_type)
{
	struct mt76x02_dev *dev = hw->priv;

	if (reconfig_type != IEEE80211_RECONFIG_TYPE_RESTART)
		return;

	clear_bit(MT76_RESTART, &dev->mphy.state);
}
EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete);

static void mt76x02_check_tx_hang(struct mt76x02_dev *dev)
{
	if (test_bit(MT76_RESTART, &dev->mphy.state))
		return;

	if (mt76x02_tx_hang(dev)) {
		if (++dev->tx_hang_check >= MT_TX_HANG_TH)
			goto restart;
Loading