summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Wang <sean.wang@mediatek.com>2026-03-07 02:22:38 +0300
committerFelix Fietkau <nbd@nbd.name>2026-03-24 18:49:32 +0300
commit9fc83205a62eeeb775739ba6d8efcfdda9b7780a (patch)
treeb680b1c2befc82d22a714c0e322881b1a2775e81
parentdb134691924fb19535ad6f27e09354c8ad001964 (diff)
downloadlinux-9fc83205a62eeeb775739ba6d8efcfdda9b7780a.tar.xz
wifi: mt76: mt7925: host-only unwind published links on add failure
Release host link resources when mt7925_mac_sta_add_links() fails after partial success. msta->link[] and dev->mt76.wcid[] may already be published, so unwind the host state to avoid leaving stale links behind. Signed-off-by: Sean Wang <sean.wang@mediatek.com> Link: https://patch.msgid.link/20260306232238.2039675-20-sean.wang@kernel.org Signed-off-by: Felix Fietkau <nbd@nbd.name>
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/main.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 95c631b57894..73d3722739d0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -989,11 +989,51 @@ out_wcid:
return ret;
}
+/*
+ * Host-only unwind for sta_add_links() failures.
+ *
+ * If add_links fail due to MCU/firmware timeouts; calling the full remove
+ * path would send more firmware commands and may hang again. So only rollback
+ * host-published state here (msta->link/valid_links, dev->mt76.wcid[idx]) and
+ * free mlink objects (RCU-safe). Firmware state is left for reset/recovery.
+ */
+static void
+mt7925_mac_sta_unwind_links_host(struct mt792x_dev *dev,
+ struct ieee80211_sta *sta,
+ unsigned long links)
+{
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ unsigned int link_id;
+
+ for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct mt792x_link_sta *mlink;
+ u16 idx;
+
+ mlink = rcu_replace_pointer(msta->link[link_id], NULL,
+ lockdep_is_held(&dev->mt76.mutex));
+ if (!mlink)
+ continue;
+
+ msta->valid_links &= ~BIT(link_id);
+ if (msta->deflink_id == link_id)
+ msta->deflink_id = IEEE80211_LINK_UNSPECIFIED;
+
+ idx = mlink->wcid.idx;
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+ mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx);
+
+ if (mlink != &msta->deflink)
+ kfree_rcu(mlink, rcu_head);
+ }
+}
+
static int
mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, unsigned long new_links)
{
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ unsigned long added_links = 0;
unsigned int link_id;
int err = 0;
@@ -1030,8 +1070,13 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
rcu_assign_pointer(msta->link[link_id], mlink);
msta->valid_links |= BIT(link_id);
+
+ added_links |= BIT(link_id);
}
+ if (err && added_links)
+ mt7925_mac_sta_unwind_links_host(dev, sta, added_links);
+
return err;
}