mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-07 23:20:32 -04:00
Merge tag 'mt76-fixes-2025-08-27' of https://github.com/nbd168/wireless
Felix Fietkay says: =================== mt76 fixes for 6.17 - fix regressions from mt7996 MLO support rework - fix offchannel handling issues on mt7996 - mt792x fixes - fix multiple wcid linked list corruption issues =================== Change-Id: Ib3e9a3217a40b9da69e122514d47fa46699c864b Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
@@ -818,6 +818,43 @@ void mt76_free_device(struct mt76_dev *dev)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_free_device);
|
||||
|
||||
static void mt76_reset_phy(struct mt76_phy *phy)
|
||||
{
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
INIT_LIST_HEAD(&phy->tx_list);
|
||||
}
|
||||
|
||||
void mt76_reset_device(struct mt76_dev *dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
rcu_read_lock();
|
||||
for (i = 0; i < ARRAY_SIZE(dev->wcid); i++) {
|
||||
struct mt76_wcid *wcid;
|
||||
|
||||
wcid = rcu_dereference(dev->wcid[i]);
|
||||
if (!wcid)
|
||||
continue;
|
||||
|
||||
wcid->sta = 0;
|
||||
mt76_wcid_cleanup(dev, wcid);
|
||||
rcu_assign_pointer(dev->wcid[i], NULL);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
INIT_LIST_HEAD(&dev->wcid_list);
|
||||
INIT_LIST_HEAD(&dev->sta_poll_list);
|
||||
dev->vif_mask = 0;
|
||||
memset(dev->wcid_mask, 0, sizeof(dev->wcid_mask));
|
||||
|
||||
mt76_reset_phy(&dev->phy);
|
||||
for (i = 0; i < ARRAY_SIZE(dev->phys); i++)
|
||||
mt76_reset_phy(dev->phys[i]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt76_reset_device);
|
||||
|
||||
struct mt76_phy *mt76_vif_phy(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
@@ -1679,6 +1716,10 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
|
||||
skb_queue_splice_tail_init(&wcid->tx_pending, &list);
|
||||
spin_unlock(&wcid->tx_pending.lock);
|
||||
|
||||
spin_lock(&wcid->tx_offchannel.lock);
|
||||
skb_queue_splice_tail_init(&wcid->tx_offchannel, &list);
|
||||
spin_unlock(&wcid->tx_offchannel.lock);
|
||||
|
||||
spin_unlock_bh(&phy->tx_lock);
|
||||
|
||||
while ((skb = __skb_dequeue(&list)) != NULL) {
|
||||
@@ -1690,7 +1731,7 @@ EXPORT_SYMBOL_GPL(mt76_wcid_cleanup);
|
||||
|
||||
void mt76_wcid_add_poll(struct mt76_dev *dev, struct mt76_wcid *wcid)
|
||||
{
|
||||
if (test_bit(MT76_MCU_RESET, &dev->phy.state))
|
||||
if (test_bit(MT76_MCU_RESET, &dev->phy.state) || !wcid->sta)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&dev->sta_poll_lock);
|
||||
|
||||
@@ -1243,6 +1243,7 @@ int mt76_register_device(struct mt76_dev *dev, bool vht,
|
||||
struct ieee80211_rate *rates, int n_rates);
|
||||
void mt76_unregister_device(struct mt76_dev *dev);
|
||||
void mt76_free_device(struct mt76_dev *dev);
|
||||
void mt76_reset_device(struct mt76_dev *dev);
|
||||
void mt76_unregister_phy(struct mt76_phy *phy);
|
||||
|
||||
struct mt76_phy *mt76_alloc_radio_phy(struct mt76_dev *dev, unsigned int size,
|
||||
|
||||
@@ -1460,17 +1460,15 @@ mt7915_mac_full_reset(struct mt7915_dev *dev)
|
||||
if (i == 10)
|
||||
dev_err(dev->mt76.dev, "chip full reset failed\n");
|
||||
|
||||
spin_lock_bh(&dev->mt76.sta_poll_lock);
|
||||
while (!list_empty(&dev->mt76.sta_poll_list))
|
||||
list_del_init(dev->mt76.sta_poll_list.next);
|
||||
spin_unlock_bh(&dev->mt76.sta_poll_lock);
|
||||
|
||||
memset(dev->mt76.wcid_mask, 0, sizeof(dev->mt76.wcid_mask));
|
||||
dev->mt76.vif_mask = 0;
|
||||
dev->phy.omac_mask = 0;
|
||||
if (phy2)
|
||||
phy2->omac_mask = 0;
|
||||
|
||||
mt76_reset_device(&dev->mt76);
|
||||
|
||||
INIT_LIST_HEAD(&dev->sta_rc_list);
|
||||
INIT_LIST_HEAD(&dev->twt_list);
|
||||
|
||||
i = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
|
||||
dev->mt76.global_wcid.idx = i;
|
||||
dev->recovery.hw_full_reset = false;
|
||||
|
||||
@@ -1459,11 +1459,8 @@ static int mt7921_pre_channel_switch(struct ieee80211_hw *hw,
|
||||
if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Avoid beacon loss due to the CAC(Channel Availability Check) time
|
||||
* of the AP.
|
||||
*/
|
||||
if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef,
|
||||
IEEE80211_CHAN_RADAR))
|
||||
IEEE80211_CHAN_DISABLED))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -1449,7 +1449,7 @@ void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
|
||||
sta = wcid_to_sta(wcid);
|
||||
|
||||
if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||
mt76_connac2_tx_check_aggr(sta, txwi);
|
||||
mt7925_tx_check_aggr(sta, e->skb, wcid);
|
||||
|
||||
skb_pull(e->skb, headroom);
|
||||
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
|
||||
|
||||
@@ -1191,6 +1191,9 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
|
||||
struct mt792x_bss_conf *mconf;
|
||||
struct mt792x_link_sta *mlink;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
break;
|
||||
|
||||
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
|
||||
if (!link_sta)
|
||||
continue;
|
||||
@@ -2069,8 +2072,10 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
GFP_KERNEL);
|
||||
mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink),
|
||||
GFP_KERNEL);
|
||||
if (!mconf || !mlink)
|
||||
if (!mconf || !mlink) {
|
||||
mt792x_mutex_release(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
mconfs[link_id] = mconf;
|
||||
|
||||
@@ -1834,13 +1834,13 @@ mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb,
|
||||
struct tlv *tlv;
|
||||
u16 eml_cap;
|
||||
|
||||
if (!ieee80211_vif_is_mld(vif))
|
||||
return;
|
||||
|
||||
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld));
|
||||
eht_mld = (struct sta_rec_eht_mld *)tlv;
|
||||
eht_mld->mld_type = 0xff;
|
||||
|
||||
if (!ieee80211_vif_is_mld(vif))
|
||||
return;
|
||||
|
||||
ext_capa = cfg80211_get_iftype_ext_capa(wiphy,
|
||||
ieee80211_vif_type_p2p(vif));
|
||||
if (!ext_capa)
|
||||
@@ -1912,6 +1912,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
|
||||
struct mt76_dev *dev = phy->dev;
|
||||
struct mt792x_bss_conf *mconf;
|
||||
struct sk_buff *skb;
|
||||
int conn_state;
|
||||
|
||||
mconf = mt792x_vif_to_link(mvif, info->wcid->link_id);
|
||||
|
||||
@@ -1920,10 +1921,13 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
|
||||
if (IS_ERR(skb))
|
||||
return PTR_ERR(skb);
|
||||
|
||||
conn_state = info->enable ? CONN_STATE_PORT_SECURE :
|
||||
CONN_STATE_DISCONNECT;
|
||||
|
||||
if (info->enable && info->link_sta) {
|
||||
mt76_connac_mcu_sta_basic_tlv(dev, skb, info->link_conf,
|
||||
info->link_sta,
|
||||
info->enable, info->newly);
|
||||
conn_state, info->newly);
|
||||
mt7925_mcu_sta_phy_tlv(skb, info->vif, info->link_sta);
|
||||
mt7925_mcu_sta_ht_tlv(skb, info->link_sta);
|
||||
mt7925_mcu_sta_vht_tlv(skb, info->link_sta);
|
||||
|
||||
@@ -62,7 +62,7 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
|
||||
int i;
|
||||
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
if (!wcid)
|
||||
if (!wcid || !wcid->sta)
|
||||
return NULL;
|
||||
|
||||
if (!mt7996_band_valid(dev, band_idx))
|
||||
@@ -903,8 +903,12 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
|
||||
IEEE80211_TX_CTRL_MLO_LINK);
|
||||
|
||||
mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
|
||||
if (mvif)
|
||||
mlink = rcu_dereference(mvif->mt76.link[link_id]);
|
||||
if (mvif) {
|
||||
if (wcid->offchannel)
|
||||
mlink = rcu_dereference(mvif->mt76.offchannel_link);
|
||||
if (!mlink)
|
||||
mlink = rcu_dereference(mvif->mt76.link[link_id]);
|
||||
}
|
||||
|
||||
if (mlink) {
|
||||
omac_idx = mlink->omac_idx;
|
||||
@@ -1243,8 +1247,10 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
|
||||
idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
|
||||
wcid = mt76_wcid_ptr(dev, idx);
|
||||
sta = wcid_to_sta(wcid);
|
||||
if (!sta)
|
||||
if (!sta) {
|
||||
link_sta = NULL;
|
||||
goto next;
|
||||
}
|
||||
|
||||
link_sta = rcu_dereference(sta->link[wcid->link_id]);
|
||||
if (!link_sta)
|
||||
@@ -1694,17 +1700,37 @@ mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
|
||||
static void
|
||||
mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_hw *hw = priv;
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
struct mt7996_phy *phy = priv;
|
||||
struct mt7996_dev *dev = phy->dev;
|
||||
unsigned int link_id;
|
||||
|
||||
|
||||
switch (vif->type) {
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
case NL80211_IFTYPE_AP:
|
||||
mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_vif_active_link(vif, link_conf, link_id) {
|
||||
struct mt7996_vif_link *link;
|
||||
|
||||
link = mt7996_vif_link(dev, vif, link_id);
|
||||
if (!link || link->phy != phy)
|
||||
continue;
|
||||
|
||||
mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf);
|
||||
}
|
||||
}
|
||||
|
||||
void mt7996_mac_update_beacons(struct mt7996_phy *phy)
|
||||
{
|
||||
ieee80211_iterate_active_interfaces(phy->mt76->hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7996_update_vif_beacon, phy);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1712,25 +1738,15 @@ mt7996_update_beacons(struct mt7996_dev *dev)
|
||||
{
|
||||
struct mt76_phy *phy2, *phy3;
|
||||
|
||||
ieee80211_iterate_active_interfaces(dev->mt76.hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7996_update_vif_beacon, dev->mt76.hw);
|
||||
mt7996_mac_update_beacons(&dev->phy);
|
||||
|
||||
phy2 = dev->mt76.phys[MT_BAND1];
|
||||
if (!phy2)
|
||||
return;
|
||||
|
||||
ieee80211_iterate_active_interfaces(phy2->hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7996_update_vif_beacon, phy2->hw);
|
||||
if (phy2)
|
||||
mt7996_mac_update_beacons(phy2->priv);
|
||||
|
||||
phy3 = dev->mt76.phys[MT_BAND2];
|
||||
if (!phy3)
|
||||
return;
|
||||
|
||||
ieee80211_iterate_active_interfaces(phy3->hw,
|
||||
IEEE80211_IFACE_ITER_RESUME_ALL,
|
||||
mt7996_update_vif_beacon, phy3->hw);
|
||||
if (phy3)
|
||||
mt7996_mac_update_beacons(phy3->priv);
|
||||
}
|
||||
|
||||
void mt7996_tx_token_put(struct mt7996_dev *dev)
|
||||
|
||||
@@ -516,6 +516,9 @@ int mt7996_set_channel(struct mt76_phy *mphy)
|
||||
struct mt7996_phy *phy = mphy->priv;
|
||||
int ret;
|
||||
|
||||
if (mphy->offchannel)
|
||||
mt7996_mac_update_beacons(phy);
|
||||
|
||||
ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -533,6 +536,8 @@ int mt7996_set_channel(struct mt76_phy *mphy)
|
||||
|
||||
mt7996_mac_reset_counters(phy);
|
||||
phy->noise = 0;
|
||||
if (!mphy->offchannel)
|
||||
mt7996_mac_update_beacons(phy);
|
||||
|
||||
out:
|
||||
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
|
||||
|
||||
@@ -1879,8 +1879,8 @@ mt7996_mcu_get_mmps_mode(enum ieee80211_smps_mode smps)
|
||||
int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
|
||||
void *data, u16 version)
|
||||
{
|
||||
struct uni_header hdr = {};
|
||||
struct ra_fixed_rate *req;
|
||||
struct uni_header hdr;
|
||||
struct sk_buff *skb;
|
||||
struct tlv *tlv;
|
||||
int len;
|
||||
@@ -2755,13 +2755,15 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf)
|
||||
{
|
||||
struct mt7996_dev *dev = mt7996_hw_dev(hw);
|
||||
struct mt76_vif_link *mlink = mt76_vif_conf_link(&dev->mt76, vif, link_conf);
|
||||
struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf);
|
||||
struct mt76_vif_link *mlink = link ? &link->mt76 : NULL;
|
||||
struct ieee80211_mutable_offsets offs;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct sk_buff *skb, *rskb;
|
||||
struct tlv *tlv;
|
||||
struct bss_bcn_content_tlv *bcn;
|
||||
int len, extra_len = 0;
|
||||
bool enabled = link_conf->enable_beacon;
|
||||
|
||||
if (link_conf->nontransmitted)
|
||||
return 0;
|
||||
@@ -2769,13 +2771,16 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
if (!mlink)
|
||||
return -EINVAL;
|
||||
|
||||
if (link->phy && link->phy->mt76->offchannel)
|
||||
enabled = false;
|
||||
|
||||
rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink,
|
||||
MT7996_MAX_BSS_OFFLOAD_SIZE);
|
||||
if (IS_ERR(rskb))
|
||||
return PTR_ERR(rskb);
|
||||
|
||||
skb = ieee80211_beacon_get_template(hw, vif, &offs, link_conf->link_id);
|
||||
if (link_conf->enable_beacon && !skb) {
|
||||
if (enabled && !skb) {
|
||||
dev_kfree_skb(rskb);
|
||||
return -EINVAL;
|
||||
}
|
||||
@@ -2794,7 +2799,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
len = ALIGN(sizeof(*bcn) + MT_TXD_SIZE + extra_len, 4);
|
||||
tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_CONTENT, len);
|
||||
bcn = (struct bss_bcn_content_tlv *)tlv;
|
||||
bcn->enable = link_conf->enable_beacon;
|
||||
bcn->enable = enabled;
|
||||
if (!bcn->enable)
|
||||
goto out;
|
||||
|
||||
@@ -3372,7 +3377,7 @@ int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans)
|
||||
{
|
||||
struct {
|
||||
u8 __rsv[4];
|
||||
} __packed hdr;
|
||||
} __packed hdr = {};
|
||||
struct hdr_trans_blacklist *req_blacklist;
|
||||
struct hdr_trans_en *req_en;
|
||||
struct sk_buff *skb;
|
||||
|
||||
@@ -732,6 +732,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
|
||||
struct sk_buff *skb, struct mt76_wcid *wcid,
|
||||
struct ieee80211_key_conf *key, int pid,
|
||||
enum mt76_txq_id qid, u32 changed);
|
||||
void mt7996_mac_update_beacons(struct mt7996_phy *phy);
|
||||
void mt7996_mac_set_coverage_class(struct mt7996_phy *phy);
|
||||
void mt7996_mac_work(struct work_struct *work);
|
||||
void mt7996_mac_reset_work(struct work_struct *work);
|
||||
|
||||
@@ -332,6 +332,7 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
|
||||
struct mt76_wcid *wcid, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct sk_buff_head *head;
|
||||
|
||||
if (mt76_testmode_enabled(phy)) {
|
||||
@@ -349,7 +350,8 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
|
||||
info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->band_idx);
|
||||
|
||||
if ((info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ||
|
||||
(info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK))
|
||||
((info->control.flags & IEEE80211_TX_CTRL_DONT_USE_RATE_MASK) &&
|
||||
ieee80211_is_probe_req(hdr->frame_control)))
|
||||
head = &wcid->tx_offchannel;
|
||||
else
|
||||
head = &wcid->tx_pending;
|
||||
@@ -644,6 +646,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid,
|
||||
static void mt76_txq_schedule_pending(struct mt76_phy *phy)
|
||||
{
|
||||
LIST_HEAD(tx_list);
|
||||
int ret = 0;
|
||||
|
||||
if (list_empty(&phy->tx_list))
|
||||
return;
|
||||
@@ -655,13 +658,13 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy)
|
||||
list_splice_init(&phy->tx_list, &tx_list);
|
||||
while (!list_empty(&tx_list)) {
|
||||
struct mt76_wcid *wcid;
|
||||
int ret;
|
||||
|
||||
wcid = list_first_entry(&tx_list, struct mt76_wcid, tx_list);
|
||||
list_del_init(&wcid->tx_list);
|
||||
|
||||
spin_unlock(&phy->tx_lock);
|
||||
ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel);
|
||||
if (ret >= 0)
|
||||
ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_offchannel);
|
||||
if (ret >= 0 && !phy->offchannel)
|
||||
ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending);
|
||||
spin_lock(&phy->tx_lock);
|
||||
@@ -670,9 +673,6 @@ static void mt76_txq_schedule_pending(struct mt76_phy *phy)
|
||||
!skb_queue_empty(&wcid->tx_offchannel) &&
|
||||
list_empty(&wcid->tx_list))
|
||||
list_add_tail(&wcid->tx_list, &phy->tx_list);
|
||||
|
||||
if (ret < 0)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&phy->tx_lock);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user