diff options
63 files changed, 2853 insertions, 872 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/Kconfig b/drivers/net/wireless/mediatek/mt76/Kconfig index 2ca96e0527c0..a4ece38f938d 100644 --- a/drivers/net/wireless/mediatek/mt76/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/Kconfig @@ -40,6 +40,7 @@ config MT792x_USB config MT76_NPU tristate depends on NET_AIROHA_NPU=y || MT76_CORE=NET_AIROHA_NPU + depends on NET_AIROHA=y || NET_AIROHA=n || MT76_CORE=NET_AIROHA source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig" source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig" diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c index 28ad7bcaffd4..192276cf19fd 100644 --- a/drivers/net/wireless/mediatek/mt76/channel.c +++ b/drivers/net/wireless/mediatek/mt76/channel.c @@ -41,7 +41,7 @@ int mt76_add_chanctx(struct ieee80211_hw *hw, if (WARN_ON_ONCE(!phy)) return ret; - if (dev->scan.phy == phy) + if (mt76_phy_scanning(phy)) mt76_abort_scan(dev); mutex_lock(&dev->mutex); @@ -66,7 +66,7 @@ void mt76_remove_chanctx(struct ieee80211_hw *hw, if (WARN_ON_ONCE(!phy)) return; - if (dev->scan.phy == phy) + if (mt76_phy_scanning(phy)) mt76_abort_scan(dev); mutex_lock(&dev->mutex); @@ -114,7 +114,7 @@ int mt76_assign_vif_chanctx(struct ieee80211_hw *hw, bool mlink_alloc = false; int ret = 0; - if (dev->scan.vif == vif) + if (dev->scan.vif == vif && mt76_phy_scanning(phy)) mt76_abort_scan(dev); mutex_lock(&dev->mutex); @@ -161,7 +161,7 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, struct mt76_phy *phy = ctx->phy; struct mt76_dev *dev = phy->dev; - if (dev->scan.vif == vif) + if (dev->scan.vif == vif && mt76_phy_scanning(phy)) mt76_abort_scan(dev); mutex_lock(&dev->mutex); @@ -209,7 +209,7 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw, continue; if (phy->chanctx != new_ctx) { - if (dev->scan.phy == phy) + if (mt76_phy_scanning(phy)) mt76_abort_scan(dev); cancel_delayed_work_sync(&phy->mac_work); @@ -295,7 +295,6 @@ struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy, kfree(mlink); return ERR_PTR(ret); } - rcu_assign_pointer(mvif->offchannel_link, mlink); return mlink; } @@ -304,14 +303,10 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, struct mt76_vif_link *mlink) { struct mt76_dev *dev = phy->dev; - struct mt76_vif_data *mvif; if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel) return; - mvif = mlink->mvif; - - rcu_assign_pointer(mvif->offchannel_link, NULL); dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink); kfree_rcu(mlink, rcu_head); } @@ -330,11 +325,13 @@ void mt76_roc_complete(struct mt76_phy *phy) !test_bit(MT76_MCU_RESET, &dev->phy.state)) { __mt76_set_channel(phy, &phy->main_chandef, false); mt76_offchannel_notify(phy, false); + } else { + phy->offchannel = false; } mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); phy->roc_vif = NULL; phy->roc_link = NULL; - if (!test_bit(MT76_MCU_RESET, &dev->phy.state)) + if (!test_bit(MT76_RESTART, &dev->phy.state)) ieee80211_remain_on_channel_expired(phy->hw); } @@ -379,8 +376,9 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mutex); - if (phy->roc_vif || dev->scan.phy == phy || - test_bit(MT76_MCU_RESET, &dev->phy.state)) { + if (phy->roc_vif || mt76_phy_scanning(phy) || + test_bit(MT76_MCU_RESET, &dev->phy.state) || + test_bit(MT76_RESTART, &dev->phy.state)) { ret = -EBUSY; goto out; } @@ -423,7 +421,7 @@ int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw, struct mt76_vif_data *mvif = mlink->mvif; struct mt76_phy *phy = mvif->roc_phy; - if (!phy) + if (!phy || phy->roc_vif != vif) return 0; mt76_abort_roc(phy); diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index afdb73661866..93552f6f7f34 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -231,12 +231,14 @@ mt76_find_power_limits_node(struct mt76_dev *dev) struct property *regd = of_find_property(cur, "regdomain", NULL); if (!country && !regd) { - fallback = cur; + of_node_put(fallback); + fallback = of_node_get(cur); continue; } if (mt76_string_prop_find(country, dev->alpha2) || mt76_string_prop_find(regd, region_name)) { + of_node_put(fallback); of_node_put(np); return cur; } @@ -429,7 +431,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, s8 target_power) { struct mt76_dev *dev = phy->dev; - struct device_node *np; + struct device_node *np, *band_np; const s8 *val; char name[16]; char band; @@ -459,15 +461,18 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, band = '6'; break; default: + of_node_put(np); return target_power; } snprintf(name, sizeof(name), "txpower-%cg", band); - np = of_get_child_by_name(np, name); - if (!np) + band_np = of_get_child_by_name(np, name); + of_node_put(np); + if (!band_np) return target_power; - np = mt76_find_channel_node(np, chan); + np = mt76_find_channel_node(band_np, chan); + of_node_put(band_np); if (!np) return target_power; @@ -514,6 +519,8 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, ARRAY_SIZE(dest->path.ru_bf), val, len, target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); + of_node_put(np); + return max_power; } EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits); diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index cda5c5d51aab..c9762082f473 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -432,6 +432,7 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) INIT_LIST_HEAD(&phy->tx_list); spin_lock_init(&phy->tx_lock); INIT_DELAYED_WORK(&phy->roc_work, mt76_roc_complete_work); + INIT_DELAYED_WORK(&phy->scan_work, mt76_scan_work); if ((void *)phy != hw->priv) return 0; @@ -729,7 +730,6 @@ mt76_alloc_device(struct device *pdev, unsigned int size, INIT_LIST_HEAD(&dev->txwi_cache); INIT_LIST_HEAD(&dev->rxwi_cache); dev->token_size = dev->drv->token_size; - INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work); spin_lock_init(&dev->scan_lock); for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++) @@ -856,8 +856,8 @@ void mt76_reset_device(struct mt76_dev *dev) continue; wcid->sta = 0; - mt76_wcid_cleanup(dev, wcid); rcu_assign_pointer(dev->wcid[i], NULL); + mt76_wcid_cleanup(dev, wcid); } rcu_read_unlock(); @@ -1045,6 +1045,20 @@ void mt76_update_survey(struct mt76_phy *phy) } EXPORT_SYMBOL_GPL(mt76_update_survey); +void mt76_phy_chandef_set(struct mt76_phy *phy, + struct cfg80211_chan_def *chandef) +{ + if (!chandef->chan) + return; + + mt76_update_survey(phy); + + phy->chandef = *chandef; + phy->main_chandef = *chandef; + phy->chan_state = mt76_channel_state(phy, chandef->chan); +} +EXPORT_SYMBOL_GPL(mt76_phy_chandef_set); + int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, bool offchannel) { @@ -1283,7 +1297,6 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb, status->rate_idx = mstat.rate_idx; status->nss = mstat.nss; status->band = mstat.band; - status->signal = mstat.signal; status->chains = mstat.chains; status->ampdu_reference = mstat.ampdu_ref; status->device_timestamp = mstat.timestamp; @@ -1471,6 +1484,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) struct ieee80211_hw *hw; struct mt76_wcid *wcid = status->wcid; u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK; + int signal; bool ps; hw = mt76_phy_hw(dev, status->phy_idx); @@ -1488,8 +1502,9 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb) sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv); - if (status->signal <= 0) - ewma_signal_add(&wcid->rssi, -status->signal); + signal = mt76_rx_signal(status->chains, status->chain_signal); + if (signal <= 0 && signal > -128) + ewma_signal_add(&wcid->rssi, -signal); wcid->inactive_count = 0; @@ -1747,9 +1762,8 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) mt76_tx_status_lock(dev, &list); mt76_tx_status_skb_get(dev, wcid, -1, &list); - mt76_tx_status_unlock(dev, &list); - idr_destroy(&wcid->pktid); + mt76_tx_status_unlock(dev, &list); /* Remove from sta_poll_list to prevent list corruption after reset. * Without this, mt76_reset_device() reinitializes sta_poll_list but @@ -2110,7 +2124,7 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif) rcu_assign_pointer(mvif->link[0], NULL); mt76_abort_scan(dev); - if (mvif->roc_phy) + if (mvif->roc_phy && mvif->roc_phy->roc_vif == vif) mt76_abort_roc(mvif->roc_phy); } EXPORT_SYMBOL_GPL(mt76_vif_cleanup); @@ -2324,7 +2338,7 @@ void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb) .bssid = hdr->addr3, }; - mt76_scan_rx_beacon(phy->dev, phy->chandef.chan); + mt76_scan_rx_beacon(phy, phy->chandef.chan); if (!phy->num_sta) return; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 2ade848fe3bb..9e851dea71d9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -767,7 +767,6 @@ struct mt76_rx_status { u8 amsdu:1, first_amsdu:1, last_amsdu:1; u8 rate_idx; u8 nss:5, band:3; - s8 signal; u8 chains; s8 chain_signal[IEEE80211_MAX_CHAINS]; }; @@ -847,7 +846,6 @@ struct mt76_vif_link { struct mt76_vif_data { struct mt76_vif_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; - struct mt76_vif_link __rcu *offchannel_link; struct mt76_phy *roc_phy; u16 valid_links; @@ -879,6 +877,15 @@ struct mt76_phy { struct ieee80211_vif *roc_vif; struct mt76_vif_link *roc_link; + struct delayed_work scan_work; + struct { + struct ieee80211_channel *chan; + struct mt76_vif_link *mlink; + int chan_idx; + bool beacon_wait; + bool beacon_received; + } scan; + struct mt76_chanctx *chanctx; struct mt76_channel_state *chan_state; @@ -1015,17 +1022,12 @@ struct mt76_dev { u32 rxfilter; - struct delayed_work scan_work; spinlock_t scan_lock; struct { - struct cfg80211_scan_request *req; - struct ieee80211_channel *chan; + struct ieee80211_scan_request *req; struct ieee80211_vif *vif; - struct mt76_vif_link *mlink; - struct mt76_phy *phy; - int chan_idx; - bool beacon_wait; - bool beacon_received; + unsigned long phy_mask; + bool aborted; } scan; #ifdef CONFIG_NL80211_TESTMODE @@ -1398,6 +1400,11 @@ mt76_phy_hw(struct mt76_dev *dev, u8 phy_idx) return mt76_dev_phy(dev, phy_idx)->hw; } +static inline bool mt76_phy_scanning(struct mt76_phy *phy) +{ + return test_bit(phy->band_idx, &phy->dev->scan.phy_mask); +} + static inline u8 * mt76_get_txwi_ptr(struct mt76_dev *dev, struct mt76_txwi_cache *t) { @@ -1555,6 +1562,8 @@ void mt76_sta_ps_transition(struct mt76_dev *dev, struct mt76_wcid *wcid, bool mt76_has_tx_pending(struct mt76_phy *phy); int mt76_update_channel(struct mt76_phy *phy); void mt76_update_survey(struct mt76_phy *phy); +void mt76_phy_chandef_set(struct mt76_phy *phy, + struct cfg80211_chan_def *chandef); void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time); int mt76_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey); @@ -1623,7 +1632,7 @@ int mt76_get_rate(struct mt76_dev *dev, int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_scan_request *hw_req); void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif); -void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan); +void mt76_scan_rx_beacon(struct mt76_phy *phy, struct ieee80211_channel *chan); void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb); void mt76_beacon_mon_check(struct mt76_phy *phy); void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 477a9b7a8cf7..491c8c937031 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -34,7 +34,7 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) int idx; u32 val; - if (skb->len < MT_TXD_SIZE + sizeof(struct ieee80211_hdr)) + if (skb->len < MT_TXD_SIZE + 2) goto free; val = le32_to_cpu(txd[1]); @@ -52,6 +52,9 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) sta = container_of(priv, struct ieee80211_sta, drv_priv); hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; + if (skb->len < MT_TXD_SIZE + ieee80211_hdrlen(hdr->frame_control)) + goto free; + hwq = wmm_queue_map[IEEE80211_AC_BE]; if (ieee80211_is_data_qos(hdr->frame_control)) { tid = *ieee80211_get_qos_ctl(hdr) & @@ -62,6 +65,19 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) } else if (ieee80211_is_data(hdr->frame_control)) { skb_set_queue_mapping(skb, IEEE80211_AC_BE); hwq = wmm_queue_map[IEEE80211_AC_BE]; + } else if (ieee80211_is_back_req(hdr->frame_control)) { + struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr; + + if (skb->len < MT_TXD_SIZE + sizeof(*bar)) + goto free; + + tid = (le16_to_cpu(bar->control) & + IEEE80211_BAR_CTRL_TID_INFO_MASK) >> + IEEE80211_BAR_CTRL_TID_INFO_SHIFT; + tid &= IEEE80211_QOS_CTL_TAG1D_MASK; + qid = tid_to_ac[tid]; + hwq = wmm_queue_map[qid]; + skb_set_queue_mapping(skb, qid); } else { skb_pull(skb, MT_TXD_SIZE); if (!ieee80211_is_bufferable_mmpdu(skb)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c index 6a1475e3c899..83cffa94bc0e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c @@ -54,7 +54,7 @@ static int mt7615_config(void *data, u64 val) int ret; mt7615_mutex_acquire(dev); - ret = mt76_connac_mcu_chip_config(&dev->mt76); + ret = mt76_connac_mcu_chip_config(&dev->mt76, "assert"); mt7615_mutex_release(dev); return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c index e437e088b2e9..665b0f1e939f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c @@ -541,8 +541,10 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) mt7615_cap_dbdc_enable(dev); mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops, MT_BAND1); - if (!mphy) - return -ENOMEM; + if (!mphy) { + ret = -ENOMEM; + goto error; + } phy = mphy->priv; phy->dev = dev; @@ -572,7 +574,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) ret = mt76_eeprom_override(mphy); if (ret) - return ret; + goto error_free_hw; /* second phy can only handle 5 GHz */ mphy->cap.has_5ghz = true; @@ -590,7 +592,14 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev) ret = mt76_register_phy(mphy, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) - ieee80211_free_hw(mphy->hw); + goto error_free_hw; + + return 0; + +error_free_hw: + ieee80211_free_hw(mphy->hw); +error: + mt7615_cap_dbdc_disable(dev); return ret; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 67f56e428d9a..175e847f49ef 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -254,8 +254,10 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw, mt7615_mutex_acquire(dev); - mt7615_mcu_add_bss_info(phy, vif, NULL, false); - mt7615_mcu_sta_add(phy, vif, NULL, false); + if (vif->type != NL80211_IFTYPE_MONITOR) { + mt7615_mcu_add_bss_info(phy, vif, NULL, false); + mt7615_mcu_sta_add(phy, vif, NULL, false); + } mt76_testmode_reset(phy->mt76, true); if (vif == phy->monitor_vif) diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index ff57ede87f71..aab4303fef65 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -145,6 +145,9 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd, } rxd = (struct mt7615_mcu_rxd *)skb->data; + if (skb->len < sizeof(*rxd)) + return -EMSGSIZE; + if (seq != rxd->seq) return -EAGAIN; @@ -152,9 +155,15 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd, skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; } else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) { + if (skb->len < sizeof(*rxd) + (is_mt7663(mdev) ? 8 : 4)) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd)); + if (is_mt7663(mdev)) + skb_pull(skb, 4); ret = le32_to_cpu(*(__le32 *)skb->data); } else if (cmd == MCU_EXT_QUERY(RF_REG_ACCESS)) { + if (skb->len < sizeof(*rxd) + 8 + sizeof(__le32)) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd)); ret = le32_to_cpu(*(__le32 *)&skb->data[8]); } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) || @@ -165,12 +174,16 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd, cmd == MCU_UNI_CMD(SUSPEND)) { struct mt76_connac_mcu_uni_event *event; + if (skb->len < sizeof(*rxd) + sizeof(*event)) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd)); event = (struct mt76_connac_mcu_uni_event *)skb->data; ret = le32_to_cpu(event->status); } else if (cmd == MCU_CE_QUERY(REG_READ)) { struct mt76_connac_mcu_reg_event *event; + if (skb->len < sizeof(*rxd) + sizeof(*event)) + return -EMSGSIZE; skb_pull(skb, sizeof(*rxd)); event = (struct mt76_connac_mcu_reg_event *)skb->data; ret = (int)le32_to_cpu(event->val); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c index a9178e077fd6..7d8580720cd8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_init.c @@ -116,6 +116,7 @@ void mt7615_unregister_device(struct mt7615_dev *dev) mcu_running = mt7615_wait_for_mcu_init(dev); mt7615_unregister_ext_phy(dev); + cancel_work_sync(&dev->reset_work); mt76_unregister_device(&dev->mt76); if (mcu_running) mt7615_mcu_exit(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c index bab7b91f14be..3629e3d9bf47 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c @@ -58,15 +58,22 @@ static void mt7663u_copy(struct mt76_dev *dev, u32 offset, const void *data, int len) { struct mt76_usb *usb = &dev->usb; - int ret, i = 0, batch_len; const u8 *val = data; + int len_aligned; + int batch_len; + int copy_len; + int ret; + int i = 0; - len = round_up(len, 4); + len_aligned = round_up(len, 4); mutex_lock(&usb->usb_ctrl_mtx); - while (i < len) { - batch_len = min_t(int, usb->data_len, len - i); - memcpy(usb->data, val + i, batch_len); + while (i < len_aligned) { + batch_len = min_t(int, usb->data_len, len_aligned - i); + copy_len = min_t(int, batch_len, len - i); + memcpy(usb->data, val + i, copy_len); + if (copy_len < batch_len) + memset(usb->data + copy_len, 0, batch_len - copy_len); ret = __mt76u_vendor_request(dev, MT_VEND_WRITE_EXT, USB_DIR_OUT | USB_TYPE_VENDOR, (offset + i) >> 16, offset + i, diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index 8a8d608dd56e..8481eac8d783 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -600,6 +600,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, vif ? &vif->bss_conf : NULL, beacon, multicast); u32 val = MT_TXD6_FIXED_BW; + u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); /* hardware won't add HTC for mgmt/ctrl frame */ txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD); @@ -608,13 +609,18 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, txwi[6] |= cpu_to_le32(val); txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); - if (!is_connac2(dev)) { - u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); - - if (!spe_idx) - spe_idx = 24 + phy_idx; - txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx)); - } + /* Fixed-rate frames (all mgmt, so auth/assoc req too) otherwise + * carry spe_idx 0 and TX 1SS 1T on WF0. Fill spe_idx like the + * other connac generations do, but do NOT touch + * MT_TXD6_SPE_ID_IDX: on connac2 setting it points HW at the + * WTBL and the index below is ignored. + * + * spe_idx 0 is also a valid single-path index (WF0), so only + * take the duplicate fallback when a second path exists. + */ + if (!spe_idx && hweight8(mphy->antenna_mask) > 1) + spe_idx = 24 + phy_idx; + txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx)); txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU); } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 2c49f3b493bd..9bdfff24b702 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -2041,13 +2041,13 @@ int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_enable); -int mt76_connac_mcu_chip_config(struct mt76_dev *dev) +int mt76_connac_mcu_chip_config(struct mt76_dev *dev, const char *cmd) { struct mt76_connac_config req = { .resp_type = 0, }; - strscpy(req.data, "assert"); + strscpy(req.data, cmd); return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG), &req, sizeof(req), false); @@ -2056,14 +2056,11 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_chip_config); int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable) { - struct mt76_connac_config req = { - .resp_type = 0, - }; + char cmd[16]; - snprintf(req.data, sizeof(req.data), "KeepFullPwr %d", !enable); + snprintf(cmd, sizeof(cmd), "KeepFullPwr %d", !enable); - return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG), - &req, sizeof(req), false); + return mt76_connac_mcu_chip_config(dev, cmd); } EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep); @@ -2487,9 +2484,7 @@ int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw, gtk_tlv->rekey_mode = 2; gtk_tlv->option = 1; - rcu_read_lock(); - ieee80211_iter_keys_rcu(hw, vif, mt76_connac_mcu_key_iter, gtk_tlv); - rcu_read_unlock(); + ieee80211_iter_keys(hw, vif, mt76_connac_mcu_key_iter, gtk_tlv); memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN); memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN); @@ -3127,7 +3122,7 @@ mt76_connac_mcu_send_phy_ram_firmware(struct mt76_dev *dev, err = mt76_connac_mcu_init_download(dev, addr, len, mode); if (err) { dev_err(dev->dev, - "The request to dowload PHY firmware failed.\n"); + "The request to download PHY firmware failed.\n"); return err; } diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 0ededa569e9a..74e37d722710 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -1357,9 +1357,11 @@ enum { MCU_UNI_CMD_ALL_STA_INFO = 0x6e, MCU_UNI_CMD_ASSERT_DUMP = 0x6f, MCU_UNI_CMD_EXT_EEPROM_CTRL = 0x74, + MCU_UNI_CMD_FACT_CAL = 0x7c, MCU_UNI_CMD_RADIO_STATUS = 0x80, MCU_UNI_CMD_MLD = 0x82, MCU_UNI_CMD_SDO = 0x88, + MCU_UNI_CMD_AXIDMA = 0xa2, }; enum { @@ -2098,7 +2100,7 @@ void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac, int mt76_connac_sta_state_dp(struct mt76_dev *dev, enum ieee80211_sta_state old_state, enum ieee80211_sta_state new_state); -int mt76_connac_mcu_chip_config(struct mt76_dev *dev); +int mt76_connac_mcu_chip_config(struct mt76_dev *dev, const char *cmd); int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable); void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb, struct mt76_connac_coredump *coredump); diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 21f8b1e64101..158aa356b710 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -302,10 +302,14 @@ mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate, txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD; fallthrough; case MT_PHY_TYPE_HT: + if (idx > 31) + return -EINVAL; txrate->flags |= IEEE80211_TX_RC_MCS; txrate->idx = idx; break; case MT_PHY_TYPE_VHT: + if ((idx & 0xf) > 9) + return -EINVAL; txrate->flags |= IEEE80211_TX_RC_VHT_MCS; txrate->idx = idx; break; @@ -493,18 +497,21 @@ mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta, first_rate = st->rate & ~MT_PKTID_RATE; first_rate |= st->pktid & MT_PKTID_RATE; - mt76x02_mac_process_tx_rate(&rate[0], first_rate, - dev->mphy.chandef.chan->band); + if (mt76x02_mac_process_tx_rate(&rate[0], first_rate, + dev->mphy.chandef.chan->band)) + return; } else if (rate[0].idx < 0) { if (!msta) return; - mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info, - dev->mphy.chandef.chan->band); + if (mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info, + dev->mphy.chandef.chan->band)) + return; } - mt76x02_mac_process_tx_rate(&last_rate, st->rate, - dev->mphy.chandef.chan->band); + if (mt76x02_mac_process_tx_rate(&last_rate, st->rate, + dev->mphy.chandef.chan->band)) + return; for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) { retry--; @@ -809,9 +816,13 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl); pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo); if (pn_len) { - int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len; - u8 *data = skb->data + offset; + unsigned int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len; + u8 *data; + if (offset + 8 > skb->len) + return -EINVAL; + + data = skb->data + offset; status->iv[0] = data[7]; status->iv[1] = data[6]; status->iv[2] = data[5]; @@ -831,6 +842,9 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, } } + if (pad_len + ieee80211_get_hdrlen_from_skb(skb) > skb->len) + return -EINVAL; + mt76x02_remove_hdr_pad(skb, pad_len); if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL)) diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c index 968c73e06a5f..6f931d483bd6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_usb_mcu.c @@ -90,7 +90,7 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb, MT_MCU_MSG_TYPE_CMD; ret = mt76x02u_skb_dma_info(skb, CPU_TX_PORT, info); if (ret) - return ret; + goto out; ret = mt76u_bulk_msg(dev, skb->data, skb->len, NULL, 500, MT_EP_OUT_INBAND_CMD); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c b/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c index 6c7273e5b0bc..db079b274a93 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/coredump.c @@ -345,11 +345,12 @@ static struct mt7915_coredump *mt7915_coredump_build(struct mt7915_dev *dev) mt7915_coredump_fw_stack(dev, dump, exception); /* gather memory content */ - dump_mem = (struct mt7915_coredump_mem *)(buf + sofar); - dump_mem->len = crash_data->memdump_buf_len; - if (coredump_memdump && crash_data->memdump_buf_len) + if (coredump_memdump && crash_data->memdump_buf_len) { + dump_mem = (struct mt7915_coredump_mem *)(buf + sofar); + dump_mem->len = crash_data->memdump_buf_len; memcpy(dump_mem->data, crash_data->memdump_buf, crash_data->memdump_buf_len); + } mutex_unlock(&dev->dump_mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index fe7b29ebc0bf..145d14a1012d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -111,6 +111,12 @@ mt7915_eeprom_load_default(struct mt7915_dev *dev) goto out; } + if (fw->size < mt7915_eeprom_size(dev)) { + dev_err(dev->mt76.dev, "Invalid default bin size\n"); + ret = -EINVAL; + goto out; + } + memcpy(eeprom, fw->data, mt7915_eeprom_size(dev)); dev->flash_mode = true; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index c8e389db63a7..358c45acf79b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -200,11 +200,17 @@ static void mt7915_unregister_thermal(struct mt7915_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; + if (phy->tzone) { + devm_thermal_of_zone_unregister(phy->dev->mt76.dev, phy->tzone); + phy->tzone = NULL; + } + if (!phy->cdev) return; sysfs_remove_link(&wiphy->dev.kobj, "cooling_device"); thermal_cooling_device_unregister(phy->cdev); + phy->cdev = NULL; } static int mt7915_thermal_init(struct mt7915_phy *phy) @@ -238,8 +244,8 @@ static int mt7915_thermal_init(struct mt7915_phy *phy) if (IS_ERR(phy->tzone)) { if (PTR_ERR(phy->tzone) != -ENODEV) dev_warn(phy->dev->mt76.dev, - "failed to register thermal zone: %ld\n", - PTR_ERR(phy->tzone)); + "failed to register thermal zone %d: %ld\n", + phy->mt76->band_idx, PTR_ERR(phy->tzone)); phy->tzone = NULL; } @@ -248,7 +254,12 @@ static int mt7915_thermal_init(struct mt7915_phy *phy) hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy, mt7915_hwmon_groups); - return PTR_ERR_OR_ZERO(hwmon); + if (IS_ERR(hwmon)) { + mt7915_unregister_thermal(phy); + return PTR_ERR(hwmon); + } + + return 0; } static void mt7915_led_set_config(struct led_classdev *led_cdev, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index a03d89aabe80..556f8948abac 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -273,9 +273,9 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, mt7915_init_bitrate_mask(vif); memset(&mvif->cap, -1, sizeof(mvif->cap)); + rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); mt7915_mcu_add_bss_info(phy, vif, true); mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, true); - rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c index a5a70d8e8544..62bf33347e9e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c @@ -237,7 +237,7 @@ static int mt7921_chip_reset(void *data, u64 val) default: /* Collect the core dump before reset wifisys. */ mt792x_mutex_acquire(dev); - ret = mt76_connac_mcu_chip_config(&dev->mt76); + ret = mt76_connac_mcu_chip_config(&dev->mt76, "assert"); mt792x_mutex_release(dev); break; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index e69978184f68..6f5e31489e2d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -188,7 +188,7 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) u16 seq_ctrl = 0; __le16 fc = 0; u8 mode = 0; - int i, idx; + int idx; memset(status, 0, sizeof(*status)); @@ -368,15 +368,6 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb) status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1); - status->signal = -128; - for (i = 0; i < hweight8(mphy->antenna_mask); i++) { - if (!(status->chains & BIT(i)) || - status->chain_signal[i] >= 0) - continue; - - status->signal = max(status->signal, - status->chain_signal[i]); - } } amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4); @@ -831,11 +822,14 @@ void mt7921_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, u16 idx; idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX); + + rcu_read_lock(); wcid = __mt76_wcid_ptr(mdev, idx); sta = wcid_to_sta(wcid); if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE))) mt76_connac2_tx_check_aggr(sta, txwi); + rcu_read_unlock(); skb_pull(e->skb, headroom); mt76_tx_complete_skb(mdev, e->wcid, e->skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 68a059504e83..09574d4417cd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -652,9 +652,9 @@ static int mt7921_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7921_sniffer_interface_iter, dev); + ieee80211_iterate_active_interfaces_mtx(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_sniffer_interface_iter, dev); } out: @@ -668,12 +668,8 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { -#define MT7921_FILTER_FCSFAIL BIT(2) -#define MT7921_FILTER_CONTROL BIT(5) -#define MT7921_FILTER_OTHER_BSS BIT(6) -#define MT7921_FILTER_ENABLE BIT(31) - struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); u32 flags = MT7921_FILTER_ENABLE; #define MT7921_FILTER(_fif, _type) do { \ @@ -685,6 +681,8 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw, MT7921_FILTER(FIF_CONTROL, CONTROL); MT7921_FILTER(FIF_OTHER_BSS, OTHER_BSS); + phy->rxfilter = flags; + mt792x_mutex_acquire(dev); mt7921_mcu_set_rxfilter(dev, flags, 0, 0); mt792x_mutex_release(dev); @@ -865,6 +863,12 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (sta->aid > MT7921_MAX_AID) return -ENOENT; + if (mvif->roc_join_held && !sta->tdls && + (ev == MT76_STA_EVENT_AUTHORIZE || ev == MT76_STA_EVENT_DISASSOC)) { + mvif->roc_join_held = false; + mt7921_abort_roc(mvif->phy, mvif); + } + if (ev != MT76_STA_EVENT_ASSOC) return 0; @@ -906,6 +910,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; mvif->wep_sta = NULL; + mvif->roc_join_held = false; ewma_rssi_init(&mvif->bss_conf.rssi); if (!sta->tdls) mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, @@ -1156,10 +1161,10 @@ static int mt7921_suspend(struct ieee80211_hw *hw, mt792x_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7921_mcu_set_suspend_iter, - &dev->mphy); + ieee80211_iterate_active_interfaces_mtx(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_mcu_set_suspend_iter, + &dev->mphy); mt792x_mutex_release(dev); @@ -1174,10 +1179,10 @@ static int mt7921_resume(struct ieee80211_hw *hw) mt792x_mutex_acquire(dev); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt76_connac_mcu_set_suspend_iter, - &dev->mphy); + ieee80211_iterate_active_interfaces_mtx(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76_connac_mcu_set_suspend_iter, + &dev->mphy); ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT792x_WATCHDOG_TIME); @@ -1423,6 +1428,7 @@ mt7921_change_chanctx(struct ieee80211_hw *hw, } else { mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); } + mt76_phy_chandef_set(mvif->phy->mt76, &ctx->def); mt792x_mutex_release(phy->dev); } @@ -1447,6 +1453,16 @@ static void mt7921_mgd_complete_tx(struct ieee80211_hw *hw, { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + /* Keep the join ROC until the station is authorized, so that it + * covers the 4-way handshake. mt7921_mac_sta_event() releases it. + */ + if (vif->type == NL80211_IFTYPE_STATION && info->success && + (info->subtype == IEEE80211_STYPE_ASSOC_REQ || + info->subtype == IEEE80211_STYPE_REASSOC_REQ)) { + mvif->roc_join_held = true; + return; + } + mt7921_abort_roc(mvif->phy, mvif); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 40546005c743..25638c68c468 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -3,6 +3,7 @@ #include <linux/fs.h> #include <linux/firmware.h> +#include <linux/of.h> #include "mt7921.h" #include "regd.h" #include "mcu.h" @@ -676,6 +677,10 @@ int mt7921_run_firmware(struct mt792x_dev *dev) return err; set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state); + err = mt7921_mcu_set_thermal_protect(dev); + if (err) + return err; + return mt7921_mcu_fw_log_2_host(dev, 1); } EXPORT_SYMBOL_GPL(mt7921_run_firmware); @@ -1231,7 +1236,7 @@ int mt7921_mcu_config_sniffer(struct mt792x_vif *vif, .len = cpu_to_le16(sizeof(req.tlv)), .control_ch = chandef->chan->hw_value, .center_ch = ieee80211_frequency_to_channel(freq1), - .drop_err = 1, + .drop_err = !(vif->phy->rxfilter & MT7921_FILTER_FCSFAIL), }, }; if (chandef->chan->band < ARRAY_SIZE(ch_band)) @@ -1359,6 +1364,7 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, .acpi_conf = mt792x_acpi_get_flags(&dev->phy), .mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2), }; + struct device_node *np; int ret, valid_cnt = 0; u32 buf_len = 0; u8 *pos; @@ -1368,8 +1374,11 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, if (dev->phy.chip_cap & MT792x_CHIP_CAP_CLC_EVT_EN) req.cap |= CLC_CAP_EVT_EN; - if (mt76_find_power_limits_node(&dev->mt76)) + + np = mt76_find_power_limits_node(&dev->mt76); + if (np) req.cap |= CLC_CAP_DTS_EN; + of_node_put(np); buf_len = le32_to_cpu(clc->len) - sizeof(*clc); pos = clc->data; @@ -1479,6 +1488,19 @@ int mt7921_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy, u8 action) sizeof(req), action ? true : false); } +#define MT7921_THERMAL_PROT_LOW_TEMP 105 +#define MT7921_THERMAL_PROT_HIGH_TEMP 115 + +int mt7921_mcu_set_thermal_protect(struct mt792x_dev *dev) +{ + char cmd[64]; + + snprintf(cmd, sizeof(cmd), "DowngradeTxStreamTemp %d %d", + MT7921_THERMAL_PROT_LOW_TEMP, MT7921_THERMAL_PROT_HIGH_TEMP); + + return mt76_connac_mcu_chip_config(&dev->mt76, cmd); +} + int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif, u8 bit_op, u32 bit_map) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index fb8654b7c5e7..3baf6094612f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -7,6 +7,11 @@ #include "../mt792x.h" #include "regs.h" +#define MT7921_FILTER_FCSFAIL BIT(2) +#define MT7921_FILTER_CONTROL BIT(5) +#define MT7921_FILTER_OTHER_BSS BIT(6) +#define MT7921_FILTER_ENABLE BIT(31) + #define MT7921_MAX_AID 20 #define MT7921_TX_RING_SIZE 2048 @@ -324,6 +329,7 @@ int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, int mt7921_mcu_config_sniffer(struct mt792x_vif *vif, struct ieee80211_chanctx_conf *ctx); int mt7921_mcu_get_temperature(struct mt792x_phy *phy); +int mt7921_mcu_set_thermal_protect(struct mt792x_dev *dev); int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, enum mt76_txq_id qid, struct mt76_wcid *wcid, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 56a914aaa81e..f87c44f2a8b6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -375,6 +375,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, } map->rx.wm2_complete_mask = 0; + map->rx.all_complete_mask &= ~MT_INT_RX_DONE_WM2; dev->irq_map = map; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 98b3469ac597..d5c33a0d409c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -57,7 +57,9 @@ int mt7921e_mac_reset(struct mt792x_dev *dev) { int i, err; - mt792xe_mcu_drv_pmctrl(dev); + err = mt792xe_mcu_drv_pmctrl(dev); + if (err) + return err; mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c index fcdeb65cd8ef..699617d9e48f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -28,6 +28,21 @@ bool mt7921_regd_clc_supported(struct mt792x_dev *dev) return true; } +static bool +mt7921_regd_dt_has_channel(struct device_node *band_np, + struct ieee80211_channel *ch) +{ + struct device_node *chan_np; + + if (!band_np) + return false; + + chan_np = mt76_find_channel_node(band_np, ch); + of_node_put(chan_np); + + return !!chan_np; +} + static void mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) { @@ -43,14 +58,14 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) sband = wiphy->bands[NL80211_BAND_5GHZ]; if (!sband) - return; + goto out; band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL; for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; cfreq = ch->center_freq; - if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) { + if (np && !mt7921_regd_dt_has_channel(band_np, ch)) { ch->flags |= IEEE80211_CHAN_DISABLED; continue; } @@ -59,17 +74,18 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) if (IS_UNII_INVALID(0, 5845, 5925)) ch->flags |= IEEE80211_CHAN_DISABLED; } + of_node_put(band_np); sband = wiphy->bands[NL80211_BAND_6GHZ]; if (!sband) - return; + goto out; band_np = np ? of_get_child_by_name(np, "txpower-6g") : NULL; for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; cfreq = ch->center_freq; - if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) { + if (np && !mt7921_regd_dt_has_channel(band_np, ch)) { ch->flags |= IEEE80211_CHAN_DISABLED; continue; } @@ -81,6 +97,10 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) IS_UNII_INVALID(4, 6875, 7125)) ch->flags |= IEEE80211_CHAN_DISABLED; } + of_node_put(band_np); + +out: + of_node_put(np); } int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile index f9dcc0bba393..33539121a15c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile @@ -6,5 +6,5 @@ obj-$(CONFIG_MT7925U) += mt7925u.o mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o mt7925-common-$(CONFIG_NL80211_TESTMODE) += testmode.o -mt7925e-y := pci.o pci_mac.o pci_mcu.o +mt7925e-y := pci.o pci_mac.o pci_mcu.o cached_cal.o mt7925u-y := usb.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.c b/drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.c new file mode 100644 index 000000000000..0209606e1a47 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* Copyright (C) 2026 MediaTek Inc. */ + +#include <linux/dma-mapping.h> +#include "../mt792x.h" +#include "cached_cal.h" + +static void mt7925_cal_cache_calc_layout(struct mt7925_cal_cache_layout *l) +{ + u32 hdr = sizeof(struct mt7925_fact_cal_buf_info); + + l->common_stride = hdr + MT7925_FACT_CAL_LEN_COM; + l->group_stride = hdr + MT7925_FACT_CAL_LEN_GRP; + l->channel_stride = hdr + MT7925_FACT_CAL_LEN_CH; + + l->common_off = 0; + l->group_off = l->common_off + + l->common_stride * MT7925_FACT_CAL_COMMON_BAND_NUM; + l->channel_off = l->group_off + + l->group_stride * MT7925_FACT_CAL_GROUP_NUM; + l->mapping_off = l->channel_off + + l->channel_stride * MT7925_FACT_CAL_CH_NUM_ALL; + l->total = l->mapping_off + + sizeof(struct mt7925_fact_cal_mapping_tbl); +} + +static u32 mt7925_cal_cache_region_size(void) +{ + struct mt7925_cal_cache_layout l; + + mt7925_cal_cache_calc_layout(&l); + + return l.total; +} + +int mt7925_axidma_alloc(struct mt792x_dev *dev) +{ + u32 total_size; + dma_addr_t dma_addr; + void *va; + + if (dev->cached_cal.va) + return 0; + + total_size = mt7925_cal_cache_region_size(); + + va = dma_alloc_coherent(dev->mt76.dev, total_size, &dma_addr, + GFP_KERNEL); + if (!va) + return -ENOMEM; + + dev->cached_cal.va = va; + dev->cached_cal.dma_addr = dma_addr; + dev->cached_cal.size = total_size; + + return 0; +} + +void mt7925_axidma_free(struct mt792x_dev *dev) +{ + if (!dev->cached_cal.va) + return; + + dma_free_coherent(dev->mt76.dev, dev->cached_cal.size, + dev->cached_cal.va, dev->cached_cal.dma_addr); + + memset(&dev->cached_cal, 0, sizeof(dev->cached_cal)); +} + +int mt7925_mcu_send_axidma_info(struct mt792x_dev *dev) +{ + struct mt7925_axidma_info_req *req; + u32 remap_base, pa_offset; + int ret; + + if (!dev->cached_cal.va) + return -EINVAL; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + remap_base = (u32)(dev->cached_cal.dma_addr >> 16); + pa_offset = (u32)(dev->cached_cal.dma_addr & 0xFFFF); + + req->remap.tag = cpu_to_le16(MT7925_AXIDMA_TAG_REMAP); + req->remap.len = cpu_to_le16(sizeof(req->remap)); + req->remap.remap_addr = cpu_to_le32(remap_base); + + req->fact_cal.tag = cpu_to_le16(MT7925_AXIDMA_TAG_FACT_CAL); + req->fact_cal.len = cpu_to_le16(sizeof(req->fact_cal)); + req->fact_cal.host_addr_offset = cpu_to_le32(pa_offset); + req->fact_cal.size = cpu_to_le32(dev->cached_cal.size); + req->fact_cal.bound = cpu_to_le32(pa_offset + dev->cached_cal.size - 1); + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(AXIDMA), + req, sizeof(*req), true); + + kfree(req); + + if (ret) + dev_err(dev->mt76.dev, + "failed to send AXI DMA info: %d\n", ret); + + return ret; +} + +static bool mt7925_cal_cache_read_slot(struct mt792x_dev *dev, u32 region_off, + u32 stride, u32 idx, + u32 *cal_param, u32 *total_buf_num) +{ + const struct mt7925_fact_cal_buf_info *bi; + u32 off = region_off + stride * idx; + + if (!dev->cached_cal.va || off + sizeof(*bi) > dev->cached_cal.size) + return false; + + bi = (const struct mt7925_fact_cal_buf_info *) + ((const u8 *)dev->cached_cal.va + off); + if (cal_param) + *cal_param = le32_to_cpu(bi->cal_param); + if (total_buf_num) + *total_buf_num = le32_to_cpu(bi->total_buf_num); + return true; +} + +static void mt7925_fact_cal_build_mapping_tbl(struct mt792x_dev *dev, + struct mt7925_fact_cal_mapping_tbl *tbl) +{ + dma_addr_t common_pa, group_pa, channel_pa, mapping_pa; + u32 hdr = sizeof(struct mt7925_fact_cal_buf_info); + dma_addr_t base = dev->cached_cal.dma_addr; + struct mt7925_cal_cache_layout l; + + mt7925_cal_cache_calc_layout(&l); + + common_pa = base + l.common_off; + group_pa = base + l.group_off; + channel_pa = base + l.channel_off; + mapping_pa = base + l.mapping_off; + + memset(tbl, 0, sizeof(*tbl)); + + tbl->common.phy_addr_h = cpu_to_le32(upper_32_bits(common_pa)); + tbl->common.phy_addr_l = cpu_to_le32(lower_32_bits(common_pa)); + tbl->common.offset = cpu_to_le32(l.common_stride); + + tbl->group.phy_addr_h = cpu_to_le32(upper_32_bits(group_pa)); + tbl->group.phy_addr_l = cpu_to_le32(lower_32_bits(group_pa)); + tbl->group.offset = cpu_to_le32(l.group_stride); + + tbl->channel.phy_addr_h = cpu_to_le32(upper_32_bits(channel_pa)); + tbl->channel.phy_addr_l = cpu_to_le32(lower_32_bits(channel_pa)); + tbl->channel.offset = cpu_to_le32(l.channel_stride); + + if (dev->cached_cal.reused) { + u32 i, cal_param, total_buf_num; + + for (i = 0; i < MT7925_FACT_CAL_COMMON_BAND_NUM; i++) + if (mt7925_cal_cache_read_slot(dev, l.common_off, + l.common_stride, i, + &cal_param, NULL)) + tbl->common.band[i] = cal_param & 0xff; + + for (i = 0; i < MT7925_FACT_CAL_GROUP_NUM; i++) + if (mt7925_cal_cache_read_slot(dev, l.group_off, + l.group_stride, i, + &cal_param, NULL)) + tbl->group.group[i] = cal_param & 0xff; + + for (i = 0; i < MT7925_FACT_CAL_CH_NUM_ALL; i++) + if (mt7925_cal_cache_read_slot(dev, l.channel_off, + l.channel_stride, i, + &cal_param, + &total_buf_num)) { + tbl->channel.cal_param[i] = + cpu_to_le32(cal_param); + tbl->channel.total_buf_num[i] = + total_buf_num & 0xff; + } + } + + tbl->buf_info_size = cpu_to_le32(hdr); + tbl->phy_addr_h = cpu_to_le32(upper_32_bits(mapping_pa)); + tbl->phy_addr_l = cpu_to_le32(lower_32_bits(mapping_pa)); +} + +static int mt7925_mcu_fact_cal_rapid_set(struct mt792x_dev *dev, u8 cal_type, + u32 seq_num, bool done, + const void *data, u32 data_len) +{ + struct mt7925_fact_cal_req *req; + int ret; + + if (data_len > MT7925_FACT_CAL_DATA_BUF_LEN) + return -EINVAL; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->set.tag = cpu_to_le16(MT7925_FACT_CAL_TAG_RAPID_SET); + req->set.len = cpu_to_le16(sizeof(req->set)); + req->set.seq_num = cpu_to_le32(seq_num); + req->set.buf_data_len = cpu_to_le32(data_len); + req->set.cal_type = cal_type; + req->set.done = done; + if (data && data_len) + memcpy(req->set.buf_data, data, data_len); + + ret = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(FACT_CAL), + req, sizeof(*req), true); + kfree(req); + + return ret; +} + +int mt7925_mcu_send_fact_cal_mapping_tbl(struct mt792x_dev *dev) +{ + struct mt7925_fact_cal_mapping_tbl *tbl; + __le32 cfg[MT7925_FACT_CAL_BUF_CFG_LEN / sizeof(__le32)] = {0}; + u32 seq = 0, off = 0, left; + int ret; + + if (!dev->cached_cal.va) + return -EINVAL; + + tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); + if (!tbl) + return -ENOMEM; + + mt7925_fact_cal_build_mapping_tbl(dev, tbl); + + cfg[1] = cpu_to_le32(sizeof(*tbl)); + cfg[2] = cpu_to_le32(MT7925_FACT_CAL_DATA_BUF_NUM_MAX); + ret = mt7925_mcu_fact_cal_rapid_set(dev, MT7925_FACT_CAL_TYPE_MAPPING_TBL, + seq, false, cfg, sizeof(cfg)); + if (ret) { + dev_err(dev->mt76.dev, + "fact-cal mapping tbl header send failed (seq=%u): %d\n", + seq, ret); + goto out; + } + + left = sizeof(*tbl); + while (left) { + u32 chunk = min_t(u32, left, MT7925_FACT_CAL_DATA_BUF_LEN); + + ret = mt7925_mcu_fact_cal_rapid_set(dev, + MT7925_FACT_CAL_TYPE_MAPPING_TBL, + ++seq, false, + (u8 *)tbl + off, chunk); + if (ret) { + dev_err(dev->mt76.dev, + "fact-cal mapping tbl data send failed (seq=%u, off=%u, chunk=%u): %d\n", + seq, off, chunk, ret); + goto out; + } + + off += chunk; + left -= chunk; + } + + ret = mt7925_mcu_fact_cal_rapid_set(dev, MT7925_FACT_CAL_TYPE_MAPPING_TBL, + ++seq, true, NULL, 0); + if (ret) { + dev_err(dev->mt76.dev, + "fact-cal mapping tbl done send failed (seq=%u): %d\n", + seq, ret); + goto out; + } +out: + kfree(tbl); + + return ret; +} + +int mt7925_mcu_fact_cal_set_bypass(struct mt792x_dev *dev, bool enable) +{ + struct { + u8 _rsv[4]; + + struct { + __le16 tag; + __le16 len; + __le32 data; + } __packed update_flag; + } req = { + .update_flag = { + .tag = cpu_to_le16(MT7925_FACT_CAL_TAG_UPDATE_FLAG), + .len = cpu_to_le16(sizeof(req.update_flag)), + .data = cpu_to_le32(enable ? 1 : 0), + }, + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(FACT_CAL), + &req, sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.h b/drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.h new file mode 100644 index 000000000000..6572513b7646 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.h @@ -0,0 +1,151 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* Copyright (C) 2026 MediaTek Inc. */ + +#ifndef __CACHED_CAL_H +#define __CACHED_CAL_H + +enum mt7925_axidma_info_tag { + MT7925_AXIDMA_TAG_REMAP = 0, + MT7925_AXIDMA_TAG_FACT_CAL = 1, + MT7925_AXIDMA_TAG_NUM +}; + +enum mt7925_fact_cal_tag { + MT7925_FACT_CAL_TAG_TRIGGER = 2, + MT7925_FACT_CAL_TAG_UPDATE_FLAG = 3, + MT7925_FACT_CAL_TAG_RAPID_GET = 4, + MT7925_FACT_CAL_TAG_RAPID_SET = 5, +}; + +enum mt7925_fact_cal_type { + MT7925_FACT_CAL_TYPE_COMMON = 0, + MT7925_FACT_CAL_TYPE_GROUP = 1, + MT7925_FACT_CAL_TYPE_CHANNEL = 2, + MT7925_FACT_CAL_TYPE_MAPPING_TBL = 4, +}; + +#define MT7925_FACT_CAL_DATA_BUF_LEN 1400 +#define MT7925_FACT_CAL_BUF_CFG_LEN 16 +#define MT7925_FACT_CAL_DATA_BUF_NUM_MAX 4 +#define MT7925_FACT_CAL_BUF_CFG_U32_LEN 4 +#define MT7925_FACT_CAL_DATA_MAX_BUF_LEN \ + (MT7925_FACT_CAL_DATA_BUF_NUM_MAX * MT7925_FACT_CAL_BUF_CFG_U32_LEN) + +#define MT7925_FACT_CAL_COMMON_BAND_NUM 2 +#define MT7925_FACT_CAL_GROUP_NUM 35 +#define MT7925_FACT_CAL_CH_NUM_2G 14 +#define MT7925_FACT_CAL_CH_NUM_5G 68 +#define MT7925_FACT_CAL_CH_NUM_6G 109 +#define MT7925_FACT_CAL_CH_NUM_ALL \ + (MT7925_FACT_CAL_CH_NUM_2G + MT7925_FACT_CAL_CH_NUM_5G + \ + MT7925_FACT_CAL_CH_NUM_6G) + +#define MT7925_FACT_CAL_LEN_COM 600 +#define MT7925_FACT_CAL_LEN_GRP 4500 +#define MT7925_FACT_CAL_LEN_CH 2800 + +struct mt7925_fact_cal_buf_info { + __le32 cal_type; + __le32 cal_param; + __le32 buf_seq_num; + __le32 total_buf_num; + __le32 buf_data_len; + u8 valid; + u8 done; + u8 rsv[2]; + __le32 buf_cfg_info[MT7925_FACT_CAL_DATA_MAX_BUF_LEN]; +} __packed; + +static_assert(sizeof(struct mt7925_fact_cal_buf_info) == 88, + "buf_info must match the MT7928 FW (88 bytes) or it rejects the mapping table"); + +struct mt7925_fact_cal_common_map { + __le32 phy_addr_h; + __le32 phy_addr_l; + __le32 offset; + u8 band[MT7925_FACT_CAL_COMMON_BAND_NUM]; + u8 rsv[2]; +} __packed; + +struct mt7925_fact_cal_group_map { + __le32 phy_addr_h; + __le32 phy_addr_l; + __le32 offset; + u8 group[MT7925_FACT_CAL_GROUP_NUM]; + u8 rsv; +} __packed; + +struct mt7925_fact_cal_channel_map { + __le32 phy_addr_h; + __le32 phy_addr_l; + __le32 offset; + __le32 cal_param[MT7925_FACT_CAL_CH_NUM_ALL]; + u8 total_buf_num[MT7925_FACT_CAL_CH_NUM_ALL]; + u8 rsv; +} __packed; + +struct mt7925_fact_cal_mapping_tbl { + struct mt7925_fact_cal_common_map common; + struct mt7925_fact_cal_group_map group; + struct mt7925_fact_cal_channel_map channel; + __le32 buf_info_size; + __le32 phy_addr_h; + __le32 phy_addr_l; +} __packed; + +static_assert(sizeof(struct mt7925_fact_cal_mapping_tbl) == 1044, + "mapping table must match the MT7928 FW (1044 bytes) or the FW parse corrupts"); + +struct mt7925_cal_cache_layout { + u32 common_off, group_off, channel_off, mapping_off; + u32 common_stride, group_stride, channel_stride; + u32 total; +}; + +struct mt7925_axidma_info_req { + u8 _rsv[4]; + + struct { + __le16 tag; + __le16 len; + __le32 remap_addr; + __le32 reserved; + } __packed remap; + + struct { + __le16 tag; + __le16 len; + __le32 host_addr_offset; + __le32 size; + __le32 bound; + __le32 reserved; + } __packed fact_cal; +} __packed; + +struct mt7925_fact_cal_req { + u8 _rsv[4]; + + struct { + __le16 tag; + __le16 len; + __le32 data; + __le32 seq_num; + __le32 buf_data_len; + u8 cal_type; + u8 done; + u8 rsv[2]; + u8 buf_data[MT7925_FACT_CAL_DATA_BUF_LEN]; + } __packed set; +} __packed; + +int mt7925_axidma_alloc(struct mt792x_dev *dev); + +void mt7925_axidma_free(struct mt792x_dev *dev); + +int mt7925_mcu_send_axidma_info(struct mt792x_dev *dev); + +int mt7925_mcu_send_fact_cal_mapping_tbl(struct mt792x_dev *dev); + +int mt7925_mcu_fact_cal_set_bypass(struct mt792x_dev *dev, bool enable); + +#endif /* __CACHED_CAL_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index cd22fcc021b1..8c3049b66a85 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -270,6 +270,8 @@ int mt7925_register_device(struct mt792x_dev *dev) INIT_WORK(&dev->reset_work, mt7925_mac_reset_work); INIT_WORK(&dev->init_work, mt7925_init_work); + INIT_WORK(&dev->nan_deferred_work, mt7925_nan_deferred_work); + spin_lock_init(&dev->nan_deferred_lock); INIT_WORK(&dev->phy.roc_work, mt7925_roc_work); timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 3b82c9de26c5..7af996abe294 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -1503,7 +1503,7 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, true, NULL); mt7925_mcu_sta_update(dev, NULL, vif, &mvif->sta.deflink, true, - MT76_STA_INFO_STATE_NONE); + MT76_STA_INFO_STATE_NONE, NULL); mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true); } } @@ -1688,11 +1688,14 @@ void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev, u16 idx; idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX); + + rcu_read_lock(); wcid = __mt76_wcid_ptr(mdev, idx); sta = wcid_to_sta(wcid); if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE))) mt7925_tx_check_aggr(sta, e->skb, wcid); + rcu_read_unlock(); skb_pull(e->skb, headroom); mt76_tx_complete_skb(mdev, e->wcid, e->skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 549f9c06b363..15d95ad32636 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -840,9 +840,9 @@ static int mt7925_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) } if (changed & IEEE80211_CONF_CHANGE_MONITOR) { - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7925_sniffer_interface_iter, dev); + ieee80211_iterate_active_interfaces_mtx(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_sniffer_interface_iter, dev); } out: @@ -856,11 +856,8 @@ static void mt7925_configure_filter(struct ieee80211_hw *hw, unsigned int *total_flags, u64 multicast) { -#define MT7925_FILTER_FCSFAIL BIT(2) -#define MT7925_FILTER_CONTROL BIT(5) -#define MT7925_FILTER_OTHER_BSS BIT(6) -#define MT7925_FILTER_ENABLE BIT(31) struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_phy *phy = mt792x_hw_phy(hw); u32 flags = MT7925_FILTER_ENABLE; #define MT7925_FILTER(_fif, _type) do { \ @@ -872,6 +869,8 @@ static void mt7925_configure_filter(struct ieee80211_hw *hw, MT7925_FILTER(FIF_CONTROL, CONTROL); MT7925_FILTER(FIF_OTHER_BSS, OTHER_BSS); + phy->rxfilter = flags; + mt792x_mutex_acquire(dev); mt7925_mcu_set_rxfilter(dev, flags, 0, 0); mt792x_mutex_release(dev); @@ -964,6 +963,21 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, link_conf = mt792x_vif_to_bss_conf(vif, link_id); + /* NAN_DATA (NDI) peers skip association - fill link_sta caps + * from sband and push BSS_INFO with correct phymode + RLM. + */ + if (vif->type == NL80211_IFTYPE_NAN_DATA) { + struct ieee80211_chanctx_conf *nan_ctx; + + nan_ctx = mt7925_nan_seed_link_sta(dev, link_sta); + mconf->mt76.ctx = nan_ctx; + + ret = mt7925_mcu_add_bss_info(&dev->phy, nan_ctx, + link_conf, link_sta, true); + if (ret) + goto out_pm; + } + /* should update bss info before STA add */ if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { struct mt792x_link_sta *mlink_bc; @@ -991,7 +1005,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, link_sta == mlink->pri_link) { ret = mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true, - MT76_STA_INFO_STATE_NONE); + MT76_STA_INFO_STATE_NONE, NULL); if (ret) goto out_pm; } else if (ieee80211_vif_is_mld(vif) && @@ -1013,19 +1027,19 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, pri_mlink, true, - MT76_STA_INFO_STATE_ASSOC); + MT76_STA_INFO_STATE_ASSOC, mlink); if (ret) goto out_pm; ret = mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true, - MT76_STA_INFO_STATE_ASSOC); + MT76_STA_INFO_STATE_ASSOC, mlink); if (ret) goto out_pm; } else { ret = mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true, - MT76_STA_INFO_STATE_NONE); + MT76_STA_INFO_STATE_NONE, NULL); if (ret) goto out_pm; } @@ -1233,7 +1247,7 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true, - MT76_STA_INFO_STATE_ASSOC); + MT76_STA_INFO_STATE_ASSOC, NULL); mt792x_mutex_release(dev); } @@ -1243,6 +1257,13 @@ int mt7925_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct ieee80211_link_sta *link_sta = &sta->deflink; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + if (mvif->roc_join_held && !sta->tdls && + (ev == MT76_STA_EVENT_AUTHORIZE || ev == MT76_STA_EVENT_DISASSOC)) { + mvif->roc_join_held = false; + mt7925_abort_roc(mvif->phy, &mvif->bss_conf); + } switch (ev) { case MT76_STA_EVENT_ASSOC: @@ -1293,7 +1314,7 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, mt76_connac_pm_wake(&dev->mphy, &dev->pm); mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false, - MT76_STA_INFO_STATE_NONE); + MT76_STA_INFO_STATE_NONE, NULL); mt7925_mac_wtbl_update(dev, mlink->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -1438,6 +1459,7 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, if (vif->type == NL80211_IFTYPE_STATION) { mvif->wep_sta = NULL; + mvif->roc_join_held = false; ewma_rssi_init(&mvif->bss_conf.rssi); } @@ -1717,10 +1739,10 @@ static int mt7925_suspend(struct ieee80211_hw *hw, mt792x_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7925_mcu_set_suspend_iter, - &dev->mphy); + ieee80211_iterate_active_interfaces_mtx(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_mcu_set_suspend_iter, + &dev->mphy); mt792x_mutex_release(dev); @@ -1735,10 +1757,10 @@ static int mt7925_resume(struct ieee80211_hw *hw) mt792x_mutex_acquire(dev); set_bit(MT76_STATE_RUNNING, &phy->mt76->state); - ieee80211_iterate_active_interfaces(hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7925_mcu_set_suspend_iter, - &dev->mphy); + ieee80211_iterate_active_interfaces_mtx(hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_mcu_set_suspend_iter, + &dev->mphy); ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT792x_WATCHDOG_TIME); @@ -1964,7 +1986,7 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, err = mt7925_mcu_sta_update(dev, NULL, vif, &mvif->sta.deflink, true, - MT76_STA_INFO_STATE_NONE); + MT76_STA_INFO_STATE_NONE, NULL); out: mt792x_mutex_release(dev); @@ -2063,6 +2085,7 @@ mt7925_change_chanctx(struct ieee80211_hw *hw, link_conf, ctx); } } + mt76_phy_chandef_set(mvif->phy->mt76, &ctx->def); mt792x_mutex_release(phy->dev); } @@ -2089,6 +2112,19 @@ static void mt7925_mgd_complete_tx(struct ieee80211_hw *hw, { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + /* Keep the join ROC until the station is authorized, so that it + * covers the 4-way handshake. mt7925_mac_sta_event() releases it. + * On MLD, the active ROC is the MLO ROC, which must be released + * before the link activation work sets its own. + */ + if (vif->type == NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) && + info->success && + (info->subtype == IEEE80211_STYPE_ASSOC_REQ || + info->subtype == IEEE80211_STYPE_REASSOC_REQ)) { + mvif->roc_join_held = true; + return; + } + mt7925_abort_roc(mvif->phy, &mvif->bss_conf); } @@ -2108,7 +2144,7 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_ASSOC) { mt7925_mcu_sta_update(dev, NULL, vif, &mvif->sta.deflink, true, - MT76_STA_INFO_STATE_ASSOC); + MT76_STA_INFO_STATE_ASSOC, NULL); mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); if (ieee80211_vif_is_mld(vif)) @@ -2411,6 +2447,7 @@ static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw, mconf->mt76.ctx = ctx; mctx->bss_conf = mconf; + mt76_phy_chandef_set(mvif->phy->mt76, &ctx->def); mutex_unlock(&dev->mt76.mutex); return 0; @@ -2599,26 +2636,18 @@ static int mt7925_start_nan(struct ieee80211_hw *hw, cfg80211_chandef_create(&link_conf->chanreq.oper, chan, NL80211_CHAN_NO_HT); - err = mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, - NULL, true); + err = mt7925_mcu_add_bss_info(&dev->phy, NULL, + link_conf, NULL, true); if (err < 0) goto out; - dev->nan_vif = vif; - - err = mt7925_nan_set_nmi_addr(dev, vif->addr); - if (err) - goto rollback_bss; - err = mt7925_nan_enable(vif, dev, conf); - if (err) - goto rollback_bss; - - goto out; + if (err) { + mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false); + goto out; + } -rollback_bss: - dev->nan_vif = NULL; - mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false); + err = mt7925_nan_update_phy_setting(dev); out: mt792x_mutex_release(dev); @@ -2633,6 +2662,13 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw, struct mt792x_dev *dev = mt792x_hw_dev(hw); int err, ret; + /* Drop a deferred event queued just before stop so a stale cluster_id + * cannot leak into a restart; the work re-checks liveness anyway. + */ + spin_lock_bh(&dev->nan_deferred_lock); + dev->nan_deferred_pending = 0; + spin_unlock_bh(&dev->nan_deferred_lock); + mt792x_mutex_acquire(dev); err = mt7925_nan_disable(vif, dev); @@ -2642,9 +2678,6 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw, if (!err) err = ret; - if (dev->nan_vif == vif) - dev->nan_vif = NULL; - mt792x_mutex_release(dev); return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index aeb017516186..26cdb3f0a98a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1914,11 +1914,9 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, phy = (struct sta_rec_phy *)tlv; if (mt7925_vif_is_nan(vif)) { - enum nl80211_band band = chandef->chan ? chandef->chan->band - : NL80211_BAND_2GHZ; phy->phy_type = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_ERP; phy->phy_type |= mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, - band, + NL80211_BAND_5GHZ, link_sta); } else { phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, @@ -2003,7 +2001,11 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, ra_info = (struct sta_rec_ra_info *)tlv; if (mt7925_vif_is_nan(vif)) - band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ; + /* NAN is OFDM-only per spec; borrow the 5 GHz band lookup to + * avoid PHY_TYPE_BIT_HR_DSSS/CCK bits being added to phy_type. + * NAN interfaces have no chanctx, so chandef->chan is always NULL. + */ + band = NL80211_BAND_5GHZ; else band = chandef->chan->band; @@ -2063,14 +2065,18 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct mt792x_bss_conf *mconf, - struct mt792x_link_sta *mlink) + struct mt792x_link_sta *mlink, + struct mt792x_link_sta *pending) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_dev *dev = mvif->phy->dev; + unsigned long valid = msta->valid_links; struct mt792x_bss_conf *mconf_pri; struct sta_rec_mld *mld; + unsigned int link_id; struct tlv *tlv; + u8 max_links; u8 cnt = 0; /* Primary link always uses driver's deflink WCID. */ @@ -2099,11 +2105,38 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb, mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx); mld->link[cnt++].bss_idx = mconf_pri->mt76.idx; - /* Optionally encode the currently-updated secondary link. */ - if (mlink && mlink != &msta->deflink && mconf) { - mld->secondary_id = cpu_to_le16(mlink->wcid.idx); - mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx); - mld->link[cnt++].bss_idx = mconf->mt76.idx; + max_links = ARRAY_SIZE(mld->link); + + /* A link being added is not set in msta->valid_links yet */ + if (pending && pending != &msta->deflink) + valid |= BIT(pending->wcid.link_id); + + for_each_set_bit(link_id, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt792x_link_sta *mlink_sec; + struct mt792x_bss_conf *mconf_sec; + + if (cnt == max_links) + break; + + if (link_id == msta->deflink_id) + continue; + + mlink_sec = mt792x_sta_to_link(msta, link_id); + if (!mlink_sec && pending && link_id == pending->wcid.link_id) + mlink_sec = pending; + if (!mlink_sec || mlink_sec == &msta->deflink) + continue; + + mconf_sec = rcu_dereference_protected(mvif->link_conf[link_id], + lockdep_is_held(&dev->mt76.mutex)); + if (!mconf_sec) + continue; + + if (cnt == 1) + mld->secondary_id = cpu_to_le16(mlink_sec->wcid.idx); + + mld->link[cnt].wlan_id = cpu_to_le16(mlink_sec->wcid.idx); + mld->link[cnt++].bss_idx = mconf_sec->mt76.idx; } mld->link_num = cnt; @@ -2122,7 +2155,8 @@ mt7925_mcu_sta_remove_tlv(struct sk_buff *skb) static int mt7925_mcu_sta_cmd(struct mt76_phy *phy, - struct mt76_sta_cmd_info *info) + struct mt76_sta_cmd_info *info, + struct mt792x_link_sta *pending) { struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv; struct mt76_dev *dev = phy->dev; @@ -2163,7 +2197,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, if (info->state != MT76_STA_INFO_STATE_NONE) { mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta, - mconf, mlink); + mconf, mlink, pending); mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta); } @@ -2188,7 +2222,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_vif *vif, struct mt792x_link_sta *mlink, bool enable, - enum mt76_sta_info_state state) + enum mt76_sta_info_state state, + struct mt792x_link_sta *pending) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi); @@ -2206,7 +2241,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, info.wcid = &mlink->wcid; info.newly = state != MT76_STA_INFO_STATE_ASSOC; - return mt7925_mcu_sta_cmd(&dev->mphy, &info); + return mt7925_mcu_sta_cmd(&dev->mphy, &info, pending); } int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev, @@ -2354,7 +2389,7 @@ int mt7925_mcu_config_sniffer(struct mt792x_vif *vif, .len = cpu_to_le16(sizeof(req.tlv)), .control_ch = chandef->chan->hw_value, .center_ch = ieee80211_frequency_to_channel(freq1), - .drop_err = 1, + .drop_err = !(vif->phy->rxfilter & MT7925_FILTER_FCSFAIL), }, }; @@ -2392,10 +2427,13 @@ mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, u8 pad[3]; } __packed hdr; struct bcn_content_tlv { + /* DW 0 */ __le16 tag; __le16 len; + /* DW 1 */ __le16 tim_ie_pos; __le16 csa_ie_pos; + /* DW 2 */ __le16 bcc_ie_pos; /* 0: disable beacon offload * 1: enable beacon offload @@ -2406,8 +2444,9 @@ mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev, * 1: only cap field IE */ u8 type; + /* DW 3~130 */ __le16 pkt_len; - u8 pkt[512]; + u8 pkt[510]; } __packed beacon_tlv; } req = { .hdr = { @@ -2847,7 +2886,7 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, bmc = (struct bss_rate_tlv *)tlv; if (mt7925_vif_is_nan(vif)) - band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ; + band = NL80211_BAND_5GHZ; else band = chandef->chan->band; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 321e732347f2..636efe038392 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -7,6 +7,11 @@ #include "../mt792x.h" #include "regs.h" +#define MT7925_FILTER_FCSFAIL BIT(2) +#define MT7925_FILTER_CONTROL BIT(5) +#define MT7925_FILTER_OTHER_BSS BIT(6) +#define MT7925_FILTER_ENABLE BIT(31) + #define MT7925_BEACON_RATES_TBL 25 #define MT7925_TX_RING_SIZE 2048 @@ -286,7 +291,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_vif *vif, struct mt792x_link_sta *mlink, bool enable, - enum mt76_sta_info_state state); + enum mt76_sta_info_state state, + struct mt792x_link_sta *pending); int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag); int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf); int mt7925_mcu_set_eeprom(struct mt792x_dev *dev); @@ -353,6 +359,7 @@ int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, int mt7925e_mac_reset(struct mt792x_dev *dev); int mt7925e_mcu_init(struct mt792x_dev *dev); +void mt7925e_axidma_cal_cache_init(struct mt792x_dev *dev); void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data); void mt7928_mac_add_txs_msg(struct mt792x_dev *dev, void *evt); void mt7925_set_runtime_pm(struct mt792x_dev *dev); @@ -361,6 +368,7 @@ void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac, void mt7925_connac_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); void mt7925_set_ipv6_ns_work(struct work_struct *work); +void mt7925_nan_deferred_work(struct work_struct *work); int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c index d260e803d056..ce2571832c08 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c @@ -32,8 +32,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev, if (!mt7925_regd_is_valid_channel(dev, NL80211_BAND_5GHZ, chan)) return; - req->config_support_5g = 1; - req->support_5g_val = 1; req->config_5g_channel = 1; if (chan->hw_value == NAN_5G_LOW_DISC_CHANNEL) @@ -44,73 +42,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev, req->channel_5g_val = cpu_to_le32(ch5g); } -static void mt7925_nan_set_2g_support(struct mt7925_nan_enable_req_tlv *req, - struct cfg80211_nan_conf *conf) -{ - if (!conf->band_cfgs[NL80211_BAND_2GHZ].chan) - return; - - req->config_2dot4g_support = 1; - req->support_2dot4g_val = 1; -} - -static void mt7925_nan_set_cluster_id(struct mt7925_nan_enable_req_tlv *req, - const u8 *cluster_id) -{ - if (!cluster_id) - return; - - req->cluster_high = cpu_to_le16(cluster_id[4] | cluster_id[5] << 8); - req->cluster_low = cpu_to_le16((u16)cluster_id[3]); -} - -static void mt7925_nan_set_dw_interval(struct mt7925_nan_enable_req_tlv *req, - struct cfg80211_nan_conf *conf) -{ - if (conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval > 0) { - req->config_dw.config_2dot4g_dw_band = 1; - req->config_dw.dw_2dot4g_interval_val = - cpu_to_le32(conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval); - } - - if (conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval > 0) { - req->config_dw.config_5g_dw_band = 1; - req->config_dw.dw_5g_interval_val = - cpu_to_le32(conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval); - } -} - -static void mt7925_nan_set_disc_beacon(struct mt7925_nan_enable_req_tlv *req, - struct cfg80211_nan_conf *conf) -{ - if (conf->discovery_beacon_interval > 0) { - req->config_2dot4g_beacons = true; - req->beacon_2dot4g_val = conf->discovery_beacon_interval; - } -} - -static void mt7925_nan_set_rssi_thresholds(struct mt7925_nan_enable_req_tlv *req, - struct cfg80211_nan_conf *conf) -{ - if (conf->band_cfgs[NL80211_BAND_2GHZ].chan) { - req->config_2dot4g_rssi_close = 1; - req->rssi_close_2dot4g_val = - abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close); - req->config_2dot4g_rssi_middle = 1; - req->rssi_middle_2dot4g_val = - abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle); - } - - if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) { - req->config_5g_rssi_close = 1; - req->rssi_close_5g_val = - abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close); - req->config_5g_rssi_middle = 1; - req->rssi_middle_5g_val = - abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle); - } -} - static void mt7925_nan_set_scan_params(struct mt7925_nan_enable_req_tlv *req, struct cfg80211_nan_conf *conf) { @@ -144,101 +75,6 @@ mt7925_nan_update_conf(struct mt792x_vif *mvif, memcpy(mvif->nan.conf.cluster_id, conf->cluster_id, ETH_ALEN); } -int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr) -{ - struct mt76_dev *mdev; - struct { - u8 rsv[4]; - struct mt7925_nan_nmi_addr_tlv nmi_addr_tlv; - } nmi_cmd = { - .rsv = { 0 }, - .nmi_addr_tlv = { - .tag = cpu_to_le16(NAN_UNI_CMD_CHANGE_NMI_ADDRESS), - .len = cpu_to_le16(sizeof(struct mt7925_nan_nmi_addr_tlv)), - }, - }; - int ret; - - if (!dev || !addr) - return -EINVAL; - - if (is_zero_ether_addr(addr) || is_multicast_ether_addr(addr)) { - dev_err(dev->mt76.dev, "NAN: invalid NMI address %pM\n", addr); - return -EINVAL; - } - - mdev = &dev->mt76; - memcpy(nmi_cmd.nmi_addr_tlv.nmi_addr, addr, ETH_ALEN); - - ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nmi_cmd, - sizeof(nmi_cmd), true); - - return ret; -} - -int mt7925_nan_enable(struct ieee80211_vif *vif, - struct mt792x_dev *dev, - struct cfg80211_nan_conf *conf) -{ - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct mt76_dev *mdev = &dev->mt76; - struct { - u8 rsv[4]; - struct mt7925_nan_enable_req_tlv nan_req_tlv; - } nan_cmd = { - .rsv = { 0 }, - .nan_req_tlv = { - .tag = cpu_to_le16(NAN_UNI_CMD_ENABLE_REQUEST), - .len = cpu_to_le16(sizeof(struct mt7925_nan_enable_req_tlv)), - .config_random_factor_force = 0, - .random_factor_force_val = 0, - .config_hop_count_force = 0, - .hop_count_force_val = 0, - }, - }; - struct mt7925_nan_enable_req_tlv *p_nan_req_tlv = &nan_cmd.nan_req_tlv; - int ret; - - if (!vif || !dev || !conf) - return -EINVAL; - - p_nan_req_tlv->master_pref = conf->master_pref; - - mt7925_nan_set_2g_support(p_nan_req_tlv, conf); - mt7925_nan_set_5g_channel(dev, p_nan_req_tlv, conf); - mt7925_nan_set_cluster_id(p_nan_req_tlv, conf->cluster_id); - mt7925_nan_set_dw_interval(p_nan_req_tlv, conf); - mt7925_nan_set_disc_beacon(p_nan_req_tlv, conf); - mt7925_nan_set_rssi_thresholds(p_nan_req_tlv, conf); - mt7925_nan_set_scan_params(p_nan_req_tlv, conf); - - mt7925_nan_update_conf(mvif, conf); - - ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true); - - return ret; -} - -int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev) -{ - struct mt76_dev *mdev = &dev->mt76; - struct { - u8 rsv[4]; - struct tlv nan_dis_tlv; - } nan_cmd = { - .rsv = { 0 }, - .nan_dis_tlv = { - .tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST), - .len = cpu_to_le16(sizeof(struct tlv)), - }, - }; - - if (!dev) - return -EINVAL; - - return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true); -} - static int mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref) { @@ -255,9 +91,6 @@ mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref) mp_tlv = (struct mt7925_nan_master_preference_tlv *)tlv; - if (master_pref > NAN_MAX_MASTER_PREFERENCE) - return 0; - mp_tlv->master_preference = master_pref; return 0; @@ -357,6 +190,213 @@ mt7925_nan_sync_rssi_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf) return 0; } +/* FW rate set bit definitions (matches FW wlan_def_cmm.h) */ +#define NAN_RATE_SET_BIT_1M BIT(0) +#define NAN_RATE_SET_BIT_2M BIT(1) +#define NAN_RATE_SET_BIT_5_5M BIT(2) +#define NAN_RATE_SET_BIT_11M BIT(3) +#define NAN_RATE_SET_BIT_6M BIT(6) +#define NAN_RATE_SET_BIT_9M BIT(7) +#define NAN_RATE_SET_BIT_12M BIT(8) +#define NAN_RATE_SET_BIT_18M BIT(9) +#define NAN_RATE_SET_BIT_24M BIT(10) +#define NAN_RATE_SET_BIT_36M BIT(11) +#define NAN_RATE_SET_BIT_48M BIT(12) +#define NAN_RATE_SET_BIT_54M BIT(13) + +#define NAN_RATE_SET_ALL_A (NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_9M | \ + NAN_RATE_SET_BIT_12M | NAN_RATE_SET_BIT_18M | \ + NAN_RATE_SET_BIT_24M | NAN_RATE_SET_BIT_36M | \ + NAN_RATE_SET_BIT_48M | NAN_RATE_SET_BIT_54M) + +/* 5G basic: 6M+12M+24M (OFDM) */ +#define NAN_BASIC_RATE_SET_5G (NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_12M | \ + NAN_RATE_SET_BIT_24M) + +/* GF_MODE_DISALLOWED = 2, RIFS_MODE_DISALLOWED = 1 */ +#define NAN_GF_MODE_DISALLOWED 2 +#define NAN_RIFS_MODE_DISALLOWED 1 + +int mt7925_nan_update_phy_setting(struct mt792x_dev *dev) +{ + struct mt76_phy *mphy = &dev->mphy; + struct ieee80211_supported_band *sband_5g; + struct mt7925_nan_phy_setting *phy; + struct { + u8 rsv[4]; + struct mt7925_nan_update_phy_setting_tlv tlv; + } req = {}; + + sband_5g = mphy->hw->wiphy->bands[NL80211_BAND_5GHZ]; + + req.tlv.tag = cpu_to_le16(NAN_UNI_CMD_UPDATE_PHY_SETTING); + req.tlv.len = cpu_to_le16(sizeof(req.tlv)); + + /* 2G: ERP + HT (no CCK/HR_DSSS - NAN uses OFDM only) */ + phy = &req.tlv.phy_2g; + phy->phy_type_set = PHY_TYPE_BIT_ERP | PHY_TYPE_BIT_HT; + phy->non_ht_basic_phy_type = PHY_TYPE_ERP_INDEX; + phy->use_short_preamble = 1; + phy->use_short_slot_time = 1; + phy->operational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A); + phy->bss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G); + phy->gf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED); + phy->rifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED); + + /* 5G: OFDM + HT + VHT (NAN_MODE_11A) */ + phy = &req.tlv.phy_5g; + phy->phy_type_set = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HT | + PHY_TYPE_BIT_VHT; + phy->non_ht_basic_phy_type = PHY_TYPE_OFDM_INDEX; + phy->use_short_preamble = 1; + phy->use_short_slot_time = 1; + phy->operational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A); + phy->bss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G); + phy->gf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED); + phy->rifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED); + + /* VHT basic MCS set from sband capability */ + if (sband_5g && sband_5g->vht_cap.vht_supported) + phy->vht_basic_mcs_set = + sband_5g->vht_cap.vht_mcs.rx_mcs_map; + + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(NAN), + &req, sizeof(req), true); +} + +struct ieee80211_chanctx_conf * +mt7925_nan_seed_link_sta(struct mt792x_dev *dev, + struct ieee80211_link_sta *link_sta) +{ + struct ieee80211_supported_band *sband_2g, *sband_5g; + struct ieee80211_chanctx_conf *nan_ctx = NULL; + struct ieee80211_vif *nan_vif = dev->nan_vif; + + /* Fill HT cap from 2G sband */ + sband_2g = dev->mphy.hw->wiphy->bands[NL80211_BAND_2GHZ]; + sband_5g = dev->mphy.hw->wiphy->bands[NL80211_BAND_5GHZ]; + if (sband_2g) + link_sta->ht_cap = sband_2g->ht_cap; + + link_sta->sta->wme = true; + link_sta->rx_nss = hweight8(dev->mphy.antenna_mask); + + /* Get chanctx from NAN schedule. + * Prefer 5G committed slot for wider BW (VHT), fallback + * to first valid slot if no 5G data slot is scheduled. + */ + if (nan_vif) { + struct ieee80211_nan_channel **slots = + nan_vif->cfg.nan_sched.schedule; + int i; + + for (i = 0; i < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; i++) { + struct ieee80211_chanctx_conf *ctx; + + if (!slots[i] || IS_ERR(slots[i]) || + !slots[i]->chanctx_conf) + continue; + + ctx = slots[i]->chanctx_conf; + if (!nan_ctx) + nan_ctx = ctx; + if (ctx->def.chan->band == NL80211_BAND_5GHZ) { + nan_ctx = ctx; + break; + } + } + } + + /* Capability describes what the device can do and must not be + * filtered by the current schedule - firmware gates the VHT rate + * mode per the data schedule and re-derives it on schedule + * change, which only works if the caps are present up front. + */ + if (sband_5g) + link_sta->vht_cap = sband_5g->vht_cap; + + /* Bandwidth here is the capability ceiling, not the operating + * width - the per-slot operating bandwidth follows the current + * slot channel via the firmware RLM sync, so deriving it from + * the schedule at STA-add time would cap a later 5 GHz schedule + * at the bring-up width. + */ + link_sta->bandwidth = IEEE80211_STA_RX_BW_80; + + return nan_ctx; +} + +int mt7925_nan_enable(struct ieee80211_vif *vif, + struct mt792x_dev *dev, + struct cfg80211_nan_conf *conf) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt76_dev *mdev = &dev->mt76; + struct mt7925_nan_common_hdr *hdr; + struct mt7925_nan_enable_req_tlv *req; + struct sk_buff *skb; + + if (!vif || !dev || !conf) + return -EINVAL; + + skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_ENABLE_MAX_SIZE); + if (!skb) + return -ENOMEM; + + hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + + /* Set cluster id before joining cluster */ + if (mt7925_nan_cluster_id_tlv(skb, conf->cluster_id)) { + dev_kfree_skb(skb); + return -ENOMEM; + } + + /* NAN enable request tlv */ + req = (struct mt7925_nan_enable_req_tlv *) + mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_ENABLE_REQUEST, + sizeof(*req)); + if (!req) { + dev_kfree_skb(skb); + return -ENOMEM; + } + + req->master_pref = conf->master_pref; + + mt7925_nan_set_5g_channel(dev, req, conf); + mt7925_nan_set_scan_params(req, conf); + + if (mt7925_nan_dw_tlv(skb, conf) || + mt7925_nan_sync_rssi_tlv(skb, conf)) { + dev_kfree_skb(skb); + return -ENOMEM; + } + + mt7925_nan_update_conf(mvif, conf); + + return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true); +} + +int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + struct { + u8 rsv[4]; + struct tlv nan_dis_tlv; + } nan_cmd = { + .rsv = { 0 }, + .nan_dis_tlv = { + .tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST), + .len = cpu_to_le16(sizeof(struct tlv)), + }, + }; + + if (!dev) + return -EINVAL; + + return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true); +} + int mt7925_nan_change_configure(struct ieee80211_vif *vif, struct mt792x_dev *dev, struct cfg80211_nan_conf *conf) @@ -473,8 +513,26 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv) dev_dbg(dev->mt76.dev, "nan: evt=%u cluster=%pM\n", de_evt->event_type, de_evt->cluster_id); - if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER) + if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER && + de_evt->event_type != NAN_EVENT_ID_STARTED_CLUSTER) + return; + + /* STARTED_CLUSTER fires during NAN_START, before nan.started is set and + * before the supplicant subscribes - defer past NAN_START via the work + * so ieee80211_nan_cluster_joined() actually reaches userspace. + */ + if (de_evt->event_type == NAN_EVENT_ID_STARTED_CLUSTER) { + dev_dbg(dev->mt76.dev, + "nan: deferring STARTED_CLUSTER cluster=%pM\n", + cluster_id); + spin_lock_bh(&dev->nan_deferred_lock); + memcpy(dev->nan_started_cluster_id, cluster_id, ETH_ALEN); + set_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER, + &dev->nan_deferred_pending); + spin_unlock_bh(&dev->nan_deferred_lock); + ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work); return; + } if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) { dev_warn(dev->mt76.dev, "nan: joined-cluster event but NAN not started\n"); @@ -487,7 +545,110 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv) dev_dbg(dev->mt76.dev, "nan: own_nmi=%pM master_nmi=%pM\n", de_evt->own_nmi, de_evt->master_nmi); - ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL); + /* joined an existing cluster, not a self-anchored new one */ + ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, false, GFP_KERNEL); +} + +/* Runs the deferred NAN MCU events in process context; takes wiphy_lock + * before nan_vif, which the NAN stop path frees under that mutex. + */ +void +mt7925_nan_deferred_work(struct work_struct *work) +{ + struct mt792x_dev *dev = container_of(work, struct mt792x_dev, + nan_deferred_work); + struct ieee80211_vif *vif; + unsigned long pending; + u8 cluster_id[ETH_ALEN]; + + spin_lock_bh(&dev->nan_deferred_lock); + pending = dev->nan_deferred_pending; + dev->nan_deferred_pending = 0; + memcpy(cluster_id, dev->nan_started_cluster_id, ETH_ALEN); + spin_unlock_bh(&dev->nan_deferred_lock); + + if (!pending) + return; + + wiphy_lock(dev->mt76.hw->wiphy); + vif = dev->nan_vif; + if (!vif || !ieee80211_vif_nan_started(vif)) + goto out; + + if (test_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER, &pending)) + ieee80211_nan_cluster_joined(vif, cluster_id, true, GFP_KERNEL); + + if (test_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &pending)) + ieee80211_nan_sched_update_done(vif); +out: + wiphy_unlock(dev->mt76.hw->wiphy); +} + +static void +mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv) +{ + struct mt7925_nan_ulw_event *evt; + struct mt7925_nan_ulw_attr attr; + struct wireless_dev *wdev; + u16 len; + + if (!dev || !tlv) + return; + + if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) + return; + + len = le16_to_cpu(tlv->len); + if (len < sizeof(*tlv) + sizeof(*evt)) { + dev_warn(dev->mt76.dev, + "nan: short ulw event tlv len=%u\n", len); + return; + } + + evt = (struct mt7925_nan_ulw_event *)tlv->data; + wdev = ieee80211_vif_to_wdev(dev->nan_vif); + if (!wdev) + return; + + dev_dbg(dev->mt76.dev, + "nan: ulw_update wdev=%p owner_nlportid=%u sched_id=%u seq=%u dur=%u\n", + wdev, wdev->owner_nlportid, + evt->sched_id, evt->seq_id, le32_to_cpu(evt->duration)); + + /* Reorder the FW fields into NAN spec Table 109 attribute layout */ + attr.attr_id = NAN_ULW_ATTR_ID; + attr.length = cpu_to_le16(NAN_ULW_FIXED_PAYLOAD); + attr.sched_id = evt->sched_id; + attr.seq_id = evt->seq_id; + attr.start_time = evt->start_time; + attr.duration = evt->duration; + attr.period = evt->period; + attr.count_down = evt->count_down; + attr.ulw_overwrite = evt->ulw_overwrite; + + cfg80211_nan_ulw_update(wdev, (const u8 *)&attr, sizeof(attr), + GFP_KERNEL); +} + +static void +mt7925_nan_handle_sched_update_done(struct mt792x_dev *dev, struct tlv *tlv) +{ + struct ieee80211_vif *vif; + + if (!dev || !tlv) + return; + + vif = dev->nan_vif; + if (!vif || !ieee80211_vif_nan_started(vif)) + return; + + /* Runs in the BH-disabled MCU-event RX path; the mac80211 helper needs + * the wiphy mutex and may sleep, so hand it to the work instead. + */ + spin_lock_bh(&dev->nan_deferred_lock); + set_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &dev->nan_deferred_pending); + spin_unlock_bh(&dev->nan_deferred_lock); + ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work); } void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb) @@ -515,9 +676,15 @@ void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb) case NAN_UNI_EVENT_ID_DE_EVENT_IND: mt7925_nan_mcu_handle_de_event(dev, tlv); break; - case NAN_UNI_EVENT_REPORT_DW_END: + case NAN_UNI_EVENT_REPORT_DW_START: mt7925_nan_handle_dw_ind(dev, tlv); break; + case NAN_UNI_EVENT_ID_ULW_UPDATE: + mt7925_nan_handle_ulw_update(dev, tlv); + break; + case NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE: + mt7925_nan_handle_sched_update_done(dev, tlv); + break; default: break; } @@ -555,6 +722,7 @@ static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb, avail_ctrl_tlv->avail_ctrl = cpu_to_le16(ctrl & NAN_AVAIL_CTRL_CHECK_FOR_CHANGED); avail_ctrl_tlv->seq_id = seq_id; + avail_ctrl_tlv->is_deferred = sched->deferred ? 1 : 0; return 0; } @@ -584,9 +752,14 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif, if (FIELD_GET(NAN_CH_CTRL_PRIMARY_CH, raw) == slot_chan->chan->hw_value) { - u32 map = le32_to_cpu(ch_list[j].avail_map[0]); + u32 dw; + + for (dw = 0; dw < NAN_TOTAL_DW; dw++) { + u32 map = le32_to_cpu(ch_list[j].avail_map[dw]); - ch_list[j].avail_map[0] = cpu_to_le32(map | BIT(i)); + ch_list[j].avail_map[dw] = + cpu_to_le32(map | BIT(i)); + } le32_add_cpu(&ch_list[j].num, 1); is_found = true; break; @@ -594,12 +767,18 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif, } if (!is_found && num_channels < NAN_TIMELINE_MGMT_CHNL_LIST_NUM) { + u32 dw; + ch_list[num_channels].ch_info = - cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_OP_CLASS, + cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_CH_TYPE, + NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL) | + FIELD_PREP(NAN_CH_CTRL_OP_CLASS, slot->channel_entry[0]) | FIELD_PREP(NAN_CH_CTRL_PRIMARY_CH, slot_chan->chan->hw_value)); - ch_list[num_channels].avail_map[0] = cpu_to_le32(BIT(i)); + for (dw = 0; dw < NAN_TOTAL_DW; dw++) + ch_list[num_channels].avail_map[dw] = + cpu_to_le32(BIT(i)); le32_add_cpu(&ch_list[num_channels].num, 1); ch_list[num_channels].is_valid++; num_channels++; @@ -647,15 +826,12 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev, { struct mt7925_nan_common_hdr *hdr; struct mt76_dev *mdev; - bool deferred; struct sk_buff *skb; - int ret = -ENOMEM; if (!dev || !vif) return; mdev = &dev->mt76; - deferred = vif->cfg.nan_sched.deferred; mt792x_mutex_acquire(dev); @@ -672,19 +848,9 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev, goto out; } - ret = mt76_mcu_skb_send_msg(mdev, skb, - MCU_UNI_CMD(NAN), true); + mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), false); out: mt792x_mutex_release(dev); - - if (deferred) { - if (ret) - dev_err(mdev->dev, - "NAN: local schedule update failed: %d\n", - ret); - - ieee80211_nan_sched_update_done(vif); - } } static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb, @@ -712,23 +878,6 @@ static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb, return 0; } -static u8 mt7925_nan_get_supported_bands(struct mt792x_vif *mvif) -{ - struct wiphy *wiphy; - u8 bands = 0; - - if (!mvif || !mvif->phy) - return BIT(NAN_SUPPORTED_BAND_ID_2P4G); - - wiphy = mvif->phy->mt76->hw->wiphy; - if (wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ)) - bands |= BIT(NAN_SUPPORTED_BAND_ID_2P4G); - if (wiphy->nan_supported_bands & BIT(NL80211_BAND_5GHZ)) - bands |= BIT(NAN_SUPPORTED_BAND_ID_5G); - - return bands ?: BIT(NAN_SUPPORTED_BAND_ID_2P4G); -} - static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, struct mt792x_sta *msta) @@ -755,8 +904,7 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb, peer_cap_tlv = (struct mt7925_nan_sched_update_peer_cap_tlv *)tlv; peer_cap_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx); - peer_cap_tlv->supported_bands = - mt7925_nan_get_supported_bands(msta->vif); + peer_cap_tlv->supported_bands = BIT(NAN_SUPPORTED_BAND_ID_2P4G); peer_cap_tlv->max_chnl_switch_time = cpu_to_le16(sched->max_chan_switch); for (i = 0; i < sched->n_channels; i++) { @@ -785,52 +933,40 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb, static void mt7925_nan_fill_crb_committed(struct mt7925_nan_sched_update_crb_tlv *crb_tlv, - struct ieee80211_vif *vif, struct ieee80211_nan_peer_sched *sched) { - struct ieee80211_nan_sched_cfg *local_sched; - u8 local_map_id; u32 m, slot; - if (!vif || !sched) + if (!sched) return; - local_sched = &vif->cfg.nan_sched; - local_map_id = mt7925_nan_avail_attr_ctrl(local_sched) & - NAN_AVAIL_CTRL_MAPID; - for (m = 0; m < CFG80211_NAN_MAX_PEER_MAPS && m < NAN_TIMELINE_MGMT_SIZE; m++) { + struct ieee80211_nan_peer_map *map = &sched->maps[m]; struct mt7925_nan_sched_timeline *tl = &crb_tlv->comm_faw_timeline[m]; - struct ieee80211_nan_peer_map *map = &sched->maps[m]; - u32 avail_map = 0; if (map->map_id == CFG80211_NAN_INVALID_MAP_ID) continue; tl->map_id = map->map_id; - tl->local_map_id = local_map_id; + /* + * Convert peer schedule slots to FW avail_map bitmap. + * Each bit represents one time slot where the peer has + * committed availability. Fill all DW intervals the same. + */ for (slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; slot++) { - struct ieee80211_nan_channel *local_ch; - struct ieee80211_nan_channel *peer_ch; + struct ieee80211_nan_channel *ch = map->slots[slot]; + u32 dw; - local_ch = local_sched->schedule[slot]; - peer_ch = map->slots[slot]; - - if (!local_ch || !local_ch->chanctx_conf || - !peer_ch || !peer_ch->chanctx_conf) + if (!ch || !ch->chanctx_conf) continue; - if (local_ch->chanctx_conf != peer_ch->chanctx_conf) - continue; - - avail_map |= BIT(slot); + for (dw = 0; dw < NAN_TOTAL_DW; dw++) + tl->avail_map[dw] |= cpu_to_le32(BIT(slot)); } - - tl->avail_map[0] = cpu_to_le32(avail_map); } } @@ -856,8 +992,38 @@ static int mt7925_nan_update_crb_tlv(struct sk_buff *skb, crb_tlv->is_use_ranging = false; crb_tlv->comm_ndc_ctrl.is_valid = false; - mt7925_nan_fill_crb_committed(crb_tlv, msta->vif->phy->dev->nan_vif, - sta->nan_sched); + mt7925_nan_fill_crb_committed(crb_tlv, sta->nan_sched); + + return 0; +} + +static int +mt7925_nan_peer_ulw_tlv(struct sk_buff *skb, + struct ieee80211_sta *sta, + struct mt792x_sta *msta) +{ + struct mt7925_nan_update_ulw_tlv *ulw_tlv = NULL; + struct ieee80211_nan_peer_sched *sched = NULL; + struct tlv *tlv = NULL; + + if (!skb || !sta || !msta) + return -EINVAL; + + sched = sta->nan_sched; + if (!sched || !sched->init_ulw || !sched->ulw_size) + return 0; /* No ULW to send, not an error */ + + if (sched->ulw_size > NAN_ULW_MAX_SIZE) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_ULW, + sizeof(struct mt7925_nan_update_ulw_tlv)); + if (!tlv) + return -ENOMEM; + + ulw_tlv = (struct mt7925_nan_update_ulw_tlv *)tlv; + ether_addr_copy(ulw_tlv->nmi_addr, sta->addr); + memcpy(ulw_tlv->ulw_attr, sched->init_ulw, sched->ulw_size); return 0; } @@ -914,6 +1080,10 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev, goto free_skb; } + ret = mt7925_nan_peer_ulw_tlv(skb, sta, msta); + if (ret) + goto free_skb; + ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true); if (ret && idx_allocated) goto clear_idx; @@ -935,18 +1105,18 @@ clear_idx: int mt792x_nan_set_peer_rec(struct mt76_dev *mdev, struct ieee80211_sta *sta) { + struct mt7925_nan_sched_update_crb_tlv *crb_tlv; struct mt7925_nan_common_hdr *hdr; struct mt792x_sta *msta; struct mt792x_nan *nan; struct sk_buff *skb; + struct tlv *tlv; int ret; if (!mdev || !sta) return -EINVAL; - skb = mt76_mcu_msg_alloc(mdev, NULL, - sizeof(struct mt7925_nan_common_hdr) + - sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv)); + skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_PEER_MAX_SIZE); if (!skb) return -ENOMEM; @@ -961,6 +1131,25 @@ int mt792x_nan_set_peer_rec(struct mt76_dev *mdev, return 0; } + /* Send a zero-avail_map CRB TLV before deactivating the peer record so + * firmware clears the committed schedule slots for this peer. Without + * this, stale CRB entries linger and cause scheduling conflicts for + * subsequent NDP connections that reuse the same sch_idx. + */ + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_CRB, + sizeof(struct mt7925_nan_sched_update_crb_tlv)); + if (!tlv) { + dev_kfree_skb(skb); + return -ENOMEM; + } + crb_tlv = (struct mt7925_nan_sched_update_crb_tlv *)tlv; + crb_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx); + crb_tlv->flags = NAN_CRB_USE_DATA_PATH; + crb_tlv->is_use_ranging = false; + crb_tlv->comm_ndc_ctrl.is_valid = false; + /* avail_map is zero-initialised by mt76_connac_mcu_add_tlv */ + + /* Deactivate peer record and release connection index */ if (mt7925_nan_peer_rec_tlv(skb, sta, msta, false)) { dev_kfree_skb(skb); return -ENOMEM; @@ -984,21 +1173,17 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev, struct mt7925_nan_common_hdr *hdr; struct ieee80211_sta *nmi_sta; struct mt792x_sta *nmi_msta; - struct mt792x_vif *mvif; struct mt792x_sta *msta; u8 nmi_addr[ETH_ALEN]; struct sk_buff *skb; int ndp_ctx_id = 0; int ret = -ENOMEM; - struct mt792x_dev *dev; struct tlv *tlv; if (!mdev || !vif || !sta) return -EINVAL; - dev = container_of(mdev, struct mt792x_dev, mt76); msta = (struct mt792x_sta *)sta->drv_priv; - mvif = (struct mt792x_vif *)vif->drv_priv; rcu_read_lock(); nmi_sta = rcu_dereference(sta->nmi); @@ -1012,33 +1197,6 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev, memcpy(nmi_addr, nmi_sta->addr, ETH_ALEN); nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv; - if (!nmi_msta->nan_sched.idx_assigned) { - if (!nmi_sta->nan_sched) { - rcu_read_unlock(); - dev_err(mdev->dev, - "NAN: peer schedule missing for NDI sta %pM\n", - sta->addr); - return -EAGAIN; - } - - rcu_read_unlock(); - ret = mt792x_nan_set_peer_schedule(dev, nmi_sta); - if (ret) - return ret; - - rcu_read_lock(); - nmi_sta = rcu_dereference(sta->nmi); - if (!nmi_sta) { - rcu_read_unlock(); - dev_err(mdev->dev, - "NAN: NMI sta not found for NDI sta %pM\n", - sta->addr); - return -EINVAL; - } - - nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv; - } - ndp_ctx_id = find_first_zero_bit(&nmi_msta->nan_sched.ndp_ctx_bitmap, NAN_MAX_NDP_CXT); if (ndp_ctx_id >= NAN_MAX_NDP_CXT) { @@ -1073,7 +1231,7 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev, memcpy(map_tlv->nmi_addr, nmi_addr, ETH_ALEN); map_tlv->sta_rec_idx = msta->deflink.wcid.idx; map_tlv->ndp_ctx_id = ndp_ctx_id; - map_tlv->role_idx = cpu_to_le32(mvif->bss_conf.mt76.idx); + map_tlv->role_idx = cpu_to_le32(NAN_BSS_INDEX_BAND0); memcpy(map_tlv->ndi_addr, vif->addr, ETH_ALEN); ret = mt76_mcu_skb_send_msg(mdev, skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h index f55730e25f46..9a0cd1d06d45 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h @@ -28,6 +28,13 @@ #define NAN_MAX_CONN_CFG 8 #define NAN_MAX_NDP_CXT 4 +#define MT7925_NAN_ENABLE_MAX_SIZE \ + (sizeof(struct mt7925_nan_common_hdr) + \ + sizeof(struct mt7925_nan_enable_req_tlv) + \ + sizeof(struct mt7925_nan_dw_interval_tlv) + \ + sizeof(struct mt7925_nan_cluster_id_tlv) + \ + sizeof(struct mt7925_nan_sync_rssi_tlv)) + #define MT7925_NAN_CONF_MAX_SIZE \ (sizeof(struct mt7925_nan_common_hdr) + \ sizeof(struct mt7925_nan_master_preference_tlv) + \ @@ -44,7 +51,8 @@ (sizeof(struct mt7925_nan_common_hdr) + \ sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv) + \ sizeof(struct mt7925_nan_sched_update_peer_cap_tlv) + \ - sizeof(struct mt7925_nan_sched_update_crb_tlv)) + sizeof(struct mt7925_nan_sched_update_crb_tlv) + \ + sizeof(struct mt7925_nan_update_ulw_tlv)) /* NAN Availability Attribute */ #define NAN_AVAIL_ATTR_ID_OFFSET 0 @@ -65,6 +73,8 @@ #define UNII3_LOWER_BOUND 149 #define UNII3_UPPER_BOUND 165 +#define NAN_BSS_INDEX_BAND0 0 + enum nan_uni_cmd_tag { NAN_UNI_CMD_SET_MASTER_PREFERENCE = 0, NAN_UNI_CMD_ENABLE_REQUEST = 7, @@ -73,6 +83,8 @@ enum nan_uni_cmd_tag { NAN_UNI_CMD_UPDATE_CRB = 10, NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD = 12, NAN_UNI_CMD_MAP_STA_RECORD = 13, + NAN_UNI_CMD_UPDATE_ULW = 16, + NAN_UNI_CMD_UPDATE_PHY_SETTING = 18, NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL = 20, NAN_UNI_CMD_UPDATE_PEER_CAPABILITY = 21, NAN_UNI_CMD_CHANGE_NMI_ADDRESS = 24, @@ -84,14 +96,26 @@ enum nan_uni_cmd_tag { enum nan_uni_event_tag { NAN_UNI_EVENT_ID_DE_EVENT_IND = 19, + NAN_UNI_EVENT_ID_ULW_UPDATE = 39, + NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE = 43, + NAN_UNI_EVENT_REPORT_DW_START = 59, NAN_UNI_EVENT_REPORT_DW_END = 60, }; enum nan_disc_event_type { NAN_EVENT_ID_DISC_MAC_ADDR = 0, + NAN_EVENT_ID_STARTED_CLUSTER = 1, NAN_EVENT_ID_JOINED_CLUSTER = 2, }; +/* bit indices into mt792x_dev->nan_deferred_pending, set from the atomic + * MCU-event RX path and consumed by mt7925_nan_deferred_work() + */ +enum mt7925_nan_deferred_event { + MT7925_NAN_DEFERRED_STARTED_CLUSTER, + MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, +}; + /* NAN 4.0 Table 79. Device Capability attribute format, Supported Bands */ enum nan_supported_bands { NAN_SUPPORTED_BAND_ID_2P4G = 2, @@ -108,12 +132,15 @@ enum nan_peer_supported_bands { NAN_SUPPORTED_BN_NUM }; +#define NAN_CH_CTRL_CH_TYPE BIT(0) #define NAN_CH_CTRL_OP_CLASS GENMASK(15, 8) #define NAN_CH_CTRL_PRIMARY_CH GENMASK(23, 16) #define NAN_CRB_USE_DATA_PATH BIT(0) #define NAN_CRB_AVAIL_6G_FORMAT GENMASK(2, 1) +#define NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL 1 + struct mt7925_nan_social_ch_scan_params { u8 dwell_time[NAN_MAX_SOCIAL_CHANNELS]; __le16 scan_period[NAN_MAX_SOCIAL_CHANNELS]; @@ -153,6 +180,32 @@ struct nan_rpt_dw_evt { __le16 dw_num; }; +#define NAN_ULW_ATTR_ID 0x17 +#define NAN_ULW_FIXED_PAYLOAD 16 /* Table 109 fixed fields */ + +struct mt7925_nan_ulw_event { + u8 sched_id; + u8 seq_id; + u8 count_down; + u8 ulw_overwrite; + __le32 start_time; + __le32 duration; + __le32 period; +} __packed; + +/* ULW attribute laid out in NAN spec Table 109 field order */ +struct mt7925_nan_ulw_attr { + u8 attr_id; + __le16 length; + u8 sched_id; + u8 seq_id; + __le32 start_time; + __le32 duration; + __le32 period; + u8 count_down; + u8 ulw_overwrite; +} __packed; + struct mt7925_nan_conf_dw { u8 config_2dot4g_dw_band; __le32 dw_2dot4g_interval_val; @@ -302,7 +355,7 @@ struct mt7925_nan_avail_ctrl_tlv { __le16 len; __le16 avail_ctrl; u8 seq_id; - u8 reserved[1]; + u8 is_deferred; } __packed __aligned(4); struct mt7925_nan_ch_timeline { @@ -346,8 +399,7 @@ struct mt7925_nan_sched_update_peer_cap_tlv { struct mt7925_nan_sched_timeline { u8 map_id; - u8 local_map_id; - u8 reserved[2]; + u8 reserved[3]; union { __le32 avail_map[NAN_TOTAL_DW]; u8 avail_block[NAN_TOTAL_DW * 4]; @@ -378,6 +430,15 @@ struct mt7925_nan_sched_update_crb_tlv { struct mt7925_nan_sched_faw_ndc_timeline faw_ndc_timeline[NAN_TIMELINE_MGMT_SIZE]; } __packed __aligned(4); +#define NAN_ULW_MAX_SIZE 256 + +struct mt7925_nan_update_ulw_tlv { + __le16 tag; + __le16 len; + u8 nmi_addr[ETH_ALEN]; + u8 ulw_attr[NAN_ULW_MAX_SIZE]; +} __packed __aligned(4); + struct mt7925_nan_sched_map_sta_rec_tlv { __le16 tag; __le16 len; @@ -390,6 +451,38 @@ struct mt7925_nan_sched_map_sta_rec_tlv { u8 reserved[2]; } __packed __aligned(4); +/* Matches FW NAN_PHY_SETTING_T (enum fields are 4 bytes on ARM) */ +struct mt7925_nan_phy_setting { + u8 phy_type_set; + u8 non_ht_basic_phy_type; + u8 use_short_preamble; + u8 use_short_slot_time; + __le16 operational_rate_set; + __le16 bss_basic_rate_set; + __le16 vht_basic_mcs_set; + u8 erp_protect_mode; + u8 ht_op_info1; + __le16 ht_op_info2; + __le16 ht_op_info3; + __le32 ht_protect_mode; + __le32 gf_operation_mode; + __le32 rifs_operation_mode; +} __packed; + +/* Matches FW NAN_SCHED_CMD_UPDATE_PHY_PARAM_T */ +struct mt7925_nan_update_phy_setting_tlv { + __le16 tag; + __le16 len; + struct mt7925_nan_phy_setting phy_2g; + struct mt7925_nan_phy_setting phy_5g; +} __packed __aligned(4); + +int mt7925_nan_update_phy_setting(struct mt792x_dev *dev); + +struct ieee80211_chanctx_conf * +mt7925_nan_seed_link_sta(struct mt792x_dev *dev, + struct ieee80211_link_sta *link_sta); + int mt7925_nan_enable(struct ieee80211_vif *vif, struct mt792x_dev *dev, struct cfg80211_nan_conf *conf); @@ -403,8 +496,6 @@ int mt7925_nan_change_configure(struct ieee80211_vif *vif, void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb); -int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr); - void mt7925_nan_local_sched_changed(struct mt792x_dev *dev, struct ieee80211_vif *vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index 02ef09dd797d..0d477dc1086c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -9,6 +9,7 @@ #include "mac.h" #include "mcu.h" #include "regd.h" +#include "cached_cal.h" #include "../dma.h" static const struct pci_device_id mt7925_pci_device_table[] = { @@ -38,6 +39,62 @@ static int mt7925e_init_reset(struct mt792x_dev *dev) return mt792x_wpdma_reset(dev, true); } +/* Set up the factory-calibration cache in host memory. PCIe only: the FW + * reaches the buffer through AXI DMA, so it has no meaning on other buses. + * Every failure just leaves the cache off, which is not fatal. + */ +void mt7925e_axidma_cal_cache_init(struct mt792x_dev *dev) +{ + if (!(dev->phy.chip_cap & MT792x_CHIP_CAP_AXIDMA_EN)) + return; + + if (dev->cached_cal.va) { + /* Carried-over buffer still holds FW-written cal data. */ + dev->cached_cal.reused = true; + } else { + if (mt7925_axidma_alloc(dev)) { + dev_warn(dev->mt76.dev, + "AXI DMA cal cache disabled: buffer alloc failed\n"); + return; + } + /* Freshly allocated buffer is zeroed: no cal data yet. */ + dev->cached_cal.reused = false; + } + + if (mt7925_mcu_send_axidma_info(dev)) { + dev_warn(dev->mt76.dev, + "AXI DMA cal cache disabled: info cmd to FW failed\n"); + return; + } + + /* Enable the bypass-cal flow so the FW reuses cached cal data + * (common / power-on group) instead of running a full calibration; + * must be set before the mapping table is sent. + */ + if (mt7925_mcu_fact_cal_set_bypass(dev, true)) { + dev_warn(dev->mt76.dev, + "AXI DMA cal cache disabled: bypass flag set failed\n"); + return; + } + + if (mt7925_mcu_send_fact_cal_mapping_tbl(dev)) { + dev_warn(dev->mt76.dev, + "AXI DMA cal cache disabled: mapping tbl send failed\n"); + return; + } + + if (mt7925_mcu_fact_cal_set_bypass(dev, false)) { + dev_warn(dev->mt76.dev, + "AXI DMA cal cache disabled: bypass flag set failed\n"); + return; + } + + dev_info(dev->mt76.dev, + "AXI DMA cal cache enabled (DMA=%pad, size=%u, reused=%d)\n", + &dev->cached_cal.dma_addr, dev->cached_cal.size, + dev->cached_cal.reused); +} + static void mt7925e_unregister_device(struct mt792x_dev *dev) { int i; @@ -47,19 +104,22 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev) if (dev->phy.chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN) wiphy_rfkill_stop_polling(hw->wiphy); - cancel_work_sync(&dev->reset_work); cancel_work_sync(&dev->init_work); mt76_unregister_device(&dev->mt76); + set_bit(MT76_REMOVED, &dev->mphy.state); + cancel_work_sync(&dev->reset_work); mt76_for_each_q_rx(&dev->mt76, i) napi_disable(&dev->mt76.napi[i]); cancel_delayed_work_sync(&pm->ps_work); cancel_delayed_work_sync(&dev->mlo_pm_work); cancel_work_sync(&pm->wake_work); + cancel_work_sync(&dev->nan_deferred_work); mt7925_tx_token_put(dev); __mt792x_mcu_drv_pmctrl(dev); mt792x_dma_cleanup(dev); mt792x_wfsys_reset(dev); + mt7925_axidma_free(dev); skb_queue_purge(&dev->mt76.mcu.res_q); tasklet_disable(&dev->mt76.irq_tasklet); @@ -493,7 +553,6 @@ static const struct mt792x_irq_map mt7925_irq_map = { .all_complete_mask = MT7925_INT_RX_DONE_ALL, .data_complete_mask = MT7925_INT_RX_DONE_DATA, .wm_complete_mask = MT7925_INT_RX_DONE_WM, - .wm2_complete_mask = MT_INT_RX_DONE_WM2, }, }; @@ -587,7 +646,7 @@ static int mt7925_pci_probe(struct pci_dev *pdev, is_mt7928_hw = (pdev->device == 0x7928 || pdev->device == 0x7935); if (is_mt7928_hw) - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(34)); + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34)); else ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); @@ -725,7 +784,6 @@ static void mt7925_pci_remove(struct pci_dev *pdev) struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); - set_bit(MT76_REMOVED, &mdev->phy.state); mt7925e_unregister_device(dev); devm_free_irq(&pdev->dev, pdev->irq, dev); mt76_free_device(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c index 8477d21abc66..18f125bf3df4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c @@ -73,7 +73,9 @@ int mt7925e_mac_reset(struct mt792x_dev *dev) const struct mt792x_irq_map *irq_map = dev->irq_map; int i, err; - mt792xe_mcu_drv_pmctrl(dev); + err = mt792xe_mcu_drv_pmctrl(dev); + if (err) + return err; mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); @@ -125,7 +127,7 @@ int mt7925e_mac_reset(struct mt792x_dev *dev) err = mt792xe_mcu_fw_pmctrl(dev); if (err) - return err; + goto out; err = __mt792xe_mcu_drv_pmctrl(dev); if (err) @@ -135,6 +137,8 @@ int mt7925e_mac_reset(struct mt792x_dev *dev) if (err) goto out; + mt7925e_axidma_cal_cache_init(dev); + err = mt7925_mcu_set_eeprom(dev); if (err) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c index 72707eddc3db..258f3753db1f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c @@ -46,6 +46,8 @@ int mt7925e_mcu_init(struct mt792x_dev *dev) mt76_rmw_field(dev, dev->pcie_reg->pm, MT_PCIE_MAC_PM_L0S_DIS, 1); err = mt7925_run_firmware(dev); + if (!err) + mt7925e_axidma_cal_cache_init(dev); mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h index ab6c33b4a180..e040dff321dd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h @@ -48,8 +48,7 @@ #define MT7925_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA2 #define MT7925_INT_RX_DONE_WM HOST_RX_DONE_INT_ENA0 #define MT7925_INT_RX_DONE_ALL (MT7925_INT_RX_DONE_DATA | \ - MT7925_INT_RX_DONE_WM | \ - MT_INT_RX_DONE_WM2) + MT7925_INT_RX_DONE_WM) #define MT7927_INT_RX_DONE_DATA MT7927_RX_DONE_INT_ENA4 #define MT7927_INT_RX_DONE_WM MT7927_RX_DONE_INT_ENA6 diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c index 1757023ea70d..f97f787b2198 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c @@ -147,6 +147,15 @@ out: return err; } +static void mt7925u_stop(struct ieee80211_hw *hw, bool suspend) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + cancel_delayed_work_sync(&dev->mlo_pm_work); + + mt792xu_stop(hw, suspend); +} + static int mt7925u_probe(struct usb_interface *usb_intf, const struct usb_device_id *id) { @@ -193,7 +202,7 @@ static int mt7925u_probe(struct usb_interface *usb_intf, if (!ops) return -ENOMEM; - ops->stop = mt792xu_stop; + ops->stop = mt7925u_stop; mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops); if (!mdev) @@ -348,6 +357,19 @@ failed: } #endif /* CONFIG_PM */ +static void mt7925u_disconnect(struct usb_interface *usb_intf) +{ + struct mt792x_dev *dev = usb_get_intfdata(usb_intf); + + /* mt792xu_disconnect() ends in mt76_free_device(), so the work has to + * go before it rather than after mt76_unregister_device() as on PCI. + */ + if (dev) + cancel_work_sync(&dev->nan_deferred_work); + + mt792xu_disconnect(usb_intf); +} + MODULE_DEVICE_TABLE(usb, mt7925u_device_table); MODULE_FIRMWARE(MT7925_FIRMWARE_WM); MODULE_FIRMWARE(MT7925_ROM_PATCH); @@ -356,7 +378,7 @@ static struct usb_driver mt7925u_driver = { .name = KBUILD_MODNAME, .id_table = mt7925u_device_table, .probe = mt7925u_probe, - .disconnect = mt792xu_disconnect, + .disconnect = mt7925u_disconnect, #ifdef CONFIG_PM .suspend = mt7925u_suspend, .resume = mt7925u_resume, diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 9efc251cb745..a7d71e007da0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -33,6 +33,7 @@ #define MT792x_CHIP_CAP_REGD_EN BIT(5) #define MT792x_CHIP_CAP_MLO_EN BIT(8) #define MT792x_CHIP_CAP_MLO_EML_EN BIT(9) +#define MT792x_CHIP_CAP_AXIDMA_EN BIT(16) /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ #define MT792x_BASIC_RATES_TBL 14 @@ -191,6 +192,7 @@ struct mt792x_vif { struct mt792x_sta *wep_sta; struct mt792x_phy *phy; + bool roc_join_held; /* join ROC kept until the STA is authorized */ u16 valid_links; u8 deflink_id; enum mt792x_mlo_pm_state mlo_pm_state; @@ -214,6 +216,7 @@ struct mt792x_phy { s16 coverage_class; u8 slottime; + u32 rxfilter; u32 rx_ampdu_ts; u32 ampdu_ref; @@ -342,6 +345,21 @@ struct mt792x_dev { struct ieee80211_vif *nan_vif; const struct ieee80211_iface_combination *iface_combinations; int n_iface_combinations; + /* deferred NAN MCU events run out of the atomic RX path on one shared + * work; see mt7925_nan_deferred_work() and enum mt7925_nan_deferred_event + */ + struct work_struct nan_deferred_work; + /* protects @nan_deferred_pending */ + spinlock_t nan_deferred_lock; + unsigned long nan_deferred_pending; + u8 nan_started_cluster_id[ETH_ALEN]; + + struct { + void *va; + dma_addr_t dma_addr; + u32 size; + bool reused; + } cached_cal; }; static inline struct mt792x_bss_conf * diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index 0ad33f74c228..3ce6c6ceac81 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -472,6 +472,7 @@ int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); mvif->bss_conf.mt76.ctx = ctx; mctx->bss_conf = &mvif->bss_conf; + mt76_phy_chandef_set(&dev->mphy, &ctx->def); mutex_unlock(&dev->mt76.mutex); return 0; @@ -857,7 +858,7 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) } EXPORT_SYMBOL_GPL(mt792x_init_wiphy); -static u8 +static int mt792x_get_offload_capability(struct device *dev, const char *fw_wm) { const struct mt76_connac2_fw_trailer *hdr; @@ -926,13 +927,20 @@ mt792x_get_mac80211_ops(struct device *dev, void *drv_data, u8 *fw_features) { struct ieee80211_ops *ops; + int ret; ops = devm_kmemdup(dev, mac80211_ops, sizeof(struct ieee80211_ops), GFP_KERNEL); if (!ops) return NULL; - *fw_features = mt792x_get_offload_capability(dev, drv_data); + ret = mt792x_get_offload_capability(dev, drv_data); + if (ret < 0) { + dev_warn(dev, "failed to read firmware offload caps: %d\n", ret); + *fw_features = 0; + } else { + *fw_features = ret; + } if (mt792x_needs_cnm_runtime(drv_data)) *fw_features |= MT792x_FW_CAP_CNM; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c index 888e5a505673..ebf4c32924c4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c @@ -165,14 +165,16 @@ mt792x_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); + int signal; - if (status->signal > 0) + signal = mt76_rx_signal(status->chains, status->chain_signal); + if (signal > 0 || signal <= -128) return; if (!ether_addr_equal(vif->addr, hdr->addr1)) return; - ewma_rssi_add(&mvif->bss_conf.rssi, -status->signal); + ewma_rssi_add(&mvif->bss_conf.rssi, -signal); } void mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb) @@ -278,6 +280,9 @@ void mt792x_reset(struct mt76_dev *mdev) if (pm->suspended) return; + if (test_bit(MT76_REMOVED, &mdev->phy.state)) + return; + queue_work(dev->mt76.wq, &dev->reset_work); } EXPORT_SYMBOL_GPL(mt792x_reset); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c index 850f6b2cfc4a..5e19e64a9a00 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c @@ -502,21 +502,26 @@ void mt792xu_disconnect(struct usb_interface *usb_intf) return; set_bit(MT76_RESET, &dev->mphy.state); - set_bit(MT76_MCU_RESET, &dev->mphy.state); clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); - wake_up(&dev->mt76.mcu.wait); - skb_queue_purge(&dev->mt76.mcu.res_q); - cancel_work_sync(&dev->reset_work); cancel_work_sync(&dev->init_work); mt76_worker_disable(&dev->mt76.tx_worker); mt792xu_reset_work_cleanup(dev); if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) { + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + skb_queue_purge(&dev->mt76.mcu.res_q); + cancel_work_sync(&dev->reset_work); set_bit(MT76_REMOVED, &dev->mphy.state); return; } mt76_unregister_device(&dev->mt76); + + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + skb_queue_purge(&dev->mt76.mcu.res_q); + cancel_work_sync(&dev->reset_work); mt792xu_cleanup(dev); set_bit(MT76_REMOVED, &dev->mphy.state); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig index 5742bce12fbb..3c51b402f44e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig +++ b/drivers/net/wireless/mediatek/mt76/mt7996/Kconfig @@ -17,5 +17,6 @@ config MT7996_NPU bool "MT7996 (PCIe) NPU support" depends on MT7996E depends on NET_AIROHA_NPU=y || MT76_CORE=NET_AIROHA_NPU + depends on NET_AIROHA=y || NET_AIROHA=n || MT76_CORE=NET_AIROHA select MT76_NPU default n diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/coredump.c b/drivers/net/wireless/mediatek/mt76/mt7996/coredump.c index 5c293ae965cd..be4c882b3184 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/coredump.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/coredump.c @@ -202,11 +202,12 @@ static struct mt7996_coredump *mt7996_coredump_build(struct mt7996_dev *dev) mt7996_coredump_fw_stack(dev, dump, exception); /* gather memory content */ - dump_mem = (struct mt7996_coredump_mem *)(buf + sofar); - dump_mem->len = crash_data->memdump_buf_len; - if (coredump_memdump && crash_data->memdump_buf_len) + if (coredump_memdump && crash_data->memdump_buf_len) { + dump_mem = (struct mt7996_coredump_mem *)(buf + sofar); + dump_mem->len = crash_data->memdump_buf_len; memcpy(dump_mem->data, crash_data->memdump_buf, crash_data->memdump_buf_len); + } mutex_unlock(&dev->dump_mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c index b85c3e549f8b..644abd0a0216 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c @@ -13,13 +13,6 @@ /** global debugfs **/ -struct hw_queue_map { - const char *name; - u8 index; - u8 pid; - u8 qid; -}; - static int mt7996_implicit_txbf_set(void *data, u64 val) { @@ -604,35 +597,176 @@ mt7996_tx_stats_show(struct seq_file *file, void *data) DEFINE_SHOW_ATTRIBUTE(mt7996_tx_stats); +enum { + MT_QUEUE_PORT_HIF, + MT_QUEUE_PORT_CPU, + MT_QUEUE_PORT_LMAC, + MT_QUEUE_PORT_PLE_CTRL, +}; + +struct mt7996_hw_queue { + const char *name; + u8 pid; + u8 qid; + u8 tgid; +}; + +#define MT7996_HW_QUEUE(_name, _pid, _qid, _tgid) \ + { .name = _name, .pid = MT_QUEUE_PORT_##_pid, .qid = _qid, .tgid = _tgid } + +static const struct mt7996_hw_queue mt7996_ple_queues[32] = { + [0] = MT7996_HW_QUEUE("CPU Q0", CPU, 0, 0), + [1] = MT7996_HW_QUEUE("CPU Q1", CPU, 1, 0), + [2] = MT7996_HW_QUEUE("CPU Q2", CPU, 2, 0), + [3] = MT7996_HW_QUEUE("CPU Q3", CPU, 3, 0), + [4] = MT7996_HW_QUEUE("ALTX Q0", LMAC, 0x10, 0), + [5] = MT7996_HW_QUEUE("BMC Q0", LMAC, 0x11, 0), + [6] = MT7996_HW_QUEUE("BCN Q0", LMAC, 0x12, 0), + [7] = MT7996_HW_QUEUE("PSMP Q0", LMAC, 0x13, 0), + [8] = MT7996_HW_QUEUE("ALTX Q1", LMAC, 0x10, 1), + [9] = MT7996_HW_QUEUE("BMC Q1", LMAC, 0x11, 1), + [10] = MT7996_HW_QUEUE("BCN Q1", LMAC, 0x12, 1), + [11] = MT7996_HW_QUEUE("PSMP Q1", LMAC, 0x13, 1), + [12] = MT7996_HW_QUEUE("ALTX Q2", LMAC, 0x1c, 2), + [13] = MT7996_HW_QUEUE("BMC Q2", LMAC, 0x1d, 2), + [14] = MT7996_HW_QUEUE("BCN Q2", LMAC, 0x1e, 2), + [15] = MT7996_HW_QUEUE("PSMP Q2", LMAC, 0x1f, 2), + [16] = MT7996_HW_QUEUE("NAF Q", LMAC, 0x18, 0), + [17] = MT7996_HW_QUEUE("NBCN Q", LMAC, 0x19, 0), + [20] = MT7996_HW_QUEUE("FIXFID Q", LMAC, 0x1a, 0), + [28] = MT7996_HW_QUEUE("RLS4 Q", PLE_CTRL, 0x7c, 0), + [29] = MT7996_HW_QUEUE("RLS3 Q", PLE_CTRL, 0x7d, 0), + [30] = MT7996_HW_QUEUE("RLS2 Q", PLE_CTRL, 0x7e, 0), + [31] = MT7996_HW_QUEUE("RLS Q", PLE_CTRL, 0x7f, 0), +}; + +static const struct mt7996_hw_queue mt7996_pse_queues[32] = { + [0] = MT7996_HW_QUEUE("CPU Q0", CPU, 0, 0), + [1] = MT7996_HW_QUEUE("CPU Q1", CPU, 1, 0), + [2] = MT7996_HW_QUEUE("CPU Q2", CPU, 2, 0), + [3] = MT7996_HW_QUEUE("CPU Q3", CPU, 3, 0), + [16] = MT7996_HW_QUEUE("LMAC Q", LMAC, 0, 0), + [17] = MT7996_HW_QUEUE("MDP TX Q0", LMAC, 1, 0), + [18] = MT7996_HW_QUEUE("MDP RX Q", LMAC, 2, 0), + [19] = MT7996_HW_QUEUE("SEC TX Q0", LMAC, 3, 0), + [20] = MT7996_HW_QUEUE("SEC RX Q", LMAC, 4, 0), + [21] = MT7996_HW_QUEUE("SFD PARK Q", LMAC, 5, 0), + [22] = MT7996_HW_QUEUE("MDP TXIOC Q0", LMAC, 6, 0), + [23] = MT7996_HW_QUEUE("MDP RXIOC Q0", LMAC, 7, 0), + [24] = MT7996_HW_QUEUE("MDP TX Q1", LMAC, 0x11, 0), + [25] = MT7996_HW_QUEUE("SEC TX Q1", LMAC, 0x13, 0), + [26] = MT7996_HW_QUEUE("MDP TXIOC Q1", LMAC, 0x16, 0), + [27] = MT7996_HW_QUEUE("MDP RXIOC Q1", LMAC, 0x17, 0), + [28] = MT7996_HW_QUEUE("CPU Q4", CPU, 4, 0), + [31] = MT7996_HW_QUEUE("RLS Q", PLE_CTRL, 0x1f, 0), +}; + +static const struct mt7996_hw_queue mt7996_pse_queues_1[32] = { + [0] = MT7996_HW_QUEUE("MDP TDPIOC Q0", LMAC, 0x08, 0), + [1] = MT7996_HW_QUEUE("MDP RDPIOC Q0", LMAC, 0x09, 0), + [2] = MT7996_HW_QUEUE("MDP TDPIOC Q1", LMAC, 0x18, 0), + [3] = MT7996_HW_QUEUE("MDP RDPIOC Q1", LMAC, 0x19, 0), + [4] = MT7996_HW_QUEUE("MDP TDPIOC Q2", LMAC, 0x28, 0), + [5] = MT7996_HW_QUEUE("MDP RDPIOC Q2", LMAC, 0x29, 0), + [7] = MT7996_HW_QUEUE("MDP RDPIOC Q3", LMAC, 0x39, 0), + [8] = MT7996_HW_QUEUE("MDP TX Q2", LMAC, 0x21, 0), + [9] = MT7996_HW_QUEUE("SEC TX Q2", LMAC, 0x23, 0), + [10] = MT7996_HW_QUEUE("MDP TXIOC Q2", LMAC, 0x26, 0), + [11] = MT7996_HW_QUEUE("MDP RXIOC Q2", LMAC, 0x27, 0), + [15] = MT7996_HW_QUEUE("MDP RXIOC Q3", LMAC, 0x37, 0), + [16] = MT7996_HW_QUEUE("HIF Q0", HIF, 0, 0), + [17] = MT7996_HW_QUEUE("HIF Q1", HIF, 1, 0), + [18] = MT7996_HW_QUEUE("HIF Q2", HIF, 2, 0), + [19] = MT7996_HW_QUEUE("HIF Q3", HIF, 3, 0), + [20] = MT7996_HW_QUEUE("HIF Q4", HIF, 4, 0), + [21] = MT7996_HW_QUEUE("HIF Q5", HIF, 5, 0), + [22] = MT7996_HW_QUEUE("HIF Q6", HIF, 6, 0), + [23] = MT7996_HW_QUEUE("HIF Q7", HIF, 7, 0), + [24] = MT7996_HW_QUEUE("HIF Q8", HIF, 8, 0), + [25] = MT7996_HW_QUEUE("HIF Q9", HIF, 9, 0), + [26] = MT7996_HW_QUEUE("HIF Q10", HIF, 10, 0), + [27] = MT7996_HW_QUEUE("HIF Q11", HIF, 11, 0), + [28] = MT7996_HW_QUEUE("HIF Q12", HIF, 12, 0), + [29] = MT7996_HW_QUEUE("HIF Q13", HIF, 13, 0), +}; + static void -mt7996_hw_queue_read(struct seq_file *s, u32 size, - const struct hw_queue_map *map) +mt7996_fl_queue_show(struct seq_file *s, struct mt7996_dev *dev, bool pse, + const struct mt7996_hw_queue *q, u16 wlan_idx) { - struct mt7996_phy *phy = s->private; - struct mt7996_dev *dev = phy->dev; - u32 i, val; + static DEFINE_SPINLOCK(lock); + u32 val, fid, num; + + val = MT_FL_Q0_CTRL_EXECUTE | + u32_encode_bits(q->qid, MT_FL_Q0_CTRL_QID) | + u32_encode_bits(q->tgid, MT_FL_Q0_CTRL_TGID) | + u32_encode_bits(q->pid, MT_FL_Q0_CTRL_PID) | + u32_encode_bits(wlan_idx, MT_FL_Q0_CTRL_WLAN_IDX); + + spin_lock(&lock); + mt76_wr(dev, pse ? MT_PSE_FL_Q0_CTRL : MT_FL_Q0_CTRL, val); + fid = mt76_rr(dev, pse ? MT_PSE_FL_Q2_CTRL : MT_FL_Q2_CTRL); + num = mt76_rr(dev, pse ? MT_PSE_FL_Q3_CTRL : MT_FL_Q3_CTRL); + spin_unlock(&lock); + + seq_printf(s, "tail/head fid 0x%04x/0x%04x, packets %u", + u32_get_bits(fid, MT_FL_Q2_CTRL_TAIL_FID), + u32_get_bits(fid, MT_FL_Q2_CTRL_HEAD_FID), + u32_get_bits(num, MT_FL_Q3_CTRL_PKT_NUM)); +} - val = mt76_rr(dev, MT_FL_Q_EMPTY); - for (i = 0; i < size; i++) { - u32 ctrl, head, tail, queued; +static void +mt7996_fl_queues_show(struct seq_file *s, struct mt7996_dev *dev, bool pse, + const struct mt7996_hw_queue *queues, unsigned long empty) +{ + unsigned int i; - if (val & BIT(map[i].index)) + for_each_clear_bit(i, &empty, 32) { + if (!queues[i].name) continue; - ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24); - mt76_wr(dev, MT_FL_Q0_CTRL, ctrl); + seq_printf(s, "\t%s: ", queues[i].name); + mt7996_fl_queue_show(s, dev, pse, &queues[i], 0); + seq_puts(s, "\n"); + } +} + +static void +mt7996_freepg_show(struct seq_file *s, u32 cnt, u32 head_tail) +{ + seq_printf(s, "\tfree pages 0x%04x, free for all 0x%04x, head/tail 0x%04x/0x%04x\n", + u32_get_bits(cnt, MT_FREEPG_CNT_FREE), + u32_get_bits(cnt, MT_FREEPG_CNT_FFA), + u32_get_bits(head_tail, MT_FREEPG_HEAD_TAIL_HEAD), + u32_get_bits(head_tail, MT_FREEPG_HEAD_TAIL_TAIL)); +} + +static void +mt7996_pg_group_show(struct seq_file *s, const char *name, u32 group, u32 info) +{ + seq_printf(s, "\t%s group: max/min quota 0x%04x/0x%04x, used/reserved 0x%04x/0x%04x\n", + name, u32_get_bits(group, MT_PG_GROUP_MAX_QUOTA), + u32_get_bits(group, MT_PG_GROUP_MIN_QUOTA), + u32_get_bits(info, MT_PG_INFO_SRC_CNT), + u32_get_bits(info, MT_PG_INFO_RSV_CNT)); +} + +static unsigned int +mt7996_ple_sta_cr_num(struct mt7996_dev *dev) +{ + return is_mt7996(&dev->mt76) ? 34 : 17; +} - head = mt76_get_field(dev, MT_FL_Q2_CTRL, - GENMASK(11, 0)); - tail = mt76_get_field(dev, MT_FL_Q2_CTRL, - GENMASK(27, 16)); - queued = mt76_get_field(dev, MT_FL_Q3_CTRL, - GENMASK(11, 0)); +static unsigned int +mt7996_ple_sta_cr(struct mt7996_dev *dev, unsigned int n) +{ + /* MT7992 and MT7990 keep the last station group in the + * extension register that follows the first 32 groups + */ + if (!is_mt7996(&dev->mt76) && n == mt7996_ple_sta_cr_num(dev) - 1) + return 32; - seq_printf(s, "\t%s: ", map[i].name); - seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n", - queued, head, tail); - } + return n; } static void @@ -640,51 +774,53 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; struct mt7996_vif *mvif = msta->vif; - struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink); struct ieee80211_link_sta *link_sta; struct seq_file *s = data; struct ieee80211_vif *vif; - struct mt7996_dev *dev; unsigned int link_id; - if (!phy) - return; - vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); - dev = phy->dev; rcu_read_lock(); for_each_sta_active_link(vif, sta, link_sta, link_id) { struct mt7996_sta_link *msta_link; struct mt76_vif_link *mlink; + struct mt7996_phy *phy; + unsigned int cr; + u16 wlan_idx; u8 ac; mlink = rcu_dereference(mvif->mt76.link[link_id]); if (!mlink) continue; + phy = mt7996_vif_link_phy(container_of(mlink, + struct mt7996_vif_link, + mt76)); + if (!phy) + continue; + msta_link = mt7996_sta_link(msta, link_id); if (!msta_link) continue; - for (ac = 0; ac < 4; ac++) { - u32 idx = msta_link->wcid.idx >> 5, qlen, ctrl, val; - u8 offs = msta_link->wcid.idx & GENMASK(4, 0); - - ctrl = BIT(31) | BIT(11) | (ac << 24); - val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx)); + wlan_idx = msta_link->wcid.idx; + cr = mt7996_ple_sta_cr(phy->dev, wlan_idx / 32); + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + struct mt7996_hw_queue q = { + .pid = MT_QUEUE_PORT_LMAC, + .qid = ac, + }; - if (val & BIT(offs)) + if (mt76_rr(phy->dev, MT_PLE_AC_QEMPTY(ac, cr)) & + BIT(wlan_idx % 32)) continue; - mt76_wr(dev, - MT_FL_Q0_CTRL, ctrl | msta_link->wcid.idx); - qlen = mt76_get_field(dev, MT_FL_Q3_CTRL, - GENMASK(11, 0)); - seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n", - sta->addr, msta_link->wcid.idx, - mlink->wmm_idx, ac, qlen); + seq_printf(s, "\tSTA %pM wcid %u AC%u%u: ", sta->addr, + wlan_idx, mlink->wmm_idx, ac); + mt7996_fl_queue_show(s, phy->dev, false, &q, wlan_idx); + seq_puts(s, "\n"); } } @@ -692,78 +828,27 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta) } static int -mt7996_hw_queues_show(struct seq_file *file, void *data) +mt7996_hw_queues_show(struct seq_file *s, void *data) { - struct mt7996_dev *dev = file->private; - struct mt7996_phy *phy = &dev->phy; - static const struct hw_queue_map ple_queue_map[] = { - { "CPU_Q0", 0, 1, MT_CTX0 }, - { "CPU_Q1", 1, 1, MT_CTX0 + 1 }, - { "CPU_Q2", 2, 1, MT_CTX0 + 2 }, - { "CPU_Q3", 3, 1, MT_CTX0 + 3 }, - { "ALTX_Q0", 8, 2, MT_LMAC_ALTX0 }, - { "BMC_Q0", 9, 2, MT_LMAC_BMC0 }, - { "BCN_Q0", 10, 2, MT_LMAC_BCN0 }, - { "PSMP_Q0", 11, 2, MT_LMAC_PSMP0 }, - { "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 }, - { "BMC_Q1", 13, 2, MT_LMAC_BMC0 + 4 }, - { "BCN_Q1", 14, 2, MT_LMAC_BCN0 + 4 }, - { "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 }, - }; - static const struct hw_queue_map pse_queue_map[] = { - { "CPU Q0", 0, 1, MT_CTX0 }, - { "CPU Q1", 1, 1, MT_CTX0 + 1 }, - { "CPU Q2", 2, 1, MT_CTX0 + 2 }, - { "CPU Q3", 3, 1, MT_CTX0 + 3 }, - { "HIF_Q0", 8, 0, MT_HIF0 }, - { "HIF_Q1", 9, 0, MT_HIF0 + 1 }, - { "HIF_Q2", 10, 0, MT_HIF0 + 2 }, - { "HIF_Q3", 11, 0, MT_HIF0 + 3 }, - { "HIF_Q4", 12, 0, MT_HIF0 + 4 }, - { "HIF_Q5", 13, 0, MT_HIF0 + 5 }, - { "LMAC_Q", 16, 2, 0 }, - { "MDP_TXQ", 17, 2, 1 }, - { "MDP_RXQ", 18, 2, 2 }, - { "SEC_TXQ", 19, 2, 3 }, - { "SEC_RXQ", 20, 2, 4 }, - }; - u32 val, head, tail; - - /* ple queue */ - val = mt76_rr(dev, MT_PLE_FREEPG_CNT); - head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0)); - tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16)); - seq_puts(file, "PLE page info:\n"); - seq_printf(file, - "\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n", - val, head, tail); - - val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP); - head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0)); - tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16)); - seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n", - val, head, tail); - - seq_puts(file, "PLE non-empty queue info:\n"); - mt7996_hw_queue_read(file, ARRAY_SIZE(ple_queue_map), - &ple_queue_map[0]); - - /* iterate per-sta ple queue */ - ieee80211_iterate_stations_atomic(phy->mt76->hw, - mt7996_sta_hw_queue_read, file); - phy = mt7996_phy2(dev); - if (phy) - ieee80211_iterate_stations_atomic(phy->mt76->hw, - mt7996_sta_hw_queue_read, file); - phy = mt7996_phy3(dev); - if (phy) - ieee80211_iterate_stations_atomic(phy->mt76->hw, - mt7996_sta_hw_queue_read, file); - - /* pse queue */ - seq_puts(file, "PSE non-empty queue info:\n"); - mt7996_hw_queue_read(file, ARRAY_SIZE(pse_queue_map), - &pse_queue_map[0]); + struct mt7996_dev *dev = s->private; + + seq_puts(s, "PLE page info:\n"); + mt7996_freepg_show(s, mt76_rr(dev, MT_PLE_FREEPG_CNT), + mt76_rr(dev, MT_PLE_FREEPG_HEAD_TAIL)); + mt7996_pg_group_show(s, "HIF", mt76_rr(dev, MT_PLE_PG_HIF_GROUP), + mt76_rr(dev, MT_PLE_HIF_PG_INFO)); + + seq_puts(s, "PLE non-empty queue info:\n"); + mt7996_fl_queues_show(s, dev, false, mt7996_ple_queues, + mt76_rr(dev, MT_FL_Q_EMPTY)); + ieee80211_iterate_stations_atomic(dev->mphy.hw, + mt7996_sta_hw_queue_read, s); + + seq_puts(s, "PSE non-empty queue info:\n"); + mt7996_fl_queues_show(s, dev, true, mt7996_pse_queues, + mt76_rr(dev, MT_PSE_QUEUE_EMPTY)); + mt7996_fl_queues_show(s, dev, true, mt7996_pse_queues_1, + mt76_rr(dev, MT_PSE_QUEUE_EMPTY_1)); return 0; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index c1d860029801..cc94eade9950 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -541,6 +541,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ieee80211_hw_set(hw, CHANCTX_STA_CSA); ieee80211_hw_set(hw, CONNECTION_MONITOR); + ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); hw->max_tx_fragments = 4; wiphy->txq_memory_limit = 32 << 20; /* 32 MiB */ @@ -1810,6 +1811,8 @@ error: void mt7996_unregister_device(struct mt7996_dev *dev) { + int i; + cancel_work_sync(&dev->dump_work); cancel_work_sync(&dev->wed_rro.work); cancel_work_sync(&dev->reset_work); @@ -1820,6 +1823,10 @@ void mt7996_unregister_device(struct mt7996_dev *dev) mt7996_coredump_unregister(dev); mt76_unregister_device(&dev->mt76); mt7996_wed_rro_free(dev); + for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++) { + if (dev->mt76.napi[i].dev) + napi_disable(&dev->mt76.napi[i]); + } mt7996_mcu_exit(dev); mt7996_tx_token_put(dev); mt7996_dma_cleanup(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 1cba381a78b8..f36da545045b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -915,7 +915,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL; if (mvif) { if (wcid->offchannel) - mlink = rcu_dereference(mvif->mt76.offchannel_link); + mlink = mt7996_offchannel_link(wcid); if (!mlink && link_id != IEEE80211_LINK_UNSPECIFIED) mlink = rcu_dereference(mvif->mt76.link[link_id]); } @@ -1057,7 +1057,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!wcid) wcid = &dev->mt76.global_wcid; - if ((is_8023 || ieee80211_is_data_qos(hdr->frame_control)) && sta->mlo && + if (sta && (is_8023 || ieee80211_is_data_qos(hdr->frame_control)) && sta->mlo && likely(tx_info->skb->protocol != cpu_to_be16(ETH_P_PAE))) { u8 tid = tx_info->skb->priority & IEEE80211_QOS_CTL_TID_MASK; @@ -1097,7 +1097,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, * compatible with 802.11 EAPOL frame, we do the translation by * software */ - if (tx_info->skb->protocol == cpu_to_be16(ETH_P_PAE) && sta->mlo) { + if (sta && tx_info->skb->protocol == cpu_to_be16(ETH_P_PAE) && sta->mlo) { struct ieee80211_hdr *hdr = (void *)tx_info->skb->data; struct ieee80211_bss_conf *link_conf; struct ieee80211_link_sta *link_sta; @@ -1196,7 +1196,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (mvif) { if (wcid->offchannel) - mlink = rcu_dereference(mvif->mt76.offchannel_link); + mlink = mt7996_offchannel_link(wcid); if (!mlink) mlink = rcu_dereference(mvif->mt76.link[wcid->link_id]); @@ -1503,7 +1503,8 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, } } - if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wcid->sta) { + if ((mtk_wed_device_active(&dev->mt76.mmio.wed) || + mt76_npu_device_active(&dev->mt76)) && wcid->sta) { struct ieee80211_sta *sta; u8 tid; @@ -1936,6 +1937,9 @@ void mt7996_rro_rx_process(struct mt76_dev *mdev, void *data) struct mt7996_msdu_page *p = NULL; int i, seq_num = 0; + if (seq_id > MT7996_RRO_MAX_SESSION) + return; + for (i = 0; i < ind_count; i++) { struct mt7996_wed_rro_addr *e; struct mt76_rx_status *status; @@ -2463,6 +2467,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) dev->recovery.hw_full_reset = true; + set_bit(MT76_RESTART, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); ieee80211_stop_queues(hw); @@ -2944,6 +2949,10 @@ void mt7996_mac_sta_rc_work(struct work_struct *work) changed = msta_link->changed; msta_link->changed = 0; + + if (!msta_link->connected) + continue; + mvif = msta_link->sta->vif; vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); @@ -3285,8 +3294,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, flow->tsf = le64_to_cpu(twt_agrt->twt); if (mt7996_mcu_twt_agrt_update(dev, &msta->vif->deflink, flow, - MCU_TWT_AGRT_ADD)) + MCU_TWT_AGRT_ADD)) { + list_del(&flow->list); goto unlock; + } setup_cmd = TWT_SETUP_CMD_ACCEPT; dev->twt.table_mask |= BIT(table_id); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index dd7a01c02a7c..9321c8146e2a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -34,6 +34,11 @@ int mt7996_run(struct mt7996_phy *phy) if (ret) return ret; + ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL, + true); + if (ret) + return ret; + set_bit(MT76_STATE_RUNNING, &phy->mt76->state); ieee80211_queue_delayed_work(dev->mphy.hw, &phy->mt76->mac_work, @@ -54,6 +59,8 @@ static int mt7996_start(struct ieee80211_hw *hw) flush_work(&dev->init_work); + clear_bit(MT76_RESTART, &dev->mphy.state); + mutex_lock(&dev->mt76.mutex); ret = mt7996_mcu_set_hdr_trans(dev, true); if (!ret && !is_mt7996(&dev->mt76)) { @@ -272,8 +279,9 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } struct mt7996_key_iter_data { - enum set_key_cmd cmd; - unsigned int link_id; + enum set_key_cmd cmd; + unsigned int link_id; + struct ieee80211_sta *sta; }; static void @@ -283,10 +291,13 @@ mt7996_key_iter(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt7996_key_iter_data *it = data; - if (sta) + if (sta != it->sta) + return; + + if (key->link_id >= 0 && key->link_id != it->link_id) return; - WARN_ON(mt7996_set_hw_key(hw, it->cmd, vif, NULL, it->link_id, key)); + WARN_ON(mt7996_set_hw_key(hw, it->cmd, vif, sta, it->link_id, key)); } int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, @@ -307,15 +318,15 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, if ((mvif->mt76.valid_links & BIT(link_conf->link_id)) && !mlink->offchannel) { - if (vif->type == NL80211_IFTYPE_AP) - return mt7996_mcu_mld_link_oper(dev, link_conf, link, - true); - /* update the link address */ ret = mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, true); if (ret) return ret; + if (vif->type == NL80211_IFTYPE_AP) + return mt7996_mcu_mld_link_oper(dev, link_conf, link, + true); + return mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, true); } @@ -333,6 +344,7 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, return -ENOSPC; link->mld_idx = mld_idx; + eth_zero_addr(link->bmc_bssid); mlink->omac_idx = idx; mlink->band_idx = band_idx; mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; @@ -417,19 +429,12 @@ static void mt7996_vif_link_destroy(struct mt7996_phy *phy, struct mt7996_sta_link *msta_link = &link->msta_link; unsigned int link_id = msta_link->wcid.link_id; struct mt76_vif_link *mlink = &link->mt76; - struct mt7996_key_iter_data it = { - .cmd = SET_KEY, - .link_id = link_id, - }; struct mt7996_dev *dev = phy->dev; int idx = msta_link->wcid.idx; if (!link_conf) link_conf = &vif->bss_conf; - if (!mlink->wcid->offchannel) - ieee80211_iter_keys(phy->mt76->hw, vif, mt7996_key_iter, &it); - mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, CONN_STATE_DISCONNECT, false); mt7996_mcu_add_bss_info(phy, vif, link_conf, mlink, msta_link, false); @@ -565,13 +570,14 @@ static int mt7996_add_interface(struct ieee80211_hw *hw, for (i = 0; i < MT7996_MAX_RADIOS; i++) { struct mt7996_phy *phy = dev->radio_phy[i]; - if (!phy || !(wdev->radio_mask & BIT(i)) || - test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) + if (!phy || !(wdev->radio_mask & BIT(i))) continue; - err = mt7996_run(phy); - if (err) - goto out; + if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state)) { + err = mt7996_run(phy); + if (err) + goto out; + } if (vif->type == NL80211_IFTYPE_MONITOR) mt7996_set_monitor(phy, true); @@ -897,6 +903,23 @@ mt7996_update_mu_group(struct ieee80211_hw *hw, struct mt7996_vif_link *link, } static void +mt7996_vif_link_bss_add(struct mt7996_phy *phy, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct mt7996_vif_link *link, bool newly) +{ + if (vif->type == NL80211_IFTYPE_STATION) { + newly = !ether_addr_equal_unaligned(link->bmc_bssid, + link_conf->bssid); + memcpy(link->bmc_bssid, link_conf->bssid, ETH_ALEN); + } + + mt7996_mcu_add_bss_info(phy, vif, link_conf, &link->mt76, + &link->msta_link, true); + mt7996_mcu_add_sta(phy->dev, link_conf, NULL, link, NULL, + CONN_STATE_PORT_SECURE, newly); +} + +static void mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 changed) { @@ -927,12 +950,8 @@ mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!phy) continue; - mt7996_mcu_add_bss_info(phy, vif, link_conf, - &link->mt76, &link->msta_link, - true); - mt7996_mcu_add_sta(dev, link_conf, NULL, link, NULL, - CONN_STATE_PORT_SECURE, - !!(changed & BSS_CHANGED_BSSID)); + mt7996_vif_link_bss_add(phy, vif, link_conf, link, + !!(changed & BSS_CHANGED_BSSID)); } } @@ -978,13 +997,11 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, * and then peer references bss_info_rfch to set bandwidth cap. */ if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) || - (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) { - mt7996_mcu_add_bss_info(phy, vif, info, &link->mt76, - &link->msta_link, true); - mt7996_mcu_add_sta(dev, info, NULL, link, NULL, - CONN_STATE_PORT_SECURE, - !!(changed & BSS_CHANGED_BSSID)); - } + (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) + mt7996_vif_link_bss_add(phy, vif, info, link, + !!(changed & BSS_CHANGED_BSSID)); + else if (changed & BSS_CHANGED_BSSID) + eth_zero_addr(link->bmc_bssid); if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) mt7996_mcu_set_protection(phy, link, info->ht_operation_mode, @@ -1131,9 +1148,90 @@ mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx) } } +static void +mt7996_sta_deflink_set(struct ieee80211_sta *sta, unsigned int link_id, + int idx) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + + msta->deflink_id = link_id; + mt7996_sta_init_txq_wcid(sta, idx); +} + +static void +mt7996_sta_link_hdr_trans_set(struct mt7996_sta *msta, + struct mt7996_sta_link *msta_link) +{ + assign_bit(MT_WCID_FLAG_4ADDR, &msta_link->wcid.flags, + test_bit(MT_WCID_FLAG_4ADDR, &msta->wcid_flags)); + assign_bit(MT_WCID_FLAG_HDR_TRANS, &msta_link->wcid.flags, + test_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid_flags)); +} + +static bool +mt7996_sta_deflink_busy(struct mt7996_dev *dev, struct mt7996_sta *msta) +{ + unsigned int link_id; + + for (link_id = 0; link_id < ARRAY_SIZE(msta->link); link_id++) { + if (mt7996_sta_link_protected(dev, msta, link_id) == + &msta->deflink) + return true; + } + + return false; +} + +static void +mt7996_sta_deflink_release(struct mt7996_dev *dev, struct ieee80211_sta *sta, + unsigned int link_id) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_sta_link *msta_seclink; + + if (msta->deflink_id != link_id) + return; + + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + if (msta->seclink_id == link_id) + return; + + /* switch to the secondary link */ + msta_seclink = mt76_dereference(msta->link[msta->seclink_id], + &dev->mt76); + if (msta_seclink) + mt7996_sta_deflink_set(sta, msta->seclink_id, + msta_seclink->wcid.idx); +} + +static u8 +mt7996_sta_seclink_get(struct mt7996_dev *dev, struct mt7996_sta *msta) +{ + struct mt7996_sta_link *msta_link; + unsigned int link_id; + + if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) + return IEEE80211_LINK_UNSPECIFIED; + + msta_link = mt7996_sta_link_protected(dev, msta, msta->seclink_id); + if (msta->seclink_id != msta->deflink_id && msta_link && + msta_link->wcid.link_valid) + return msta->seclink_id; + + for (link_id = 0; link_id < ARRAY_SIZE(msta->link); link_id++) { + if (link_id == msta->deflink_id) + continue; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + if (msta_link && msta_link->wcid.link_valid) + return link_id; + } + + return msta->deflink_id; +} + static int mt7996_mac_sta_init_link(struct mt7996_dev *dev, - struct ieee80211_bss_conf *link_conf, struct ieee80211_link_sta *link_sta, struct mt7996_vif_link *link, unsigned int link_id) { @@ -1150,25 +1248,24 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, if (idx < 0) return -ENOSPC; - if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { - msta_link = &msta->deflink; - msta->deflink_id = link_id; - msta->seclink_id = msta->deflink_id; - mt7996_sta_init_txq_wcid(sta, idx); - } else { + if (mt7996_sta_deflink_busy(dev, msta)) { msta_link = kzalloc_obj(*msta_link); - if (!msta_link) + if (!msta_link) { + mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx); return -ENOMEM; - - if (msta->seclink_id == msta->deflink_id && - (sta->valid_links & ~BIT(msta->deflink_id))) - msta->seclink_id = __ffs(sta->valid_links & - ~BIT(msta->deflink_id)); + } + } else { + msta_link = &msta->deflink; } + if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) + mt7996_sta_deflink_set(sta, link_id, idx); + INIT_LIST_HEAD(&msta_link->rc_list); INIT_LIST_HEAD(&msta_link->wcid.poll_list); msta_link->sta = msta; + msta_link->connected = false; + msta_link->wcid.tx_info = 0; msta_link->wcid.sta = 1; msta_link->wcid.idx = idx; msta_link->wcid.link_id = link_id; @@ -1178,14 +1275,15 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, if (link_sta->sta->tdls) set_bit(MT_WCID_FLAG_TDLS_PEER, &msta_link->wcid.flags); + mt7996_sta_link_hdr_trans_set(msta, msta_link); + ewma_avg_signal_init(&msta_link->avg_ack_signal); ewma_signal_init(&msta_link->wcid.rssi); rcu_assign_pointer(msta->link[link_id], msta_link); + msta->seclink_id = mt7996_sta_seclink_get(dev, msta); mt7996_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - mt7996_mcu_add_sta(dev, link_conf, link_sta, link, msta_link, - CONN_STATE_DISCONNECT, true); rcu_assign_pointer(dev->mt76.wcid[idx], &msta_link->wcid); mt76_wcid_init(&msta_link->wcid, phy->mt76->band_idx); @@ -1217,28 +1315,9 @@ void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - if (msta->deflink_id == link_id) { - msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; - if (msta->seclink_id == link_id) { - /* no secondary link available */ - msta->seclink_id = msta->deflink_id; - } else { - struct mt7996_sta_link *msta_seclink; - - /* switch to the secondary link */ - msta_seclink = mt76_dereference( - msta->link[msta->seclink_id], - &dev->mt76); - if (msta_seclink) { - msta->deflink_id = msta->seclink_id; - mt7996_sta_init_txq_wcid(sta, - msta_seclink->wcid.idx); - } - } - } else if (msta->seclink_id == link_id) { - msta->seclink_id = msta->deflink_id; - } + mt7996_sta_deflink_release(dev, sta, link_id); msta_link->wcid.link_valid = false; + msta->seclink_id = mt7996_sta_seclink_get(dev, msta); } if (flush) { @@ -1256,6 +1335,36 @@ void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, } } +u16 mt7996_mac_sta_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct ieee80211_link_sta *link_sta; + unsigned int link_id; + u16 links = 0; + + for_each_sta_active_link(vif, sta, link_sta, link_id) { + struct mt7996_sta_link *msta_link; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + if (!msta_link) + continue; + + if (sta->valid_links && !msta_link->wcid.link_valid) + continue; + + if (!link_conf_dereference_protected(vif, link_id)) + continue; + + if (!mt7996_vif_link(dev, vif, link_id)) + continue; + + links |= BIT(link_id); + } + + return links; +} + static void mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, unsigned long links, @@ -1272,11 +1381,11 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, unsigned long new_links) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + unsigned long created = 0, returned = 0; unsigned int link_id; int err = 0; for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct ieee80211_bss_conf *link_conf; struct ieee80211_link_sta *link_sta; struct mt7996_sta_link *msta_link; struct mt7996_vif_link *link; @@ -1285,11 +1394,16 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); if (msta_link) { msta_link->wcid.link_valid = true; + mt7996_sta_link_hdr_trans_set(msta, msta_link); + if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) + mt7996_sta_deflink_set(sta, link_id, + msta_link->wcid.idx); + msta->seclink_id = mt7996_sta_seclink_get(dev, msta); + returned |= BIT(link_id); continue; } - link_conf = link_conf_dereference_protected(vif, link_id); - if (!link_conf) { + if (!link_conf_dereference_protected(vif, link_id)) { err = -EINVAL; goto error_unlink; } @@ -1312,43 +1426,24 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, goto error_unlink; } - err = mt7996_mac_sta_init_link(dev, link_conf, link_sta, link, - link_id); + err = mt7996_mac_sta_init_link(dev, link_sta, link, link_id); if (err) goto error_unlink; mphy->num_sta++; + created |= BIT(link_id); } return 0; error_unlink: - mt7996_mac_sta_remove_links(dev, vif, sta, new_links, true); + mt7996_mac_sta_remove_links(dev, vif, sta, created, true); + mt7996_mac_sta_remove_links(dev, vif, sta, returned, false); return err; } static int -mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, u16 old_links, - u16 new_links) -{ - struct mt7996_dev *dev = mt7996_hw_dev(hw); - unsigned long add = new_links & ~old_links; - unsigned long rem = old_links & ~new_links; - int ret; - - mutex_lock(&dev->mt76.mutex); - - mt7996_mac_sta_remove_links(dev, vif, sta, rem, false); - ret = mt7996_mac_sta_add_links(dev, vif, sta, add); - - mutex_unlock(&dev->mt76.mutex); - - return ret; -} - -static int mt7996_mac_sta_add(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -1361,6 +1456,9 @@ mt7996_mac_sta_add(struct mt7996_dev *dev, struct ieee80211_vif *vif, msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; msta->seclink_id = IEEE80211_LINK_UNSPECIFIED; + msta->conn_state = CONN_STATE_DISCONNECT; + msta->ba_tx_mask = 0; + msta->ba_rx_mask = 0; msta->vif = mvif; err = mt7996_mac_sta_add_links(dev, vif, sta, links); @@ -1370,34 +1468,26 @@ mt7996_mac_sta_add(struct mt7996_dev *dev, struct ieee80211_vif *vif, } static int -mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, enum mt76_sta_event ev) +mt7996_mac_sta_links_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long links, + enum mt76_sta_event ev) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - unsigned long links = sta->valid_links; - struct ieee80211_link_sta *link_sta; + unsigned long iter_links = links; unsigned int link_id; - int err = 0; - - mutex_lock(&dev->mt76.mutex); + int err; - for_each_sta_active_link(vif, sta, link_sta, link_id) { + for_each_set_bit(link_id, &iter_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct ieee80211_bss_conf *link_conf; + struct ieee80211_link_sta *link_sta; struct mt7996_sta_link *msta_link; struct mt7996_vif_link *link; int i; link_conf = link_conf_dereference_protected(vif, link_id); - if (!link_conf) - continue; - - link = mt7996_vif_link(dev, vif, link_id); - if (!link) - continue; - + link_sta = link_sta_dereference_protected(sta, link_id); msta_link = mt7996_sta_link_protected(dev, msta, link_id); - if (!msta_link) - continue; + link = mt7996_vif_link(dev, vif, link_id); switch (ev) { case MT76_STA_EVENT_ASSOC: @@ -1405,12 +1495,13 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, link, msta_link, CONN_STATE_CONNECT, true); if (err) - goto unlock; + return err; + msta_link->connected = true; err = mt7996_mcu_add_rate_ctrl(dev, msta_link->sta, vif, link_id, false); if (err) - goto unlock; + return err; msta_link->wcid.tx_info |= MT_WCID_TX_INFO_SET; break; @@ -1419,7 +1510,7 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, link, msta_link, CONN_STATE_PORT_SECURE, false); if (err) - goto unlock; + return err; break; case MT76_STA_EVENT_DISASSOC: for (i = 0; i < ARRAY_SIZE(msta_link->twt.flow); i++) @@ -1440,13 +1531,350 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, break; } } -unlock: + + return 0; +} + +static void +mt7996_mac_sta_link_ps_leave(struct mt7996_dev *dev, + struct mt7996_vif_link *link, + struct mt7996_sta_link *msta_link) +{ + /* HW cannot derive the BSSID from 4-address non-AMSDU frames, + * so PS exit is missed on links other than the setup link. + * Let the firmware wake those links instead. + */ + if (!is_mt7996(&dev->mt76) || + !test_bit(MT_WCID_FLAG_4ADDR, &msta_link->wcid.flags) || + msta_link->wcid.link_id == msta_link->sta->deflink_id) + return; + + mt7996_mcu_ps_leave(dev, link, msta_link); +} + +static void +mt7996_mac_sta_clear_connected(struct mt7996_dev *dev, struct mt7996_sta *msta) +{ + unsigned int link_id; + + for (link_id = 0; link_id < ARRAY_SIZE(msta->link); link_id++) { + struct mt7996_sta_link *msta_link; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + if (msta_link) + msta_link->connected = false; + } +} + +static int +mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, enum mt76_sta_event ev) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + int err; + + mutex_lock(&dev->mt76.mutex); + + err = mt7996_mac_sta_links_event(dev, vif, sta, + mt7996_mac_sta_links(dev, vif, sta), + ev); + if (err) + goto out; + + switch (ev) { + case MT76_STA_EVENT_ASSOC: + msta->conn_state = CONN_STATE_CONNECT; + break; + case MT76_STA_EVENT_AUTHORIZE: + msta->conn_state = CONN_STATE_PORT_SECURE; + break; + case MT76_STA_EVENT_DISASSOC: + msta->conn_state = CONN_STATE_DISCONNECT; + mt7996_mac_sta_clear_connected(dev, msta); + break; + } + +out: mutex_unlock(&dev->mt76.mutex); return err; } static void +mt7996_mac_sta_links_set_keys(struct mt7996_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long links) +{ + unsigned int link_id; + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_key_iter_data it = { + .cmd = SET_KEY, + .link_id = link_id, + .sta = sta, + }; + + ieee80211_iter_keys(mt76_hw(dev), vif, mt7996_key_iter, &it); + } +} + +static bool +mt7996_rx_reorder_host(struct mt7996_dev *dev) +{ + return !mt7996_has_hwrro(dev) && + !mtk_wed_device_active(&dev->mt76.mmio.wed) && + !mt76_npu_device_active(&dev->mt76); +} + +static u16 +mt7996_mac_sta_ba_rx_ssn(struct mt7996_dev *dev, struct mt7996_sta *msta, + unsigned int tid) +{ + struct mt76_rx_tid *tid_rx; + u16 ssn; + + tid_rx = mt76_dereference(msta->deflink.wcid.aggr[tid], &dev->mt76); + if (!tid_rx) + return msta->ba_rx[tid].ssn; + + spin_lock_bh(&tid_rx->lock); + ssn = tid_rx->head; + spin_unlock_bh(&tid_rx->lock); + + return ssn; +} + +static int +mt7996_mac_sta_links_ba_add(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long links) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + u16 rx_restart = 0; + unsigned int tid; + int err; + + if (!links) + return 0; + + for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) { + struct ieee80211_ampdu_params params = { + .sta = sta, + .tid = tid, + }; + + if (msta->ba_tx_mask & BIT(tid)) { + params.ssn = msta->ba_tx[tid].ssn; + params.buf_size = msta->ba_tx[tid].buf_size; + params.amsdu = msta->ba_tx[tid].amsdu; + err = mt7996_mcu_add_tx_ba(dev, ¶ms, vif, links, + true); + if (err) + return err; + } + + if (!(msta->ba_rx_mask & BIT(tid))) + continue; + + /* without host reordering, the reorder head stays at the + * session start, so have the originator set up a new session + */ + if (!mt7996_rx_reorder_host(dev)) { + rx_restart |= BIT(tid); + continue; + } + + params.ssn = mt7996_mac_sta_ba_rx_ssn(dev, msta, tid); + params.buf_size = msta->ba_rx[tid].buf_size; + params.amsdu = msta->ba_rx[tid].amsdu; + err = mt7996_mcu_add_rx_ba(dev, ¶ms, vif, links, true); + if (err) + return err; + } + + if (rx_restart) + ieee80211_stop_rx_ba_session(vif, rx_restart, sta->addr); + + return 0; +} + +static int +mt7996_mac_sta_links_sync(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long links, + unsigned long add) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + unsigned long new_links = 0, resumed = 0, joined, updated; + unsigned int link_id; + int err; + + if (msta->conn_state == CONN_STATE_DISCONNECT) + return 0; + + links &= mt7996_mac_sta_links(dev, vif, sta); + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_sta_link *msta_link; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + if (!msta_link->connected) + new_links |= BIT(link_id); + else if (!(msta_link->wcid.tx_info & MT_WCID_TX_INFO_SET)) + resumed |= BIT(link_id); + } + + err = mt7996_mac_sta_links_event(dev, vif, sta, new_links, + MT76_STA_EVENT_ASSOC); + if (err) + return err; + + for_each_set_bit(link_id, &resumed, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_sta_link *msta_link; + struct mt7996_vif_link *link; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + link = mt7996_vif_link(dev, vif, link_id); + + if (msta->conn_state != CONN_STATE_PORT_SECURE) { + err = mt7996_mcu_wtbl_update_hdr_trans(dev, vif, link, + msta_link); + if (err) + return err; + } + + err = mt7996_mcu_add_rate_ctrl(dev, msta, vif, link_id, false); + if (err) + return err; + + msta_link->wcid.tx_info |= MT_WCID_TX_INFO_SET; + } + + mt7996_mac_sta_links_set_keys(dev, vif, sta, links & add); + + updated = new_links; + if (msta->conn_state == CONN_STATE_PORT_SECURE) { + updated |= resumed; + err = mt7996_mac_sta_links_event(dev, vif, sta, updated, + MT76_STA_EVENT_AUTHORIZE); + if (err) + return err; + } + + joined = new_links | resumed; + for_each_set_bit(link_id, &joined, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_sta_link *msta_link; + struct mt7996_vif_link *link; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + link = mt7996_vif_link(dev, vif, link_id); + mt7996_mac_sta_link_ps_leave(dev, link, msta_link); + } + + updated = sta->mlo ? links & ~updated : 0; + for_each_set_bit(link_id, &updated, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_sta_link *msta_link; + struct mt7996_vif_link *link; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + link = mt7996_vif_link(dev, vif, link_id); + err = mt7996_mcu_update_mld_sta(dev, vif, sta, link, msta_link); + if (err) + return err; + } + + return mt7996_mac_sta_links_ba_add(dev, vif, sta, new_links | resumed); +} + +static void +mt7996_mac_sta_links_reset(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long links) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + unsigned int link_id; + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_sta_link *msta_link; + struct mt7996_vif_link *link; + int i; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + if (!msta_link) + continue; + + link = mt7996_vif_link(dev, vif, link_id); + if (link) { + for (i = 0; i < ARRAY_SIZE(msta_link->twt.flow); i++) + mt7996_mac_twt_teardown_flow(dev, link, + msta_link, i); + } + + msta_link->wcid.tx_info &= ~MT_WCID_TX_INFO_SET; + msta_link->wcid.hw_key_idx = -1; + } +} + +static void +mt7996_mac_sta_links_bss_add(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long links) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + unsigned int link_id; + + if (vif->type != NL80211_IFTYPE_STATION || + msta->conn_state == CONN_STATE_DISCONNECT) + return; + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf; + struct mt7996_vif_link *link; + struct mt7996_phy *phy; + + link_conf = link_conf_dereference_protected(vif, link_id); + if (!link_conf || !link_conf->bssid || + is_zero_ether_addr(link_conf->bssid)) + continue; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + continue; + + phy = mt7996_vif_link_phy(link); + if (phy) + mt7996_vif_link_bss_add(phy, vif, link_conf, link, true); + } +} + +static int +mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, u16 old_links, + u16 new_links) +{ + struct mt7996_dev *dev = mt7996_hw_dev(hw); + unsigned long add = new_links & ~old_links; + unsigned long rem = old_links & ~new_links; + int ret; + + mutex_lock(&dev->mt76.mutex); + + mt7996_mac_sta_links_reset(dev, vif, sta, rem); + mt7996_mac_sta_remove_links(dev, vif, sta, rem, false); + mt7996_mac_sta_links_bss_add(dev, vif, sta, add); + ret = mt7996_mac_sta_add_links(dev, vif, sta, add); + if (ret) + goto out; + + ret = mt7996_mac_sta_links_sync(dev, vif, sta, new_links, add); + if (ret) { + mt7996_mac_sta_links_reset(dev, vif, sta, add); + mt7996_mac_sta_remove_links(dev, vif, sta, add, false); + mt7996_mac_sta_links_sync(dev, vif, sta, new_links & ~add, 0); + } + +out: + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static void mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { @@ -1477,6 +1905,30 @@ mt7996_set_active_links(struct ieee80211_vif *vif) ieee80211_set_active_links_async(vif, active_links); } +static void +mt7996_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + unsigned int link_id; + + mutex_lock(&dev->mt76.mutex); + spin_lock_bh(&dev->mt76.status_lock); + + for (link_id = 0; link_id < ARRAY_SIZE(msta->link); link_id++) { + struct mt7996_sta_link *msta_link; + + msta_link = mt7996_sta_link_protected(dev, msta, link_id); + if (msta_link) + rcu_assign_pointer(dev->mt76.wcid[msta_link->wcid.idx], + NULL); + } + + spin_unlock_bh(&dev->mt76.status_lock); + mutex_unlock(&dev->mt76.mutex); +} + static int mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, enum ieee80211_sta_state old_state, @@ -1493,6 +1945,17 @@ mt7996_sta_state(struct ieee80211_hw *hw, struct ieee80211_vif *vif, new_state == IEEE80211_STA_NOTEXIST) mt7996_mac_sta_remove(dev, vif, sta); + if (old_state == IEEE80211_STA_AUTHORIZED && + new_state == IEEE80211_STA_ASSOC) { + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + + mutex_lock(&dev->mt76.mutex); + msta->conn_state = CONN_STATE_CONNECT; + mutex_unlock(&dev->mt76.mutex); + + return 0; + } + if (old_state == IEEE80211_STA_AUTH && new_state == IEEE80211_STA_ASSOC) { mt7996_set_active_links(vif); @@ -1624,6 +2087,21 @@ static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx, return ret; } +static void +mt7996_sta_ba_update(u16 *mask, struct mt7996_sta_ba *ba, + struct ieee80211_ampdu_params *params, bool enable) +{ + if (!enable) { + *mask &= ~BIT(params->tid); + return; + } + + *mask |= BIT(params->tid); + ba[params->tid].ssn = params->ssn; + ba[params->tid].buf_size = params->buf_size; + ba[params->tid].amsdu = params->amsdu; +} + static int mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_ampdu_params *params) @@ -1635,6 +2113,7 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 tid = params->tid; u16 ssn = params->ssn; struct mt76_txq *mtxq; + unsigned long links; int ret = 0; if (!txq) @@ -1644,6 +2123,8 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); + links = mt7996_mac_sta_links(dev, vif, sta); + switch (params->action) { case IEEE80211_AMPDU_RX_START: /* Since packets belonging to the same TID can be split over @@ -1652,22 +2133,30 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, */ mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn, params->buf_size); - ret = mt7996_mcu_add_rx_ba(dev, params, vif, true); + ret = mt7996_mcu_add_rx_ba(dev, params, vif, links, true); + mt7996_sta_ba_update(&msta->ba_rx_mask, msta->ba_rx, params, + !ret); break; case IEEE80211_AMPDU_RX_STOP: mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid); - ret = mt7996_mcu_add_rx_ba(dev, params, vif, false); + mt7996_sta_ba_update(&msta->ba_rx_mask, msta->ba_rx, params, + false); + ret = mt7996_mcu_add_rx_ba(dev, params, vif, links, false); break; case IEEE80211_AMPDU_TX_OPERATIONAL: mtxq->aggr = true; mtxq->send_bar = false; - ret = mt7996_mcu_add_tx_ba(dev, params, vif, true); + ret = mt7996_mcu_add_tx_ba(dev, params, vif, links, true); + mt7996_sta_ba_update(&msta->ba_tx_mask, msta->ba_tx, params, + !ret); break; case IEEE80211_AMPDU_TX_STOP_FLUSH: case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: mtxq->aggr = false; clear_bit(tid, &msta->deflink.wcid.ampdu_state); - ret = mt7996_mcu_add_tx_ba(dev, params, vif, false); + mt7996_sta_ba_update(&msta->ba_tx_mask, msta->ba_tx, params, + false); + ret = mt7996_mcu_add_tx_ba(dev, params, vif, links, false); break; case IEEE80211_AMPDU_TX_START: set_bit(tid, &msta->deflink.wcid.ampdu_state); @@ -1676,7 +2165,9 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif, case IEEE80211_AMPDU_TX_STOP_CONT: mtxq->aggr = false; clear_bit(tid, &msta->deflink.wcid.ampdu_state); - ret = mt7996_mcu_add_tx_ba(dev, params, vif, false); + mt7996_sta_ba_update(&msta->ba_tx_mask, msta->ba_tx, params, + false); + ret = mt7996_mcu_add_tx_ba(dev, params, vif, links, false); ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); break; } @@ -1884,9 +2375,16 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, { struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct mt7996_sta_link *msta_link = &msta->deflink; - struct rate_info *txrate = &msta_link->wcid.rate; + struct mt7996_sta_link *msta_link; + struct rate_info *txrate; + rcu_read_lock(); + + msta_link = mt7996_sta_link(msta, msta->deflink_id); + if (!msta_link) + goto out; + + txrate = &msta_link->wcid.rate; if (txrate->legacy || txrate->flags) { if (txrate->legacy) { sinfo->txrate.legacy = txrate->legacy; @@ -1929,6 +2427,9 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, sinfo->rx_packets = msta_link->wcid.stats.rx_packets; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS); } + +out: + rcu_read_unlock(); } static void mt7996_link_rate_ctrl_update(void *data, @@ -2025,6 +2526,7 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); + assign_bit(MT_WCID_FLAG_4ADDR, &msta->wcid_flags, enabled); for_each_sta_active_link(vif, sta, link_sta, link_id) { struct mt7996_sta_link *msta_link; struct mt7996_vif_link *link; @@ -2037,23 +2539,12 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw, if (!msta_link) continue; - if (enabled) - set_bit(MT_WCID_FLAG_4ADDR, &msta_link->wcid.flags); - else - clear_bit(MT_WCID_FLAG_4ADDR, &msta_link->wcid.flags); - - if (!msta_link->wcid.sta) + mt7996_sta_link_hdr_trans_set(msta, msta_link); + if (!msta_link->connected) continue; mt7996_mcu_wtbl_update_hdr_trans(dev, vif, link, msta_link); - - /* HW cannot derive the BSSID from 4-address non-AMSDU frames, - * so PS exit is missed on links other than the setup link. - * Let the firmware wake those links instead. - */ - if (enabled && msta->deflink_id != link_id && - is_mt7996(&dev->mt76)) - mt7996_mcu_ps_leave(dev, link, msta_link); + mt7996_mac_sta_link_ps_leave(dev, link, msta_link); } mutex_unlock(&dev->mt76.mutex); @@ -2071,6 +2562,7 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); + assign_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid_flags, enabled); for_each_sta_active_link(vif, sta, link_sta, link_id) { struct mt7996_sta_link *msta_link; struct mt7996_vif_link *link; @@ -2083,14 +2575,8 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw, if (!msta_link) continue; - if (enabled) - set_bit(MT_WCID_FLAG_HDR_TRANS, - &msta_link->wcid.flags); - else - clear_bit(MT_WCID_FLAG_HDR_TRANS, - &msta_link->wcid.flags); - - if (!msta_link->wcid.sta) + mt7996_sta_link_hdr_trans_set(msta, msta_link); + if (!msta_link->connected) continue; mt7996_mcu_wtbl_update_hdr_trans(dev, vif, link, msta_link); @@ -2228,11 +2714,15 @@ static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta) { struct mt76_ethtool_worker_info *wi = wi_data; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct mt7996_sta_link *msta_link = &msta->deflink; + struct mt7996_sta_link *msta_link; if (msta->vif->deflink.mt76.idx != wi->idx) return; + msta_link = mt7996_sta_link(msta, msta->deflink_id); + if (!msta_link) + return; + mt76_ethtool_worker(wi, &msta_link->wcid.stats, true); } @@ -2568,7 +3058,7 @@ const struct ieee80211_ops mt7996_ops = { .vif_cfg_changed = mt7996_vif_cfg_changed, .link_info_changed = mt7996_link_info_changed, .sta_state = mt7996_sta_state, - .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, + .sta_pre_rcu_remove = mt7996_sta_pre_rcu_remove, .link_sta_rc_update = mt7996_link_sta_rc_update, .set_key = mt7996_set_key, .ampdu_action = mt7996_ampdu_action, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index cd7587ce5b8a..c324d199b212 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -488,6 +488,9 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) struct mt7996_mcu_countdown_notify *event; struct mt7996_mcu_countdown_data cdata; + if (skb->len < sizeof(*rxd) + sizeof(*hdr)) + return; + if (hdr->band >= ARRAY_SIZE(dev->mt76.phys)) return; @@ -497,9 +500,14 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) tail = skb->data + skb->len; data += sizeof(*hdr); - while (data + sizeof(*tlv) < tail && le16_to_cpu(tlv->len)) { - event = (struct mt7996_mcu_countdown_notify *)tlv->data; + while (data + sizeof(*tlv) <= tail) { + u16 tag_len = le16_to_cpu(tlv->len); + + if (tag_len < sizeof(*tlv) + sizeof(*event) || + data + tag_len > tail) + break; + event = (struct mt7996_mcu_countdown_notify *)tlv->data; cdata.omac_idx = event->omac_idx; switch (le16_to_cpu(tlv->tag)) { @@ -517,7 +525,7 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) break; } - data += le16_to_cpu(tlv->len); + data += tag_len; tlv = (struct tlv *)data; } } @@ -572,21 +580,32 @@ mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb) { #define UNI_EVENT_FW_LOG_FORMAT 0 struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; - const char *data = (char *)&rxd[1] + 4, *type; - struct tlv *tlv = (struct tlv *)data; + const char *data, *type; + struct tlv *tlv; int len; + if (skb->len < sizeof(*rxd)) + return; + if (!(rxd->option & MCU_UNI_CMD_EVENT)) { - len = skb->len - sizeof(*rxd); data = (char *)&rxd[1]; + len = skb->len - sizeof(*rxd); goto out; } + if (skb->len < sizeof(*rxd) + 4 + sizeof(*tlv)) + return; + + tlv = (struct tlv *)((char *)&rxd[1] + 4); if (le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_FORMAT) return; - data += sizeof(*tlv) + 4; + if (le16_to_cpu(tlv->len) < sizeof(*tlv) + 4) + return; + + data = (char *)tlv + sizeof(*tlv) + 4; len = le16_to_cpu(tlv->len) - sizeof(*tlv) - 4; + len = min_t(int, len, skb->len - (int)(data - (char *)skb->data)); out: switch (rxd->s2d_index) { @@ -648,13 +667,38 @@ static void mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb) { struct mt7996_mcu_all_sta_info_event *res; + u32 elem_size; + u16 sta_num; u16 i; + if (skb->len < sizeof(struct mt7996_mcu_rxd)) + return; + skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); res = (struct mt7996_mcu_all_sta_info_event *)skb->data; + if (skb->len < sizeof(*res)) + return; - for (i = 0; i < le16_to_cpu(res->sta_num); i++) { + sta_num = le16_to_cpu(res->sta_num); + switch (le16_to_cpu(res->tag)) { + case UNI_ALL_STA_TXRX_RATE: + elem_size = sizeof(res->rate[0]); + break; + case UNI_ALL_STA_TXRX_ADM_STAT: + elem_size = sizeof(res->adm_stat[0]); + break; + case UNI_ALL_STA_TXRX_MSDU_COUNT: + elem_size = sizeof(res->msdu_cnt[0]); + break; + default: + return; + } + + if (sta_num > (skb->len - sizeof(*res)) / elem_size) + sta_num = (skb->len - sizeof(*res)) / elem_size; + + for (i = 0; i < sta_num; i++) { u8 ac; u16 wlan_idx; struct mt76_wcid *wcid; @@ -1467,15 +1511,15 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif, /** starec & wtbl **/ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, - struct ieee80211_vif *vif, bool enable) + struct ieee80211_vif *vif, unsigned long links, + bool enable) { struct ieee80211_sta *sta = params->sta; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct ieee80211_link_sta *link_sta; unsigned int link_id; int ret = 0; - for_each_sta_active_link(vif, sta, link_sta, link_id) { + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { struct mt7996_sta_link *msta_link; struct mt7996_vif_link *link; @@ -1501,15 +1545,15 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, - struct ieee80211_vif *vif, bool enable) + struct ieee80211_vif *vif, unsigned long links, + bool enable) { struct ieee80211_sta *sta = params->sta; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct ieee80211_link_sta *link_sta; unsigned int link_id; int ret = 0; - for_each_sta_active_link(vif, sta, link_sta, link_id) { + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { struct mt7996_sta_link *msta_link; struct mt7996_vif_link *link; @@ -2715,18 +2759,20 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, struct ieee80211_sta *sta) { struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - unsigned int nlinks = hweight16(sta->valid_links); + unsigned long links = mt7996_mac_sta_links(dev, vif, sta); + unsigned int nlinks = hweight16(links); struct mld_setup_link *mld_setup_link; - struct ieee80211_link_sta *link_sta; struct sta_rec_mld_setup *mld_setup; struct mt7996_sta_link *msta_link; + u8 seclink_id = msta->deflink_id; unsigned int link_id; struct tlv *tlv; - msta_link = mt7996_sta_link_protected(dev, msta, msta->deflink_id); - if (!msta_link) + if (!(links & BIT(msta->deflink_id))) return; + msta_link = mt7996_sta_link_protected(dev, msta, msta->deflink_id); + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(struct sta_rec_mld_setup) + sizeof(struct mld_setup_link) * nlinks); @@ -2736,26 +2782,18 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, mld_setup->setup_wcid = cpu_to_le16(msta_link->wcid.idx); mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx); - if (nlinks > 1) { - msta_link = mt7996_sta_link_protected(dev, msta, - msta->seclink_id); - if (!msta_link) - return; - } + if (links & BIT(msta->seclink_id)) + seclink_id = msta->seclink_id; + msta_link = mt7996_sta_link_protected(dev, msta, seclink_id); mld_setup->seconed_id = cpu_to_le16(msta_link->wcid.idx); mld_setup->link_num = nlinks; mld_setup_link = (struct mld_setup_link *)mld_setup->link_info; - for_each_sta_active_link(vif, sta, link_sta, link_id) { + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { struct mt7996_vif_link *link; msta_link = mt7996_sta_link_protected(dev, msta, link_id); - if (!msta_link) - continue; - link = mt7996_vif_link(dev, vif, link_id); - if (!link) - continue; mld_setup_link->wcid = cpu_to_le16(msta_link->wcid.idx); mld_setup_link->bss_idx = link->mt76.idx; @@ -2872,6 +2910,27 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } +int mt7996_mcu_update_mld_sta(struct mt7996_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct mt7996_vif_link *link, + struct mt7996_sta_link *msta_link) +{ + struct sk_buff *skb; + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, + &msta_link->wcid, + MT7996_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7996_mcu_sta_mld_setup_tlv(dev, skb, vif, sta); + mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); +} + void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta) { struct mt7996_vif_link *link = (struct mt7996_vif_link *)data; @@ -5444,6 +5503,40 @@ int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled) sizeof(req), true); } +int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data) +{ + struct mt7996_dev *dev = phy->dev; + struct tx_power_ctrl req = { + .tag = cpu_to_le16(power_ctrl_id), + .len = cpu_to_le16(sizeof(req) - 4), + .power_ctrl_id = power_ctrl_id, + .band_idx = phy->mt76->band_idx, + }; + + switch (power_ctrl_id) { + case UNI_TXPOWER_SKU_POWER_LIMIT_CTRL: + req.sku_enable = !!data; + break; + case UNI_TXPOWER_PERCENTAGE_CTRL: + req.percentage_ctrl_enable = !!data; + break; + case UNI_TXPOWER_PERCENTAGE_DROP_CTRL: + req.power_drop_level = data; + break; + case UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL: + req.bf_backoff_enable = !!data; + break; + case UNI_TXPOWER_ATE_MODE_CTRL: + req.ate_mode_enable = !!data; + break; + default: + return -EINVAL; + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TXPOWER), + &req, sizeof(req), false); +} + int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy) { #define TX_POWER_LIMIT_TABLE_RATE 0 diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 1b272e904100..6078f8811b1e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -1039,8 +1039,31 @@ enum { UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG, }; +struct tx_power_ctrl { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + + u8 power_ctrl_id; + union { + bool sku_enable; + bool ate_mode_enable; + bool percentage_ctrl_enable; + bool bf_backoff_enable; + u8 power_drop_level; + }; + u8 band_idx; + u8 rsv[1]; +} __packed; + enum { + UNI_TXPOWER_SKU_POWER_LIMIT_CTRL = 0, + UNI_TXPOWER_PERCENTAGE_CTRL = 1, + UNI_TXPOWER_PERCENTAGE_DROP_CTRL = 2, + UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3, UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4, + UNI_TXPOWER_ATE_MODE_CTRL = 6, }; enum { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 2a0cdb56f822..da9958647b54 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -244,6 +244,7 @@ struct mt7996_sta_link { struct mt76_wcid wcid; /* must be first */ struct mt7996_sta *sta; + bool connected; struct list_head rc_list; u32 airtime_ac[8]; @@ -263,11 +264,25 @@ struct mt7996_sta_link { struct rcu_head rcu_head; }; +struct mt7996_sta_ba { + u16 ssn; + u16 buf_size; + bool amsdu; +}; + struct mt7996_sta { struct mt7996_sta_link deflink; /* must be first */ struct mt7996_sta_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; u8 deflink_id; u8 seclink_id; + u8 conn_state; + + unsigned long wcid_flags; + + u16 ba_tx_mask; + u16 ba_rx_mask; + struct mt7996_sta_ba ba_tx[IEEE80211_NUM_TIDS]; + struct mt7996_sta_ba ba_rx[IEEE80211_NUM_TIDS]; struct mt7996_vif *vif; }; @@ -279,6 +294,7 @@ struct mt7996_vif_link { struct cfg80211_bitrate_mask bitrate_mask; u8 mld_idx; + u8 bmc_bssid[ETH_ALEN]; }; struct mt7996_vif_link_info { @@ -643,6 +659,18 @@ mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif, link_conf); } +static inline struct mt76_vif_link * +mt7996_offchannel_link(struct mt76_wcid *wcid) +{ + struct mt7996_sta_link *msta_link; + struct mt7996_vif_link *link; + + msta_link = container_of(wcid, struct mt7996_sta_link, wcid); + link = container_of(msta_link, struct mt7996_vif_link, msta_link); + + return &link->mt76; +} + static inline struct mt7996_sta_link * mt7996_sta_link(struct mt7996_sta *msta, u8 link_id) { @@ -725,13 +753,20 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, struct mt7996_vif_link *link, struct mt7996_sta_link *msta_link); +int mt7996_mcu_update_mld_sta(struct mt7996_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct mt7996_vif_link *link, + struct mt7996_sta_link *msta_link); void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta); int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, - struct ieee80211_vif *vif, bool enable); + struct ieee80211_vif *vif, unsigned long links, + bool enable); int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, struct ieee80211_ampdu_params *params, - struct ieee80211_vif *vif, bool enable); + struct ieee80211_vif *vif, unsigned long links, + bool enable); int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct mt76_vif_link *mlink, struct cfg80211_he_bss_color *he_bss_color); @@ -778,6 +813,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy); int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy); +int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data); int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy); int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val); int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, @@ -893,6 +929,8 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, struct ieee80211_sta *sta, unsigned int link_id, bool flush); +u16 mt7996_mac_sta_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta); void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct ieee80211_twt_setup *twt); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c index b8006b8729a1..3fb9f39c2f61 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c @@ -283,7 +283,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan rx ring0 addr\n"); + "failed retrieving NPU wlan rx ring0 addr\n"); return err; } writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base); @@ -292,7 +292,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan rx ring2 addr\n"); + "failed retrieving NPU wlan rx ring2 addr\n"); return err; } writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2].regs->desc_base); @@ -302,7 +302,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan msdu pg ring addr\n"); + "failed retrieving NPU wlan msdu pg ring addr\n"); return err; } writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND0].regs->desc_base); @@ -311,7 +311,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan msdu pg ring addr\n"); + "failed retrieving NPU wlan msdu pg ring addr\n"); return err; } writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND1].regs->desc_base); @@ -320,7 +320,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan msdu pg ring addr\n"); + "failed retrieving NPU wlan msdu pg ring addr\n"); return err; } writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND2].regs->desc_base); @@ -330,7 +330,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan ind_cmd ring addr\n"); + "failed retrieving NPU wlan ind_cmd ring addr\n"); return err; } writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_IND].regs->desc_base); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c index b7d9193e042f..a7c23b33dde0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c @@ -63,12 +63,18 @@ static void mt7996_put_hif2(struct mt7996_hif *hif) static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev) { + struct pci_dev *tmp_pdev; + hif_idx++; - if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2, NULL) && - !pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL) && - !pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID_2, NULL)) + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2, NULL); + if (!tmp_pdev) + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL); + if (!tmp_pdev) + tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID_2, NULL); + if (!tmp_pdev) return NULL; + pci_dev_put(tmp_pdev); writel(hif_idx | MT_PCIE_RECOG_ID_SEM, pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index 8ff78cf6eb04..6df6e4c3d45d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -155,14 +155,42 @@ enum offs_rev { #define MT_FL_Q2_CTRL MT_PLE(0x3e8) #define MT_FL_Q3_CTRL MT_PLE(0x3ec) -#define MT_PLE_FREEPG_CNT MT_PLE(0x380) -#define MT_PLE_FREEPG_HEAD_TAIL MT_PLE(0x384) +#define MT_FL_Q0_CTRL_EXECUTE BIT(31) +#define MT_FL_Q0_CTRL_QID GENMASK(30, 24) +#define MT_FL_Q0_CTRL_TGID GENMASK(21, 20) +#define MT_FL_Q0_CTRL_PID GENMASK(17, 16) +#define MT_FL_Q0_CTRL_WLAN_IDX GENMASK(11, 0) +#define MT_FL_Q2_CTRL_TAIL_FID GENMASK(28, 16) +#define MT_FL_Q2_CTRL_HEAD_FID GENMASK(12, 0) +#define MT_FL_Q3_CTRL_PKT_NUM GENMASK(12, 0) + +#define MT_PLE_FREEPG_CNT MT_PLE(0x3a0) +#define MT_PLE_FREEPG_HEAD_TAIL MT_PLE(0x3a4) #define MT_PLE_PG_HIF_GROUP MT_PLE(0x00c) -#define MT_PLE_HIF_PG_INFO MT_PLE(0x388) +#define MT_PLE_HIF_PG_INFO MT_PLE(0x3a8) -#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x600 + 0x80 * (ac) + ((n) << 2)) +#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x600 + 0x100 * (ac) + ((n) << 2)) #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) +#define MT_FREEPG_CNT_FFA GENMASK(28, 16) +#define MT_FREEPG_CNT_FREE GENMASK(12, 0) +#define MT_FREEPG_HEAD_TAIL_TAIL GENMASK(28, 16) +#define MT_FREEPG_HEAD_TAIL_HEAD GENMASK(12, 0) +#define MT_PG_GROUP_MAX_QUOTA GENMASK(28, 16) +#define MT_PG_GROUP_MIN_QUOTA GENMASK(12, 0) +#define MT_PG_INFO_SRC_CNT GENMASK(28, 16) +#define MT_PG_INFO_RSV_CNT GENMASK(12, 0) + +/* PSE */ +#define MT_PSE_BASE 0x820c8000 +#define MT_PSE(ofs) (MT_PSE_BASE + (ofs)) + +#define MT_PSE_QUEUE_EMPTY MT_PSE(0x0b0) +#define MT_PSE_QUEUE_EMPTY_1 MT_PSE(0x0bc) +#define MT_PSE_FL_Q0_CTRL MT_PSE(0x1b0) +#define MT_PSE_FL_Q2_CTRL MT_PSE(0x1b8) +#define MT_PSE_FL_Q3_CTRL MT_PSE(0x1bc) + /* WF MDP TOP */ #define MT_MDP_BASE 0x820cc000 #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c index 3594b599662d..3271a2fa100d 100644 --- a/drivers/net/wireless/mediatek/mt76/scan.c +++ b/drivers/net/wireless/mediatek/mt76/scan.c @@ -4,16 +4,26 @@ */ #include "mt76.h" -static void mt76_scan_complete(struct mt76_dev *dev, bool abort) +static struct mt76_phy * +mt76_scan_chan_phy(struct ieee80211_hw *hw, struct ieee80211_channel *chan) { - struct mt76_phy *phy = dev->scan.phy; - struct cfg80211_scan_info info = { - .aborted = abort, - }; + struct mt76_phy *phy = hw->priv; + + if (hw->wiphy->n_radio > 1) + return phy->dev->band_phys[chan->band]; + + return phy; +} + +static void mt76_scan_phy_complete(struct mt76_phy *phy, bool abort) +{ + struct mt76_dev *dev = phy->dev; + struct cfg80211_scan_info info = {}; + struct ieee80211_hw *hw = phy->hw; lockdep_assert_held(&dev->mutex); - if (!phy) + if (!mt76_phy_scanning(phy)) return; clear_bit(MT76_SCANNING, &phy->state); @@ -29,41 +39,75 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) __mt76_set_channel(phy, &phy->main_chandef, false); if (offchannel) mt76_offchannel_notify(phy, false); + } else { + /* A phy that has no operating channel has nothing to restore, + * but the flag also gates the TX queues of every station whose + * wcid points at this band, so leaving it set stalls them until + * something else happens to set a channel. + */ + phy->offchannel = false; } - mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); + mt76_put_vif_phy_link(phy, dev->scan.vif, phy->scan.mlink); + memset(&phy->scan, 0, sizeof(phy->scan)); + + clear_bit(phy->band_idx, &dev->scan.phy_mask); + if (abort) + dev->scan.aborted = true; + + if (dev->scan.phy_mask) + return; + + info.aborted = dev->scan.aborted; memset(&dev->scan, 0, sizeof(dev->scan)); - if (!test_bit(MT76_MCU_RESET, &dev->phy.state)) - ieee80211_scan_completed(phy->hw, &info); + ieee80211_scan_completed(hw, &info); } void mt76_abort_scan(struct mt76_dev *dev) { - spin_lock_bh(&dev->scan_lock); - dev->scan.beacon_wait = false; - spin_unlock_bh(&dev->scan_lock); + struct mt76_phy *phy; + int i; + + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { + phy = dev->phys[i]; + if (!phy) + continue; + + spin_lock_bh(&dev->scan_lock); + phy->scan.beacon_wait = false; + spin_unlock_bh(&dev->scan_lock); - cancel_delayed_work_sync(&dev->scan_work); + disable_delayed_work_sync(&phy->scan_work); + } mutex_lock(&dev->mutex); - mt76_scan_complete(dev, true); + for (i = 0; i < ARRAY_SIZE(dev->phys); i++) { + phy = dev->phys[i]; + if (!phy) + continue; + + mt76_scan_phy_complete(phy, true); + enable_delayed_work(&phy->scan_work); + } mutex_unlock(&dev->mutex); } EXPORT_SYMBOL_GPL(mt76_abort_scan); static void -mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) +mt76_scan_send_probe(struct mt76_phy *phy, struct cfg80211_ssid *ssid) { - struct cfg80211_scan_request *req = dev->scan.req; + struct mt76_dev *dev = phy->dev; + struct cfg80211_scan_request *req = &dev->scan.req->req; + struct ieee80211_scan_ies *ies = &dev->scan.req->ies; struct ieee80211_vif *vif = dev->scan.vif; - struct mt76_vif_link *mvif = dev->scan.mlink; - enum nl80211_band band = dev->scan.chan->band; - struct mt76_phy *phy = dev->scan.phy; + struct mt76_vif_link *mvif = phy->scan.mlink; + enum nl80211_band band = phy->scan.chan->band; struct ieee80211_tx_info *info; struct sk_buff *skb; u8 link_id; skb = ieee80211_probereq_get(phy->hw, vif->addr, ssid->ssid, - ssid->ssid_len, req->ie_len); + ssid->ssid_len, + ies->len[band] + ies->common_ie_len); if (!skb) return; @@ -74,8 +118,10 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) ether_addr_copy(hdr->addr3, req->bssid); } - if (req->ie_len) - skb_put_data(skb, req->ie, req->ie_len); + if (ies->len[band]) + skb_put_data(skb, ies->ies[band], ies->len[band]); + if (ies->common_ie_len) + skb_put_data(skb, ies->common_ies, ies->common_ie_len); skb->priority = 7; skb_set_queue_mapping(skb, IEEE80211_AC_VO); @@ -100,65 +146,77 @@ out: rcu_read_unlock(); } -void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan) +void mt76_scan_rx_beacon(struct mt76_phy *phy, struct ieee80211_channel *chan) { - struct mt76_phy *phy; + struct mt76_dev *dev = phy->dev; spin_lock(&dev->scan_lock); - if (!dev->scan.beacon_wait || dev->scan.beacon_received || - dev->scan.chan != chan) - goto out; - - phy = dev->scan.phy; - if (!phy) + if (!phy->scan.beacon_wait || phy->scan.beacon_received || + phy->scan.chan != chan) goto out; - dev->scan.beacon_received = true; - ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0); + phy->scan.beacon_received = true; + ieee80211_queue_delayed_work(phy->hw, &phy->scan_work, 0); out: spin_unlock(&dev->scan_lock); } +static int mt76_scan_next_chan_idx(struct mt76_phy *phy) +{ + struct cfg80211_scan_request *req = &phy->dev->scan.req->req; + int i; + + for (i = phy->scan.chan_idx; i < req->n_channels; i++) + if (mt76_scan_chan_phy(phy->hw, req->channels[i]) == phy) + return i; + + return -1; +} + void mt76_scan_work(struct work_struct *work) { - struct mt76_dev *dev = container_of(work, struct mt76_dev, + struct mt76_phy *phy = container_of(work, struct mt76_phy, scan_work.work); - struct cfg80211_scan_request *req = dev->scan.req; + struct mt76_dev *dev = phy->dev; + struct cfg80211_scan_request *req; struct cfg80211_chan_def chandef = {}; - struct mt76_phy *phy = dev->scan.phy; int duration = HZ / 9; /* ~110 ms */ bool beacon_rx, offchannel = true; - int i; + int i, idx; - if (!phy || !req) + if (!dev->scan.req || !mt76_phy_scanning(phy)) return; + req = &dev->scan.req->req; + spin_lock_bh(&dev->scan_lock); - beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received; - dev->scan.beacon_wait = false; + beacon_rx = phy->scan.beacon_wait && phy->scan.beacon_received; + phy->scan.beacon_wait = false; spin_unlock_bh(&dev->scan_lock); if (beacon_rx) goto probe; - if (dev->scan.chan_idx >= req->n_channels) { + idx = mt76_scan_next_chan_idx(phy); + if (idx < 0) { mutex_lock(&dev->mutex); - mt76_scan_complete(dev, false); + mt76_scan_phy_complete(phy, false); mutex_unlock(&dev->mutex); return; } - if (dev->scan.chan && phy->num_sta && phy->offchannel) { - dev->scan.chan = NULL; + if (phy->scan.chan && phy->num_sta && phy->offchannel) { + phy->scan.chan = NULL; mt76_set_channel(phy, &phy->main_chandef, false); mt76_offchannel_notify(phy, false); goto out; } - dev->scan.chan = req->channels[dev->scan.chan_idx++]; - offchannel = mt76_offchannel_chandef(phy, dev->scan.chan, &chandef); + phy->scan.chan = req->channels[idx]; + phy->scan.chan_idx = idx + 1; + offchannel = mt76_offchannel_chandef(phy, phy->scan.chan, &chandef); if (offchannel) mt76_offchannel_notify(phy, true); @@ -169,8 +227,8 @@ void mt76_scan_work(struct work_struct *work) if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) { spin_lock_bh(&dev->scan_lock); - dev->scan.beacon_received = false; - dev->scan.beacon_wait = true; + phy->scan.beacon_received = false; + phy->scan.beacon_wait = true; spin_unlock_bh(&dev->scan_lock); goto out; } @@ -180,16 +238,16 @@ probe: duration = HZ / 16; /* ~60 ms */ local_bh_disable(); for (i = 0; i < req->n_ssids; i++) - mt76_scan_send_probe(dev, &req->ssids[i]); + mt76_scan_send_probe(phy, &req->ssids[i]); local_bh_enable(); out: - if (dev->scan.chan && phy->offchannel) + if (phy->scan.chan && phy->offchannel) duration = max_t(int, duration, msecs_to_jiffies(req->duration + (req->duration >> 5))); - ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, duration); + ieee80211_queue_delayed_work(phy->hw, &phy->scan_work, duration); } int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -197,36 +255,67 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; + unsigned long phy_mask = 0; struct mt76_vif_link *mlink; - int ret = 0; + int i, ret = 0; - if (hw->wiphy->n_radio > 1) { - phy = dev->band_phys[req->req.channels[0]->band]; + for (i = 0; i < req->req.n_channels; i++) { + phy = mt76_scan_chan_phy(hw, req->req.channels[i]); if (!phy) return -EINVAL; + + phy_mask |= BIT(phy->band_idx); } mutex_lock(&dev->mutex); - if (dev->scan.req || phy->roc_vif || - test_bit(MT76_MCU_RESET, &dev->phy.state)) { + if (dev->scan.req || test_bit(MT76_MCU_RESET, &dev->phy.state) || + test_bit(MT76_RESTART, &dev->phy.state)) { ret = -EBUSY; goto out; } - mlink = mt76_get_vif_phy_link(phy, vif); - if (IS_ERR(mlink)) { - ret = PTR_ERR(mlink); - goto out; + for_each_set_bit(i, &phy_mask, ARRAY_SIZE(dev->phys)) { + if (dev->phys[i]->roc_vif) { + ret = -EBUSY; + goto out; + } } - memset(&dev->scan, 0, sizeof(dev->scan)); - dev->scan.req = &req->req; + for_each_set_bit(i, &phy_mask, ARRAY_SIZE(dev->phys)) { + phy = dev->phys[i]; + mlink = mt76_get_vif_phy_link(phy, vif); + if (IS_ERR(mlink)) { + ret = PTR_ERR(mlink); + goto put_links; + } + + memset(&phy->scan, 0, sizeof(phy->scan)); + phy->scan.mlink = mlink; + } + + dev->scan.req = req; dev->scan.vif = vif; - dev->scan.phy = phy; - dev->scan.mlink = mlink; - set_bit(MT76_SCANNING, &phy->state); - ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, 0); + dev->scan.phy_mask = phy_mask; + dev->scan.aborted = false; + + for_each_set_bit(i, &phy_mask, ARRAY_SIZE(dev->phys)) { + phy = dev->phys[i]; + set_bit(MT76_SCANNING, &phy->state); + ieee80211_queue_delayed_work(phy->hw, &phy->scan_work, 0); + } + + goto out; + +put_links: + for_each_set_bit(i, &phy_mask, ARRAY_SIZE(dev->phys)) { + phy = dev->phys[i]; + if (!phy->scan.mlink) + break; + + mt76_put_vif_phy_link(phy, vif, phy->scan.mlink); + phy->scan.mlink = NULL; + } out: mutex_unlock(&dev->mutex); diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 3c623df2e741..b022d3843473 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -129,7 +129,7 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, memset(cb, 0, sizeof(*cb)); - if (!wcid || !rcu_access_pointer(dev->wcid[wcid->idx])) + if (!wcid) return MT_PACKET_ID_NO_ACK; if (info->flags & IEEE80211_TX_CTL_NO_ACK) @@ -147,6 +147,11 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid, spin_lock_bh(&dev->status_lock); + if (rcu_access_pointer(dev->wcid[wcid->idx]) != wcid) { + pid = MT_PACKET_ID_NO_ACK; + goto out; + } + pid = idr_alloc(&wcid->pktid, skb, MT_PACKET_ID_FIRST, MT_PACKET_ID_MASK, GFP_ATOMIC); if (pid < 0) { @@ -885,7 +890,7 @@ int mt76_skb_adjust_pad(struct sk_buff *skb, int pad) } } - if (skb_pad(last, pad)) + if (__skb_pad(last, pad, false)) return -ENOMEM; __skb_put(last, pad); diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index a9af3aa6b80a..be48a88a3ad0 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -171,8 +171,10 @@ static void mt76u_copy(struct mt76_dev *dev, u32 offset, { struct mt76_usb *usb = &dev->usb; const u8 *val = data; - int ret; int current_batch_size; + int len_aligned; + int copy_len; + int ret; int i = 0; /* Assure that always a multiple of 4 bytes are copied, @@ -180,12 +182,16 @@ static void mt76u_copy(struct mt76_dev *dev, u32 offset, * See: "mt76: round up length on mt76_wr_copy" * Commit 850e8f6fbd5d0003b0 */ - len = round_up(len, 4); + len_aligned = round_up(len, 4); mutex_lock(&usb->usb_ctrl_mtx); - while (i < len) { - current_batch_size = min_t(int, usb->data_len, len - i); - memcpy(usb->data, val + i, current_batch_size); + while (i < len_aligned) { + current_batch_size = min_t(int, usb->data_len, len_aligned - i); + copy_len = min_t(int, current_batch_size, len - i); + memcpy(usb->data, val + i, copy_len); + if (copy_len < current_batch_size) + memset(usb->data + copy_len, 0, + current_batch_size - copy_len); ret = __mt76u_vendor_request(dev, MT_VEND_MULTI_WRITE, USB_DIR_OUT | USB_TYPE_VENDOR, 0, offset + i, usb->data, @@ -893,6 +899,9 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { + struct ieee80211_tx_status status = { + .sta = sta, + }; struct mt76_tx_info tx_info = { .skb = skb, }; @@ -900,17 +909,27 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, u16 idx = q->head; int err; - if (q->queued == q->ndesc) - return -ENOSPC; + if (q->queued == q->ndesc) { + err = -ENOSPC; + goto err_free_skb; + } skb->prev = skb->next = NULL; err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); if (err < 0) - return err; + goto err_free_skb; err = mt76u_tx_setup_buffers(dev, tx_info.skb, q->entry[idx].urb); - if (err < 0) - return err; + if (err < 0) { + /* + * mt76_tx_status_skb_get() walks the idr and dereferences + * a freed skb. This SKB is not counted in non-AQL counter + * due to error return, so using 0xffff as wcid to keep + * balanced. + */ + mt76_tx_complete_skb(dev, 0xffff, tx_info.skb); + goto err_ret; + } mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q->ep, q->entry[idx].urb, mt76u_complete_tx, &q->entry[idx]); @@ -921,6 +940,14 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, q->queued++; return idx; + +err_free_skb: + status.skb = tx_info.skb; + spin_lock_bh(&dev->rx_lock); + ieee80211_tx_status_ext(dev->hw, &status); + spin_unlock_bh(&dev->rx_lock); +err_ret: + return err; } static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q) |
