mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 23:52:08 +02:00
wifi: mt76: mt7996: improve hardware restart reliability
Port latest version of similar changes from mt7915: - use reconfig_complete to restart mac_work / queues - clear wcid and vif mask to avoid leak - fix sta poll list corruption - reset station links - reset interface links - clear rro list Link: https://patch.msgid.link/20250915075910.47558-2-nbd@nbd.name Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
parent
0a5df0ec47
commit
ace5d3b6b4
|
|
@ -2355,11 +2355,59 @@ mt7996_mac_restart(struct mt7996_dev *dev)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta)
|
||||||
|
{
|
||||||
|
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
|
||||||
|
struct mt7996_dev *dev = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(msta->link); i++) {
|
||||||
|
struct mt7996_sta_link *msta_link = NULL;
|
||||||
|
|
||||||
|
msta_link = rcu_replace_pointer(msta->link[i], msta_link,
|
||||||
|
lockdep_is_held(&dev->mt76.mutex));
|
||||||
|
if (!msta_link)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
mt7996_mac_sta_deinit_link(dev, msta_link);
|
||||||
|
|
||||||
|
if (msta->deflink_id == i) {
|
||||||
|
msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
kfree_rcu(msta_link, rcu_head);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mt7996_mac_reset_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||||
|
{
|
||||||
|
struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv;
|
||||||
|
struct mt76_vif_data *mvif = mlink->mvif;
|
||||||
|
struct mt7996_dev *dev = data;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
for (i = 0; i < ARRAY_SIZE(mvif->link); i++) {
|
||||||
|
|
||||||
|
mlink = mt76_dereference(mvif->link[i], &dev->mt76);
|
||||||
|
if (!mlink || mlink == (struct mt76_vif_link *)vif->drv_priv)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rcu_assign_pointer(mvif->link[i], NULL);
|
||||||
|
kfree_rcu(mlink, rcu_head);
|
||||||
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mt7996_mac_full_reset(struct mt7996_dev *dev)
|
mt7996_mac_full_reset(struct mt7996_dev *dev)
|
||||||
{
|
{
|
||||||
struct ieee80211_hw *hw = mt76_hw(dev);
|
struct ieee80211_hw *hw = mt76_hw(dev);
|
||||||
struct mt7996_phy *phy;
|
struct mt7996_phy *phy;
|
||||||
|
LIST_HEAD(list);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
dev->recovery.hw_full_reset = true;
|
dev->recovery.hw_full_reset = true;
|
||||||
|
|
@ -2376,18 +2424,42 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
|
||||||
if (!mt7996_mac_restart(dev))
|
if (!mt7996_mac_restart(dev))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mutex_unlock(&dev->mt76.mutex);
|
|
||||||
|
|
||||||
if (i == 10)
|
if (i == 10)
|
||||||
dev_err(dev->mt76.dev, "chip full reset failed\n");
|
dev_err(dev->mt76.dev, "chip full reset failed\n");
|
||||||
|
|
||||||
ieee80211_restart_hw(mt76_hw(dev));
|
|
||||||
ieee80211_wake_queues(mt76_hw(dev));
|
|
||||||
|
|
||||||
dev->recovery.hw_full_reset = false;
|
|
||||||
mt7996_for_each_phy(dev, phy)
|
mt7996_for_each_phy(dev, phy)
|
||||||
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
|
phy->omac_mask = 0;
|
||||||
MT7996_WATCHDOG_TIME);
|
|
||||||
|
ieee80211_iterate_stations_atomic(hw, mt7996_mac_reset_sta_iter, dev);
|
||||||
|
ieee80211_iterate_active_interfaces_atomic(hw,
|
||||||
|
IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER,
|
||||||
|
mt7996_mac_reset_vif_iter, dev);
|
||||||
|
mt76_reset_device(&dev->mt76);
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&dev->sta_rc_list);
|
||||||
|
INIT_LIST_HEAD(&dev->twt_list);
|
||||||
|
|
||||||
|
spin_lock_bh(&dev->wed_rro.lock);
|
||||||
|
list_splice_init(&dev->wed_rro.poll_list, &list);
|
||||||
|
spin_unlock_bh(&dev->wed_rro.lock);
|
||||||
|
|
||||||
|
while (!list_empty(&list)) {
|
||||||
|
struct mt7996_wed_rro_session_id *e;
|
||||||
|
|
||||||
|
e = list_first_entry(&list, struct mt7996_wed_rro_session_id,
|
||||||
|
list);
|
||||||
|
list_del_init(&e->list);
|
||||||
|
kfree(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
|
||||||
|
dev->mt76.global_wcid.idx = i;
|
||||||
|
dev->recovery.hw_full_reset = false;
|
||||||
|
|
||||||
|
mutex_unlock(&dev->mt76.mutex);
|
||||||
|
|
||||||
|
ieee80211_restart_hw(mt76_hw(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mt7996_mac_reset_work(struct work_struct *work)
|
void mt7996_mac_reset_work(struct work_struct *work)
|
||||||
|
|
|
||||||
|
|
@ -986,13 +986,9 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
|
||||||
mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
|
struct mt7996_sta_link *msta_link)
|
||||||
struct mt7996_sta_link *msta_link)
|
|
||||||
{
|
{
|
||||||
mt7996_mac_wtbl_update(dev, msta_link->wcid.idx,
|
|
||||||
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
|
||||||
|
|
||||||
spin_lock_bh(&dev->mt76.sta_poll_lock);
|
spin_lock_bh(&dev->mt76.sta_poll_lock);
|
||||||
if (!list_empty(&msta_link->wcid.poll_list))
|
if (!list_empty(&msta_link->wcid.poll_list))
|
||||||
list_del_init(&msta_link->wcid.poll_list);
|
list_del_init(&msta_link->wcid.poll_list);
|
||||||
|
|
@ -1022,6 +1018,9 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
|
||||||
if (!msta_link)
|
if (!msta_link)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
mt7996_mac_wtbl_update(dev, msta_link->wcid.idx,
|
||||||
|
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
|
||||||
|
|
||||||
mt7996_mac_sta_deinit_link(dev, msta_link);
|
mt7996_mac_sta_deinit_link(dev, msta_link);
|
||||||
link = mt7996_vif_link(dev, vif, link_id);
|
link = mt7996_vif_link(dev, vif, link_id);
|
||||||
if (!link)
|
if (!link)
|
||||||
|
|
@ -2206,6 +2205,19 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mt7996_reconfig_complete(struct ieee80211_hw *hw,
|
||||||
|
enum ieee80211_reconfig_type reconfig_type)
|
||||||
|
{
|
||||||
|
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||||
|
struct mt7996_phy *phy;
|
||||||
|
|
||||||
|
ieee80211_wake_queues(hw);
|
||||||
|
mt7996_for_each_phy(dev, phy)
|
||||||
|
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
|
||||||
|
MT7996_WATCHDOG_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
const struct ieee80211_ops mt7996_ops = {
|
const struct ieee80211_ops mt7996_ops = {
|
||||||
.add_chanctx = mt76_add_chanctx,
|
.add_chanctx = mt76_add_chanctx,
|
||||||
.remove_chanctx = mt76_remove_chanctx,
|
.remove_chanctx = mt76_remove_chanctx,
|
||||||
|
|
@ -2264,4 +2276,5 @@ const struct ieee80211_ops mt7996_ops = {
|
||||||
#endif
|
#endif
|
||||||
.change_vif_links = mt7996_change_vif_links,
|
.change_vif_links = mt7996_change_vif_links,
|
||||||
.change_sta_links = mt7996_mac_sta_change_links,
|
.change_sta_links = mt7996_mac_sta_change_links,
|
||||||
|
.reconfig_complete = mt7996_reconfig_complete,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -817,6 +817,8 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
|
||||||
struct mt7996_vif_link *link,
|
struct mt7996_vif_link *link,
|
||||||
struct mt7996_sta_link *msta_link,
|
struct mt7996_sta_link *msta_link,
|
||||||
u8 flowid);
|
u8 flowid);
|
||||||
|
void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev,
|
||||||
|
struct mt7996_sta_link *msta_link);
|
||||||
void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
|
void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
|
||||||
struct ieee80211_sta *sta,
|
struct ieee80211_sta *sta,
|
||||||
struct ieee80211_twt_setup *twt);
|
struct ieee80211_twt_setup *twt);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user