diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c index 2b705bdb7993..05eee64706ea 100644 --- a/drivers/net/wireless/mediatek/mt76/channel.c +++ b/drivers/net/wireless/mediatek/mt76/channel.c @@ -88,6 +88,9 @@ void mt76_change_chanctx(struct ieee80211_hw *hw, IEEE80211_CHANCTX_CHANGE_RADAR))) return; + if (phy->roc_vif) + mt76_abort_roc(phy); + cancel_delayed_work_sync(&phy->mac_work); mutex_lock(&dev->mutex); @@ -155,8 +158,6 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, { struct mt76_chanctx *ctx = (struct mt76_chanctx *)conf->drv_priv; struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; - struct mt76_vif_data *mvif = mlink->mvif; - int link_id = link_conf->link_id; struct mt76_phy *phy = ctx->phy; struct mt76_dev *dev = phy->dev; @@ -173,15 +174,8 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw, if (!mlink) goto out; - if (mlink != (struct mt76_vif_link *)vif->drv_priv) - rcu_assign_pointer(mvif->link[link_id], NULL); - dev->drv->vif_link_remove(phy, vif, link_conf, mlink); mlink->ctx = NULL; - - if (mlink != (struct mt76_vif_link *)vif->drv_priv) - kfree_rcu(mlink, rcu_head); - out: mutex_unlock(&dev->mutex); } @@ -254,6 +248,8 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw, continue; mlink->ctx = vifs->new_ctx; + if (mlink->beacon_mon_interval) + WRITE_ONCE(mlink->beacon_mon_last, jiffies); } out: @@ -324,9 +320,11 @@ void mt76_roc_complete(struct mt76_phy *phy) if (mlink) mlink->mvif->roc_phy = NULL; - if (phy->main_chandef.chan && - !test_bit(MT76_MCU_RESET, &dev->phy.state)) - mt76_set_channel(phy, &phy->main_chandef, false); + if (phy->chanctx && phy->main_chandef.chan && phy->offchannel && + !test_bit(MT76_MCU_RESET, &dev->phy.state)) { + __mt76_set_channel(phy, &phy->main_chandef, false); + mt76_offchannel_notify(phy, false); + } mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link); phy->roc_vif = NULL; phy->roc_link = NULL; @@ -364,12 +362,15 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct mt76_phy *phy = hw->priv; struct mt76_dev *dev = phy->dev; struct mt76_vif_link *mlink; + bool offchannel; int ret = 0; phy = dev->band_phys[chan->band]; if (!phy) return -EINVAL; + cancel_delayed_work_sync(&phy->mac_work); + mutex_lock(&dev->mutex); if (phy->roc_vif || dev->scan.phy == phy || @@ -387,8 +388,18 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mlink->mvif->roc_phy = phy; phy->roc_vif = vif; phy->roc_link = mlink; - cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_HT20); - mt76_set_channel(phy, &chandef, true); + + offchannel = mt76_offchannel_chandef(phy, chan, &chandef); + if (offchannel) + mt76_offchannel_notify(phy, true); + ret = __mt76_set_channel(phy, &chandef, offchannel); + if (ret) { + mlink->mvif->roc_phy = NULL; + phy->roc_vif = NULL; + phy->roc_link = NULL; + mt76_put_vif_phy_link(phy, vif, mlink); + goto out; + } ieee80211_ready_on_channel(hw); ieee80211_queue_delayed_work(phy->hw, &phy->roc_work, msecs_to_jiffies(duration)); diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index f240016ed9f0..f8c2fe5f2f58 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -6,6 +6,7 @@ #include #include "mt76.h" #include "dma.h" +#include "mt76_connac.h" static struct mt76_txwi_cache * mt76_alloc_txwi(struct mt76_dev *dev) @@ -188,16 +189,18 @@ mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q) static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { - Q_WRITE(q, desc_base, q->desc_dma); - if ((q->flags & MT_QFLAG_WED_RRO_EN) && !mt76_npu_device_active(dev)) + if ((q->flags & MT_QFLAG_WED_RRO_EN) && + (!is_mt7992(dev) || !mt76_npu_device_active(dev))) Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); else Q_WRITE(q, ring_size, q->ndesc); if (mt76_queue_is_npu_tx(q)) { - writel(q->desc_dma, &q->regs->desc_base); writel(q->ndesc, &q->regs->ring_size); + writel(q->desc_dma, &q->regs->desc_base); } + + Q_WRITE(q, desc_base, q->desc_dma); q->head = Q_READ(q, dma_idx); q->tail = q->head; } @@ -663,6 +666,8 @@ mt76_dma_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, if (!t) goto free_skb; + t->phy_idx = phy->band_idx; + t->qid = qid; txwi = mt76_get_txwi_ptr(dev, t); skb->prev = skb->next = NULL; @@ -874,7 +879,16 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) if (!buf) break; - if (!mt76_queue_is_wed_rro(q)) + if (mtk_wed_device_active(&dev->mmio.wed) && + mt76_queue_is_wed_rro(q)) + continue; + + if (mt76_npu_device_active(dev) && + mt76_queue_is_wed_rro(q)) + continue; + + if (!mt76_queue_is_wed_rro_rxdmad_c(q) && + !mt76_queue_is_wed_rro_ind(q)) mt76_put_page_pool_buf(buf, false); } while (1); @@ -915,6 +929,13 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) mt76_queue_is_wed_rro(q)) return; + if (mt76_npu_device_active(dev) && + mt76_queue_is_wed_rro(q)) + return; + + if (mt76_queue_is_npu_txfree(q)) + return; + mt76_dma_sync_idx(dev, q); if (mt76_queue_is_npu(q)) mt76_npu_fill_rx_queue(dev, q); @@ -1168,10 +1189,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev) mt76_for_each_q_rx(dev, i) { struct mt76_queue *q = &dev->q_rx[i]; - if (mtk_wed_device_active(&dev->mmio.wed) && - mt76_queue_is_wed_rro(q)) - continue; - netif_napi_del(&dev->napi[i]); mt76_dma_rx_cleanup(dev, q); diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 4a63de6c5bf5..2a0226c83f3c 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -174,7 +174,9 @@ void mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, static inline void mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q) { - dev->queue_ops->reset_q(dev, q, true); + bool reset_idx = q && !mt76_queue_is_npu_tx(q); + + dev->queue_ops->reset_q(dev, q, reset_idx); if (mtk_wed_device_active(&dev->mmio.wed)) mt76_wed_dma_setup(dev, q, true); } diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c index 573400d57ce7..afdb73661866 100644 --- a/drivers/net/wireless/mediatek/mt76/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -9,6 +9,13 @@ #include #include #include "mt76.h" +#include "mt76_connac.h" + +enum mt76_sku_type { + MT76_SKU_RATE, + MT76_SKU_BACKOFF, + MT76_SKU_BACKOFF_BF_OFFSET, +}; static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len) { @@ -292,7 +299,6 @@ mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan) } EXPORT_SYMBOL_GPL(mt76_find_channel_node); - static s8 mt76_get_txs_delta(struct device_node *np, u8 nss) { @@ -306,9 +312,24 @@ mt76_get_txs_delta(struct device_node *np, u8 nss) return be32_to_cpu(val[nss - 1]); } +static inline u8 mt76_backoff_n_chains(struct mt76_dev *dev, u8 idx) +{ + /* 0:1T1ss, 1:2T1ss, ..., 14:5T5ss */ + static const u8 connac3_table[] = { + 1, 2, 3, 4, 5, 2, 3, 4, 5, 3, 4, 5, 4, 5, 5}; + static const u8 connac2_table[] = { + 1, 2, 3, 4, 2, 3, 4, 3, 4, 4, 0, 0, 0, 0, 0}; + + if (idx >= ARRAY_SIZE(connac3_table)) + return 0; + + return is_mt799x(dev) ? connac3_table[idx] : connac2_table[idx]; +} + static void -mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, - s8 target_power, s8 nss_delta, s8 *max_power) +mt76_apply_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len, + const s8 *data, s8 target_power, s8 nss_delta, + s8 *max_power, int n_chains, enum mt76_sku_type type) { int i; @@ -316,18 +337,51 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const s8 *data, return; for (i = 0; i < pwr_len; i++) { - pwr[i] = min_t(s8, target_power, data[i] + nss_delta); + u8 backoff_chain_idx = i; + int backoff_n_chains; + s8 backoff_delta; + s8 delta; + + switch (type) { + case MT76_SKU_RATE: + delta = 0; + backoff_delta = 0; + backoff_n_chains = 0; + break; + case MT76_SKU_BACKOFF_BF_OFFSET: + backoff_chain_idx += 1; + fallthrough; + case MT76_SKU_BACKOFF: + delta = mt76_tx_power_path_delta(n_chains); + backoff_n_chains = mt76_backoff_n_chains(dev, backoff_chain_idx); + backoff_delta = mt76_tx_power_path_delta(backoff_n_chains); + break; + default: + return; + } + + pwr[i] = min_t(s8, target_power + delta - backoff_delta, data[i] + nss_delta); + + /* used for padding, doesn't need to be considered */ + if (data[i] >= S8_MAX - 1) + continue; + + /* only consider backoff value for the configured chain number */ + if (type != MT76_SKU_RATE && n_chains != backoff_n_chains) + continue; + *max_power = max(*max_power, pwr[i]); } } static void -mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, - const s8 *data, size_t len, s8 target_power, - s8 nss_delta) +mt76_apply_multi_array_limit(struct mt76_dev *dev, s8 *pwr, size_t pwr_len, + s8 pwr_num, const s8 *data, size_t len, + s8 target_power, s8 nss_delta, s8 *max_power, + int n_chains, enum mt76_sku_type type) { + static const int connac2_backoff_ru_idx = 2; int i, cur; - s8 max_power = -128; if (!data) return; @@ -337,8 +391,26 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num, if (len < pwr_len + 1) break; - mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1, - target_power, nss_delta, &max_power); + /* Each RU entry (RU26, RU52, RU106, BW20, ...) in the DTS + * corresponds to 10 stream combinations (1T1ss, 2T1ss, 3T1ss, + * 4T1ss, 2T2ss, 3T2ss, 4T2ss, 3T3ss, 4T3ss, 4T4ss). + * + * For beamforming tables: + * - In connac2, beamforming entries for BW20~BW160 and OFDM + * do not include 1T1ss. + * - In connac3, beamforming entries for BW20~BW160 and RU + * include 1T1ss, but OFDM beamforming does not include 1T1ss. + * + * Non-beamforming and RU entries for both connac2 and connac3 + * include 1T1ss. + */ + if (!is_mt799x(dev) && type == MT76_SKU_BACKOFF && + i > connac2_backoff_ru_idx) + type = MT76_SKU_BACKOFF_BF_OFFSET; + + mt76_apply_array_limit(dev, pwr + pwr_len * i, pwr_len, data + 1, + target_power, nss_delta, max_power, + n_chains, type); if (--cur > 0) continue; @@ -360,18 +432,11 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, struct device_node *np; const s8 *val; char name[16]; - u32 mcs_rates = dev->drv->mcs_rates; - u32 ru_rates = ARRAY_SIZE(dest->ru[0]); char band; size_t len; - s8 max_power = 0; - s8 max_power_backoff = -127; + s8 max_power = -127; s8 txs_delta; int n_chains = hweight16(phy->chainmask); - s8 target_power_combine = target_power + mt76_tx_power_path_delta(n_chains); - - if (!mcs_rates) - mcs_rates = 10; memset(dest, target_power, sizeof(*dest) - sizeof(dest->path)); memset(&dest->path, 0, sizeof(dest->path)); @@ -409,46 +474,45 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy, txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask)); val = mt76_get_of_array_s8(np, "rates-cck", &len, ARRAY_SIZE(dest->cck)); - mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val, - target_power, txs_delta, &max_power); + mt76_apply_array_limit(dev, dest->cck, ARRAY_SIZE(dest->cck), val, + target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE); - val = mt76_get_of_array_s8(np, "rates-ofdm", - &len, ARRAY_SIZE(dest->ofdm)); - mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val, - target_power, txs_delta, &max_power); + val = mt76_get_of_array_s8(np, "rates-ofdm", &len, ARRAY_SIZE(dest->ofdm)); + mt76_apply_array_limit(dev, dest->ofdm, ARRAY_SIZE(dest->ofdm), val, + target_power, txs_delta, &max_power, n_chains, MT76_SKU_RATE); - val = mt76_get_of_array_s8(np, "rates-mcs", &len, mcs_rates + 1); - mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), - ARRAY_SIZE(dest->mcs), val, len, - target_power, txs_delta); + val = mt76_get_of_array_s8(np, "rates-mcs", &len, ARRAY_SIZE(dest->mcs[0]) + 1); + mt76_apply_multi_array_limit(dev, dest->mcs[0], ARRAY_SIZE(dest->mcs[0]), + ARRAY_SIZE(dest->mcs), val, len, target_power, + txs_delta, &max_power, n_chains, MT76_SKU_RATE); - val = mt76_get_of_array_s8(np, "rates-ru", &len, ru_rates + 1); - mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]), - ARRAY_SIZE(dest->ru), val, len, - target_power, txs_delta); + val = mt76_get_of_array_s8(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1); + mt76_apply_multi_array_limit(dev, dest->ru[0], ARRAY_SIZE(dest->ru[0]), + ARRAY_SIZE(dest->ru), val, len, target_power, + txs_delta, &max_power, n_chains, MT76_SKU_RATE); - max_power_backoff = max_power; val = mt76_get_of_array_s8(np, "paths-cck", &len, ARRAY_SIZE(dest->path.cck)); - mt76_apply_array_limit(dest->path.cck, ARRAY_SIZE(dest->path.cck), val, - target_power_combine, txs_delta, &max_power_backoff); + mt76_apply_array_limit(dev, dest->path.cck, ARRAY_SIZE(dest->path.cck), val, + target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); val = mt76_get_of_array_s8(np, "paths-ofdm", &len, ARRAY_SIZE(dest->path.ofdm)); - mt76_apply_array_limit(dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val, - target_power_combine, txs_delta, &max_power_backoff); + mt76_apply_array_limit(dev, dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val, + target_power, txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); val = mt76_get_of_array_s8(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest->path.ofdm_bf)); - mt76_apply_array_limit(dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val, - target_power_combine, txs_delta, &max_power_backoff); + mt76_apply_array_limit(dev, dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val, + target_power, txs_delta, &max_power, n_chains, + MT76_SKU_BACKOFF_BF_OFFSET); val = mt76_get_of_array_s8(np, "paths-ru", &len, ARRAY_SIZE(dest->path.ru[0]) + 1); - mt76_apply_multi_array_limit(dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]), - ARRAY_SIZE(dest->path.ru), val, len, - target_power_combine, txs_delta); + mt76_apply_multi_array_limit(dev, dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]), + ARRAY_SIZE(dest->path.ru), val, len, target_power, + txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); val = mt76_get_of_array_s8(np, "paths-ru-bf", &len, ARRAY_SIZE(dest->path.ru_bf[0]) + 1); - mt76_apply_multi_array_limit(dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]), - ARRAY_SIZE(dest->path.ru_bf), val, len, - target_power_combine, txs_delta); + mt76_apply_multi_array_limit(dev, dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]), + ARRAY_SIZE(dest->path.ru_bf), val, len, target_power, + txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF); return max_power; } diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 75772979f438..4ae5e4715a9c 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -726,6 +726,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size, 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++) skb_queue_head_init(&dev->rx_skb[i]); @@ -970,6 +971,9 @@ bool mt76_has_tx_pending(struct mt76_phy *phy) return true; } + if (atomic_read(&phy->mgmt_tx_pending)) + return true; + return false; } EXPORT_SYMBOL_GPL(mt76_has_tx_pending); @@ -1030,9 +1034,10 @@ int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, int timeout = HZ / 5; int ret; - set_bit(MT76_RESET, &phy->state); - mt76_worker_disable(&dev->tx_worker); + mt76_txq_schedule_pending(phy); + + set_bit(MT76_RESET, &phy->state); wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout); mt76_update_survey(phy); @@ -1716,6 +1721,16 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid) idr_destroy(&wcid->pktid); + /* Remove from sta_poll_list to prevent list corruption after reset. + * Without this, mt76_reset_device() reinitializes sta_poll_list but + * leaves wcid->poll_list with stale pointers, causing list corruption + * when mt76_wcid_add_poll() checks list_empty(). + */ + spin_lock_bh(&dev->sta_poll_lock); + if (!list_empty(&wcid->poll_list)) + list_del_init(&wcid->poll_list); + spin_unlock_bh(&dev->sta_poll_lock); + spin_lock_bh(&phy->tx_lock); if (!list_empty(&wcid->tx_list)) @@ -2121,3 +2136,214 @@ u16 mt76_select_links(struct ieee80211_vif *vif, int max_active_links) return sel_links; } EXPORT_SYMBOL_GPL(mt76_select_links); + +struct mt76_offchannel_cb_data { + struct mt76_phy *phy; + bool offchannel; +}; + +static void +mt76_offchannel_send_nullfunc(struct mt76_offchannel_cb_data *data, + struct ieee80211_vif *vif, int link_id) +{ + struct mt76_phy *phy = data->phy; + struct ieee80211_tx_info *info; + struct ieee80211_sta *sta = NULL; + struct ieee80211_hdr *hdr; + struct mt76_wcid *wcid; + struct sk_buff *skb; + + skb = ieee80211_nullfunc_get(phy->hw, vif, link_id, true); + if (!skb) + return; + + hdr = (struct ieee80211_hdr *)skb->data; + if (data->offchannel) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + + skb->priority = 7; + skb_set_queue_mapping(skb, IEEE80211_AC_VO); + + if (!ieee80211_tx_prepare_skb(phy->hw, vif, skb, + phy->main_chandef.chan->band, + &sta)) + return; + + if (sta) + wcid = (struct mt76_wcid *)sta->drv_priv; + else + wcid = ((struct mt76_vif_link *)vif->drv_priv)->wcid; + + if (link_id >= 0) { + info = IEEE80211_SKB_CB(skb); + info->control.flags &= ~IEEE80211_TX_CTRL_MLO_LINK; + info->control.flags |= + u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); + } + + mt76_tx(phy, sta, wcid, skb); +} + +static void +mt76_offchannel_notify_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt76_offchannel_cb_data *data = _data; + struct mt76_vif_link *mlink; + struct mt76_vif_data *mvif; + int link_id; + + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) + return; + + mlink = (struct mt76_vif_link *)vif->drv_priv; + mvif = mlink->mvif; + + if (!ieee80211_vif_is_mld(vif)) { + if (mt76_vif_link_phy(mlink) == data->phy) { + if (!data->offchannel && mlink->beacon_mon_interval) + WRITE_ONCE(mlink->beacon_mon_last, jiffies); + mt76_offchannel_send_nullfunc(data, vif, -1); + } + return; + } + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + if (link_id == mvif->deflink_id) + mlink = (struct mt76_vif_link *)vif->drv_priv; + else + mlink = rcu_dereference(mvif->link[link_id]); + if (!mlink) + continue; + if (mt76_vif_link_phy(mlink) != data->phy) + continue; + + if (!data->offchannel && mlink->beacon_mon_interval) + WRITE_ONCE(mlink->beacon_mon_last, jiffies); + + mt76_offchannel_send_nullfunc(data, vif, link_id); + } +} + +void mt76_offchannel_notify(struct mt76_phy *phy, bool offchannel) +{ + struct mt76_offchannel_cb_data data = { + .phy = phy, + .offchannel = offchannel, + }; + + if (!phy->num_sta) + return; + + local_bh_disable(); + ieee80211_iterate_active_interfaces_atomic(phy->hw, + IEEE80211_IFACE_ITER_NORMAL, + mt76_offchannel_notify_iter, &data); + local_bh_enable(); +} +EXPORT_SYMBOL_GPL(mt76_offchannel_notify); + +struct mt76_rx_beacon_data { + struct mt76_phy *phy; + const u8 *bssid; +}; + +static void mt76_rx_beacon_iter(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt76_rx_beacon_data *data = _data; + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + int link_id; + + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) + return; + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + struct ieee80211_bss_conf *link_conf; + + if (link_id == mvif->deflink_id) + mlink = (struct mt76_vif_link *)vif->drv_priv; + else + mlink = rcu_dereference(mvif->link[link_id]); + if (!mlink || !mlink->beacon_mon_interval) + continue; + + if (mt76_vif_link_phy(mlink) != data->phy) + continue; + + link_conf = rcu_dereference(vif->link_conf[link_id]); + if (!link_conf) + continue; + + if (!ether_addr_equal(link_conf->bssid, data->bssid) && + (!link_conf->nontransmitted || + !ether_addr_equal(link_conf->transmitter_bssid, + data->bssid))) + continue; + + WRITE_ONCE(mlink->beacon_mon_last, jiffies); + } +} + +void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb) +{ + struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; + struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb); + struct mt76_rx_beacon_data data = { + .phy = phy, + .bssid = hdr->addr3, + }; + + mt76_scan_rx_beacon(phy->dev, phy->chandef.chan); + + if (!phy->num_sta) + return; + + if (status->flag & (RX_FLAG_FAILED_FCS_CRC | RX_FLAG_ONLY_MONITOR)) + return; + + ieee80211_iterate_active_interfaces_atomic(phy->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76_rx_beacon_iter, &data); +} +EXPORT_SYMBOL_GPL(mt76_rx_beacon); + +static void mt76_beacon_mon_iter(void *data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mt76_phy *phy = data; + struct mt76_vif_link *mlink = (struct mt76_vif_link *)vif->drv_priv; + struct mt76_vif_data *mvif = mlink->mvif; + int link_id; + + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) + return; + + for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++) { + if (link_id == mvif->deflink_id) + mlink = (struct mt76_vif_link *)vif->drv_priv; + else + mlink = rcu_dereference(mvif->link[link_id]); + if (!mlink || !mlink->beacon_mon_interval) + continue; + + if (mt76_vif_link_phy(mlink) != phy) + continue; + + if (time_after(jiffies, + READ_ONCE(mlink->beacon_mon_last) + + MT76_BEACON_MON_MAX_MISS * mlink->beacon_mon_interval)) + ieee80211_beacon_loss(vif); + } +} + +void mt76_beacon_mon_check(struct mt76_phy *phy) +{ + if (phy->offchannel) + return; + + ieee80211_iterate_active_interfaces_atomic(phy->hw, + IEEE80211_IFACE_ITER_RESUME_ALL, + mt76_beacon_mon_iter, phy); +} +EXPORT_SYMBOL_GPL(mt76_beacon_mon_check); diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index 535c3d8a9cc0..cbfb3bbec503 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -98,7 +98,7 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb, /* orig skb might be needed for retry, mcu_skb_send_msg consumes it */ if (orig_skb) skb_get(orig_skb); - ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, &seq); + ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb, cmd, wait_resp ? &seq : NULL); if (ret < 0) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index d05e83ea1cac..527bef97e122 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -55,6 +55,8 @@ FIELD_PREP(MT_QFLAG_WED_RING, _n)) #define MT_NPU_Q_TX(_n) __MT_NPU_Q(MT76_WED_Q_TX, _n) #define MT_NPU_Q_RX(_n) __MT_NPU_Q(MT76_WED_Q_RX, _n) +#define MT_NPU_Q_TXFREE(_n) (FIELD_PREP(MT_QFLAG_WED_TYPE, MT76_WED_Q_TXFREE) | \ + FIELD_PREP(MT_QFLAG_WED_RING, _n)) struct mt76_dev; struct mt76_phy; @@ -362,6 +364,7 @@ enum mt76_wcid_flags { }; #define MT76_N_WCIDS 1088 +#define MT76_BEACON_MON_MAX_MISS 7 /* stored in ieee80211_tx_info::hw_queue */ #define MT_TX_HW_QUEUE_PHY GENMASK(3, 2) @@ -448,6 +451,7 @@ struct mt76_txwi_cache { }; u8 qid; + u8 phy_idx; }; struct mt76_rx_tid { @@ -540,7 +544,6 @@ struct mt76_driver_ops { u32 survey_flags; u16 txwi_size; u16 token_size; - u8 mcs_rates; unsigned int link_data_size; @@ -831,6 +834,8 @@ struct mt76_vif_link { u8 mcast_rates_idx; u8 beacon_rates_idx; bool offchannel; + unsigned long beacon_mon_last; + u16 beacon_mon_interval; struct ieee80211_chanctx_conf *ctx; struct mt76_wcid *wcid; struct mt76_vif_data *mvif; @@ -859,6 +864,8 @@ struct mt76_phy { struct list_head tx_list; struct mt76_queue *q_tx[__MT_TXQ_MAX]; + atomic_t mgmt_tx_pending; + struct cfg80211_chan_def chandef; struct cfg80211_chan_def main_chandef; bool offchannel; @@ -1002,6 +1009,7 @@ struct mt76_dev { u32 rxfilter; struct delayed_work scan_work; + spinlock_t scan_lock; struct { struct cfg80211_scan_request *req; struct ieee80211_channel *chan; @@ -1009,6 +1017,8 @@ struct mt76_dev { struct mt76_vif_link *mlink; struct mt76_phy *phy; int chan_idx; + bool beacon_wait; + bool beacon_received; } scan; #ifdef CONFIG_NL80211_TESTMODE @@ -1518,6 +1528,7 @@ void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta, void mt76_tx_check_agg_ssn(struct ieee80211_sta *sta, struct sk_buff *skb); void mt76_txq_schedule(struct mt76_phy *phy, enum mt76_txq_id qid); void mt76_txq_schedule_all(struct mt76_phy *phy); +void mt76_txq_schedule_pending(struct mt76_phy *phy); void mt76_tx_worker_run(struct mt76_dev *dev); void mt76_tx_worker(struct mt76_worker *w); void mt76_release_buffered_frames(struct ieee80211_hw *hw, @@ -1596,6 +1607,9 @@ 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_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, const u8 *mac); void mt76_sw_scan_complete(struct ieee80211_hw *hw, @@ -1649,6 +1663,9 @@ void mt76_npu_txdesc_cleanup(struct mt76_queue *q, int index); int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct net_device *dev, enum tc_setup_type type, void *type_data); +int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex, + u32 direction, u32 i_count_addr, + u32 o_status_addr, u32 o_count_addr); #else static inline void mt76_npu_check_ppe(struct mt76_dev *dev, struct sk_buff *skb, u32 info) @@ -1707,6 +1724,13 @@ static inline int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, { return -EOPNOTSUPP; } + +static inline int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex, + u32 direction, u32 i_count_addr, + u32 o_status_addr, u32 o_count_addr) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_MT76_NPU */ static inline bool mt76_npu_device_active(struct mt76_dev *dev) @@ -1775,6 +1799,18 @@ void mt76_queue_tx_complete(struct mt76_dev *dev, struct mt76_queue *q, struct mt76_queue_entry *e); int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, bool offchannel); + +static inline bool +mt76_offchannel_chandef(struct mt76_phy *phy, struct ieee80211_channel *chan, + struct cfg80211_chan_def *chandef) +{ + cfg80211_chandef_create(chandef, chan, NL80211_CHAN_HT20); + if (phy->main_chandef.chan != chan) + return true; + + *chandef = phy->main_chandef; + return false; +} int mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef, bool offchannel); void mt76_scan_work(struct work_struct *work); @@ -1786,6 +1822,7 @@ struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif); void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif, struct mt76_vif_link *mlink); +void mt76_offchannel_notify(struct mt76_phy *phy, bool offchannel); /* usb */ static inline bool mt76u_urb_error(struct urb *urb) @@ -1993,6 +2030,14 @@ static inline bool mt76_queue_is_npu_rx(struct mt76_queue *q) FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; } +static inline bool mt76_queue_is_npu_txfree(struct mt76_queue *q) +{ + if (q->flags & MT_QFLAG_WED) + return false; + + return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; +} + struct mt76_txwi_cache * mt76_token_release(struct mt76_dev *dev, int token, bool *wake); int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c index 45992fdcec60..ce0051468501 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c @@ -1167,21 +1167,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta, } EXPORT_SYMBOL_GPL(mt7615_mac_set_rates); -void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, - struct ieee80211_vif *vif, bool enable) -{ - struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; - u32 addr; - - addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4; - - if (enable) - mt76_set(dev, addr, MT_WTBL_W3_RTS); - else - mt76_clear(dev, addr, MT_WTBL_W3_RTS); -} -EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts); - static int mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index 727266892c3d..fc619acbb40d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -583,9 +583,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_ERP_CTS_PROT) - mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot); - if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) { mt7615_mcu_add_bss_info(phy, vif, NULL, true); mt7615_mcu_sta_add(phy, vif, NULL, true); @@ -598,6 +595,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw, BSS_CHANGED_BEACON_ENABLED)) mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon); + if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) + mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode, + info->use_cts_prot); + if (changed & BSS_CHANGED_PS) mt76_connac_mcu_set_vif_ps(&dev->mt76, vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c index fc0054f8bd60..ff57ede87f71 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c @@ -2564,3 +2564,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC), &req, sizeof(req), false); } + +int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, + u8 ht_mode, bool use_cts_prot) +{ + struct mt7615_dev *dev = phy->dev; + struct { + u8 prot_idx; + u8 band; + u8 rsv[2]; + + bool long_nav; + bool prot_mm; + bool prot_gf; + bool prot_bw40; + bool prot_rifs; + bool prot_bw80; + bool prot_bw160; + u8 prot_erp_mask; + } __packed req = { + .prot_idx = 0x2, + .band = phy != &dev->phy, + }; + + switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + req.prot_mm = true; + req.prot_gf = true; + fallthrough; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + req.prot_bw40 = true; + break; + } + + if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) + req.prot_gf = true; + + if (use_cts_prot) { + struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv; + u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx; + + req.prot_erp_mask = BIT(i); + } + + return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req, + sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h index c93fd245c90f..391928405f32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h @@ -467,8 +467,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy); void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy); void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable); void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy); -void mt7615_mac_enable_rtscts(struct mt7615_dev *dev, - struct ieee80211_vif *vif, bool enable); void mt7615_mac_sta_poll(struct mt7615_dev *dev); int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, @@ -523,7 +521,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable); int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy); int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy); int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy); - +int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif, + u8 ht_mode, bool use_cts_prot); int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif, struct ieee80211_channel *chan, int duration); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h index eb3c24d51987..e4133e9181d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h @@ -455,8 +455,6 @@ enum mt7615_reg_base { #define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8) #define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20) -#define MT_WTBL_W3_RTS BIT(22) - #define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5) #define MT_WTBL_W5_SHORT_GI_20 BIT(8) #define MT_WTBL_W5_SHORT_GI_40 BIT(9) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 813d61bffc2c..51423c7740bd 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -182,14 +182,20 @@ static inline bool is_mt7920(struct mt76_dev *dev) return mt76_chip(dev) == 0x7920; } +static inline bool is_mt7902(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7902; +} + static inline bool is_mt7922(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7922; } -static inline bool is_mt7921(struct mt76_dev *dev) +static inline bool is_connac2(struct mt76_dev *dev) { - return mt76_chip(dev) == 0x7961 || is_mt7922(dev) || is_mt7920(dev); + return mt76_chip(dev) == 0x7961 || is_mt7922(dev) || is_mt7920(dev) || + is_mt7902(dev); } static inline bool is_mt7663(struct mt76_dev *dev) @@ -271,6 +277,7 @@ static inline bool is_mt76_fw_txp(struct mt76_dev *dev) case 0x7961: case 0x7920: case 0x7922: + case 0x7902: case 0x7925: case 0x7663: case 0x7622: diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index f946ddc20a47..0339e2e7ab60 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -173,7 +173,7 @@ void mt76_connac_write_hw_txp(struct mt76_dev *dev, txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID); - if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev)) + if (is_mt7663(dev) || is_connac2(dev) || is_mt7925(dev)) last_mask = MT_TXD_LEN_LAST; else last_mask = MT_TXD_LEN_AMSDU_LAST | @@ -217,7 +217,7 @@ mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev, u32 last_mask; int i; - if (is_mt7663(dev) || is_mt7921(dev) || is_mt7925(dev)) + if (is_mt7663(dev) || is_connac2(dev) || is_mt7925(dev)) last_mask = MT_TXD_LEN_LAST; else last_mask = MT_TXD_LEN_MSDU_LAST; @@ -309,7 +309,7 @@ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, chandef = mvif->ctx ? &mvif->ctx->def : &mphy->chandef; band = chandef->chan->band; - if (is_mt7921(mphy->dev)) { + if (is_connac2(mphy->dev)) { rateidx = ffs(conf->basic_rates) - 1; goto legacy; } @@ -548,7 +548,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, val = MT_TXD1_LONG_FORMAT | FIELD_PREP(MT_TXD1_WLAN_IDX, wcid->idx) | FIELD_PREP(MT_TXD1_OWN_MAC, omac_idx); - if (!is_mt7921(dev)) + if (!is_connac2(dev)) val |= MT_TXD1_VTA; if (phy_idx || band_idx) val |= MT_TXD1_TGID; @@ -557,7 +557,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, txwi[2] = 0; val = FIELD_PREP(MT_TXD3_REM_TX_COUNT, 15); - if (!is_mt7921(dev)) + if (!is_connac2(dev)) val |= MT_TXD3_SW_POWER_MGMT; if (key) val |= MT_TXD3_PROTECT_FRAME; @@ -599,7 +599,7 @@ 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_mt7921(dev)) { + if (!is_connac2(dev)) { u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask); if (!spe_idx) @@ -831,7 +831,7 @@ mt76_connac2_mac_decode_he_mu_radiotap(struct mt76_dev *dev, struct sk_buff *skb }; struct ieee80211_radiotap_he_mu *he_mu; - if (is_mt7921(dev)) { + if (is_connac2(dev)) { mu_known.flags1 |= HE_BITS(MU_FLAGS1_SIG_B_COMP_KNOWN); mu_known.flags2 |= HE_BITS(MU_FLAGS2_PUNC_FROM_SIG_A_BW_KNOWN); } @@ -1047,7 +1047,7 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev, stbc = FIELD_GET(MT_PRXV_HT_STBC, v0); gi = FIELD_GET(MT_PRXV_HT_SGI, v0); *mode = FIELD_GET(MT_PRXV_TX_MODE, v0); - if (is_mt7921(dev)) + if (is_connac2(dev)) dcm = !!(idx & MT_PRXV_TX_DCM); else dcm = FIELD_GET(MT_PRXV_DCM, v0); @@ -1153,8 +1153,10 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) return; wcid = (struct mt76_wcid *)sta->drv_priv; - if (!test_and_set_bit(tid, &wcid->ampdu_state)) - ieee80211_start_tx_ba_session(sta, tid, 0); + if (!test_and_set_bit(tid, &wcid->ampdu_state)) { + if (ieee80211_start_tx_ba_session(sta, tid, 0)) + clear_bit(tid, &wcid->ampdu_state); + } } EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr); @@ -1207,5 +1209,11 @@ void mt76_connac2_tx_token_put(struct mt76_dev *dev) } spin_unlock_bh(&dev->token_lock); idr_destroy(&dev->token); + + for (id = 0; id < __MT_MAX_BAND; id++) { + struct mt76_phy *phy = dev->phys[id]; + if (phy) + atomic_set(&phy->mgmt_tx_pending, 0); + } } EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put); diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 0457712286d5..89bd52ea8bf7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -4,6 +4,7 @@ #include #include "mt76_connac2_mac.h" #include "mt76_connac_mcu.h" +#include "mt792x_regs.h" int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option) { @@ -65,7 +66,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, int cmd; if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || - (is_mt7921(dev) && addr == 0x900000) || + (is_connac2(dev) && addr == 0x900000) || (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) || (is_mt799x(dev) && addr == 0x900000)) cmd = MCU_CMD(PATCH_START_REQ); @@ -402,7 +403,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, switch (vif->type) { case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_AP: - if (vif->p2p && !is_mt7921(dev)) + if (vif->p2p && !is_connac2(dev)) conn_type = CONNECTION_P2P_GC; else conn_type = CONNECTION_INFRA_STA; @@ -410,7 +411,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, basic->aid = cpu_to_le16(link_sta->sta->aid); break; case NL80211_IFTYPE_STATION: - if (vif->p2p && !is_mt7921(dev)) + if (vif->p2p && !is_connac2(dev)) conn_type = CONNECTION_P2P_GO; else conn_type = CONNECTION_INFRA_AP; @@ -874,7 +875,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, struct sta_rec_vht *vht; int len; - len = is_mt7921(dev) ? sizeof(*vht) : sizeof(*vht) - 4; + len = is_connac2(dev) ? sizeof(*vht) : sizeof(*vht) - 4; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, len); vht = (struct sta_rec_vht *)tlv; vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap); @@ -885,7 +886,7 @@ void mt76_connac_mcu_sta_tlv(struct mt76_phy *mphy, struct sk_buff *skb, /* starec uapsd */ mt76_connac_mcu_sta_uapsd(skb, vif, sta); - if (!is_mt7921(dev)) + if (!is_connac2(dev)) return; if (sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he) @@ -1295,8 +1296,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, wtbl_hdr); ret = mt76_connac_mcu_sta_wed_update(dev, skb); - if (ret) + if (ret) { + dev_kfree_skb(skb); return ret; + } ret = mt76_mcu_skb_send_msg(dev, skb, cmd, true); if (ret) @@ -1309,8 +1312,10 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif, mt76_connac_mcu_sta_ba_tlv(skb, params, enable, tx); ret = mt76_connac_mcu_sta_wed_update(dev, skb); - if (ret) + if (ret) { + dev_kfree_skb(skb); return ret; + } return mt76_mcu_skb_send_msg(dev, skb, cmd, true); } @@ -1774,7 +1779,7 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, req->ssid_type_ext = n_ssids ? BIT(0) : 0; req->ssids_num = n_ssids; - duration = is_mt7921(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME; + duration = is_connac2(phy->dev) ? 0 : MT76_CONNAC_SCAN_CHANNEL_TIME; /* increase channel time for passive scan */ if (!sreq->n_ssids) duration *= 2; @@ -1817,7 +1822,7 @@ int mt76_connac_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, req->ies_len = cpu_to_le16(sreq->ie_len); } - if (is_mt7921(phy->dev)) + if (is_connac2(phy->dev)) req->scan_func |= SCAN_FUNC_SPLIT_SCAN; memcpy(req->bssid, sreq->bssid, ETH_ALEN); @@ -1893,7 +1898,7 @@ int mt76_connac_mcu_sched_scan_req(struct mt76_phy *phy, get_random_mask_addr(addr, sreq->mac_addr, sreq->mac_addr_mask); } - if (is_mt7921(phy->dev)) { + if (is_connac2(phy->dev)) { req->mt7921.bss_idx = mvif->idx; req->mt7921.delay = cpu_to_le32(sreq->delay); } @@ -2033,7 +2038,7 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku, struct mt76_power_limits *limits, enum nl80211_band band) { - int max_power = is_mt7921(dev) ? 127 : 63; + int max_power = is_connac2(dev) ? 127 : 63; int i, offset = sizeof(limits->cck); memset(sku, max_power, MT_SKU_POWER_LIMIT); @@ -2061,7 +2066,7 @@ mt76_connac_mcu_build_sku(struct mt76_dev *dev, s8 *sku, offset += 12; } - if (!is_mt7921(dev)) + if (!is_connac2(dev)) return; /* he */ @@ -2117,7 +2122,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, enum nl80211_band band) { struct mt76_dev *dev = phy->dev; - int sku_len, batch_len = is_mt7921(dev) ? 8 : 16; + int sku_len, batch_len = is_connac2(dev) ? 8 : 16; static const u8 chan_list_2ghz[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 @@ -2158,7 +2163,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, if (!limits) return -ENOMEM; - sku_len = is_mt7921(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92; + sku_len = is_connac2(dev) ? sizeof(sku_tlbv) : sizeof(sku_tlbv) - 92; tx_power = 2 * phy->hw->conf.power_level; if (!tx_power) tx_power = 127; @@ -2242,6 +2247,9 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, false); if (err < 0) goto out; + + /* read a CR to avoid PSE buffer underflow */ + mt76_connac_mcu_reg_rr(dev, MT_PSE_BASE); } out: @@ -2764,12 +2772,16 @@ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); ret = mt76_connac_mcu_sta_key_tlv(sta_key_conf, skb, key, cmd); - if (ret) + if (ret) { + dev_kfree_skb(skb); return ret; + } ret = mt76_connac_mcu_sta_wed_update(dev, skb); - if (ret) + if (ret) { + dev_kfree_skb(skb); return ret; + } return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } @@ -3072,7 +3084,7 @@ static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info) { u32 mode = DL_MODE_NEED_RSP; - if ((!is_mt7921(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT) + if ((!is_connac2(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT) return mode; switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 8d59cf43f0e2..ac5126ab68ff 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -628,6 +628,13 @@ struct sta_rec_tx_proc { __le32 flag; } __packed; +struct sta_rec_eml_op { + __le16 tag; + __le16 len; + u8 link_bitmap; + u8 link_ant_num[3]; +} __packed; + /* wtbl_rec */ struct wtbl_req_hdr { @@ -796,6 +803,7 @@ struct wtbl_raw { sizeof(struct sta_rec_he_6g_capa) + \ sizeof(struct sta_rec_pn_info) + \ sizeof(struct sta_rec_tx_proc) + \ + sizeof(struct sta_rec_eml_op) + \ sizeof(struct tlv) + \ MT76_CONNAC_WTBL_UPDATE_MAX_SIZE) @@ -832,6 +840,7 @@ enum { STA_REC_PN_INFO = 0x26, STA_REC_KEY_V3 = 0x27, STA_REC_HDRT = 0x28, + STA_REC_EML_OP = 0x29, STA_REC_HDR_TRANS = 0x2B, STA_REC_MAX_NUM }; @@ -1308,7 +1317,9 @@ enum { MCU_UNI_CMD_PER_STA_INFO = 0x6d, MCU_UNI_CMD_ALL_STA_INFO = 0x6e, MCU_UNI_CMD_ASSERT_DUMP = 0x6f, + MCU_UNI_CMD_EXT_EEPROM_CTRL = 0x74, MCU_UNI_CMD_RADIO_STATUS = 0x80, + MCU_UNI_CMD_MLD = 0x82, MCU_UNI_CMD_SDO = 0x88, }; @@ -1363,6 +1374,7 @@ enum { UNI_BSS_INFO_BASIC = 0, UNI_BSS_INFO_RA = 1, UNI_BSS_INFO_RLM = 2, + UNI_BSS_INFO_PROTECT_INFO = 3, UNI_BSS_INFO_BSS_COLOR = 4, UNI_BSS_INFO_HE_BASIC = 5, UNI_BSS_INFO_11V_MBSSID = 6, @@ -1383,6 +1395,7 @@ enum { UNI_BSS_INFO_MLD = 26, UNI_BSS_INFO_PM_DISABLE = 27, UNI_BSS_INFO_EHT = 30, + UNI_BSS_INFO_MLD_LINK_OP = 36, }; enum { @@ -1865,7 +1878,7 @@ mt76_connac_mcu_gen_dl_mode(struct mt76_dev *dev, u8 feature_set, bool is_wa) ret |= feature_set & FW_FEATURE_SET_ENCRYPT ? DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV : 0; - if (is_mt7921(dev) || is_mt7925(dev)) + if (is_connac2(dev) || is_mt7925(dev)) ret |= feature_set & FW_FEATURE_ENCRY_MODE ? DL_CONFIG_ENCRY_MODE_SEL : 0; ret |= FIELD_PREP(DL_MODE_KEY_IDX, diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c index dd71c1c95cc9..dc7c03d23123 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c @@ -534,6 +534,7 @@ void mt76x02_reconfig_complete(struct ieee80211_hw *hw, return; clear_bit(MT76_RESTART, &dev->mphy.state); + ieee80211_wake_queues(hw); } EXPORT_SYMBOL_GPL(mt76x02_reconfig_complete); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 22443cbc74ad..250c2d2479b0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -1294,6 +1294,7 @@ int mt7915_register_device(struct mt7915_dev *dev) void mt7915_unregister_device(struct mt7915_dev *dev) { + cancel_work_sync(&dev->dump_work); mt7915_unregister_ext_phy(dev); mt7915_coredump_unregister(dev); mt7915_unregister_thermal(&dev->phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c index cefe56c05731..cec2c4208255 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -232,19 +232,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) rcu_read_unlock(); } -void mt7915_mac_enable_rtscts(struct mt7915_dev *dev, - struct ieee80211_vif *vif, bool enable) -{ - struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; - u32 addr; - - addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5); - if (enable) - mt76_set(dev, addr, BIT(5)); - else - mt76_clear(dev, addr, BIT(5)); -} - static void mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q, struct mt7915_sta *msta, struct sk_buff *skb, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 90d5e79fbf74..e1d83052aa6d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw) if (ret) goto out; - ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, + ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES, phy->mt76->band_idx); if (ret) goto out; @@ -633,8 +633,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw, if (set_sta == 1) mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false); - if (changed & BSS_CHANGED_ERP_CTS_PROT) - mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot); + if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) + mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode, + info->use_cts_prot); if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = 9; @@ -851,8 +852,10 @@ int mt7915_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, return mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_PORT_SECURE, false); case MT76_STA_EVENT_DISASSOC: + mutex_lock(&dev->mt76.mutex); for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++) mt7915_mac_twt_teardown_flow(dev, msta, i); + mutex_unlock(&dev->mt76.mutex); mt7915_mcu_add_sta(dev, vif, sta, CONN_STATE_DISCONNECT, false); msta->wcid.sta_disabled = 1; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index 2d2f34aa465d..318c38149463 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -1765,8 +1765,10 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif, } out: ret = mt76_connac_mcu_sta_wed_update(&dev->mt76, skb); - if (ret) + if (ret) { + dev_kfree_skb(skb); return ret; + } return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_EXT_CMD(STA_REC_UPDATE), true); @@ -3954,6 +3956,68 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif, return ret; } +int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, + u8 ht_mode, bool use_cts_prot) +{ + struct mt7915_dev *dev = phy->dev; + int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot); + struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv; + struct bss_info_prot *prot; + struct sk_buff *skb; + struct tlv *tlv; + enum { + PROT_NONMEMBER = BIT(1), + PROT_20MHZ = BIT(2), + PROT_NONHT_MIXED = BIT(3), + PROT_LEGACY_ERP = BIT(5), + PROT_NONGF_STA = BIT(7), + }; + u32 rts_threshold; + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, + NULL, len); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO, + sizeof(*prot)); + prot = (struct bss_info_prot *)tlv; + + switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); + break; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + prot->prot_mode = cpu_to_le32(PROT_20MHZ); + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); + break; + } + + if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) + prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); + + if (use_cts_prot) + prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); + + /* reuse current RTS setting */ + rts_threshold = phy->mt76->hw->wiphy->rts_threshold; + if (rts_threshold == (u32)-1) + prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES); + else + prot->rts_len_thres = cpu_to_le32(rts_threshold); + + prot->rts_pkt_thres = 0x2; + + prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th); + if (!prot->he_rts_thres) + prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_EXT_CMD(BSS_INFO_UPDATE), true); +} + int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif, struct cfg80211_he_bss_color *he_bss_color) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 3af11a075a2f..22f73a5ed425 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -399,6 +399,17 @@ struct bss_info_inband_discovery { __le16 prob_rsp_len; } __packed __aligned(4); +struct bss_info_prot { + __le16 tag; + __le16 len; + __le32 prot_type; + __le32 prot_mode; + __le32 rts_len_thres; + __le16 he_rts_thres; + u8 rts_pkt_thres; + u8 rsv[5]; +} __packed; + enum { BSS_INFO_BCN_CSA, BSS_INFO_BCN_BCC, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index b5c06201b707..bf1d915a3ca2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -84,6 +84,8 @@ #define MT7915_CRIT_TEMP 110 #define MT7915_MAX_TEMP 120 +#define MT7915_RTS_LEN_THRES 0x92b + struct mt7915_vif; struct mt7915_sta; struct mt7915_dfs_pulse; @@ -473,6 +475,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v u32 changed); int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, int enable, u32 changed); +int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif, + u8 ht_mode, bool use_cts_prot); int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif, struct ieee80211_he_obss_pd *he_obss_pd); int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c index 29732315af1c..8e7790702191 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c @@ -302,7 +302,9 @@ int mt7921_register_device(struct mt792x_dev *dev) dev->pm.idle_timeout = MT792x_PM_TIMEOUT; dev->pm.stats.last_wake_event = jiffies; dev->pm.stats.last_doze_event = jiffies; - if (!mt76_is_usb(&dev->mt76)) { + + if (!mt76_is_usb(&dev->mt76) && + !is_mt7902(&dev->mt76)) { dev->pm.enable_user = true; dev->pm.enable = true; dev->pm.ds_enable_user = true; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 5fae9a6e273c..3d74fabe7408 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -371,12 +371,15 @@ void mt7921_roc_abort_sync(struct mt792x_dev *dev) { struct mt792x_phy *phy = &dev->phy; + if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + return; + timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - ieee80211_iterate_interfaces(mt76_hw(dev), - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7921_roc_iter, (void *)phy); + cancel_work(&phy->roc_work); + + ieee80211_iterate_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7921_roc_iter, (void *)phy); } EXPORT_SYMBOL_GPL(mt7921_roc_abort_sync); @@ -387,10 +390,11 @@ void mt7921_roc_work(struct work_struct *work) phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, roc_work); - if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - return; - mt792x_mutex_acquire(phy->dev); + if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) { + mt792x_mutex_release(phy->dev); + return; + } ieee80211_iterate_active_interfaces(phy->mt76->hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7921_roc_iter, phy); @@ -796,7 +800,8 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) } out: - mt7921_mcu_set_clc(dev, dev->mt76.alpha2, dev->country_ie_env); + if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ) + mt7921_regd_update(dev); } int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, @@ -807,6 +812,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; int ret, idx; + if (sta->aid > MT7921_MAX_AID) + return -ENOENT; + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); if (idx < 0) return -ENOSPC; @@ -850,6 +858,9 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + if (sta->aid > MT7921_MAX_AID) + return -ENOENT; + if (ev != MT76_STA_EVENT_ASSOC) return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 833d0ab64230..8442dbd2ee23 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -1353,6 +1353,9 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, u16 len = le16_to_cpu(rule->len); u16 offset = len + sizeof(*rule); + if (buf_len < offset) + break; + pos += offset; buf_len -= offset; if (rule->alpha2[0] != alpha2[0] || diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h index 83fc7f49ff84..64f60c4fc60c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h @@ -7,6 +7,8 @@ #include "../mt792x.h" #include "regs.h" +#define MT7921_MAX_AID 20 + #define MT7921_TX_RING_SIZE 2048 #define MT7921_TX_MCU_RING_SIZE 256 #define MT7921_TX_FWDL_RING_SIZE 128 @@ -15,6 +17,9 @@ #define MT7921_RX_MCU_RING_SIZE 8 #define MT7921_RX_MCU_WA_RING_SIZE 512 +/* MT7902 Rx Ring0 is for both Rx Event and Tx Done Event */ +#define MT7902_RX_MCU_RING_SIZE 512 + #define MT7921_EEPROM_SIZE 3584 #define MT7921_TOKEN_SIZE 8192 @@ -117,6 +122,17 @@ enum mt7921_rxq_id { MT7921_RXQ_MCU_WM = 0, }; +/* MT7902 assigns its MCU-WM TXQ at index 15 */ +enum mt7902_txq_id { + MT7902_TXQ_MCU_WM = 15, +}; + +struct mt7921_dma_layout { + u8 mcu_wm_txq; + u16 mcu_rxdone_ring_size; + bool has_mcu_wa; +}; + enum { MT7921_CLC_POWER, MT7921_CLC_CHAN, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index ec9686183251..7a790ddf43bb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -26,6 +26,8 @@ static const struct pci_device_id mt7921_pci_device_table[] = { .driver_data = (kernel_ulong_t)MT7922_FIRMWARE_WM }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7920), .driver_data = (kernel_ulong_t)MT7920_FIRMWARE_WM }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7902), + .driver_data = (kernel_ulong_t)MT7902_FIRMWARE_WM }, { }, }; @@ -167,8 +169,29 @@ static u32 mt7921_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) static int mt7921_dma_init(struct mt792x_dev *dev) { + struct mt7921_dma_layout layout = { + /* General case: MT7921 / MT7922 /MT7920 */ + .mcu_wm_txq = MT7921_TXQ_MCU_WM, + .mcu_rxdone_ring_size = MT7921_RX_MCU_RING_SIZE, + .has_mcu_wa = true, + }; + bool is_mt7902; int ret; + is_mt7902 = mt7921_l1_rr(dev, MT_HW_CHIPID) == 0x7902; + + /* + * MT7902 special case: + * - MCU-WM TXQ uses index 15 + * - RX Ring0 is larger and shared for event/TX-done + * - MT7902 does not use the MCU_WA ring + */ + if (is_mt7902) { + layout.mcu_wm_txq = MT7902_TXQ_MCU_WM; + layout.mcu_rxdone_ring_size = MT7902_RX_MCU_RING_SIZE; + layout.has_mcu_wa = false; + } + mt76_dma_attach(&dev->mt76); ret = mt792x_dma_disable(dev, true); @@ -185,7 +208,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4); /* command to WM */ - ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7921_TXQ_MCU_WM, + ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, layout.mcu_wm_txq, MT7921_TX_MCU_RING_SIZE, MT_TX_RING_BASE); if (ret) return ret; @@ -199,18 +222,20 @@ static int mt7921_dma_init(struct mt792x_dev *dev) /* event from WM before firmware download */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], MT7921_RXQ_MCU_WM, - MT7921_RX_MCU_RING_SIZE, + layout.mcu_rxdone_ring_size, MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE); if (ret) return ret; - /* Change mcu queue after firmware download */ - ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], - MT7921_RXQ_MCU_WM, - MT7921_RX_MCU_WA_RING_SIZE, - MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); - if (ret) - return ret; + if (layout.has_mcu_wa) { + /* Change mcu queue after firmware download */ + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], + MT7921_RXQ_MCU_WM, + MT7921_RX_MCU_WA_RING_SIZE, + MT_RX_BUF_SIZE, MT_WFDMA0(0x540)); + if (ret) + return ret; + } /* rx data */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], @@ -276,6 +301,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, struct mt76_bus_ops *bus_ops; struct mt792x_dev *dev; struct mt76_dev *mdev; + void __iomem *regs; u16 cmd, chipid; u8 features; int ret; @@ -284,10 +310,6 @@ static int mt7921_pci_probe(struct pci_dev *pdev, if (ret) return ret; - ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); - if (ret) - return ret; - pci_read_config_word(pdev, PCI_COMMAND, &cmd); if (!(cmd & PCI_COMMAND_MEMORY)) { cmd |= PCI_COMMAND_MEMORY; @@ -321,11 +343,29 @@ static int mt7921_pci_probe(struct pci_dev *pdev, pci_set_drvdata(pdev, mdev); + regs = pcim_iomap_region(pdev, 0, pci_name(pdev)); + if (IS_ERR(regs)) + return PTR_ERR(regs); + dev = container_of(mdev, struct mt792x_dev, mt76); dev->fw_features = features; dev->hif_ops = &mt7921_pcie_ops; dev->irq_map = &irq_map; - mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); + mt76_mmio_init(&dev->mt76, regs); + + if (id->device == 0x7902) { + struct mt792x_irq_map *map; + + /* MT7902 needs a mutable copy because wm2_complete_mask differs */ + map = devm_kmemdup(&pdev->dev, &irq_map, + sizeof(irq_map), GFP_KERNEL); + if (!map) + return -ENOMEM; + + map->rx.wm2_complete_mask = 0; + dev->irq_map = map; + } + tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); dev->phy.dev = dev; @@ -579,6 +619,8 @@ MODULE_FIRMWARE(MT7921_FIRMWARE_WM); MODULE_FIRMWARE(MT7921_ROM_PATCH); MODULE_FIRMWARE(MT7922_FIRMWARE_WM); MODULE_FIRMWARE(MT7922_ROM_PATCH); +MODULE_FIRMWARE(MT7902_FIRMWARE_WM); +MODULE_FIRMWARE(MT7902_ROM_PATCH); MODULE_AUTHOR("Sean Wang "); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("MediaTek MT7921E (PCIe) wireless driver"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 5ec084432ae3..0db7acb3a637 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -71,9 +71,9 @@ int mt7921e_mac_reset(struct mt792x_dev *dev) mt76_txq_schedule_all(&dev->mphy); mt76_worker_disable(&dev->mt76.tx_worker); - napi_disable(&dev->mt76.napi[MT_RXQ_MAIN]); - napi_disable(&dev->mt76.napi[MT_RXQ_MCU]); - napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]); + mt76_for_each_q_rx(&dev->mt76, i) { + napi_disable(&dev->mt76.napi[i]); + } napi_disable(&dev->mt76.tx_napi); mt76_connac2_tx_token_put(&dev->mt76); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c index 3421e53dc948..9150f185716c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/sdio.c @@ -19,6 +19,8 @@ static const struct sdio_device_id mt7921s_table[] = { { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7901), .driver_data = (kernel_ulong_t)MT7921_FIRMWARE_WM }, + { SDIO_DEVICE(SDIO_VENDOR_ID_MEDIATEK, 0x7902), + .driver_data = (kernel_ulong_t)MT7902_FIRMWARE_WM }, { } /* Terminating entry */ }; @@ -317,6 +319,8 @@ static int mt7921s_resume(struct device *__dev) MODULE_DEVICE_TABLE(sdio, mt7921s_table); MODULE_FIRMWARE(MT7921_FIRMWARE_WM); MODULE_FIRMWARE(MT7921_ROM_PATCH); +MODULE_FIRMWARE(MT7902_FIRMWARE_WM); +MODULE_FIRMWARE(MT7902_ROM_PATCH); static DEFINE_SIMPLE_DEV_PM_OPS(mt7921s_pm_ops, mt7921s_suspend, mt7921s_resume); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index 3ce5d6fcc69d..c0c5cb9aff75 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -91,6 +91,8 @@ int mt7925_mac_init(struct mt792x_dev *dev) mt7925_mac_init_basic_rates(dev); + memzero_explicit(&dev->mt76.alpha2, sizeof(dev->mt76.alpha2)); + return 0; } EXPORT_SYMBOL_GPL(mt7925_mac_init); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index caaf71c31480..c47bd812b66b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -804,8 +804,8 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, txwi[5] = cpu_to_le32(val); val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); - if (!ieee80211_vif_is_mld(vif) || - (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0)) + if (vif && (!ieee80211_vif_is_mld(vif) || + (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))) val |= MT_TXD6_DIS_MAT; txwi[6] = cpu_to_le32(val); txwi[7] = 0; @@ -846,11 +846,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, bool is_8023; u16 fc, tid; + if (!sta) + return; + link_sta = rcu_dereference(sta->link[wcid->link_id]); if (!link_sta) return; - if (!sta || !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) + if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) return; tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; @@ -882,8 +885,10 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb, else mlink = &msta->deflink; - if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) - ieee80211_start_tx_ba_session(sta, tid, 0); + if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) { + if (ieee80211_start_tx_ba_session(sta, tid, 0)) + clear_bit(tid, &mlink->wcid.ampdu_state); + } } static bool @@ -1280,7 +1285,8 @@ mt7925_vif_connect_iter(void *priv, u8 *mac, if (vif->type == NL80211_IFTYPE_AP) { mt76_connac_mcu_uni_add_bss(dev->phy.mt76, vif, &mvif->sta.deflink.wcid, true, NULL); - mt7925_mcu_sta_update(dev, NULL, vif, true, + mt7925_mcu_sta_update(dev, NULL, vif, + &mvif->sta.deflink, true, MT76_STA_INFO_STATE_NONE); mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 2d358a96640c..73d3722739d0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -245,6 +245,7 @@ int mt7925_init_mlo_caps(struct mt792x_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; static const u8 ext_capa_sta[] = { + [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING, [2] = WLAN_EXT_CAPA3_MULTI_BSSID_SUPPORT, [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF, }; @@ -438,6 +439,9 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) if (phy->chip_cap & MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN) vif->driver_flags |= IEEE80211_VIF_SUPPORTS_CQM_RSSI; + INIT_WORK(&mvif->csa_work, mt7925_csa_work); + timer_setup(&mvif->csa_timer, mt792x_csa_timer, 0); + out: mt792x_mutex_release(dev); @@ -457,12 +461,16 @@ void mt7925_roc_abort_sync(struct mt792x_dev *dev) { struct mt792x_phy *phy = &dev->phy; + if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) + return; + timer_delete_sync(&phy->roc_timer); - cancel_work_sync(&phy->roc_work); - if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state)) - ieee80211_iterate_interfaces(mt76_hw(dev), - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7925_roc_iter, (void *)phy); + + cancel_work(&phy->roc_work); + + ieee80211_iterate_interfaces(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7925_roc_iter, (void *)phy); } EXPORT_SYMBOL_GPL(mt7925_roc_abort_sync); @@ -541,7 +549,7 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy, phy->roc_grant = false; - err = mt7925_mcu_set_mlo_roc(mconf, sel_links, 5, ++phy->roc_token_id); + err = mt7925_mcu_set_mlo_roc(phy, mconf, sel_links, 5, ++phy->roc_token_id); if (err < 0) { clear_bit(MT76_STATE_ROC, &phy->mt76->state); goto out; @@ -586,7 +594,8 @@ static int mt7925_cancel_remain_on_channel(struct ieee80211_hw *hw, static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_vif *vif, struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, int link_id) + struct ieee80211_key_conf *key, int link_id, + struct mt792x_link_sta *mlink) { struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; @@ -595,7 +604,6 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_bss_conf *link_conf; struct ieee80211_link_sta *link_sta; int idx = key->keyidx, err = 0; - struct mt792x_link_sta *mlink; struct mt792x_bss_conf *mconf; struct mt76_wcid *wcid; u8 *wcid_keyidx; @@ -603,7 +611,6 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, link_conf = mt792x_vif_to_bss_conf(vif, link_id); link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL; mconf = mt792x_vif_to_link(mvif, link_id); - mlink = mt792x_sta_to_link(msta, link_id); wcid = &mlink->wcid; wcid_keyidx = &wcid->hw_key_idx; @@ -671,6 +678,7 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; + struct mt792x_link_sta *mlink; int err; /* The hardware does not support per-STA RX GTK, fallback @@ -692,12 +700,16 @@ static int mt7925_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, add = key->link_id != -1 ? BIT(key->link_id) : msta->valid_links; for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) { - err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id); + mlink = mt792x_sta_to_link(msta, link_id); + err = mt7925_set_link_key(hw, cmd, vif, sta, key, link_id, + mlink); if (err < 0) break; } } else { - err = mt7925_set_link_key(hw, cmd, vif, sta, key, vif->bss_conf.link_id); + mlink = mt792x_sta_to_link(msta, vif->bss_conf.link_id); + err = mt7925_set_link_key(hw, cmd, vif, sta, key, + vif->bss_conf.link_id, mlink); } mt792x_mutex_release(dev); @@ -842,20 +854,24 @@ mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif, static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, - struct ieee80211_link_sta *link_sta) + struct ieee80211_link_sta *link_sta, + struct mt792x_link_sta *mlink) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct ieee80211_bss_conf *link_conf; struct mt792x_bss_conf *mconf; u8 link_id = link_sta->link_id; - struct mt792x_link_sta *mlink; + bool wcid_published = false; struct mt792x_sta *msta; struct mt76_wcid *wcid; + bool pm_woken = false; int ret, idx; msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_id); + + if (WARN_ON_ONCE(!mlink)) + return -EINVAL; idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1); if (idx < 0) @@ -874,14 +890,15 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, wcid = &mlink->wcid; ewma_signal_init(&wcid->rssi); rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid); - mt76_wcid_init(wcid, 0); + wcid_published = true; ewma_avg_signal_init(&mlink->avg_ack_signal); memset(mlink->airtime_ac, 0, sizeof(msta->deflink.airtime_ac)); ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm); if (ret) - return ret; + goto out_wcid; + pm_woken = true; mt7925_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -890,41 +907,125 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev, /* should update bss info before STA add */ if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) { - if (ieee80211_vif_is_mld(vif)) - mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, - link_conf, link_sta, link_sta != mlink->pri_link); - else - mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, - link_conf, link_sta, false); + struct mt792x_link_sta *mlink_bc; + + mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); + + if (ieee80211_vif_is_mld(vif)) { + ret = mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx, + link_conf, link_sta, + mlink_bc->wcid.idx, mlink->wcid.idx, + link_sta != mlink->pri_link); + if (ret) + goto out_pm; + } else { + ret = mt7925_mcu_add_bss_info_sta(&dev->phy, mconf->mt76.ctx, + link_conf, link_sta, + mlink_bc->wcid.idx, mlink->wcid.idx, + false); + if (ret) + goto out_pm; + } } if (ieee80211_vif_is_mld(vif) && link_sta == mlink->pri_link) { - ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + ret = mt7925_mcu_sta_update(dev, link_sta, vif, + mlink, true, MT76_STA_INFO_STATE_NONE); if (ret) - return ret; + goto out_pm; } else if (ieee80211_vif_is_mld(vif) && link_sta != mlink->pri_link) { - ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, - true, MT76_STA_INFO_STATE_ASSOC); - if (ret) - return ret; + struct mt792x_link_sta *pri_mlink; + struct mt76_wcid *pri_wcid; - ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + /* alternative lookup via def_wcid */ + pri_wcid = mlink->wcid.def_wcid; + + pri_mlink = pri_wcid ? + container_of(pri_wcid, struct mt792x_link_sta, wcid) : + NULL; + + if (WARN_ON_ONCE(!pri_mlink)) { + ret = -EINVAL; + goto out_pm; + } + + ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif, + pri_mlink, true, MT76_STA_INFO_STATE_ASSOC); if (ret) - return ret; + goto out_pm; + + ret = mt7925_mcu_sta_update(dev, link_sta, vif, + mlink, true, + MT76_STA_INFO_STATE_ASSOC); + if (ret) + goto out_pm; } else { - ret = mt7925_mcu_sta_update(dev, link_sta, vif, true, + ret = mt7925_mcu_sta_update(dev, link_sta, vif, + mlink, true, MT76_STA_INFO_STATE_NONE); if (ret) - return ret; + goto out_pm; } mt76_connac_power_save_sched(&dev->mphy, &dev->pm); return 0; + +out_pm: + if (pm_woken) + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); +out_wcid: + if (wcid_published) { + u16 idx = wcid->idx; + + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + mt76_wcid_cleanup(mdev, wcid); + mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx); + } + return ret; +} + +/* + * Host-only unwind for sta_add_links() failures. + * + * If add_links fail due to MCU/firmware timeouts; calling the full remove + * path would send more firmware commands and may hang again. So only rollback + * host-published state here (msta->link/valid_links, dev->mt76.wcid[idx]) and + * free mlink objects (RCU-safe). Firmware state is left for reset/recovery. + */ +static void +mt7925_mac_sta_unwind_links_host(struct mt792x_dev *dev, + struct ieee80211_sta *sta, + unsigned long links) +{ + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + unsigned int link_id; + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt792x_link_sta *mlink; + u16 idx; + + mlink = rcu_replace_pointer(msta->link[link_id], NULL, + lockdep_is_held(&dev->mt76.mutex)); + if (!mlink) + continue; + + msta->valid_links &= ~BIT(link_id); + if (msta->deflink_id == link_id) + msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; + + idx = mlink->wcid.idx; + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + mt76_wcid_cleanup(&dev->mt76, &mlink->wcid); + mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx); + + if (mlink != &msta->deflink) + kfree_rcu(mlink, rcu_head); + } } static int @@ -932,34 +1033,50 @@ mt7925_mac_sta_add_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, unsigned long new_links) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + unsigned long added_links = 0; unsigned int link_id; int err = 0; for_each_set_bit(link_id, &new_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct ieee80211_link_sta *link_sta; struct mt792x_link_sta *mlink; + bool is_deflink = false; if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { mlink = &msta->deflink; - msta->deflink_id = link_id; + is_deflink = true; } else { - mlink = devm_kzalloc(dev->mt76.dev, sizeof(*mlink), GFP_KERNEL); + mlink = kzalloc(sizeof(*mlink), GFP_KERNEL); if (!mlink) { err = -ENOMEM; break; } } - msta->valid_links |= BIT(link_id); - rcu_assign_pointer(msta->link[link_id], mlink); mlink->sta = msta; mlink->pri_link = &sta->deflink; mlink->wcid.def_wcid = &msta->deflink.wcid; link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); - mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta); + err = mt7925_mac_link_sta_add(&dev->mt76, vif, link_sta, mlink); + if (err) { + if (!is_deflink) + kfree_rcu(mlink, rcu_head); + break; + } + + if (is_deflink) + msta->deflink_id = link_id; + + rcu_assign_pointer(msta->link[link_id], mlink); + msta->valid_links |= BIT(link_id); + + added_links |= BIT(link_id); } + if (err && added_links) + mt7925_mac_sta_unwind_links_host(dev, sta, added_links); + return err; } @@ -981,7 +1098,8 @@ int mt7925_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, err = mt7925_mac_sta_add_links(dev, vif, sta, sta->valid_links); } else { - err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink); + err = mt7925_mac_link_sta_add(mdev, vif, &sta->deflink, + &msta->deflink); } return err; @@ -1030,11 +1148,11 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, struct mt792x_link_sta *mlink; struct mt792x_sta *msta; + mt792x_mutex_acquire(dev); + msta = (struct mt792x_sta *)link_sta->sta->drv_priv; mlink = mt792x_sta_to_link(msta, link_sta->link_id); - mt792x_mutex_acquire(dev); - if (ieee80211_vif_is_mld(vif)) { link_conf = mt792x_vif_to_bss_conf(vif, msta->deflink_id); } else { @@ -1055,7 +1173,8 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac)); - mt7925_mcu_sta_update(dev, link_sta, vif, true, MT76_STA_INFO_STATE_ASSOC); + mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true, + MT76_STA_INFO_STATE_ASSOC); mt792x_mutex_release(dev); } @@ -1083,23 +1202,21 @@ EXPORT_SYMBOL_GPL(mt7925_mac_sta_event); static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif, - struct ieee80211_link_sta *link_sta) + struct ieee80211_link_sta *link_sta, + struct mt792x_link_sta *mlink) { struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + struct mt76_wcid *wcid = &mlink->wcid; struct ieee80211_bss_conf *link_conf; u8 link_id = link_sta->link_id; - struct mt792x_link_sta *mlink; - struct mt792x_sta *msta; - - msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_id); + u16 idx = wcid->idx; mt7925_roc_abort_sync(dev); - mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid); + mt76_connac_free_pending_tx_skbs(&dev->pm, wcid); mt76_connac_pm_wake(&dev->mphy, &dev->pm); - mt7925_mcu_sta_update(dev, link_sta, vif, false, + mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false, MT76_STA_INFO_STATE_NONE); mt7925_mac_wtbl_update(dev, mlink->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); @@ -1123,6 +1240,10 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev, list_del_init(&mlink->wcid.poll_list); spin_unlock_bh(&mdev->sta_poll_lock); + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + mt76_wcid_cleanup(mdev, wcid); + mt76_wcid_mask_clear(mdev->wcid_mask, idx); + mt76_connac_power_save_sched(&dev->mphy, &dev->pm); } @@ -1132,7 +1253,6 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; struct mt76_dev *mdev = &dev->mt76; - struct mt76_wcid *wcid; unsigned int link_id; /* clean up bss before starec */ @@ -1171,22 +1291,19 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif, if (!link_sta) continue; - mlink = mt792x_sta_to_link(msta, link_id); + mlink = rcu_replace_pointer(msta->link[link_id], NULL, + lockdep_is_held(&mdev->mutex)); if (!mlink) continue; - mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta); - - wcid = &mlink->wcid; - rcu_assign_pointer(msta->link[link_id], NULL); msta->valid_links &= ~BIT(link_id); mlink->sta = NULL; mlink->pri_link = NULL; - if (link_sta != mlink->pri_link) { - mt76_wcid_cleanup(mdev, wcid); - mt76_wcid_mask_clear(mdev->wcid_mask, wcid->idx); - } + mt7925_mac_link_sta_remove(&dev->mt76, vif, link_sta, mlink); + + if (mlink != &msta->deflink) + kfree_rcu(mlink, rcu_head); if (msta->deflink_id == link_id) msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; @@ -1323,10 +1440,18 @@ void mt7925_mlo_pm_work(struct work_struct *work) void mt7925_scan_work(struct work_struct *work) { struct mt792x_phy *phy; + struct mt792x_dev *dev; + struct mt76_connac_pm *pm; phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy, scan_work.work); + dev = phy->dev; + pm = &dev->pm; + + if (pm->suspended) + return; + while (true) { struct sk_buff *skb; struct tlv *tlv; @@ -1544,8 +1669,10 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, valid = ieee80211_vif_is_mld(vif) ? mvif->valid_links : BIT(0); for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt792x_bss_conf *mconf; struct mt792x_link_sta *mlink; + mconf = mt792x_vif_to_link(mvif, i); mlink = mt792x_sta_to_link(msta, i); if (enabled) @@ -1556,7 +1683,7 @@ static void mt7925_sta_set_decap_offload(struct ieee80211_hw *hw, if (!mlink->wcid.sta) continue; - mt7925_mcu_wtbl_update_hdr_trans(dev, vif, sta, i); + mt7925_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink); } mt792x_mutex_release(dev); @@ -1716,7 +1843,8 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (err) goto out; - err = mt7925_mcu_sta_update(dev, NULL, vif, true, + err = mt7925_mcu_sta_update(dev, NULL, vif, + &mvif->sta.deflink, true, MT76_STA_INFO_STATE_NONE); out: mt792x_mutex_release(dev); @@ -1749,6 +1877,10 @@ static int mt7925_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + dev->new_ctx = ctx; + return 0; } @@ -1756,6 +1888,11 @@ static void mt7925_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + if (dev->new_ctx == ctx) + dev->new_ctx = NULL; + } static void @@ -1850,7 +1987,8 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, mt792x_mutex_acquire(dev); if (changed & BSS_CHANGED_ASSOC) { - mt7925_mcu_sta_update(dev, NULL, vif, true, + mt7925_mcu_sta_update(dev, NULL, vif, + &mvif->sta.deflink, true, MT76_STA_INFO_STATE_ASSOC); mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc); @@ -1894,10 +2032,8 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt792x_bss_conf *mconf; - struct ieee80211_bss_conf *link_conf; mconf = mt792x_vif_to_link(mvif, info->link_id); - link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id); mt792x_mutex_acquire(dev); @@ -1939,10 +2075,6 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw, mvif->mlo_pm_state = MT792x_MLO_CHANGED_PS; } - if (changed & IEEE80211_CHANCTX_CHANGE_PUNCTURING) - mt7925_mcu_set_eht_pp(mvif->phy->mt76, &mconf->mt76, - link_conf, NULL); - if (changed & BSS_CHANGED_CQM) mt7925_mcu_set_rssimonitor(dev, vif); @@ -2144,6 +2276,11 @@ static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw, mctx->bss_conf = NULL; mconf->mt76.ctx = NULL; mutex_unlock(&dev->mt76.mutex); + + if (link_conf->csa_active) { + timer_delete_sync(&mvif->csa_timer); + cancel_work_sync(&mvif->csa_work); + } } static void mt7925_rfkill_poll(struct ieee80211_hw *hw) @@ -2158,6 +2295,121 @@ static void mt7925_rfkill_poll(struct ieee80211_hw *hw) wiphy_rfkill_set_hw_state(hw->wiphy, ret == 0); } +static int mt7925_switch_vif_chanctx(struct ieee80211_hw *hw, + struct ieee80211_vif_chanctx_switch *vifs, + int n_vifs, + enum ieee80211_chanctx_switch_mode mode) +{ + return mt7925_assign_vif_chanctx(hw, vifs->vif, vifs->link_conf, + vifs->new_ctx); +} + +void mt7925_csa_work(struct work_struct *work) +{ + struct mt792x_vif *mvif; + struct mt792x_dev *dev; + struct ieee80211_vif *vif; + struct ieee80211_bss_conf *link_conf; + struct mt792x_bss_conf *mconf; + u8 link_id, roc_rtype; + int ret = 0; + + mvif = (struct mt792x_vif *)container_of(work, struct mt792x_vif, + csa_work); + dev = mvif->phy->dev; + vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv); + + if (ieee80211_vif_is_mld(vif)) + return; + + if (!dev->new_ctx) + return; + + link_id = 0; + mconf = &mvif->bss_conf; + link_conf = &vif->bss_conf; + roc_rtype = MT7925_ROC_REQ_JOIN; + + mt792x_mutex_acquire(dev); + ret = mt7925_set_roc(mvif->phy, mconf, dev->new_ctx->def.chan, + 4000, roc_rtype); + mt792x_mutex_release(dev); + if (!ret) { + mt792x_mutex_acquire(dev); + ret = mt7925_mcu_set_chctx(mvif->phy->mt76, &mconf->mt76, link_conf, + dev->new_ctx); + mt792x_mutex_release(dev); + + mt7925_abort_roc(mvif->phy, mconf); + } + + ieee80211_chswitch_done(vif, !ret, link_id); +} + +static int mt7925_pre_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) +{ + if (ieee80211_vif_is_mld(vif)) + return -EOPNOTSUPP; + + if (vif->type != NL80211_IFTYPE_STATION || !vif->cfg.assoc) + return -EOPNOTSUPP; + + if (!cfg80211_chandef_usable(hw->wiphy, &chsw->chandef, + IEEE80211_CHAN_DISABLED)) + return -EOPNOTSUPP; + + return 0; +} + +static void mt7925_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + u16 beacon_interval; + + if (ieee80211_vif_is_mld(vif)) + return; + + beacon_interval = vif->bss_conf.beacon_int; + + mvif->csa_timer.expires = TU_TO_EXP_TIME(beacon_interval * chsw->count); + add_timer(&mvif->csa_timer); +} + +static void mt7925_abort_channel_switch(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + + timer_delete_sync(&mvif->csa_timer); + cancel_work_sync(&mvif->csa_work); +} + +static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_channel_switch *chsw) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + u16 beacon_interval; + + if (ieee80211_vif_is_mld(vif)) + return; + + beacon_interval = vif->bss_conf.beacon_int; + + if (cfg80211_chandef_identical(&chsw->chandef, + &dev->new_ctx->def) && + chsw->count) { + mod_timer(&mvif->csa_timer, + TU_TO_EXP_TIME(beacon_interval * chsw->count)); + } +} + const struct ieee80211_ops mt7925_ops = { .tx = mt792x_tx, .start = mt7925_start, @@ -2221,6 +2473,12 @@ const struct ieee80211_ops mt7925_ops = { .change_vif_links = mt7925_change_vif_links, .change_sta_links = mt7925_change_sta_links, .rfkill_poll = mt7925_rfkill_poll, + + .switch_vif_chanctx = mt7925_switch_vif_chanctx, + .pre_channel_switch = mt7925_pre_channel_switch, + .channel_switch = mt7925_channel_switch, + .abort_channel_switch = mt7925_abort_channel_switch, + .channel_switch_rx_beacon = mt7925_channel_switch_rx_beacon, }; EXPORT_SYMBOL_GPL(mt7925_ops); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c index cf0fdea45cf7..37cdf3e8a067 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -1066,9 +1066,8 @@ EXPORT_SYMBOL_GPL(mt7925_run_firmware); static void mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_link_sta *link_sta) + struct mt792x_link_sta *mlink) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct sta_rec_hdr_trans *hdr_trans; struct mt76_wcid *wcid; struct tlv *tlv; @@ -1082,19 +1081,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, else hdr_trans->from_ds = true; - if (link_sta) { - struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - struct mt792x_link_sta *mlink; - - mlink = mt792x_sta_to_link(msta, link_sta->link_id); - wcid = &mlink->wcid; - } else { - wcid = &mvif->sta.deflink.wcid; - } - - if (!wcid) + if (WARN_ON_ONCE(!mlink)) return; + wcid = &mlink->wcid; + hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags); if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) { hdr_trans->to_ds = true; @@ -1104,30 +1095,18 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb, int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - int link_id) + struct mt792x_bss_conf *mconf, + struct mt792x_link_sta *mlink) { - struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; - struct ieee80211_link_sta *link_sta = sta ? &sta->deflink : NULL; - struct mt792x_link_sta *mlink; - struct mt792x_bss_conf *mconf; - struct mt792x_sta *msta; struct sk_buff *skb; - msta = sta ? (struct mt792x_sta *)sta->drv_priv : &mvif->sta; - - mlink = mt792x_sta_to_link(msta, link_id); - link_sta = mt792x_sta_to_link_sta(vif, sta, link_id); - mconf = mt792x_vif_to_link(mvif, link_id); - skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, &mlink->wcid, MT7925_STA_UPDATE_MAX_SIZE); if (IS_ERR(skb)) return PTR_ERR(skb); - /* starec hdr trans */ - mt7925_mcu_sta_hdr_trans_tlv(skb, vif, link_sta); + mt7925_mcu_sta_hdr_trans_tlv(skb, vif, mlink); return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } @@ -1288,14 +1267,16 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, return PTR_ERR(skb); ret = mt7925_mcu_sta_key_tlv(wcid, sta_key_conf, skb, key, cmd, msta); - if (ret) + if (ret) { + dev_kfree_skb(skb); return ret; + } return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true); } -int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, - int duration, u8 token_id) +int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + u16 sel_links, int duration, u8 token_id) { struct mt792x_vif *mvif = mconf->vif; struct ieee80211_vif *vif = container_of((void *)mvif, @@ -1330,6 +1311,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, .roc[1].len = cpu_to_le16(sizeof(struct roc_acquire_tlv)) }; + struct wiphy *wiphy = phy->mt76->hw->wiphy; + if (!mconf || hweight16(vif->valid_links) < 2 || hweight16(sel_links) != 2) return -EPERM; @@ -1352,7 +1335,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, is_AG_band |= links[i].chan->band == NL80211_BAND_2GHZ; } - if (vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP) + if (!(wiphy->iftype_ext_capab[0].mld_capa_and_ops & + IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS)) type = is_AG_band ? MT7925_ROC_REQ_MLSR_AG : MT7925_ROC_REQ_MLSR_AA; else @@ -1721,10 +1705,9 @@ mt7925_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta) static void mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, - struct ieee80211_link_sta *link_sta) + struct ieee80211_link_sta *link_sta, + struct mt792x_link_sta *mlink) { - struct mt792x_sta *msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - struct mt792x_link_sta *mlink; struct sta_rec_amsdu *amsdu; struct tlv *tlv; @@ -1740,7 +1723,6 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb, amsdu->max_amsdu_num = 8; amsdu->amsdu_en = true; - mlink = mt792x_sta_to_link(msta, link_sta->link_id); mlink->wcid.amsdu = true; switch (link_sta->agg.max_amsdu_len) { @@ -1911,36 +1893,53 @@ mt7925_mcu_sta_eht_mld_tlv(struct sk_buff *skb, static void mt7925_mcu_sta_mld_tlv(struct sk_buff *skb, - struct ieee80211_vif *vif, struct ieee80211_sta *sta) + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct mt792x_bss_conf *mconf, + struct mt792x_link_sta *mlink) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; - unsigned long valid = mvif->valid_links; - struct mt792x_bss_conf *mconf; - struct mt792x_link_sta *mlink; + struct mt792x_dev *dev = mvif->phy->dev; + struct mt792x_bss_conf *mconf_pri; struct sta_rec_mld *mld; struct tlv *tlv; - int i, cnt = 0; + u8 cnt = 0; + + /* Primary link always uses driver's deflink WCID. */ + mconf_pri = (msta->deflink_id != IEEE80211_LINK_UNSPECIFIED) ? + mt792x_vif_to_link(mvif, msta->deflink_id) : NULL; + + /* If caller is operating on deflink, reuse its mconf as primary. */ + if (!mconf_pri && mlink == &msta->deflink) + mconf_pri = mconf; + + if (!mconf_pri) { + dev_warn_ratelimited(dev->mt76.dev, + "mt7925: MLD_TLV_LINK skip (no primary mconf) sta=%pM\n", + sta->addr); + return; + } tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD, sizeof(*mld)); mld = (struct sta_rec_mld *)tlv; memcpy(mld->mac_addr, sta->addr, ETH_ALEN); + mld->primary_id = cpu_to_le16(msta->deflink.wcid.idx); mld->wlan_id = cpu_to_le16(msta->deflink.wcid.idx); - mld->link_num = min_t(u8, hweight16(mvif->valid_links), 2); - for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { - if (cnt == mld->link_num) - break; + /* Always encode primary link first. */ + mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx); + mld->link[cnt++].bss_idx = mconf_pri->mt76.idx; - mconf = mt792x_vif_to_link(mvif, i); - mlink = mt792x_sta_to_link(msta, i); + /* 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; - - if (mlink != &msta->deflink) - mld->secondary_id = cpu_to_le16(mlink->wcid.idx); } + + mld->link_num = cnt; } static void @@ -1961,10 +1960,12 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv; struct mt76_dev *dev = phy->dev; struct mt792x_bss_conf *mconf; + struct mt792x_link_sta *mlink; struct sk_buff *skb; int conn_state; mconf = mt792x_vif_to_link(mvif, info->wcid->link_id); + mlink = container_of(info->wcid, struct mt792x_link_sta, wcid); skb = __mt76_connac_mcu_alloc_sta_req(dev, &mconf->mt76, info->wcid, MT7925_STA_UPDATE_MAX_SIZE); @@ -1982,7 +1983,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt7925_mcu_sta_ht_tlv(skb, info->link_sta); mt7925_mcu_sta_vht_tlv(skb, info->link_sta); mt76_connac_mcu_sta_uapsd(skb, info->vif, info->link_sta->sta); - mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta); + mt7925_mcu_sta_amsdu_tlv(skb, info->vif, info->link_sta, mlink); mt7925_mcu_sta_he_tlv(skb, info->link_sta); mt7925_mcu_sta_he_6g_tlv(skb, info->link_sta); mt7925_mcu_sta_eht_tlv(skb, info->link_sta); @@ -1993,7 +1994,10 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, info->state); if (info->state != MT76_STA_INFO_STATE_NONE) { - mt7925_mcu_sta_mld_tlv(skb, info->vif, info->link_sta->sta); + mt7925_mcu_sta_mld_tlv(skb, info->vif, + info->link_sta->sta, + mconf, mlink); + mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta); } } @@ -2003,7 +2007,10 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_OFF, sizeof(struct tlv)); } else { - mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, info->link_sta); + if (!info->link_sta) + mlink = &mvif->sta.deflink; + + mt7925_mcu_sta_hdr_trans_tlv(skb, info->vif, mlink); } return mt76_mcu_skb_send_msg(dev, skb, info->cmd, true); @@ -2011,7 +2018,9 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy, int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_link_sta *link_sta, - struct ieee80211_vif *vif, bool enable, + struct ieee80211_vif *vif, + struct mt792x_link_sta *mlink, + bool enable, enum mt76_sta_info_state state) { struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; @@ -2026,14 +2035,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev, .offload_fw = true, .rcpi = to_rcpi(rssi), }; - struct mt792x_sta *msta; - struct mt792x_link_sta *mlink; - if (link_sta) { - msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_sta->link_id); - } - info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid; + info.wcid = &mlink->wcid; info.newly = state != MT76_STA_INFO_STATE_ASSOC; return mt7925_mcu_sta_cmd(&dev->mphy, &info); @@ -2470,7 +2473,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, struct ieee80211_link_sta *link_sta, struct ieee80211_chanctx_conf *ctx, - struct mt76_phy *phy, u16 wlan_idx, + struct mt76_phy *phy, + u16 bmc_tx_wlan_idx, + u16 sta_wlan_idx, bool enable) { struct ieee80211_vif *vif = link_conf->vif; @@ -2479,7 +2484,6 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, &link_conf->chanreq.oper; enum nl80211_band band = chandef->chan->band; struct mt76_connac_bss_basic_tlv *basic_req; - struct mt792x_link_sta *mlink; struct tlv *tlv; int conn_type; u8 idx; @@ -2503,20 +2507,9 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, link_sta); basic_req->bcn_interval = cpu_to_le16(link_conf->beacon_int); basic_req->dtim_period = link_conf->dtim_period; - basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx); + basic_req->bmc_tx_wlan_idx = cpu_to_le16(bmc_tx_wlan_idx); basic_req->link_idx = mconf->mt76.idx; - - if (link_sta) { - struct mt792x_sta *msta; - - msta = (struct mt792x_sta *)link_sta->sta->drv_priv; - mlink = mt792x_sta_to_link(msta, link_sta->link_id); - - } else { - mlink = &mconf->vif->sta.deflink; - } - - basic_req->sta_idx = cpu_to_le16(mlink->wcid.idx); + basic_req->sta_idx = cpu_to_le16(sta_wlan_idx); basic_req->omac_idx = mconf->mt76.omac_idx; basic_req->band_idx = mconf->mt76.band_idx; basic_req->wmm_idx = mconf->mt76.wmm_idx; @@ -2823,16 +2816,16 @@ void mt7925_mcu_del_dev(struct mt76_dev *mdev, &dev_req, sizeof(dev_req), true); } -int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, - struct ieee80211_chanctx_conf *ctx, - struct ieee80211_bss_conf *link_conf, - struct ieee80211_link_sta *link_sta, - int enable) +int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy, + struct ieee80211_chanctx_conf *ctx, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_link_sta *link_sta, + u16 bmc_tx_wlan_idx, + u16 sta_wlan_idx, + int enable) { - struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct mt792x_dev *dev = phy->dev; - struct mt792x_link_sta *mlink_bc; struct sk_buff *skb; skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, @@ -2840,11 +2833,9 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, if (IS_ERR(skb)) return PTR_ERR(skb); - mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); - /* bss_basic must be first */ mt7925_mcu_bss_basic_tlv(skb, link_conf, link_sta, ctx, phy->mt76, - mlink_bc->wcid.idx, enable); + bmc_tx_wlan_idx, sta_wlan_idx, enable); mt7925_mcu_bss_sec_tlv(skb, link_conf); mt7925_mcu_bss_bmc_tlv(skb, phy, ctx, link_conf); mt7925_mcu_bss_qos_tlv(skb, link_conf); @@ -2865,6 +2856,33 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, MCU_UNI_CMD(BSS_INFO_UPDATE), true); } +int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, + struct ieee80211_chanctx_conf *ctx, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_link_sta *link_sta, + int enable) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)link_conf->vif->drv_priv; + struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); + struct mt792x_link_sta *mlink_bc; + struct mt792x_link_sta *mlink; + + mlink_bc = mt792x_sta_to_link(&mvif->sta, mconf->link_id); + + if (link_sta) { + struct mt792x_sta *msta = (void *)link_sta->sta->drv_priv; + + mlink = mt792x_sta_to_link(msta, link_sta->link_id); + if (WARN_ON(!mlink)) + return -EINVAL; + } else { + mlink = &mconf->vif->sta.deflink; + } + + return mt7925_mcu_add_bss_info_sta(phy, ctx, link_conf, link_sta, + mlink_bc->wcid.idx, mlink->wcid.idx, enable); +} + int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable) { struct mt76_dev *mdev = phy->dev; @@ -3375,7 +3393,6 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, u8 rsvd[64]; } __packed req = { .tag = cpu_to_le16(0x3), - .len = cpu_to_le16(sizeof(req) - 4), .idx = idx, .env = env_cap, @@ -3404,6 +3421,7 @@ __mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, memcpy(req.type, rule->type, 2); req.size = cpu_to_le16(seg->len); + req.len = cpu_to_le16(sizeof(req) + seg->len - 4); dev->phy.clc_chan_conf = clc->ver == 1 ? 0xff : rule->flag; skb = __mt76_mcu_msg_alloc(&dev->mt76, &req, le16_to_cpu(req.size) + sizeof(req), @@ -3727,7 +3745,7 @@ mt7925_mcu_rate_txpower_band(struct mt76_phy *phy, memcpy(tx_power_tlv->alpha2, dev->alpha2, sizeof(dev->alpha2)); tx_power_tlv->n_chan = num_ch; tx_power_tlv->tag = cpu_to_le16(0x1); - tx_power_tlv->len = cpu_to_le16(sizeof(*tx_power_tlv)); + tx_power_tlv->len = cpu_to_le16(msg_len); switch (band) { case NL80211_BAND_2GHZ: diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h index e09e0600534a..56e2772f3ffe 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -693,6 +693,13 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy, struct ieee80211_bss_conf *link_conf, struct ieee80211_link_sta *link_sta, int enable); +int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy, + struct ieee80211_chanctx_conf *ctx, + struct ieee80211_bss_conf *link_conf, + struct ieee80211_link_sta *link_sta, + u16 bmc_tx_wlan_idx, + u16 sta_wlan_idx, + int enable); int mt7925_mcu_set_timing(struct mt792x_phy *phy, struct ieee80211_bss_conf *link_conf); int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 6b9bf1b89032..46b480f7d813 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -250,7 +250,9 @@ int mt7925_mcu_set_bss_pm(struct mt792x_dev *dev, bool enable); int mt7925_mcu_sta_update(struct mt792x_dev *dev, struct ieee80211_link_sta *link_sta, - struct ieee80211_vif *vif, bool enable, + struct ieee80211_vif *vif, + struct mt792x_link_sta *mlink, + bool enable, enum mt76_sta_info_state state); 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); @@ -298,6 +300,7 @@ int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev, void mt7925_mlo_pm_work(struct work_struct *work); void mt7925_scan_work(struct work_struct *work); void mt7925_roc_work(struct work_struct *work); +void mt7925_csa_work(struct work_struct *work); int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev, struct ieee80211_bss_conf *link_conf); void mt7925_coredump_work(struct work_struct *work); @@ -349,8 +352,8 @@ int mt7925_set_tx_sar_pwr(struct ieee80211_hw *hw, int mt7925_mcu_regval(struct mt792x_dev *dev, u32 regidx, u32 *val, bool set); int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap env_cap); -int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links, - int duration, u8 token_id); +int mt7925_mcu_set_mlo_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, + u16 sel_links, int duration, u8 token_id); int mt7925_mcu_set_roc(struct mt792x_phy *phy, struct mt792x_bss_conf *mconf, struct ieee80211_channel *chan, int duration, enum mt7925_roc_req type, u8 token_id); @@ -367,8 +370,8 @@ int mt7925_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif, int mt7925_mcu_set_rts_thresh(struct mt792x_phy *phy, u32 val); int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - int link_id); + struct mt792x_bss_conf *mconf, + struct mt792x_link_sta *mlink); int mt7925_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy); int mt7925_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c index 292087e882d1..16f56ee879d4 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c @@ -232,7 +232,8 @@ int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2) dev->regd_user) return -EINVAL; - if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0') + if ((mdev->alpha2[0] && mdev->alpha2[0] != '0') && + (mdev->alpha2[1] && mdev->alpha2[1] != '0')) return 0; /* do not need to update the same country twice */ diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 8388638ed550..4ff93f2cd624 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -41,11 +41,13 @@ #define MT792x_MCU_INIT_RETRY_COUNT 10 #define MT792x_WFSYS_INIT_RETRY_COUNT 2 +#define MT7902_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7902_1.bin" #define MT7920_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1a.bin" #define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin" #define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin" #define MT7925_FIRMWARE_WM "mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin" +#define MT7902_ROM_PATCH "mediatek/WIFI_MT7902_patch_mcu_1_1_hdr.bin" #define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin" #define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin" #define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin" @@ -95,6 +97,7 @@ DECLARE_EWMA(avg_signal, 10, 8) struct mt792x_link_sta { struct mt76_wcid wcid; /* must be first */ + struct rcu_head rcu_head; u32 airtime_ac[8]; @@ -448,6 +451,8 @@ void mt792x_config_mac_addr_list(struct mt792x_dev *dev); static inline char *mt792x_ram_name(struct mt792x_dev *dev) { switch (mt76_chip(&dev->mt76)) { + case 0x7902: + return MT7902_FIRMWARE_WM; case 0x7920: return MT7920_FIRMWARE_WM; case 0x7922: @@ -462,6 +467,8 @@ static inline char *mt792x_ram_name(struct mt792x_dev *dev) static inline char *mt792x_patch_name(struct mt792x_dev *dev) { switch (mt76_chip(&dev->mt76)) { + case 0x7902: + return MT7902_ROM_PATCH; case 0x7920: return MT7920_ROM_PATCH; case 0x7922: diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index f2ed16feb6c1..152cfcca2f90 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -151,7 +151,7 @@ void mt792x_stop(struct ieee80211_hw *hw, bool suspend) cancel_work_sync(&dev->reset_work); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); - if (is_mt7921(&dev->mt76)) { + if (is_connac2(&dev->mt76)) { mt792x_mutex_acquire(dev); mt76_connac_mcu_set_mac_enable(&dev->mt76, 0, false, false); mt792x_mutex_release(dev); @@ -691,9 +691,8 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); ieee80211_hw_set(hw, SUPPORTS_ONLY_HE_MULTI_BSSID); - if (is_mt7921(&dev->mt76)) { - ieee80211_hw_set(hw, CHANCTX_STA_CSA); - } + ieee80211_hw_set(hw, CHANCTX_STA_CSA); + if (dev->pm.enable) ieee80211_hw_set(hw, CONNECTION_MONITOR); @@ -927,6 +926,13 @@ int mt792x_load_firmware(struct mt792x_dev *dev) { int ret; + mt76_connac_mcu_restart(&dev->mt76); + + if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC_FW_STATE, + MT_TOP_MISC2_FW_PWR_ON, 1000)) + dev_warn(dev->mt76.dev, + "MCU is not ready for firmware download\n"); + ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev)); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c index 1ddec7788b66..002aece857b2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c @@ -103,6 +103,22 @@ static void mt792x_dma_prefetch(struct mt792x_dev *dev) mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0400, 0x10)); mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0500, 0x4)); mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0540, 0x4)); + } else if (is_mt7902(&dev->mt76)) { + /* rx ring */ + mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0000, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x0040, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x0080, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x00c0, 0x4)); + /* tx ring */ + mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x0100, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x0140, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x0180, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x01c0, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING4_EXT_CTRL, PREFETCH(0x0200, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING5_EXT_CTRL, PREFETCH(0x0240, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING6_EXT_CTRL, PREFETCH(0x0280, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x02c0, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0300, 0x4)); } else { /* rx ring */ mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4)); @@ -356,7 +372,7 @@ EXPORT_SYMBOL_GPL(mt792x_poll_rx); int mt792x_wfsys_reset(struct mt792x_dev *dev) { - u32 addr = is_mt7921(&dev->mt76) ? 0x18000140 : 0x7c000140; + u32 addr = is_connac2(&dev->mt76) ? 0x18000140 : 0x7c000140; mt76_clear(dev, addr, WFSYS_SW_RST_B); msleep(50); diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c index 71dec93094eb..888e5a505673 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_mac.c @@ -375,7 +375,7 @@ void mt792x_pm_power_save_work(struct work_struct *work) } if (!mt792x_mcu_fw_pmctrl(dev)) { - cancel_delayed_work_sync(&mphy->mac_work); + cancel_delayed_work(&mphy->mac_work); return; } out: diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h index acf627aed609..d2a8b2b0df32 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h @@ -25,6 +25,8 @@ #define MT_PLE_AC_QEMPTY(_n) MT_PLE(0x500 + 0x40 * (_n)) #define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2)) +#define MT_PSE_BASE 0x820c8000 + /* TMAC: band 0(0x21000), band 1(0xa1000) */ #define MT_WF_TMAC_BASE(_band) ((_band) ? 0x820f4000 : 0x820e4000) #define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs)) @@ -390,6 +392,10 @@ #define MT_CBTOP_RGU_WF_SUBSYS_RST MT_CBTOP_RGU(0x600) #define MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH BIT(0) +#define MT7925_CBTOP_RGU_WF_SUBSYS_RST 0x70028600 +#define MT7925_WFSYS_INIT_DONE_ADDR 0x184c1604 +#define MT7925_WFSYS_INIT_DONE 0x00001d1e + #define MT_HW_BOUND 0x70010020 #define MT_HW_CHIPID 0x70010200 #define MT_HW_REV 0x70010204 diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c index 552808458138..47827d1c5ccb 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c @@ -206,6 +206,33 @@ static void mt792xu_epctl_rst_opt(struct mt792x_dev *dev, bool reset) mt792xu_uhw_wr(&dev->mt76, MT_SSUSB_EPCTL_CSR_EP_RST_OPT, val); } +struct mt792xu_wfsys_desc { + u32 rst_reg; + u32 done_reg; + u32 done_mask; + u32 done_val; + u32 delay_ms; + bool need_status_sel; +}; + +static const struct mt792xu_wfsys_desc mt7921_wfsys_desc = { + .rst_reg = MT_CBTOP_RGU_WF_SUBSYS_RST, + .done_reg = MT_UDMA_CONN_INFRA_STATUS, + .done_mask = MT_UDMA_CONN_WFSYS_INIT_DONE, + .done_val = MT_UDMA_CONN_WFSYS_INIT_DONE, + .delay_ms = 0, + .need_status_sel = true, +}; + +static const struct mt792xu_wfsys_desc mt7925_wfsys_desc = { + .rst_reg = MT7925_CBTOP_RGU_WF_SUBSYS_RST, + .done_reg = MT7925_WFSYS_INIT_DONE_ADDR, + .done_mask = U32_MAX, + .done_val = MT7925_WFSYS_INIT_DONE, + .delay_ms = 20, + .need_status_sel = false, +}; + int mt792xu_dma_init(struct mt792x_dev *dev, bool resume) { int err; @@ -236,25 +263,33 @@ EXPORT_SYMBOL_GPL(mt792xu_dma_init); int mt792xu_wfsys_reset(struct mt792x_dev *dev) { + const struct mt792xu_wfsys_desc *desc = is_mt7925(&dev->mt76) ? + &mt7925_wfsys_desc : + &mt7921_wfsys_desc; u32 val; int i; mt792xu_epctl_rst_opt(dev, false); - val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST); + val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg); val |= MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH; - mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val); + mt792xu_uhw_wr(&dev->mt76, desc->rst_reg, val); - usleep_range(10, 20); + if (desc->delay_ms) + msleep(desc->delay_ms); + else + usleep_range(10, 20); - val = mt792xu_uhw_rr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST); + val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg); val &= ~MT_CBTOP_RGU_WF_SUBSYS_RST_WF_WHOLE_PATH; - mt792xu_uhw_wr(&dev->mt76, MT_CBTOP_RGU_WF_SUBSYS_RST, val); + mt792xu_uhw_wr(&dev->mt76, desc->rst_reg, val); + + if (desc->need_status_sel) + mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0); - mt792xu_uhw_wr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS_SEL, 0); for (i = 0; i < MT792x_WFSYS_INIT_RETRY_COUNT; i++) { - val = mt792xu_uhw_rr(&dev->mt76, MT_UDMA_CONN_INFRA_STATUS); - if (val & MT_UDMA_CONN_WFSYS_INIT_DONE) + val = mt792xu_uhw_rr(&dev->mt76, desc->done_reg); + if ((val & desc->done_mask) == desc->done_val) break; msleep(100); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c index 76d623b2cafb..34af800964d1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c @@ -226,14 +226,23 @@ mt7996_radar_trigger(void *data, u64 val) #define RADAR_BACKGROUND 2 struct mt7996_dev *dev = data; struct mt7996_phy *phy = mt7996_band_phy(dev, NL80211_BAND_5GHZ); - int rdd_idx; + struct cfg80211_chan_def *chandef; + int rdd_idx, ret; if (!phy || !val || val > RADAR_BACKGROUND) return -EINVAL; - if (val == RADAR_BACKGROUND && !dev->rdd2_phy) { - dev_err(dev->mt76.dev, "Background radar is not enabled\n"); - return -EINVAL; + if (test_bit(MT76_SCANNING, &phy->mt76->state)) + return -EBUSY; + + if (val == RADAR_BACKGROUND) { + if (!dev->rdd2_phy || !cfg80211_chandef_valid(&dev->rdd2_chandef)) { + dev_err(dev->mt76.dev, "Background radar is not enabled\n"); + return -EINVAL; + } + chandef = &dev->rdd2_chandef; + } else { + chandef = &phy->mt76->chandef; } rdd_idx = mt7996_get_rdd_idx(phy, val == RADAR_BACKGROUND); @@ -242,6 +251,11 @@ mt7996_radar_trigger(void *data, u64 val) return -EINVAL; } + ret = cfg80211_chandef_dfs_required(dev->mt76.hw->wiphy, chandef, + NL80211_IFTYPE_AP); + if (ret <= 0) + return ret; + return mt7996_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, rdd_idx, 0); } @@ -626,13 +640,18 @@ 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_dev *dev = mvif->deflink.phy->dev; + 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(); @@ -979,13 +998,17 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file, #define LONG_PREAMBLE 1 struct ieee80211_link_sta *link_sta = file->private_data; struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv; - struct mt7996_dev *dev = msta->vif->deflink.phy->dev; + struct mt7996_phy *link_phy = mt7996_vif_link_phy(&msta->vif->deflink); struct mt7996_sta_link *msta_link; struct ra_rate phy = {}; + struct mt7996_dev *dev; char buf[100]; int ret; u16 gi, ltf; + if (!link_phy) + return -EINVAL; + if (count >= sizeof(buf)) return -EINVAL; @@ -1008,6 +1031,7 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file, * spe - off: 0, on: 1 * ltf - 1xltf: 0, 2xltf: 1, 4xltf: 2 */ + dev = link_phy->dev; if (sscanf(buf, "%hhu %hhu %hhu %hhu %hu %hhu %hhu %hhu %hhu %hu", &phy.mode, &phy.bw, &phy.mcs, &phy.nss, &gi, &phy.preamble, &phy.stbc, &phy.ldpc, &phy.spe, <f) != 10) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c index 274b273df1ee..8f5d297dafce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c @@ -128,15 +128,27 @@ static void mt7996_dma_config(struct mt7996_dev *dev) /* data tx queue */ if (is_mt7996(&dev->mt76)) { - TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); if (dev->hif2) { - /* default bn1:ring19 bn2:ring21 */ - TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, - MT7996_TXQ_BAND1); - TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, - MT7996_TXQ_BAND2); + if (mt76_npu_device_active(&dev->mt76)) { + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND2, + MT7996_TXQ_BAND2); + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND0, + MT7996_TXQ_BAND0); + TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1, + MT7996_TXQ_BAND1); + } else { + /* default bn1:ring19 bn2:ring21 */ + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, + MT7996_TXQ_BAND0); + TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, + MT7996_TXQ_BAND1); + TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, + MT7996_TXQ_BAND2); + } } else { /* single pcie bn0/1:ring18 bn2:ring19 */ + TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, + MT7996_TXQ_BAND0); TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); } @@ -350,6 +362,9 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) if (!mt7996_has_wa(dev) || mt76_npu_device_active(&dev->mt76)) irq_mask &= ~(MT_INT_RX(MT_RXQ_MAIN_WA) | MT_INT_RX(MT_RXQ_BAND1_WA)); + if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76)) + irq_mask &= ~(MT_INT_RX(MT_RXQ_TXFREE_BAND0) | + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2)); irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; mt7996_irq_enable(dev, irq_mask); @@ -430,39 +445,48 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 | MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); - if (is_mt7996(&dev->mt76)) - mt76_set(dev, MT_WFDMA_HOST_CONFIG, - MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); - else + if (is_mt7996(&dev->mt76)) { + if (mt76_npu_device_active(&dev->mt76)) + mt76_set(dev, MT_WFDMA_HOST_CONFIG, + MT_WFDMA_HOST_CONFIG_BAND0_PCIE1); + else + mt76_set(dev, MT_WFDMA_HOST_CONFIG, + MT_WFDMA_HOST_CONFIG_BAND2_PCIE1); + } else { mt76_set(dev, MT_WFDMA_HOST_CONFIG, MT_WFDMA_HOST_CONFIG_BAND1_PCIE1); + } /* AXI read outstanding number */ mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL, MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14); - if (dev->hif2->speed < PCIE_SPEED_5_0GT || - (dev->hif2->speed == PCIE_SPEED_5_0GT && - dev->hif2->width < PCIE_LNK_X2)) { - mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, - WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, - FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, - 0x1)); - mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, - MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, - FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, - 0x1)); - } else if (dev->hif2->speed < PCIE_SPEED_8_0GT || - (dev->hif2->speed == PCIE_SPEED_8_0GT && - dev->hif2->width < PCIE_LNK_X2)) { - mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, - WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, - FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, - 0x2)); - mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, - MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, - FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, - 0x2)); + if (!is_mt7996(&dev->mt76) || + !mt76_npu_device_active(&dev->mt76)) { + if (dev->hif2->speed < PCIE_SPEED_5_0GT || + (dev->hif2->speed == PCIE_SPEED_5_0GT && + dev->hif2->width < PCIE_LNK_X2)) { + mt76_rmw(dev, + WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, + WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, + FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, + 0x1)); + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, + MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, + FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, + 0x1)); + } else if (dev->hif2->speed < PCIE_SPEED_8_0GT || + (dev->hif2->speed == PCIE_SPEED_8_0GT && + dev->hif2->width < PCIE_LNK_X2)) { + mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs, + WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, + FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, + 0x2)); + mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2, + MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, + FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, + 0x2)); + } } /* WFDMA rx threshold */ @@ -497,7 +521,7 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) int mt7996_dma_rro_init(struct mt7996_dev *dev) { struct mt76_dev *mdev = &dev->mt76; - u32 irq_mask; + u32 size; int ret; if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { @@ -524,7 +548,8 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) mt76_queue_reset(dev, &mdev->q_rx[MT_RXQ_RRO_RXDMAD_C], true); } - goto start_hw_rro; + + return 0; } /* ind cmd */ @@ -545,10 +570,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; + + size = is_mt7996(mdev) && mt76_npu_device_active(mdev) + ? MT7996_NPU_RX_RING_SIZE / 4 : MT7996_RX_RING_SIZE; ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), - MT7996_RX_RING_SIZE, - MT7996_RX_MSDU_PAGE_SIZE, + size, MT7996_RX_MSDU_PAGE_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); if (ret) return ret; @@ -560,10 +587,12 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; + + size = is_mt7996(mdev) && mt76_npu_device_active(mdev) + ? MT7996_NPU_RX_RING_SIZE / 2 : MT7996_RX_RING_SIZE; ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), - MT7996_RX_RING_SIZE, - MT7996_RX_MSDU_PAGE_SIZE, + size, MT7996_RX_MSDU_PAGE_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); if (ret) return ret; @@ -576,52 +605,60 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev) if (mtk_wed_device_active(&mdev->mmio.wed) && mtk_wed_get_rx_capa(&mdev->mmio.wed)) mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; + + size = is_mt7996(mdev) && mt76_npu_device_active(mdev) + ? MT7996_NPU_RX_RING_SIZE : MT7996_RX_RING_SIZE; ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), - MT7996_RX_RING_SIZE, - MT7996_RX_MSDU_PAGE_SIZE, + size, MT7996_RX_MSDU_PAGE_SIZE, MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); if (ret) return ret; } -start_hw_rro: - if (mtk_wed_device_active(&mdev->mmio.wed)) { - irq_mask = mdev->mmio.irqmask | + return 0; +} + +void mt7996_dma_rro_start(struct mt7996_dev *dev) +{ + u32 irq_mask; + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { + irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); - mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); + mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, irq_mask, + false); mt7996_irq_enable(dev, irq_mask); - } else { - if (is_mt7996(&dev->mt76)) { - mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1, - mt76_dma_rx_poll); - mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2, - mt76_dma_rx_poll); - mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2, - mt76_dma_rx_poll); - } else { - mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1, - mt76_dma_rx_poll); - } - - mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll); - if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { - mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C, - mt76_dma_rx_poll); - } else { - mt76_queue_rx_init(dev, MT_RXQ_RRO_IND, - mt76_dma_rx_poll); - mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0, - mt76_dma_rx_poll); - } - - if (!mt76_npu_device_active(&dev->mt76)) - mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE); + return; } - return 0; + if (is_mt7996(&dev->mt76)) { + mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1, + mt76_dma_rx_poll); + mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2, + mt76_dma_rx_poll); + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2, + mt76_dma_rx_poll); + } else { + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1, + mt76_dma_rx_poll); + } + + mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll); + if (dev->mt76.hwrro_mode == MT76_HWRRO_V3_1) { + mt76_queue_rx_init(dev, MT_RXQ_RRO_RXDMAD_C, + mt76_dma_rx_poll); + } else { + mt76_queue_rx_init(dev, MT_RXQ_RRO_IND, + mt76_dma_rx_poll); + mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0, + mt76_dma_rx_poll); + } + + if (!mt76_npu_device_active(&dev->mt76)) + mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE); } int mt7996_dma_init(struct mt7996_dev *dev) @@ -642,11 +679,16 @@ int mt7996_dma_init(struct mt7996_dev *dev) mt7996_dma_disable(dev, true); /* init tx queue */ - ret = mt7996_init_tx_queues(&dev->phy, - MT_TXQ_ID(dev->mphy.band_idx), - MT7996_TX_RING_SIZE, - MT_TXQ_RING_BASE(0), - wed); + if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76)) + ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(0), + MT7996_NPU_TX_RING_SIZE, + MT_TXQ_RING_BASE(0) + hif1_ofs, + NULL); + else + ret = mt7996_init_tx_queues(&dev->phy, + MT_TXQ_ID(dev->mphy.band_idx), + MT7996_TX_RING_SIZE, + MT_TXQ_RING_BASE(0), wed); if (ret) return ret; @@ -714,6 +756,9 @@ int mt7996_dma_init(struct mt7996_dev *dev) (is_mt7992(&dev->mt76)))) { dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; + } else if (is_mt7992(&dev->mt76) && + mt76_npu_device_active(&dev->mt76)) { + dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_NPU_Q_TXFREE(0); } if (mt7996_has_wa(dev)) { @@ -846,6 +891,8 @@ int mt7996_dma_init(struct mt7996_dev *dev) /* tx free notify event from WA for band0 */ dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; + } else if (mt76_npu_device_active(&dev->mt76)) { + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_NPU_Q_TXFREE(0); } ret = mt76_queue_alloc(dev, @@ -859,16 +906,21 @@ int mt7996_dma_init(struct mt7996_dev *dev) } if (mt7996_band_valid(dev, MT_BAND2)) { + u32 size; + /* rx rro data queue for band2 */ dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; + + size = is_mt7996(&dev->mt76) && + mt76_npu_device_active(&dev->mt76) + ? MT7996_NPU_RX_RING_SIZE : MT7996_RX_RING_SIZE; ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], MT_RXQ_ID(MT_RXQ_RRO_BAND2), - MT7996_RX_RING_SIZE, - MT7996_RX_BUF_SIZE, + size, MT7996_RX_BUF_SIZE, MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index 8f60772913b4..ac05f7d75d63 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -33,6 +33,8 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev) if (dev->var.fem == MT7996_FEM_INT) return MT7992_EEPROM_DEFAULT_23_INT; return MT7992_EEPROM_DEFAULT_23; + case MT7992_VAR_TYPE_24: + return MT7992_EEPROM_DEFAULT_24; case MT7992_VAR_TYPE_44: default: if (dev->var.fem == MT7996_FEM_INT) @@ -153,7 +155,7 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default) dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n"); memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE); - dev->flash_mode = true; + dev->eeprom_mode = EEPROM_MODE_DEFAULT_BIN; out: release_firmware(fw); @@ -163,26 +165,31 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default) static int mt7996_eeprom_load(struct mt7996_dev *dev) { + u32 eeprom_blk_size, block_num; bool use_default = false; - int ret; + int ret, i; ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE); if (ret < 0) return ret; if (ret && !mt7996_check_eeprom(dev)) { - dev->flash_mode = true; + dev->eeprom_mode = EEPROM_MODE_FLASH; goto out; } - if (!dev->flash_mode) { - u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; - u32 block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); + memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); + if (mt7996_has_ext_eeprom(dev)) { + /* external eeprom mode */ + dev->eeprom_mode = EEPROM_MODE_EXT; + eeprom_blk_size = MT7996_EXT_EEPROM_BLOCK_SIZE; + } else { u8 free_block_num; - int i; - memset(dev->mt76.eeprom.data, 0, MT7996_EEPROM_SIZE); - ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num); + /* efuse mode */ + dev->eeprom_mode = EEPROM_MODE_EFUSE; + eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE; + ret = mt7996_mcu_get_efuse_free_block(dev, &free_block_num); if (ret < 0) return ret; @@ -191,27 +198,29 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev) use_default = true; goto out; } + } - /* check if eeprom data from fw is valid */ - if (mt7996_mcu_get_eeprom(dev, 0, NULL, 0) || - mt7996_check_eeprom(dev)) { + /* check if eeprom data from fw is valid */ + if (mt7996_mcu_get_eeprom(dev, 0, NULL, eeprom_blk_size, + dev->eeprom_mode) || + mt7996_check_eeprom(dev)) { + use_default = true; + goto out; + } + + /* read eeprom data from fw */ + block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size); + for (i = 1; i < block_num; i++) { + u32 len = eeprom_blk_size; + + if (i == block_num - 1) + len = MT7996_EEPROM_SIZE % eeprom_blk_size; + ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, + NULL, len, dev->eeprom_mode); + if (ret && ret != -EINVAL) { use_default = true; goto out; } - - /* read eeprom data from fw */ - for (i = 1; i < block_num; i++) { - u32 len = eeprom_blk_size; - - if (i == block_num - 1) - len = MT7996_EEPROM_SIZE % eeprom_blk_size; - ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, - NULL, len); - if (ret && ret != -EINVAL) { - use_default = true; - goto out; - } - } } out: @@ -385,7 +394,8 @@ bool mt7996_eeprom_has_background_radar(struct mt7996_dev *dev) return false; break; case MT7992_DEVICE_ID: - if (dev->var.type == MT7992_VAR_TYPE_23) + if (dev->var.type == MT7992_VAR_TYPE_23 || + dev->var.type == MT7992_VAR_TYPE_24) return false; break; case MT7990_DEVICE_ID: { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index 00a8286bd136..d6f9aa1ab52d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -34,6 +34,20 @@ static const struct ieee80211_iface_combination if_comb_global = { BIT(NL80211_CHAN_WIDTH_40) | BIT(NL80211_CHAN_WIDTH_80) | BIT(NL80211_CHAN_WIDTH_160), + .beacon_int_min_gcd = 100, +}; + +static const struct ieee80211_iface_combination if_comb_global_7992 = { + .limits = &if_limits_global, + .n_limits = 1, + .max_interfaces = 32, + .num_different_channels = MT7996_MAX_RADIOS - 1, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80) | + BIT(NL80211_CHAN_WIDTH_160), + .beacon_int_min_gcd = 100, }; static const struct ieee80211_iface_limit if_limits[] = { @@ -85,6 +99,7 @@ static const struct wiphy_iftype_ext_capab iftypes_ext_capa[] = { .extended_capabilities_mask = if_types_ext_capa_ap, .extended_capabilities_len = sizeof(if_types_ext_capa_ap), .mld_capa_and_ops = + FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_FREQ_SEP_TYPE_IND, 1) | FIELD_PREP_CONST(IEEE80211_MLD_CAP_OP_MAX_SIMUL_LINKS, MT7996_MAX_RADIOS - 1), }, @@ -485,7 +500,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) hw->vif_data_size = sizeof(struct mt7996_vif); hw->chanctx_data_size = sizeof(struct mt76_chanctx); - wiphy->iface_combinations = &if_comb_global; + wiphy->iface_combinations = is_mt7996(&dev->mt76) ? &if_comb_global : + &if_comb_global_7992; wiphy->n_iface_combinations = 1; wiphy->radio = dev->radios; @@ -521,8 +537,10 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID); + ieee80211_hw_set(hw, CHANCTX_STA_CSA); hw->max_tx_fragments = 4; + wiphy->txq_memory_limit = 32 << 20; /* 32 MiB */ /* init led callbacks */ if (IS_ENABLED(CONFIG_MT76_LEDS)) { @@ -592,7 +610,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) void mt7996_mac_init(struct mt7996_dev *dev) { #define HIF_TXD_V2_1 0x21 - int i; + int i, rx_path_type; mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT); @@ -606,11 +624,16 @@ void mt7996_mac_init(struct mt7996_dev *dev) } /* rro module init */ - if (dev->hif2) + if (dev->hif2) { + if (mt76_npu_device_active(&dev->mt76)) + rx_path_type = is_mt7996(&dev->mt76) ? 6 : 8; + else + rx_path_type = is_mt7996(&dev->mt76) ? 2 : 7; mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, - is_mt7996(&dev->mt76) ? 2 : 7); - else + rx_path_type); + } else { mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 0); + } if (mt7996_has_hwrro(dev)) { u16 timeout; @@ -668,8 +691,9 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) return 0; if (dev->hif2 && - ((is_mt7996(&dev->mt76) && band == MT_BAND2) || - (is_mt7992(&dev->mt76) && band == MT_BAND1))) { + ((is_mt7992(&dev->mt76) && band == MT_BAND1) || + (is_mt7996(&dev->mt76) && band == MT_BAND2 && + !mt76_npu_device_active(&dev->mt76)))) { hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); wed = &dev->mt76.mmio.wed_hif2; } @@ -709,14 +733,19 @@ static int mt7996_register_phy(struct mt7996_dev *dev, enum mt76_band_id band) /* init wiphy according to mphy and phy */ mt7996_init_wiphy_band(mphy->hw, phy); - if (is_mt7996(&dev->mt76) && !dev->hif2 && band == MT_BAND1) { + if (is_mt7996(&dev->mt76) && + ((band == MT_BAND1 && !dev->hif2) || + (band == MT_BAND2 && mt76_npu_device_active(&dev->mt76)))) { int i; for (i = 0; i <= MT_TXQ_PSD; i++) - mphy->q_tx[i] = dev->mt76.phys[MT_BAND0]->q_tx[0]; + mphy->q_tx[i] = dev->mt76.phys[band - 1]->q_tx[0]; } else { - ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), - MT7996_TX_RING_SIZE, + int size = is_mt7996(&dev->mt76) && + mt76_npu_device_active(&dev->mt76) + ? MT7996_NPU_TX_RING_SIZE / 2 : MT7996_TX_RING_SIZE; + + ret = mt7996_init_tx_queues(mphy->priv, MT_TXQ_ID(band), size, MT_TXQ_RING_BASE(band) + hif1_ofs, wed); if (ret) @@ -756,15 +785,41 @@ static void mt7996_init_work(struct work_struct *work) mt7996_mcu_set_eeprom(dev); mt7996_mac_init(dev); mt7996_txbf_init(dev); + + if (!is_mt7990(&dev->mt76)) + mt7996_mcu_set_dup_wtbl(dev); } void mt7996_wfsys_reset(struct mt7996_dev *dev) { - mt76_set(dev, MT_WF_SUBSYS_RST, 0x1); + if (!is_mt7990(&dev->mt76)) { + mt76_set(dev, MT_WF_SUBSYS_RST, 0x1); + msleep(20); + + mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1); + msleep(20); + + return; + } + + if (!dev->recovery.hw_full_reset) + return; + + mt76_set(dev, MT_WF_SUBSYS_RST, + MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT | + MT_WF_SUBSYS_RST_BYPASS_WFDMA_SLP_PROT | + MT_WF_SUBSYS_RST_BYPASS_WFDMA2_SLP_PROT); + mt76_rmw(dev, MT_WF_SUBSYS_RST, + MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE, + u32_encode_bits(0x20, MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE)); + mt76_clear(dev, MT_WF_L05_RST, MT_WF_L05_RST_WF_RST_MASK); + mt76_set(dev, MT_WF_SUBSYS_RST, MT_WF_SUBSYS_RST_WHOLE_PATH_RST); msleep(20); - mt76_clear(dev, MT_WF_SUBSYS_RST, 0x1); - msleep(20); + if (mt76_poll(dev, MT_WF_L05_RST, MT_WF_L05_RST_WF_RST_MASK, 0x1a, 1000)) + return; + + dev_err(dev->mt76.dev, "wfsys reset fail\n"); } static void mt7996_rro_hw_init_v3(struct mt7996_dev *dev) @@ -842,8 +897,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev) } } else { /* set emul 3.0 function */ - mt76_wr(dev, MT_RRO_3_0_EMU_CONF, - MT_RRO_3_0_EMU_CONF_EN_MASK); + mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE0, dev->wed_rro.addr_elem[0].phy_addr); @@ -935,6 +989,12 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev) addr++; } + if (is_mt7996(&dev->mt76) && + mt76_npu_device_active(&dev->mt76)) + mt76_npu_send_txrx_addr(&dev->mt76, 0, i, + dev->wed_rro.addr_elem[i].phy_addr, + 0, 0); + #ifdef CONFIG_NET_MEDIATEK_SOC_WED if (mtk_wed_device_active(&dev->mt76.mmio.wed) && mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) { @@ -995,6 +1055,10 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev) addr++; } + if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76)) + mt76_npu_send_txrx_addr(&dev->mt76, 1, 0, + dev->wed_rro.session.phy_addr, 0, 0); + mt7996_rro_hw_init(dev); return mt7996_dma_rro_init(dev); @@ -1081,8 +1145,12 @@ static void mt7996_wed_rro_work(struct work_struct *work) list); list_del_init(&e->list); - if (mt76_npu_device_active(&dev->mt76)) + if (mt76_npu_device_active(&dev->mt76)) { + if (is_mt7996(&dev->mt76)) + mt76_npu_send_txrx_addr(&dev->mt76, 3, e->id, + 0, 0, 0); goto reset_session; + } for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { void *ptr = dev->wed_rro.session.ptr; @@ -1129,7 +1197,7 @@ static int mt7996_variant_type_init(struct mt7996_dev *dev) else if (u32_get_bits(val, MT_PAD_GPIO_ADIE_COMB_7992)) var_type = MT7992_VAR_TYPE_44; else - return -EINVAL; + var_type = MT7992_VAR_TYPE_24; break; case MT7990_DEVICE_ID: var_type = MT7990_VAR_TYPE_23; @@ -1163,7 +1231,8 @@ static int mt7996_variant_fem_init(struct mt7996_dev *dev) if (ret) return ret; - ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf)); + ret = mt7996_mcu_get_eeprom(dev, MT7976C_EFUSE_OFFSET, buf, sizeof(buf), + EEPROM_MODE_EFUSE); if (ret && ret != -EINVAL) return ret; @@ -1696,6 +1765,8 @@ int mt7996_register_device(struct mt7996_dev *dev) if (ret) return ret; + mt7996_dma_rro_start(dev); + ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) @@ -1726,6 +1797,7 @@ int mt7996_register_device(struct mt7996_dev *dev) void mt7996_unregister_device(struct mt7996_dev *dev) { + cancel_work_sync(&dev->dump_work); cancel_work_sync(&dev->wed_rro.work); mt7996_unregister_phy(mt7996_phy3(dev)); mt7996_unregister_phy(mt7996_phy2(dev)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 84cbf36b493c..e2a83da3a09c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -13,45 +13,6 @@ #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2) -static const struct mt7996_dfs_radar_spec etsi_radar_specs = { - .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, - .radar_pattern = { - [5] = { 1, 0, 6, 32, 28, 0, 990, 5010, 17, 1, 1 }, - [6] = { 1, 0, 9, 32, 28, 0, 615, 5010, 27, 1, 1 }, - [7] = { 1, 0, 15, 32, 28, 0, 240, 445, 27, 1, 1 }, - [8] = { 1, 0, 12, 32, 28, 0, 240, 510, 42, 1, 1 }, - [9] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 12, 32, 28, { }, 126 }, - [10] = { 1, 1, 0, 0, 0, 0, 2490, 3343, 14, 0, 0, 15, 32, 24, { }, 126 }, - [11] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 18, 32, 28, { }, 54 }, - [12] = { 1, 1, 0, 0, 0, 0, 823, 2510, 14, 0, 0, 27, 32, 24, { }, 54 }, - }, -}; - -static const struct mt7996_dfs_radar_spec fcc_radar_specs = { - .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, - .radar_pattern = { - [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, - [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, - [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, - [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, - [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, - }, -}; - -static const struct mt7996_dfs_radar_spec jp_radar_specs = { - .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 }, - .radar_pattern = { - [0] = { 1, 0, 8, 32, 28, 0, 508, 3076, 13, 1, 1 }, - [1] = { 1, 0, 12, 32, 28, 0, 140, 240, 17, 1, 1 }, - [2] = { 1, 0, 8, 32, 28, 0, 190, 510, 22, 1, 1 }, - [3] = { 1, 0, 6, 32, 28, 0, 190, 510, 32, 1, 1 }, - [4] = { 1, 0, 9, 255, 28, 0, 323, 343, 13, 1, 32 }, - [13] = { 1, 0, 7, 32, 28, 0, 3836, 3856, 14, 1, 1 }, - [14] = { 1, 0, 6, 32, 28, 0, 615, 5010, 110, 1, 1 }, - [15] = { 1, 1, 0, 0, 0, 0, 15, 5010, 110, 0, 0, 12, 32, 28 }, - }, -}; - static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev, u16 idx, u8 band_idx) { @@ -527,7 +488,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, !(csum_status & (BIT(0) | BIT(2) | BIT(3)))) skb->ip_summed = CHECKSUM_UNNECESSARY; - if (rxd1 & MT_RXD3_NORMAL_FCS_ERR) + if (rxd3 & MT_RXD3_NORMAL_FCS_ERR) status->flag |= RX_FLAG_FAILED_FCS_CRC; if (rxd1 & MT_RXD1_NORMAL_TKIP_MIC_ERR) @@ -700,6 +661,8 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, hdr = mt76_skb_get_hdr(skb); fc = hdr->frame_control; + if (ieee80211_is_beacon(fc)) + mt76_rx_beacon(mphy, skb); if (ieee80211_is_data_qos(fc)) { u8 *qos = ieee80211_get_qos_ctl(hdr); @@ -1139,10 +1102,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, * req */ if (le32_to_cpu(ptr[7]) & MT_TXD7_MAC_TXD) { - u32 val; + u32 val, mac_txp_size = sizeof(struct mt76_connac_hw_txp); ptr = (__le32 *)(txwi + MT_TXD_SIZE); - memset((void *)ptr, 0, sizeof(struct mt76_connac_fw_txp)); + memset((void *)ptr, 0, mac_txp_size); val = FIELD_PREP(MT_TXP0_TOKEN_ID0, id) | MT_TXP0_TOKEN_ID0_VALID_MASK; @@ -1161,6 +1124,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, tx_info->buf[1].addr >> 32); #endif ptr[3] = cpu_to_le32(val); + + tx_info->buf[0].len = MT_TXD_SIZE + mac_txp_size; } else { struct mt76_connac_txp_common *txp; @@ -1270,8 +1235,9 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta, if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA))) return; - if (!test_and_set_bit(tid, &wcid->ampdu_state)) - ieee80211_start_tx_ba_session(link_sta->sta, tid, 0); + if (!test_and_set_bit(tid, &wcid->ampdu_state) && + ieee80211_start_tx_ba_session(link_sta->sta, tid, 0)) + clear_bit(tid, &wcid->ampdu_state); } static void @@ -2203,9 +2169,14 @@ mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif) for_each_vif_active_link(vif, link_conf, link_id) { struct mt7996_vif_link *link; + struct mt7996_phy *link_phy; link = mt7996_vif_link(dev, vif, link_id); - if (!link || link->phy != phy) + if (!link) + continue; + + link_phy = mt7996_vif_link_phy(link); + if (link_phy != phy) continue; mt7996_mcu_add_beacon(dev->mt76.hw, vif, link_conf, @@ -2248,6 +2219,12 @@ void mt7996_tx_token_put(struct mt7996_dev *dev) } spin_unlock_bh(&dev->mt76.token_lock); idr_destroy(&dev->mt76.token); + + for (id = 0; id < __MT_MAX_BAND; id++) { + struct mt76_phy *phy = dev->mt76.phys[id]; + if (phy) + atomic_set(&phy->mgmt_tx_pending, 0); + } } static int @@ -2395,23 +2372,8 @@ mt7996_mac_reset_sta_iter(void *data, struct ieee80211_sta *sta) struct mt7996_dev *dev = data; int i; - for (i = 0; i < ARRAY_SIZE(msta->link); i++) { - struct mt7996_sta_link *msta_link = NULL; - - msta_link = rcu_replace_pointer(msta->link[i], msta_link, - lockdep_is_held(&dev->mt76.mutex)); - if (!msta_link) - continue; - - mt7996_mac_sta_deinit_link(dev, msta_link); - - if (msta->deflink_id == i) { - msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; - continue; - } - - kfree_rcu(msta_link, rcu_head); - } + for (i = 0; i < ARRAY_SIZE(msta->link); i++) + mt7996_mac_sta_remove_link(dev, sta, i, true); } static void @@ -2544,6 +2506,7 @@ void mt7996_mac_reset_work(struct work_struct *work) if (mtk_wed_device_active(&dev->mt76.mmio.wed)) mtk_wed_device_stop(&dev->mt76.mmio.wed); + mt7996_npu_hw_stop(dev); ieee80211_stop_queues(mt76_hw(dev)); set_bit(MT76_RESET, &dev->mphy.state); @@ -2564,14 +2527,19 @@ void mt7996_mac_reset_work(struct work_struct *work) mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) continue; + if (mt76_npu_device_active(&dev->mt76) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + + if (mt76_queue_is_npu_txfree(&dev->mt76.q_rx[i])) + continue; + napi_disable(&dev->mt76.napi[i]); } napi_disable(&dev->mt76.tx_napi); mutex_lock(&dev->mt76.mutex); - mt7996_npu_hw_stop(dev); - mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { @@ -2591,7 +2559,7 @@ void mt7996_mac_reset_work(struct work_struct *work) mt7996_dma_start(dev, false, false); if (!is_mt7996(&dev->mt76) && dev->mt76.hwrro_mode == MT76_HWRRO_V3) - mt76_wr(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); + mt76_set(dev, MT_RRO_3_0_EMU_CONF, MT_RRO_3_0_EMU_CONF_EN_MASK); if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { u32 wed_irq_mask = MT_INT_TX_DONE_BAND2 | @@ -2610,6 +2578,8 @@ void mt7996_mac_reset_work(struct work_struct *work) MT_INT_TX_RX_DONE_EXT); } + __mt7996_npu_hw_init(dev); + clear_bit(MT76_MCU_RESET, &dev->mphy.state); mt7996_for_each_phy(dev, phy) clear_bit(MT76_RESET, &phy->mt76->state); @@ -2619,6 +2589,13 @@ void mt7996_mac_reset_work(struct work_struct *work) mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) continue; + if (mt76_npu_device_active(&dev->mt76) && + mt76_queue_is_wed_rro(&dev->mt76.q_rx[i])) + continue; + + if (mt76_queue_is_npu_txfree(&dev->mt76.q_rx[i])) + continue; + napi_enable(&dev->mt76.napi[i]); local_bh_disable(); napi_schedule(&dev->mt76.napi[i]); @@ -2639,8 +2616,6 @@ void mt7996_mac_reset_work(struct work_struct *work) mutex_unlock(&dev->mt76.mutex); - mt7996_npu_hw_init(dev); - mt7996_for_each_phy(dev, phy) ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work, MT7996_WATCHDOG_TIME); @@ -2737,6 +2712,11 @@ void mt7996_reset(struct mt7996_dev *dev) return; } + if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA) { + set_bit(MT76_MCU_RESET, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + } + queue_work(dev->mt76.wq, &dev->reset_work); wake_up(&dev->reset_wait); } @@ -2955,6 +2935,7 @@ void mt7996_mac_work(struct work_struct *work) mutex_unlock(&mphy->dev->mutex); + mt76_beacon_mon_check(mphy); mt76_tx_status_check(mphy->dev, false); ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work, @@ -2974,7 +2955,7 @@ static void mt7996_dfs_stop_radar_detector(struct mt7996_phy *phy) static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) { - int err, region; + int region; switch (dev->mt76.region) { case NL80211_DFS_ETSI: @@ -2989,11 +2970,7 @@ static int mt7996_dfs_start_rdd(struct mt7996_dev *dev, int rdd_idx) break; } - err = mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); - if (err < 0) - return err; - - return mt7996_mcu_rdd_cmd(dev, RDD_DET_MODE, rdd_idx, 1); + return mt7996_mcu_rdd_cmd(dev, RDD_START, rdd_idx, region); } static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) @@ -3015,40 +2992,6 @@ static int mt7996_dfs_start_radar_detector(struct mt7996_phy *phy) return err; } -static int -mt7996_dfs_init_radar_specs(struct mt7996_phy *phy) -{ - const struct mt7996_dfs_radar_spec *radar_specs; - struct mt7996_dev *dev = phy->dev; - int err, i; - - switch (dev->mt76.region) { - case NL80211_DFS_FCC: - radar_specs = &fcc_radar_specs; - err = mt7996_mcu_set_fcc5_lpn(dev, 8); - if (err < 0) - return err; - break; - case NL80211_DFS_ETSI: - radar_specs = &etsi_radar_specs; - break; - case NL80211_DFS_JP: - radar_specs = &jp_radar_specs; - break; - default: - return -EINVAL; - } - - for (i = 0; i < ARRAY_SIZE(radar_specs->radar_pattern); i++) { - err = mt7996_mcu_set_radar_th(dev, i, - &radar_specs->radar_pattern[i]); - if (err < 0) - return err; - } - - return mt7996_mcu_set_pulse_th(dev, &radar_specs->pulse_th); -} - int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) { struct mt7996_dev *dev = phy->dev; @@ -3068,10 +3011,6 @@ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy) goto stop; if (prev_state <= MT_DFS_STATE_DISABLED) { - err = mt7996_dfs_init_radar_specs(phy); - if (err < 0) - return err; - err = mt7996_dfs_start_radar_detector(phy); if (err < 0) return err; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.h b/drivers/net/wireless/mediatek/mt76/mt7996/mac.h index 4eca37b013fc..70ee30f32f88 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.h @@ -37,9 +37,4 @@ struct mt7996_dfs_pattern { u32 min_stgpr_diff; } __packed; -struct mt7996_dfs_radar_spec { - struct mt7996_dfs_pulse pulse_th; - struct mt7996_dfs_pattern radar_pattern[16]; -}; - #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index f16135f0b7f9..a8a6552d49f6 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -56,7 +56,7 @@ static int mt7996_start(struct ieee80211_hw *hw) mutex_lock(&dev->mt76.mutex); ret = mt7996_mcu_set_hdr_trans(dev, true); - if (!ret && is_mt7992(&dev->mt76)) { + if (!ret && !is_mt7996(&dev->mt76)) { u8 queue = mt76_connac_lmac_mapping(IEEE80211_AC_VI); ret = mt7996_mcu_cp_support(dev, queue); @@ -79,6 +79,7 @@ static void mt7996_stop_phy(struct mt7996_phy *phy) mutex_lock(&dev->mt76.mutex); + mt7996_mcu_rdd_resume_tx(phy); mt7996_mcu_set_radio_en(phy, false); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); @@ -238,10 +239,13 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, link_conf = &vif->bss_conf; if (cmd == SET_KEY && !sta && !link->mt76.cipher) { + struct mt7996_phy *phy = mt7996_vif_link_phy(link); + link->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher); - mt7996_mcu_add_bss_info(link->phy, vif, link_conf, - &link->mt76, msta_link, true); + if (phy) + mt7996_mcu_add_bss_info(phy, vif, link_conf, + &link->mt76, msta_link, true); } if (cmd == SET_KEY) @@ -300,9 +304,16 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, .cmd = SET_KEY, .link_id = link_conf->link_id, }; - struct mt76_txq *mtxq; int mld_idx, idx, ret; + 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); + return 0; + } + mlink->idx = __ffs64(~dev->mt76.vif_mask); if (mlink->idx >= mt7996_max_interface_num(dev)) return -ENOSPC; @@ -316,7 +327,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, return -ENOSPC; link->mld_idx = mld_idx; - link->phy = phy; mlink->omac_idx = idx; mlink->band_idx = band_idx; mlink->wmm_idx = vif->type == NL80211_IFTYPE_AP ? 0 : 3; @@ -343,11 +353,6 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, mt7996_mac_wtbl_update(dev, idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - if (vif->txq) { - mtxq = (struct mt76_txq *)vif->txq->drv_priv; - mtxq->wcid = idx; - } - if (vif->type != NL80211_IFTYPE_AP && (!mlink->omac_idx || mlink->omac_idx > 3)) vif->offload_flags = 0; @@ -370,13 +375,81 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); - if (!mlink->wcid->offchannel && - mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) - mvif->mt76.deflink_id = link_conf->link_id; + if (!mlink->wcid->offchannel) { + if (vif->txq && + mvif->mt76.deflink_id == IEEE80211_LINK_UNSPECIFIED) { + struct mt76_txq *mtxq; + + mtxq = (struct mt76_txq *)vif->txq->drv_priv; + mvif->mt76.deflink_id = link_conf->link_id; + mtxq->wcid = idx; + } + mvif->mt76.valid_links |= BIT(link_conf->link_id); + } + + if (vif->type == NL80211_IFTYPE_STATION) { + vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER; + + if (vif->cfg.assoc && link_conf->beacon_int) { + mlink->beacon_mon_interval = + msecs_to_jiffies(ieee80211_tu_to_usec( + link_conf->beacon_int) / 1000); + WRITE_ONCE(mlink->beacon_mon_last, jiffies); + } + } return 0; } +static void mt7996_vif_link_destroy(struct mt7996_phy *phy, + struct mt7996_vif_link *link, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + 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); + mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false); + + rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + + dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); + dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx); + phy->omac_mask &= ~BIT_ULL(mlink->omac_idx); + if (!mlink->wcid->offchannel) + mvif->mt76.valid_links &= ~BIT(link_id); + + spin_lock_bh(&dev->mt76.sta_poll_lock); + if (!list_empty(&msta_link->wcid.poll_list)) + list_del_init(&msta_link->wcid.poll_list); + spin_unlock_bh(&dev->mt76.sta_poll_lock); + + mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); + + if (mlink != (struct mt76_vif_link *)vif->drv_priv && + !mlink->wcid->offchannel) { + rcu_assign_pointer(mlink->mvif->link[link_id], NULL); + kfree_rcu(mlink, rcu_head); + } +} + void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct mt76_vif_link *mlink) @@ -384,49 +457,43 @@ void mt7996_vif_link_remove(struct mt76_phy *mphy, struct ieee80211_vif *vif, struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76); struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; struct mt7996_sta_link *msta_link = &link->msta_link; + unsigned int link_id = msta_link->wcid.link_id; struct mt7996_phy *phy = mphy->priv; - struct mt7996_dev *dev = phy->dev; - struct mt7996_key_iter_data it = { - .cmd = SET_KEY, - .link_id = link_conf->link_id, - }; - int idx = msta_link->wcid.idx; - if (!mlink->wcid->offchannel) - ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); + /* Hw requires to destroy active links tearing down the interface, so + * postpone it removing the interface. + */ + if (mlink->wcid->offchannel) { + mt7996_vif_link_destroy(phy, link, vif, link_conf); + } else { + if (vif->type == NL80211_IFTYPE_AP) { + mt7996_mcu_mld_reconf_stop_link(phy->dev, vif, + BIT(link_id)); + mt7996_mcu_mld_link_oper(phy->dev, link_conf, link, + false); + } - 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); + if (vif->txq && mvif->mt76.deflink_id == link_id) { + struct ieee80211_bss_conf *iter; + struct mt76_txq *mtxq; - mt7996_mcu_add_dev_info(phy, vif, link_conf, mlink, false); + mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED; + mtxq = (struct mt76_txq *)vif->txq->drv_priv; + /* Primary link will be removed, look for a new one */ + for_each_vif_active_link(vif, iter, link_id) { + if (link_id == msta_link->wcid.link_id) + continue; - rcu_assign_pointer(dev->mt76.wcid[idx], NULL); + link = mt7996_vif_link(phy->dev, vif, link_id); + if (!link) + continue; - if (!mlink->wcid->offchannel && - mvif->mt76.deflink_id == link_conf->link_id) { - struct ieee80211_bss_conf *iter; - unsigned int link_id; - - mvif->mt76.deflink_id = IEEE80211_LINK_UNSPECIFIED; - for_each_vif_active_link(vif, iter, link_id) { - if (link_id != IEEE80211_LINK_UNSPECIFIED) { + mtxq->wcid = link->msta_link.wcid.idx; mvif->mt76.deflink_id = link_id; break; } } } - - dev->mt76.vif_mask &= ~BIT_ULL(mlink->idx); - dev->mld_idx_mask &= ~BIT_ULL(link->mld_idx); - phy->omac_mask &= ~BIT_ULL(mlink->omac_idx); - - spin_lock_bh(&dev->mt76.sta_poll_lock); - if (!list_empty(&msta_link->wcid.poll_list)) - list_del_init(&msta_link->wcid.poll_list); - spin_unlock_bh(&dev->mt76.sta_poll_lock); - - mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); } static void mt7996_phy_set_rxfilter(struct mt7996_phy *phy) @@ -472,6 +539,8 @@ static void mt7996_set_monitor(struct mt7996_phy *phy, bool enabled) mt76_rmw_field(dev, MT_DMA_DCR0(phy->mt76->band_idx), MT_DMA_DCR0_RXD_G5_EN, enabled); + mt76_rmw_field(dev, MT_MDP_DCR0, + MT_MDP_DCR0_RX_HDR_TRANS_EN, !enabled); mt7996_phy_set_rxfilter(phy); mt7996_mcu_set_sniffer_mode(phy, enabled); } @@ -530,10 +599,29 @@ static void mt7996_remove_iter(void *data, u8 *mac, struct ieee80211_vif *vif) static void mt7996_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + unsigned long rem_links = mvif->mt76.valid_links; struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_radio_data rdata = {}; + unsigned int link_id; int i; + /* Remove all active links */ + for_each_set_bit(link_id, &rem_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_vif_link *link; + struct mt7996_phy *phy; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + continue; + + phy = __mt7996_phy(dev, link->msta_link.wcid.phy_idx); + if (!phy) + continue; + + mt7996_vif_link_destroy(phy, link, vif, NULL); + } + ieee80211_iterate_active_interfaces_mtx(hw, 0, mt7996_remove_iter, &rdata); mt76_vif_cleanup(&dev->mt76, vif); @@ -811,15 +899,24 @@ mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, for_each_vif_active_link(vif, link_conf, link_id) { struct mt7996_vif_link *link; + struct mt7996_phy *phy; link = mt7996_vif_link(dev, vif, link_id); if (!link) continue; - if (!link->phy) + if (vif->type == NL80211_IFTYPE_STATION) { + link->mt76.beacon_mon_interval = + msecs_to_jiffies(ieee80211_tu_to_usec( + link_conf->beacon_int) / 1000); + WRITE_ONCE(link->mt76.beacon_mon_last, jiffies); + } + + phy = mt7996_vif_link_phy(link); + if (!phy) continue; - mt7996_mcu_add_bss_info(link->phy, vif, link_conf, + 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, @@ -828,6 +925,20 @@ mt7996_vif_cfg_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } } + if ((changed & BSS_CHANGED_ASSOC) && !vif->cfg.assoc && + vif->type == NL80211_IFTYPE_STATION) { + struct ieee80211_bss_conf *link_conf; + unsigned long link_id; + + for_each_vif_active_link(vif, link_conf, link_id) { + struct mt7996_vif_link *link; + + link = mt7996_vif_link(dev, vif, link_id); + if (link) + link->mt76.beacon_mon_interval = 0; + } + } + mutex_unlock(&dev->mt76.mutex); } @@ -864,6 +975,10 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, !!(changed & BSS_CHANGED_BSSID)); } + if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT) + mt7996_mcu_set_protection(phy, link, info->ht_operation_mode, + info->use_cts_prot); + if (changed & BSS_CHANGED_ERP_SLOT) { int slottime = info->use_short_slot ? 9 : 20; @@ -927,12 +1042,84 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw, struct cfg80211_chan_def *chandef) { struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band); + struct ieee80211_bss_conf *link_conf; + unsigned int link_id; mutex_lock(&dev->mt76.mutex); - mt7996_mcu_add_beacon(hw, vif, &vif->bss_conf, vif->bss_conf.enable_beacon); + + for_each_vif_active_link(vif, link_conf, link_id) { + struct mt7996_vif_link *link; + struct mt7996_phy *link_phy; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + continue; + + link_phy = mt7996_vif_link_phy(link); + if (link_phy != phy) + continue; + + /* Reset beacon when channel switch triggered during CAC to let + * FW correctly perform CSA countdown + */ + if (!cfg80211_reg_can_beacon(hw->wiphy, &phy->mt76->chandef, + vif->type)) + mt7996_mcu_add_beacon(hw, vif, link_conf, false); + + mt7996_mcu_add_beacon(hw, vif, link_conf, true); + break; + } + mutex_unlock(&dev->mt76.mutex); } +static int +mt7996_post_channel_switch(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper; + struct mt7996_dev *dev = mt7996_hw_dev(hw); + struct mt7996_phy *phy = mt7996_band_phy(dev, chandef->chan->band); + struct mt7996_vif_link *link; + int ret = -EINVAL; + + mutex_lock(&dev->mt76.mutex); + + link = mt7996_vif_conf_link(dev, vif, link_conf); + if (!link) + goto out; + + ret = mt7996_mcu_update_bss_rfch(phy, link); + if (ret) + goto out; + + ieee80211_iterate_stations_mtx(hw, mt7996_mcu_update_sta_rec_bw, link); + + ret = mt7996_mcu_rdd_resume_tx(phy); + +out: + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + +static void +mt7996_sta_init_txq_wcid(struct ieee80211_sta *sta, int idx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { + struct mt76_txq *mtxq; + + if (!sta->txq[i]) + continue; + + mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; + mtxq->wcid = idx; + } +} + static int mt7996_mac_sta_init_link(struct mt7996_dev *dev, struct ieee80211_bss_conf *link_conf, @@ -941,30 +1128,22 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, { struct ieee80211_sta *sta = link_sta->sta; struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; - struct mt7996_phy *phy = link->phy; + struct mt7996_phy *phy = mt7996_vif_link_phy(link); struct mt7996_sta_link *msta_link; int idx; + if (!phy) + return -EINVAL; + idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA); if (idx < 0) return -ENOSPC; if (msta->deflink_id == IEEE80211_LINK_UNSPECIFIED) { - int i; - msta_link = &msta->deflink; msta->deflink_id = link_id; msta->seclink_id = msta->deflink_id; - - for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { - struct mt76_txq *mtxq; - - if (!sta->txq[i]) - continue; - - mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv; - mtxq->wcid = idx; - } + mt7996_sta_init_txq_wcid(sta, idx); } else { msta_link = kzalloc_obj(*msta_link); if (!msta_link) @@ -1000,9 +1179,17 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev, return 0; } -void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, - struct mt7996_sta_link *msta_link) +void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, + struct ieee80211_sta *sta, + unsigned int link_id, bool flush) { + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_sta_link *msta_link; + + msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); + if (!msta_link) + return; + spin_lock_bh(&dev->mt76.sta_poll_lock); if (!list_empty(&msta_link->wcid.poll_list)) list_del_init(&msta_link->wcid.poll_list); @@ -1011,49 +1198,59 @@ void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, spin_unlock_bh(&dev->mt76.sta_poll_lock); mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); - mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx); -} -static void -mt7996_mac_sta_remove_links(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; - struct mt76_dev *mdev = &dev->mt76; - unsigned int link_id; - - for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) { - struct mt7996_sta_link *msta_link = NULL; - struct mt7996_vif_link *link; - struct mt76_phy *mphy; - - msta_link = rcu_replace_pointer(msta->link[link_id], msta_link, - lockdep_is_held(&mdev->mutex)); - if (!msta_link) - continue; + if (msta_link->wcid.link_valid) { + struct mt7996_phy *phy; mt7996_mac_wtbl_update(dev, msta_link->wcid.idx, MT_WTBL_UPDATE_ADM_COUNT_CLEAR); - mt7996_mac_sta_deinit_link(dev, msta_link); - link = mt7996_vif_link(dev, vif, link_id); - if (!link) - continue; + phy = __mt7996_phy(dev, msta_link->wcid.phy_idx); + if (phy) + phy->mt76->num_sta--; - mphy = mt76_vif_link_phy(&link->mt76); - if (!mphy) - continue; - - mphy->num_sta--; if (msta->deflink_id == link_id) { msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; - continue; - } else if (msta->seclink_id == link_id) { - msta->seclink_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; - kfree_rcu(msta_link, rcu_head); + /* 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; + } + msta_link->wcid.link_valid = false; } + + if (flush) { + rcu_assign_pointer(msta->link[link_id], NULL); + rcu_assign_pointer(dev->mt76.wcid[msta_link->wcid.idx], NULL); + mt76_wcid_mask_clear(dev->mt76.wcid_mask, msta_link->wcid.idx); + if (msta_link != &msta->deflink) + kfree_rcu(msta_link, rcu_head); + } +} + +static void +mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, unsigned long links, + bool flush) +{ + unsigned int link_id; + + for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) + mt7996_mac_sta_remove_link(dev, sta, link_id, flush); } static int @@ -1067,11 +1264,15 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, 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; struct mt76_phy *mphy; - if (rcu_access_pointer(msta->link[link_id])) + msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); + if (msta_link) { + msta_link->wcid.link_valid = true; continue; + } link_conf = link_conf_dereference_protected(vif, link_id); if (!link_conf) { @@ -1108,7 +1309,7 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif, return 0; error_unlink: - mt7996_mac_sta_remove_links(dev, vif, sta, new_links); + mt7996_mac_sta_remove_links(dev, vif, sta, new_links, true); return err; } @@ -1125,7 +1326,7 @@ mt7996_mac_sta_change_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, mutex_lock(&dev->mt76.mutex); - mt7996_mac_sta_remove_links(dev, vif, sta, rem); + 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); @@ -1234,10 +1435,12 @@ static void mt7996_mac_sta_remove(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct ieee80211_sta *sta) { - unsigned long links = sta->valid_links ? sta->valid_links : BIT(0); + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + int i; mutex_lock(&dev->mt76.mutex); - mt7996_mac_sta_remove_links(dev, vif, sta, links); + for (i = 0; i < ARRAY_SIZE(msta->link); i++) + mt7996_mac_sta_remove_link(dev, sta, i, true); mutex_unlock(&dev->mt76.mutex); } @@ -1489,8 +1692,8 @@ mt7996_get_stats(struct ieee80211_hw *hw, u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif_link *link) { + struct mt7996_phy *phy = mt7996_vif_link_phy(link); struct mt7996_dev *dev = mt7996_hw_dev(hw); - struct mt7996_phy *phy = link->phy; union { u64 t64; u32 t32[2]; @@ -1549,7 +1752,7 @@ mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, n = link->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : link->mt76.omac_idx; - phy = link->phy; + phy = mt7996_vif_link_phy(link); if (!phy) goto unlock; @@ -1583,7 +1786,7 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!link) goto unlock; - phy = link->phy; + phy = mt7996_vif_link_phy(link); if (!phy) goto unlock; @@ -1713,9 +1916,14 @@ static void mt7996_link_rate_ctrl_update(void *data, struct mt7996_sta_link *msta_link) { struct mt7996_sta *msta = msta_link->sta; - struct mt7996_dev *dev = msta->vif->deflink.phy->dev; + struct mt7996_phy *phy = mt7996_vif_link_phy(&msta->vif->deflink); + struct mt7996_dev *dev; u32 *changed = data; + if (!phy) + return; + + dev = phy->dev; spin_lock_bh(&dev->mt76.sta_poll_lock); msta_link->changed |= *changed; @@ -2204,6 +2412,10 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, path->mtk_wdma.wdma_idx = wed->wdma_idx; else #endif + if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76) && + msta_link->wcid.phy_idx == MT_BAND2) + path->mtk_wdma.wdma_idx = 1; + else path->mtk_wdma.wdma_idx = link->mt76.band_idx; path->mtk_wdma.bss = link->mt76.idx; path->mtk_wdma.queue = 0; @@ -2275,6 +2487,21 @@ mt7996_reconfig_complete(struct ieee80211_hw *hw, MT7996_WATCHDOG_TIME); } +static int +mt7996_set_eml_op_mode(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_eml_params *eml_params) +{ + struct mt7996_dev *dev = mt7996_hw_dev(hw); + int ret; + + mutex_lock(&dev->mt76.mutex); + ret = mt7996_mcu_set_emlsr_mode(dev, vif, sta, eml_params); + mutex_unlock(&dev->mt76.mutex); + + return ret; +} + const struct ieee80211_ops mt7996_ops = { .add_chanctx = mt76_add_chanctx, .remove_chanctx = mt76_remove_chanctx, @@ -2306,6 +2533,7 @@ const struct ieee80211_ops mt7996_ops = { .release_buffered_frames = mt76_release_buffered_frames, .get_txpower = mt7996_get_txpower, .channel_switch_beacon = mt7996_channel_switch_beacon, + .post_channel_switch = mt7996_post_channel_switch, .get_stats = mt7996_get_stats, .get_et_sset_count = mt7996_get_et_sset_count, .get_et_stats = mt7996_get_et_stats, @@ -2337,4 +2565,5 @@ const struct ieee80211_ops mt7996_ops = { .change_vif_links = mt7996_change_vif_links, .change_sta_links = mt7996_mac_sta_change_links, .reconfig_complete = mt7996_reconfig_complete, + .set_eml_op_mode = mt7996_set_eml_op_mode, }; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index b4422a4754cd..16420375112d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -18,6 +18,9 @@ case MT7992_VAR_TYPE_23: \ _fw = MT7992_##name##_23; \ break; \ + case MT7992_VAR_TYPE_24: \ + _fw = MT7992_##name##_24; \ + break; \ default: \ _fw = MT7992_##name; \ } \ @@ -125,9 +128,16 @@ mt7996_mcu_set_sta_he_mcs(struct ieee80211_link_sta *link_sta, struct mt7996_vif_link *link, __le16 *he_mcs, u16 mcs_map) { + struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss; - enum nl80211_band band = link->phy->mt76->chandef.chan->band; - const u16 *mask = link->bitrate_mask.control[band].he_mcs; + enum nl80211_band band; + const u16 *mask; + + if (!mphy) + return; + + band = mphy->chandef.chan->band; + mask = link->bitrate_mask.control[band].he_mcs; for (nss = 0; nss < max_nss; nss++) { int mcs; @@ -209,6 +219,7 @@ static int mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) { + struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); struct mt7996_mcu_rxd *rxd; struct mt7996_mcu_uni_event *event; int mcu_cmd = FIELD_GET(__MCU_CMD_FIELD_ID, cmd); @@ -217,6 +228,14 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, if (!skb) { dev_err(mdev->dev, "Message %08x (seq %d) timeout\n", cmd, seq); + + if (!test_and_set_bit(MT76_MCU_RESET, &dev->mphy.state)) { + dev->recovery.restart = true; + wake_up(&dev->mt76.mcu.wait); + queue_work(dev->mt76.wq, &dev->reset_work); + wake_up(&dev->reset_wait); + } + return -ETIMEDOUT; } @@ -233,7 +252,7 @@ mt7996_mcu_parse_response(struct mt76_dev *mdev, int cmd, event = (struct mt7996_mcu_uni_event *)skb->data; ret = le32_to_cpu(event->status); /* skip invalid event */ - if (mcu_cmd != event->cid) + if (mcu_cmd != le16_to_cpu(event->cid)) ret = -EAGAIN; } else { skb_pull(skb, sizeof(struct mt7996_mcu_rxd)); @@ -259,7 +278,8 @@ mt7996_mcu_set_timeout(struct mt76_dev *mdev, int cmd) mdev->mcu.timeout = 2 * HZ; return; case MCU_UNI_CMD_EFUSE_CTRL: - mdev->mcu.timeout = 20 * HZ; + case MCU_UNI_CMD_EXT_EEPROM_CTRL: + mdev->mcu.timeout = 30 * HZ; return; default: break; @@ -313,13 +333,12 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb, uni_txd->pkt_type = MCU_PKT_ID; uni_txd->seq = seq; - if (cmd & __MCU_CMD_FIELD_QUERY) - uni_txd->option = MCU_CMD_UNI_QUERY_ACK; - else - uni_txd->option = MCU_CMD_UNI_EXT_ACK; + uni_txd->option = MCU_CMD_UNI; + if (!(cmd & __MCU_CMD_FIELD_QUERY)) + uni_txd->option |= MCU_CMD_SET; - if (mcu_cmd == MCU_UNI_CMD_SDO) - uni_txd->option &= ~MCU_CMD_ACK; + if (wait_seq) + uni_txd->option |= MCU_CMD_ACK; if ((cmd & __MCU_CMD_FIELD_WA) && (cmd & __MCU_CMD_FIELD_WM)) uni_txd->s2d_index = MCU_S2D_H2CN; @@ -390,13 +409,117 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3) sizeof(req), false); } +struct mt7996_mcu_countdown_data { + struct mt76_phy *mphy; + u8 omac_idx; +}; + static void mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) { - if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION) + struct mt7996_mcu_countdown_data *cdata = (void *)priv; + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf = NULL; + unsigned long valid_links = vif->valid_links ?: BIT(0); + unsigned int link_id; + + if (vif->type == NL80211_IFTYPE_STATION) return; - ieee80211_csa_finish(vif, 0); + for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt76_vif_link *mlink = + rcu_dereference(mvif->mt76.link[link_id]); + + if (mlink && mlink->band_idx == cdata->mphy->band_idx && + mlink->omac_idx == cdata->omac_idx) { + link_conf = rcu_dereference(vif->link_conf[link_id]); + break; + } + } + + if (!link_conf || !link_conf->csa_active) + return; + + ieee80211_csa_finish(vif, link_conf->link_id); +} + +static void +mt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) +{ + struct mt7996_mcu_countdown_data *cdata = (void *)priv; + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct ieee80211_bss_conf *link_conf = NULL; + unsigned long valid_links = vif->valid_links ?: BIT(0); + unsigned int link_id; + + if (vif->type == NL80211_IFTYPE_STATION) + return; + + for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt76_vif_link *mlink = + rcu_dereference(mvif->mt76.link[link_id]); + + if (mlink && mlink->band_idx == cdata->mphy->band_idx && + mlink->omac_idx == cdata->omac_idx) { + link_conf = rcu_dereference(vif->link_conf[link_id]); + break; + } + } + + if (!link_conf || !link_conf->color_change_active) + return; + + ieee80211_color_change_finish(vif, link_conf->link_id); +} + +static void +mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) +{ +#define UNI_EVENT_IE_COUNTDOWN_CSA 0 +#define UNI_EVENT_IE_COUNTDOWN_BCC 1 + struct header { + u8 band; + u8 rsv[3]; + }; + struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; + const char *data = (char *)&rxd[1], *tail; + struct header *hdr = (struct header *)data; + struct tlv *tlv = (struct tlv *)(data + 4); + struct mt7996_mcu_countdown_notify *event; + struct mt7996_mcu_countdown_data cdata; + + if (hdr->band >= ARRAY_SIZE(dev->mt76.phys)) + return; + + cdata.mphy = dev->mt76.phys[hdr->band]; + if (!cdata.mphy) + return; + + 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; + + cdata.omac_idx = event->omac_idx; + + switch (le16_to_cpu(tlv->tag)) { + case UNI_EVENT_IE_COUNTDOWN_CSA: + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7996_mcu_csa_finish, &cdata); + break; + case UNI_EVENT_IE_COUNTDOWN_BCC: + ieee80211_iterate_active_interfaces_atomic(mt76_hw(dev), + IEEE80211_IFACE_ITER_RESUME_ALL, + mt7996_mcu_cca_finish, &cdata); + break; + default: + break; + } + + data += le16_to_cpu(tlv->len); + tlv = (struct tlv *)data; + } } static void @@ -416,24 +539,32 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb) break; case MT_RDD_IDX_BACKGROUND: if (!dev->rdd2_phy) - return; + goto err; mphy = dev->rdd2_phy->mt76; break; default: - dev_err(dev->mt76.dev, "Unknown RDD idx %d\n", r->rdd_idx); - return; + goto err; } if (!mphy) - return; + goto err; - if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) + if (r->rdd_idx == MT_RDD_IDX_BACKGROUND) { cfg80211_background_radar_event(mphy->hw->wiphy, &dev->rdd2_chandef, GFP_ATOMIC); - else + } else { + struct mt7996_phy *phy = mphy->priv; + + phy->rdd_tx_paused = true; ieee80211_radar_detected(mphy->hw, NULL); + } dev->hw_pattern++; + + return; + +err: + dev_err(dev->mt76.dev, "Invalid RDD idx %d\n", r->rdd_idx); } static void @@ -476,57 +607,6 @@ mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb) wiphy_info(mt76_hw(dev)->wiphy, "%s: %.*s", type, len, data); } -static void -mt7996_mcu_cca_finish(void *priv, u8 *mac, struct ieee80211_vif *vif) -{ - if (!vif->bss_conf.color_change_active || vif->type == NL80211_IFTYPE_STATION) - return; - - ieee80211_color_change_finish(vif, 0); -} - -static void -mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb) -{ -#define UNI_EVENT_IE_COUNTDOWN_CSA 0 -#define UNI_EVENT_IE_COUNTDOWN_BCC 1 - struct header { - u8 band; - u8 rsv[3]; - }; - struct mt76_phy *mphy = &dev->mt76.phy; - struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data; - const char *data = (char *)&rxd[1], *tail; - struct header *hdr = (struct header *)data; - struct tlv *tlv = (struct tlv *)(data + 4); - - if (hdr->band >= ARRAY_SIZE(dev->mt76.phys)) - return; - - if (hdr->band && dev->mt76.phys[hdr->band]) - mphy = dev->mt76.phys[hdr->band]; - - tail = skb->data + skb->len; - data += sizeof(struct header); - while (data + sizeof(struct tlv) < tail && le16_to_cpu(tlv->len)) { - switch (le16_to_cpu(tlv->tag)) { - case UNI_EVENT_IE_COUNTDOWN_CSA: - ieee80211_iterate_active_interfaces_atomic(mphy->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7996_mcu_csa_finish, mphy->hw); - break; - case UNI_EVENT_IE_COUNTDOWN_BCC: - ieee80211_iterate_active_interfaces_atomic(mphy->hw, - IEEE80211_IFACE_ITER_RESUME_ALL, - mt7996_mcu_cca_finish, mphy->hw); - break; - } - - data += le16_to_cpu(tlv->len); - tlv = (struct tlv *)data; - } -} - static int mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate) { @@ -1170,6 +1250,123 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); } +int mt7996_mcu_update_bss_rfch(struct mt7996_phy *phy, struct mt7996_vif_link *link) +{ + struct mt7996_dev *dev = phy->dev; + struct sk_buff *skb; + + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, + MT7996_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt7996_mcu_bss_rfch_tlv(skb, phy); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); +} + +int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *link, + u8 ht_mode, bool use_cts_prot) +{ + struct mt7996_dev *dev = phy->dev; + struct bss_prot_tlv *prot; + struct sk_buff *skb; + struct tlv *tlv; + enum { + PROT_NONMEMBER = BIT(1), + PROT_20MHZ = BIT(2), + PROT_NONHT_MIXED = BIT(3), + PROT_LEGACY_ERP = BIT(5), + PROT_NONGF_STA = BIT(7), + }; + + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, + MT7996_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_PROTECT_INFO, + sizeof(*prot)); + prot = (struct bss_prot_tlv *)tlv; + + switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) { + case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER: + prot->prot_mode = cpu_to_le32(PROT_NONMEMBER); + break; + case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ: + prot->prot_mode = cpu_to_le32(PROT_20MHZ); + break; + case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED: + prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED); + break; + } + + if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT) + prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA); + + if (use_cts_prot) + prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WM_UNI_CMD(BSS_INFO_UPDATE), true); +} + +int mt7996_mcu_set_emlsr_mode(struct mt7996_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_eml_params *eml_params) +{ + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_sta_link *msta_link; + struct sta_rec_eml_op *eml_op; + struct mt7996_vif_link *link; + struct sk_buff *skb; + struct tlv *tlv; + + msta_link = mt76_dereference(msta->link[eml_params->link_id], + &dev->mt76); + if (!msta_link) + return -EINVAL; + + link = mt7996_vif_link(dev, vif, eml_params->link_id); + if (!link) + return -EINVAL; + + 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); + + tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EML_OP, sizeof(*eml_op)); + eml_op = (struct sta_rec_eml_op *)tlv; + eml_op->link_bitmap = 0; + + if (eml_params->control & IEEE80211_EML_CTRL_EMLSR_MODE) { + unsigned long link_bitmap = eml_params->link_bitmap; + unsigned int link_id; + + for_each_set_bit(link_id, &link_bitmap, + IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt76_phy *mphy; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + continue; + + mphy = mt76_vif_link_phy(&link->mt76); + if (!mphy) + continue; + + eml_op->link_bitmap |= BIT(mphy->band_idx); + } + } + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); +} + int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { @@ -1779,9 +1976,8 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, #define EBF_MODE BIT(0) #define IBF_MODE BIT(1) #define BF_MAT_ORDER 4 + struct mt7996_phy *phy = mt7996_vif_link_phy(link); struct ieee80211_vif *vif = link_conf->vif; - struct mt7996_phy *phy = link->phy; - int tx_ant = hweight16(phy->mt76->chainmask) - 1; struct sta_rec_bf *bf; struct tlv *tlv; static const u8 matrix[BF_MAT_ORDER][BF_MAT_ORDER] = { @@ -1790,8 +1986,12 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, {2, 4, 4, 0}, /* 3x1, 3x2, 3x3, 3x4 */ {3, 5, 6, 0} /* 4x1, 4x2, 4x3, 4x4 */ }; + int tx_ant; bool ebf; + if (!phy) + return; + if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he)) return; @@ -1807,17 +2007,18 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb, * ht: iBF only, since mac80211 lacks of eBF support */ if (link_sta->eht_cap.has_eht) - mt7996_mcu_sta_bfer_eht(link_sta, vif, link->phy, bf, ebf); + mt7996_mcu_sta_bfer_eht(link_sta, vif, phy, bf, ebf); else if (link_sta->he_cap.has_he) - mt7996_mcu_sta_bfer_he(link_sta, vif, link->phy, bf, ebf); + mt7996_mcu_sta_bfer_he(link_sta, vif, phy, bf, ebf); else if (link_sta->vht_cap.vht_supported) - mt7996_mcu_sta_bfer_vht(link_sta, link->phy, bf, ebf); + mt7996_mcu_sta_bfer_vht(link_sta, phy, bf, ebf); else if (link_sta->ht_cap.ht_supported) - mt7996_mcu_sta_bfer_ht(link_sta, link->phy, bf, ebf); + mt7996_mcu_sta_bfer_ht(link_sta, phy, bf, ebf); else return; bf->bf_cap = ebf ? EBF_MODE : (dev->ibf ? IBF_MODE : 0); + tx_ant = hweight16(phy->mt76->chainmask) - 1; if (is_mt7992(&dev->mt76) && tx_ant == 4) bf->bf_cap |= IBF_MODE; @@ -1849,11 +2050,14 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, struct ieee80211_link_sta *link_sta, struct mt7996_vif_link *link) { - struct mt7996_phy *phy = link->phy; - int tx_ant = hweight8(phy->mt76->antenna_mask) - 1; + struct mt7996_phy *phy = mt7996_vif_link_phy(link); struct sta_rec_bfee *bfee; struct tlv *tlv; u8 nrow = 0; + int tx_ant; + + if (!phy) + return; if (!(link_sta->vht_cap.vht_supported || link_sta->he_cap.has_he)) return; @@ -1877,6 +2081,7 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb, } /* reply with identity matrix to avoid 2x2 BF negative gain */ + tx_ant = hweight8(phy->mt76->antenna_mask) - 1; bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2); } @@ -2060,6 +2265,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta, struct ieee80211_sta *sta; int ret, nrates = 0, idx; enum nl80211_band band; + struct mt76_phy *mphy; bool has_he; #define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \ @@ -2093,7 +2299,11 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta, if (!link_sta) goto error_unlock; - band = link->phy->mt76->chandef.chan->band; + mphy = mt76_vif_link_phy(&link->mt76); + if (!mphy) + goto error_unlock; + + band = mphy->chandef.chan->band; has_he = link_sta->he_cap.has_he; mask = link->bitrate_mask; idx = msta_link->wcid.idx; @@ -2173,18 +2383,25 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, struct mt7996_vif_link *link) { #define INIT_RCPI 180 - struct mt76_phy *mphy = link->phy->mt76; - struct cfg80211_chan_def *chandef = &mphy->chandef; + struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); struct cfg80211_bitrate_mask *mask = &link->bitrate_mask; u32 cap = link_sta->sta->wme ? STA_CAP_WMM : 0; - enum nl80211_band band = chandef->chan->band; + struct cfg80211_chan_def *chandef; struct sta_rec_ra_uni *ra; + enum nl80211_band band; struct tlv *tlv; - u32 supp_rate = link_sta->supp_rates[band]; + u32 supp_rate; + + if (!mphy) + return; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra)); ra = (struct sta_rec_ra_uni *)tlv; + chandef = &mphy->chandef; + band = chandef->chan->band; + supp_rate = link_sta->supp_rates[band]; + ra->valid = true; ra->auto_rate = true; ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, link_sta); @@ -2366,6 +2583,72 @@ mt7996_mcu_add_group(struct mt7996_dev *dev, struct mt7996_vif_link *link, sizeof(req), true); } +int mt7996_mcu_mld_reconf_stop_link(struct mt7996_dev *dev, + struct ieee80211_vif *vif, + u16 removed_links) +{ + unsigned long rem_links = removed_links; + struct mld_reconf_stop_link *sl; + struct mld_req_hdr hdr = {}; + unsigned int link_id; + struct sk_buff *skb; + struct tlv *tlv; + + skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, sizeof(hdr) + sizeof(*sl)); + if (!skb) + return -ENOMEM; + + memcpy(hdr.mld_addr, vif->addr, ETH_ALEN); + skb_put_data(skb, &hdr, sizeof(hdr)); + + tlv = mt7996_mcu_add_uni_tlv(skb, UNI_CMD_MLD_RECONF_STOP_LINK, + sizeof(*sl)); + sl = (struct mld_reconf_stop_link *)tlv; + sl->link_bitmap = cpu_to_le16(removed_links); + + for_each_set_bit(link_id, &rem_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct mt7996_vif_link *link; + + link = mt7996_vif_link(dev, vif, link_id); + if (!link) + continue; + + sl->bss_idx[link_id] = link->mt76.idx; + } + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, MCU_WM_UNI_CMD(MLD), + true); +} + +int mt7996_mcu_mld_link_oper(struct mt7996_dev *dev, + struct ieee80211_bss_conf *link_conf, + struct mt7996_vif_link *link, bool add) +{ + struct ieee80211_vif *vif = link_conf->vif; + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; + struct bss_mld_link_op_tlv *mld_op; + struct sk_buff *skb; + struct tlv *tlv; + + skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76, + MT7996_BSS_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_MLD_LINK_OP, + sizeof(*mld_op)); + mld_op = (struct bss_mld_link_op_tlv *)tlv; + mld_op->link_operation = add; + mld_op->own_mld_id = link->mld_idx; + mld_op->link_id = link_conf->link_id; + mld_op->group_mld_id = add ? mvif->mld_group_idx : 0xff; + mld_op->remap_idx = add ? mvif->mld_remap_idx : 0xff; + memcpy(mld_op->mac_addr, vif->addr, ETH_ALEN); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true); +} + static void mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb, struct ieee80211_vif *vif, @@ -2529,6 +2812,53 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev, 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; + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; + struct mt7996_phy *phy = mt7996_vif_link_phy(link); + struct mt7996_sta_link *msta_link; + struct mt7996_dev *dev; + struct ieee80211_bss_conf *link_conf; + struct ieee80211_link_sta *link_sta; + struct ieee80211_vif *vif; + struct sk_buff *skb; + int link_id; + + if (!phy) + return; + + if (link->mt76.mvif != &msta->vif->mt76) + return; + + dev = phy->dev; + link_id = link->msta_link.wcid.link_id; + link_sta = link_sta_dereference_protected(sta, link_id); + if (!link_sta) + return; + + msta_link = mt76_dereference(msta->link[link_id], &dev->mt76); + if (!msta_link) + return; + + vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv); + link_conf = link_conf_dereference_protected(vif, link_id); + if (!link_conf) + return; + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, + &msta_link->wcid, + MT7996_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return; + + mt7996_mcu_sta_bfer_tlv(dev, skb, link_conf, link_sta, link); + mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, link_conf, link_sta, link); + + mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); +} + static int mt7996_mcu_sta_key_tlv(struct mt76_dev *dev, struct mt76_wcid *wcid, struct sk_buff *skb, @@ -2676,6 +3006,16 @@ mt7996_mcu_beacon_cntdwn(struct sk_buff *rskb, struct sk_buff *skb, info = (struct bss_bcn_cntdwn_tlv *)tlv; info->cnt = skb->data[offs->cntdwn_counter_offs[0]]; + + /* abort the CCA countdown when starting CSA countdown */ + if (csa) { + struct bss_bcn_cntdwn_tlv *cca_info; + + tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_BCC, + sizeof(*cca_info)); + cca_info = (struct bss_bcn_cntdwn_tlv *)tlv; + cca_info->cca.abort = true; + } } static void @@ -2768,6 +3108,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct mt7996_dev *dev = mt7996_hw_dev(hw); struct mt7996_vif_link *link = mt7996_vif_conf_link(dev, vif, link_conf); + struct mt76_phy *mphy = link ? mt76_vif_link_phy(&link->mt76) : NULL; struct mt76_vif_link *mlink = link ? &link->mt76 : NULL; struct ieee80211_mutable_offsets offs; struct ieee80211_tx_info *info; @@ -2782,7 +3123,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (!mlink) return -EINVAL; - if (link->phy && link->phy->mt76->offchannel) + if (mphy && mphy->offchannel) enabled = false; rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, @@ -2833,9 +3174,9 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, { #define OFFLOAD_TX_MODE_SU BIT(0) #define OFFLOAD_TX_MODE_MU BIT(1) + struct mt76_phy *mphy = mt76_vif_link_phy(&link->mt76); struct ieee80211_vif *vif = link_conf->vif; struct ieee80211_hw *hw = mt76_hw(dev); - struct mt7996_phy *phy = link->phy; struct mt76_wcid *wcid = &dev->mt76.global_wcid; struct bss_inband_discovery_tlv *discov; struct ieee80211_tx_info *info; @@ -2846,10 +3187,10 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, u8 *buf, interval; int len; - if (!phy) + if (!mphy) return -EINVAL; - chandef = &phy->mt76->chandef; + chandef = &mphy->chandef; band = chandef->chan->band; if (link_conf->nontransmitted) @@ -2887,7 +3228,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev, info = IEEE80211_SKB_CB(skb); info->control.vif = vif; info->band = band; - info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, phy->mt76->band_idx); + info->hw_queue |= FIELD_PREP(MT_TX_HW_QUEUE_PHY, mphy->band_idx); len = ALIGN(sizeof(*discov) + MT_TXD_SIZE + skb->len, 4); tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_OFFLOAD, len); @@ -3742,8 +4083,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR) req.switch_reason = CH_SWITCH_NORMAL; - else if (phy->mt76->offchannel || - phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE) + else if (phy->mt76->offchannel || !phy->mt76->chanctx) req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD; else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef, NL80211_IFTYPE_AP)) @@ -3764,23 +4104,173 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag) &req, sizeof(req), true); } -static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev) +static int +mt7996_mcu_get_cal_free_data(struct mt7996_dev *dev) +{ +#define MT_EE_7977BN_OFFSET (0x1200 - 0x500) + struct cal_free_data { + u16 adie_offs; + u16 eep_offs; + }; + static const struct cal_free_data cal_7975[] = { + { 0x5cd, 0x451 }, { 0x5cf, 0x453 }, { 0x5d1, 0x455 }, + { 0x5d3, 0x457 }, { 0x6c0, 0x44c }, { 0x6c1, 0x44d }, + { 0x6c2, 0x44e }, { 0x6c3, 0x44f }, { 0x7a1, 0xba1 }, + { 0x7a6, 0xba6 }, { 0x7a8, 0xba8 }, { 0x7aa, 0xbaa }, + }; + static const struct cal_free_data cal_7976[] = { + { 0x4c, 0x44c }, { 0x4d, 0x44d }, { 0x4e, 0x44e }, + { 0x4f, 0x44f }, { 0x50, 0x450 }, { 0x51, 0x451 }, + { 0x53, 0x453 }, { 0x55, 0x455 }, { 0x57, 0x457 }, + { 0x59, 0x459 }, { 0x70, 0x470 }, { 0x71, 0x471 }, + { 0x790, 0xb90 }, { 0x791, 0xb91 }, { 0x794, 0xb94 }, + { 0x795, 0xb95 }, { 0x7a6, 0xba6 }, { 0x7a8, 0xba8 }, + { 0x7aa, 0xbaa }, + }; + static const struct cal_free_data cal_7977[] = { + { 0x4c, 0x124c }, { 0x4d, 0x124d }, { 0x4e, 0x124e }, + { 0x4f, 0x124f }, { 0x50, 0x1250 }, { 0x51, 0x1251 }, + { 0x53, 0x1253 }, { 0x55, 0x1255 }, { 0x57, 0x1257 }, + { 0x59, 0x1259 }, { 0x69, 0x1269 }, { 0x6a, 0x126a }, + { 0x7a, 0x127a }, { 0x7b, 0x127b }, { 0x7c, 0x127c }, + { 0x7d, 0x127d }, { 0x7e, 0x127e }, + }; + static const struct cal_free_data cal_7978[] = { + { 0x91, 0xb91 }, { 0x95, 0xb95 }, { 0x100, 0x480 }, + { 0x102, 0x482 }, { 0x104, 0x484 }, { 0x106, 0x486 }, + { 0x107, 0x487 }, { 0x108, 0x488 }, { 0x109, 0x489 }, + { 0x10a, 0x48a }, { 0x10b, 0x48b }, { 0x10c, 0x48c }, + { 0x10e, 0x48e }, { 0x110, 0x490 }, + }; + static const struct cal_free_data cal_7979[] = { + { 0x4c, 0x124c }, { 0x4d, 0x124d }, { 0x4e, 0x124e }, + { 0x4f, 0x124f }, { 0x50, 0x1250 }, { 0x51, 0x1251 }, + { 0x53, 0x1253 }, { 0x55, 0x1255 }, { 0x57, 0x1257 }, + { 0x59, 0x1259 }, { 0x69, 0x1269 }, { 0x6a, 0x126a }, + { 0x7a, 0x127a }, { 0x7b, 0x127b }, { 0x7c, 0x127c }, + { 0x7e, 0x127e }, { 0x80, 0x1280 }, + }; + const struct cal_free_data *cal_arr[__MT_MAX_BAND]; + u16 cal_arr_len[__MT_MAX_BAND] = {}; + u8 *eeprom = (u8 *)dev->mt76.eeprom.data; + int band, i, ret; + +#define CAL_ARR(_band, _adie) do { \ + cal_arr[_band] = cal_##_adie; \ + cal_arr_len[_band] = ARRAY_SIZE(cal_##_adie); \ + } while (0) + + switch (mt76_chip(&dev->mt76)) { + case MT7996_DEVICE_ID: + /* adie 0 */ + if (dev->var.fem == MT7996_FEM_INT && + dev->var.type != MT7996_VAR_TYPE_233) + CAL_ARR(0, 7975); + else + CAL_ARR(0, 7976); + + /* adie 1 */ + if (dev->var.type == MT7996_VAR_TYPE_444) + CAL_ARR(1, 7977); + + /* adie 2 */ + CAL_ARR(2, 7977); + break; + case MT7992_DEVICE_ID: + /* adie 0 */ + if (dev->var.type == MT7992_VAR_TYPE_44 && + dev->var.fem != MT7996_FEM_EXT) + CAL_ARR(0, 7975); + else if (dev->var.type == MT7992_VAR_TYPE_24) + CAL_ARR(0, 7978); + else + CAL_ARR(0, 7976); + + /* adie 1 */ + if (dev->var.type == MT7992_VAR_TYPE_44 && + dev->var.fem != MT7996_FEM_INT) + CAL_ARR(1, 7977); + else if (dev->var.type != MT7992_VAR_TYPE_23) + CAL_ARR(1, 7979); + break; + case MT7990_DEVICE_ID: + /* adie 0 */ + CAL_ARR(0, 7976); + break; + default: + return -EINVAL; + } + + for (band = 0; band < __MT_MAX_BAND; band++) { + u8 buf[MT7996_EEPROM_BLOCK_SIZE]; + const struct cal_free_data *cal; + u16 prev_block_idx = -1; + u16 adie_base; + + if (!cal_arr_len[band]) + continue; + + if (band == MT_BAND0) + adie_base = MT7996_EFUSE_BASE_OFFS_ADIE0; + else if (band == MT_BAND1 && is_mt7992(&dev->mt76)) + adie_base = MT7992_EFUSE_BASE_OFFS_ADIE1; + else if (band == MT_BAND1) + adie_base = MT7996_EFUSE_BASE_OFFS_ADIE1; + else + adie_base = MT7996_EFUSE_BASE_OFFS_ADIE2; + + cal = cal_arr[band]; + for (i = 0; i < cal_arr_len[band]; i++) { + u16 adie_offset = cal[i].adie_offs + adie_base; + u16 eep_offset = cal[i].eep_offs; + u16 block_idx = adie_offset / MT7996_EEPROM_BLOCK_SIZE; + u16 offset = adie_offset % MT7996_EEPROM_BLOCK_SIZE; + + if (is_mt7996(&dev->mt76) && band == MT_BAND1 && + dev->var.type == MT7996_VAR_TYPE_444) + eep_offset -= MT_EE_7977BN_OFFSET; + + if (prev_block_idx != block_idx) { + memset(buf, 0, sizeof(buf)); + ret = mt7996_mcu_get_eeprom(dev, adie_offset, buf, + MT7996_EEPROM_BLOCK_SIZE, + EEPROM_MODE_EFUSE); + if (ret) { + if (ret != -EINVAL) + return ret; + prev_block_idx = -1; + continue; + } + } + eeprom[eep_offset] = buf[offset]; + prev_block_idx = block_idx; + } + } + + return 0; +} + +int mt7996_mcu_set_eeprom(struct mt7996_dev *dev) { #define MAX_PAGE_IDX_MASK GENMASK(7, 5) #define PAGE_IDX_MASK GENMASK(4, 2) #define PER_PAGE_SIZE 0x400 - struct mt7996_mcu_eeprom req = { + struct mt7996_mcu_eeprom_update req = { .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), .buffer_mode = EE_MODE_BUFFER }; u16 eeprom_size = MT7996_EEPROM_SIZE; u8 total = DIV_ROUND_UP(eeprom_size, PER_PAGE_SIZE); u8 *eep = (u8 *)dev->mt76.eeprom.data; - int eep_len, i; + int ret, eep_len, i; + + ret = mt7996_mcu_get_cal_free_data(dev); + if (ret) + return ret; for (i = 0; i < total; i++, eep += eep_len) { struct sk_buff *skb; - int ret, msg_len; + int msg_len; if (i == total - 1 && !!(eeprom_size % PER_PAGE_SIZE)) eep_len = eeprom_size % PER_PAGE_SIZE; @@ -3809,59 +4299,66 @@ static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev) return 0; } -int mt7996_mcu_set_eeprom(struct mt7996_dev *dev) +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len, + enum mt7996_eeprom_mode mode) { - struct mt7996_mcu_eeprom req = { - .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), - .len = cpu_to_le16(sizeof(req) - 4), - .buffer_mode = EE_MODE_EFUSE, - .format = EE_FORMAT_WHOLE - }; - - if (dev->flash_mode) - return mt7996_mcu_set_eeprom_flash(dev); - - return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL), - &req, sizeof(req), true); -} - -int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len) -{ - struct { - u8 _rsv[4]; - - __le16 tag; - __le16 len; - __le32 addr; - __le32 valid; - u8 data[16]; - } __packed req = { - .tag = cpu_to_le16(UNI_EFUSE_ACCESS), - .len = cpu_to_le16(sizeof(req) - 4), - .addr = cpu_to_le32(round_down(offset, - MT7996_EEPROM_BLOCK_SIZE)), + struct mt7996_mcu_eeprom_access req = { + .info.len = cpu_to_le16(sizeof(req) - 4), }; + struct mt7996_mcu_eeprom_access_event *event; struct sk_buff *skb; - bool valid; - int ret; + int ret, cmd; + u32 addr; - ret = mt76_mcu_send_and_get_msg(&dev->mt76, - MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL), - &req, sizeof(req), true, &skb); + switch (mode) { + case EEPROM_MODE_EFUSE: + addr = round_down(offset, MT7996_EEPROM_BLOCK_SIZE); + cmd = MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL); + req.info.tag = cpu_to_le16(UNI_EFUSE_ACCESS); + break; + case EEPROM_MODE_EXT: + addr = round_down(offset, MT7996_EXT_EEPROM_BLOCK_SIZE); + cmd = MCU_WM_UNI_CMD_QUERY(EXT_EEPROM_CTRL); + req.info.tag = cpu_to_le16(UNI_EXT_EEPROM_ACCESS); + req.eeprom.ext_eeprom.data_len = cpu_to_le32(buf_len); + break; + default: + return -EINVAL; + } + + req.info.addr = cpu_to_le32(addr); + ret = mt76_mcu_send_and_get_msg(&dev->mt76, cmd, &req, sizeof(req), + true, &skb); if (ret) return ret; - valid = le32_to_cpu(*(__le32 *)(skb->data + 16)); - if (valid) { - u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12)); + event = (struct mt7996_mcu_eeprom_access_event *)skb->data; + if (event->valid) { + u32 ret_len = le32_to_cpu(event->eeprom.ext_eeprom.data_len); + + addr = le32_to_cpu(event->addr); if (!buf) buf = (u8 *)dev->mt76.eeprom.data + addr; - if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE) - buf_len = MT7996_EEPROM_BLOCK_SIZE; - skb_pull(skb, 48); - memcpy(buf, skb->data, buf_len); + switch (mode) { + case EEPROM_MODE_EFUSE: + if (!buf_len || buf_len > MT7996_EEPROM_BLOCK_SIZE) + buf_len = MT7996_EEPROM_BLOCK_SIZE; + + memcpy(buf, event->eeprom.efuse, buf_len); + break; + case EEPROM_MODE_EXT: + if (!buf_len || buf_len > MT7996_EXT_EEPROM_BLOCK_SIZE) + buf_len = MT7996_EXT_EEPROM_BLOCK_SIZE; + + memcpy(buf, event->eeprom.ext_eeprom.data, + ret_len < buf_len ? ret_len : buf_len); + break; + default: + ret = -EINVAL; + break; + } } else { ret = -EINVAL; } @@ -3871,7 +4368,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l return ret; } -int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) +int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num) { struct { u8 _rsv[4]; @@ -3903,7 +4400,6 @@ int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num) int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) { -#define NIC_CAP 3 #define UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION 0x21 struct { u8 _rsv[4]; @@ -3911,7 +4407,7 @@ int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) __le16 tag; __le16 len; } __packed req = { - .tag = cpu_to_le16(NIC_CAP), + .tag = cpu_to_le16(UNI_CHIP_CONFIG_NIC_CAPA), .len = cpu_to_le16(sizeof(req) - 4), }; struct sk_buff *skb; @@ -4559,6 +5055,35 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable) &req, sizeof(req), true); } +int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy) +{ + struct { + u8 band_idx; + u8 _rsv[3]; + + __le16 tag; + __le16 len; + u8 mac_enable; + u8 _rsv2[3]; + } __packed req = { + .band_idx = phy->mt76->band_idx, + .tag = cpu_to_le16(UNI_BAND_CONFIG_MAC_ENABLE_CTRL), + .len = cpu_to_le16(sizeof(req) - 4), + .mac_enable = 2, + }; + int ret; + + if (!phy->rdd_tx_paused) + return 0; + + ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG), + &req, sizeof(req), true); + if (!ret) + phy->rdd_tx_paused = false; + + return ret; +} + int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val) { struct { @@ -4889,3 +5414,25 @@ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode) return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT), &cp_mode, sizeof(cp_mode), true); } + +int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev) +{ +#define DUP_WTBL_NUM 80 + struct { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + __le16 base; + __le16 num; + u8 _rsv2[4]; + } __packed req = { + .tag = cpu_to_le16(UNI_CHIP_CONFIG_DUP_WTBL), + .len = cpu_to_le16(sizeof(req) - 4), + .base = cpu_to_le16(MT7996_WTBL_STA - DUP_WTBL_NUM + 1), + .num = cpu_to_le16(DUP_WTBL_NUM), + }; + + return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(CHIP_CONFIG), &req, + sizeof(req), true); +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index e0b83ac9f5e2..8902e16508b7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -25,8 +25,8 @@ struct mt7996_mcu_rxd { }; struct mt7996_mcu_uni_event { - u8 cid; - u8 __rsv[3]; + __le16 cid; + u8 __rsv[2]; __le32 status; /* 0: success, others: fail */ } __packed; @@ -52,12 +52,10 @@ struct mt7996_mcu_thermal_enable { u8 rsv[2]; } __packed; -struct mt7996_mcu_csa_notify { - struct mt7996_mcu_rxd rxd; - +struct mt7996_mcu_countdown_notify { u8 omac_idx; - u8 csa_count; - u8 band_idx; + u8 count; + u8 csa_failure_reason; /* 0: success, 1: beacon disabled */ u8 rsv; } __packed; @@ -147,7 +145,7 @@ struct mt7996_mcu_background_chain_ctrl { u8 rsv[2]; } __packed; -struct mt7996_mcu_eeprom { +struct mt7996_mcu_eeprom_update { u8 _rsv[4]; __le16 tag; @@ -157,6 +155,43 @@ struct mt7996_mcu_eeprom { __le16 buf_len; } __packed; +union eeprom_data { + struct { + __le32 data_len; + DECLARE_FLEX_ARRAY(u8, data); + } ext_eeprom; + DECLARE_FLEX_ARRAY(u8, efuse); +} __packed; + +struct mt7996_mcu_eeprom_info { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + __le32 addr; + __le32 valid; +} __packed; + +struct mt7996_mcu_eeprom_access { + struct mt7996_mcu_eeprom_info info; + union eeprom_data eeprom; +} __packed; + +struct mt7996_mcu_eeprom_access_event { + u8 _rsv[4]; + + __le16 tag; + __le16 len; + __le32 version; + __le32 addr; + __le32 valid; + __le32 size; + __le32 magic_no; + __le32 type; + __le32 rsv[4]; + union eeprom_data eeprom; +} __packed; + struct mt7996_mcu_phy_rx_info { u8 category; u8 rate; @@ -414,7 +449,16 @@ struct bss_bcn_cntdwn_tlv { __le16 tag; __le16 len; u8 cnt; - u8 rsv[3]; + union { + struct { + bool static_pp; + bool abort; + } csa; + struct { + bool abort; + } cca; + }; + u8 rsv; } __packed; struct bss_bcn_mbss_tlv { @@ -474,6 +518,24 @@ struct bss_mld_tlv { u8 __rsv[2]; } __packed; +struct bss_prot_tlv { + __le16 tag; + __le16 len; + __le32 prot_mode; +} __packed; + +struct bss_mld_link_op_tlv { + __le16 tag; + __le16 len; + u8 group_mld_id; + u8 own_mld_id; + u8 mac_addr[ETH_ALEN]; + u8 remap_idx; + u8 link_operation; + u8 link_id; + u8 rsv[2]; +} __packed; + struct sta_rec_ht_uni { __le16 tag; __le16 len; @@ -647,6 +709,28 @@ struct mld_setup_link { u8 __rsv; } __packed; +struct mld_req_hdr { + u8 ver; + u8 mld_addr[ETH_ALEN]; + u8 mld_idx; + u8 flag; + u8 rsv[3]; + u8 buf[]; +} __packed; + +struct mld_reconf_stop_link { + __le16 tag; + __le16 len; + __le16 link_bitmap; + u8 rsv[2]; + u8 bss_idx[16]; +} __packed; + +enum { + UNI_CMD_MLD_RECONF_AP_REM_TIMER = 0x03, + UNI_CMD_MLD_RECONF_STOP_LINK = 0x04, +}; + struct hdr_trans_en { __le16 tag; __le16 len; @@ -791,6 +875,11 @@ enum { UNI_CHANNEL_RX_PATH, }; +enum { + UNI_CHIP_CONFIG_NIC_CAPA = 3, + UNI_CHIP_CONFIG_DUP_WTBL = 4, +}; + #define MT7996_BSS_UPDATE_MAX_SIZE (sizeof(struct bss_req_hdr) + \ sizeof(struct mt76_connac_bss_basic_tlv) + \ sizeof(struct bss_rlm_tlv) + \ @@ -837,6 +926,7 @@ enum { enum { UNI_BAND_CONFIG_RADIO_ENABLE, UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, + UNI_BAND_CONFIG_MAC_ENABLE_CTRL = 0x0c, }; enum { @@ -856,6 +946,10 @@ enum { UNI_EFUSE_BUFFER_RD, }; +enum { + UNI_EXT_EEPROM_ACCESS = 1, +}; + enum { UNI_VOW_DRR_CTRL, UNI_VOW_RX_AT_AIRTIME_EN = 0x0b, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 7a884311800e..bdcf72457954 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -29,6 +29,10 @@ #define MT7996_RX_RING_SIZE 1536 #define MT7996_RX_MCU_RING_SIZE 512 #define MT7996_RX_MCU_RING_SIZE_WA 1024 +#define MT7996_NPU_TX_RING_SIZE 1024 +#define MT7996_NPU_RX_RING_SIZE 1024 +#define MT7996_NPU_TXD_SIZE 3 + /* scatter-gather of mcu event is not supported in connac3 */ #define MT7996_RX_MCU_BUF_SIZE (2048 + \ SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) @@ -60,6 +64,11 @@ #define MT7992_FIRMWARE_DSP_23 "mediatek/mt7996/mt7992_dsp_23.bin" #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin" +#define MT7992_FIRMWARE_WA_24 "mediatek/mt7996/mt7992_wa_24.bin" +#define MT7992_FIRMWARE_WM_24 "mediatek/mt7996/mt7992_wm_24.bin" +#define MT7992_FIRMWARE_DSP_24 "mediatek/mt7996/mt7992_dsp_24.bin" +#define MT7992_ROM_PATCH_24 "mediatek/mt7996/mt7992_rom_patch_24.bin" + #define MT7990_FIRMWARE_WA "" #define MT7990_FIRMWARE_WM "mediatek/mt7996/mt7990_wm.bin" #define MT7990_FIRMWARE_DSP "" @@ -75,12 +84,14 @@ #define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin" #define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23.bin" #define MT7992_EEPROM_DEFAULT_23_INT "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin" +#define MT7992_EEPROM_DEFAULT_24 "mediatek/mt7996/mt7992_eeprom_24_2i5i.bin" #define MT7990_EEPROM_DEFAULT "mediatek/mt7996/mt7990_eeprom.bin" #define MT7990_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7990_eeprom_2i5i.bin" #define MT7996_EEPROM_SIZE 7680 #define MT7996_EEPROM_BLOCK_SIZE 16 +#define MT7996_EXT_EEPROM_BLOCK_SIZE 1024 #define MT7996_TOKEN_SIZE 16384 #define MT7996_HW_TOKEN_SIZE 8192 @@ -153,6 +164,7 @@ enum mt7996_var_type { enum mt7992_var_type { MT7992_VAR_TYPE_44, MT7992_VAR_TYPE_23, + MT7992_VAR_TYPE_24, }; enum mt7990_var_type { @@ -165,6 +177,18 @@ enum mt7996_fem_type { MT7996_FEM_MIX, }; +enum mt7996_eeprom_mode { + EEPROM_MODE_DEFAULT_BIN, + EEPROM_MODE_EFUSE, + EEPROM_MODE_FLASH, + EEPROM_MODE_EXT, +}; + +#define MT7996_EFUSE_BASE_OFFS_ADIE0 0x400 +#define MT7996_EFUSE_BASE_OFFS_ADIE1 0x1e00 +#define MT7996_EFUSE_BASE_OFFS_ADIE2 0x1200 +#define MT7992_EFUSE_BASE_OFFS_ADIE1 0x1200 + enum mt7996_txq_id { MT7996_TXQ_FWDL = 16, MT7996_TXQ_MCU_WM, @@ -252,8 +276,6 @@ struct mt7996_vif_link { struct mt76_vif_link mt76; /* must be first */ struct mt7996_sta_link msta_link; - struct mt7996_phy *phy; - struct cfg80211_bitrate_mask bitrate_mask; u8 mld_idx; @@ -377,6 +399,7 @@ struct mt7996_phy { bool has_aux_rx; bool counter_reset; + bool rdd_tx_paused; }; struct mt7996_dev { @@ -436,7 +459,7 @@ struct mt7996_dev { u32 hw_pattern; - bool flash_mode:1; + u8 eeprom_mode; bool has_eht:1; struct { @@ -473,6 +496,8 @@ struct mt7996_dev { struct list_head page_map[MT7996_RRO_MSDU_PG_HASH_SIZE]; } wed_rro; + dma_addr_t npu_txd_addr[2 * MT7996_NPU_TXD_SIZE]; + bool ibf; u8 fw_debug_wm; u8 fw_debug_wa; @@ -669,6 +694,8 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, struct mt76_vif_link *mlink, struct mt7996_sta_link *msta_link, int enable); +int mt7996_mcu_update_bss_rfch(struct mt7996_phy *phy, + struct mt7996_vif_link *link); int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *link_conf, struct ieee80211_link_sta *link_sta, @@ -678,6 +705,7 @@ 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); +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); @@ -707,8 +735,9 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev, int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta, void *data, u8 link_id, u32 field); int mt7996_mcu_set_eeprom(struct mt7996_dev *dev); -int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len); -int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num); +int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_len, + enum mt7996_eeprom_mode mode); +int mt7996_mcu_get_efuse_free_block(struct mt7996_dev *dev, u8 *block_num); int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap); int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band); int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action); @@ -719,6 +748,8 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index, const struct mt7996_dfs_pattern *pattern); int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable); int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val); +int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *link, + u8 ht_mode, bool use_cts_prot); int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf); int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); @@ -726,6 +757,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_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, struct cfg80211_chan_def *chandef); @@ -743,6 +775,13 @@ void mt7996_mcu_exit(struct mt7996_dev *dev); int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag); int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id); int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled); +int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev); +int mt7996_mcu_mld_reconf_stop_link(struct mt7996_dev *dev, + struct ieee80211_vif *vif, + u16 removed_links); +int mt7996_mcu_mld_link_oper(struct mt7996_dev *dev, + struct ieee80211_bss_conf *link_conf, + struct mt7996_vif_link *link, bool add); static inline bool mt7996_has_hwrro(struct mt7996_dev *dev) { @@ -802,6 +841,11 @@ static inline bool mt7996_has_wa(struct mt7996_dev *dev) return !is_mt7990(&dev->mt76); } +static inline bool mt7996_has_ext_eeprom(struct mt7996_dev *dev) +{ + return !is_mt7996(&dev->mt76); +} + void mt7996_mac_init(struct mt7996_dev *dev); u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw); bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); @@ -823,8 +867,9 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev, struct mt7996_vif_link *link, struct mt7996_sta_link *msta_link, u8 flowid); -void mt7996_mac_sta_deinit_link(struct mt7996_dev *dev, - struct mt7996_sta_link *msta_link); +void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, + struct ieee80211_sta *sta, + unsigned int link_id, bool flush); void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, struct ieee80211_sta *sta, struct ieee80211_twt_setup *twt); @@ -861,6 +906,10 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, struct mt7996_vif_link *link, struct mt7996_sta_link *msta_link); int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode); +int mt7996_mcu_set_emlsr_mode(struct mt7996_dev *dev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_eml_params *eml_params); #ifdef CONFIG_MAC80211_DEBUGFS void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_sta *sta, struct dentry *dir); @@ -877,12 +926,19 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); #endif int mt7996_dma_rro_init(struct mt7996_dev *dev); +void mt7996_dma_rro_start(struct mt7996_dev *dev); #ifdef CONFIG_MT7996_NPU +int __mt7996_npu_hw_init(struct mt7996_dev *dev); int mt7996_npu_hw_init(struct mt7996_dev *dev); int mt7996_npu_hw_stop(struct mt7996_dev *dev); int mt7996_npu_rx_queues_init(struct mt7996_dev *dev); #else +static inline int __mt7996_npu_hw_init(struct mt7996_dev *dev) +{ + return 0; +} + static inline int mt7996_npu_hw_init(struct mt7996_dev *dev) { return 0; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c index 29bb735da4cb..b8006b8729a1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/npu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/npu.c @@ -8,55 +8,20 @@ #include "mt7996.h" -static int mt7996_npu_offload_init(struct mt7996_dev *dev, - struct airoha_npu *npu) +static int mt7992_npu_txrx_offload_init(struct mt7996_dev *dev, + struct airoha_npu *npu) { + u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; - u32 val, hif1_ofs = 0, dma_addr; + u32 dma_addr; int i, err; - err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_NPU_VERSION, - &val, GFP_KERNEL); - if (err) { - dev_warn(dev->mt76.dev, "failed getting NPU fw version\n"); - return err; - } - - dev_info(dev->mt76.dev, "NPU version: %0d.%d\n", - (val >> 16) & 0xffff, val & 0xffff); - - err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE, - dev->mt76.mmio.npu_type, GFP_KERNEL); - if (err) { - dev_warn(dev->mt76.dev, - "failed setting NPU wlan PCIe port type\n"); - return err; - } - - if (dev->hif2) - hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); - for (i = MT_BAND0; i < MT_BAND2; i++) { - dma_addr = phy_addr; - if (i) - dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + 0x90 + - hif1_ofs; - else - dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0) + 0x80; - - err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_PCIE_ADDR, - dma_addr, GFP_KERNEL); - if (err) { - dev_warn(dev->mt76.dev, - "failed setting NPU wlan PCIe desc addr\n"); - return err; - } - err = mt76_npu_send_msg(npu, i, WLAN_FUNC_SET_WAIT_DESC, MT7996_RX_RING_SIZE, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed setting NPU wlan PCIe desc size\n"); + "failed setting NPU wlan rx desc size\n"); return err; } @@ -97,10 +62,173 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev, phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed setting NPU wlan rro_ack_sn desc addr\n"); + "failed setting NPU wlan tx desc addr\n"); return err; } + return 0; +} + +static int mt7996_npu_txrx_offload_init(struct mt7996_dev *dev, + struct airoha_npu *npu) +{ + u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; + phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; + u32 dma_addr; + int err; + + /* npu rx rro ring0 */ + err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_DESC, + MT7996_RX_RING_SIZE, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan rx desc size\n"); + return err; + } + + /* npu rx rro ring1 */ + err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_DESC, + MT7996_NPU_RX_RING_SIZE, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan rx desc size\n"); + return err; + } + + /* msdu pg 2GHz */ + dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0) + 0xa0; + err = mt76_npu_send_msg(npu, 5, WLAN_FUNC_SET_WAIT_PCIE_ADDR, + dma_addr, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan PCIe desc addr\n"); + return err; + } + + err = mt76_npu_send_msg(npu, 5, WLAN_FUNC_SET_WAIT_DESC, + MT7996_NPU_RX_RING_SIZE / 4, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan rx desc size\n"); + return err; + } + + /* msdu pg 5GHz */ + dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1) + 0xb0; + err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_PCIE_ADDR, + dma_addr, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan PCIe desc addr\n"); + return err; + } + + err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_DESC, + MT7996_NPU_RX_RING_SIZE / 2, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan rx desc size\n"); + return err; + } + + /* msdu pg 6GHz */ + dma_addr = phy_addr + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2) + 0xc0; + err = mt76_npu_send_msg(npu, 7, WLAN_FUNC_SET_WAIT_PCIE_ADDR, + dma_addr, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan PCIe desc addr\n"); + return err; + } + + err = mt76_npu_send_msg(npu, 7, WLAN_FUNC_SET_WAIT_DESC, + MT7996_NPU_RX_RING_SIZE, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan rx desc size\n"); + return err; + } + + /* ind cmd ring */ + err = mt76_npu_send_msg(npu, 8, WLAN_FUNC_SET_WAIT_PCIE_ADDR, + phy_addr + MT_RXQ_RRO_IND_RING_BASE, + GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan PCIe desc addr\n"); + return err; + } + + err = mt76_npu_send_msg(npu, 8, WLAN_FUNC_SET_WAIT_DESC, + MT7996_RX_RING_SIZE, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan rx desc size\n"); + return err; + } + + err = mt76_npu_send_msg(npu, 3, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, + phy_addr + MT_RRO_ACK_SN_CTRL, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan tx desc addr\n"); + return err; + } + + /* npu tx */ + dma_addr = phy_addr + MT_TXQ_RING_BASE(1) + 0x120; + err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, + dma_addr, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan tx desc addr\n"); + return err; + } + + dma_addr = phy_addr + MT_TXQ_RING_BASE(0) + 0x150 + hif1_ofs; + err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_TX_RING_PCIE_ADDR, + dma_addr, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan tx desc addr\n"); + return err; + } + + return 0; +} + +static int mt7996_npu_offload_init(struct mt7996_dev *dev, + struct airoha_npu *npu) +{ + u32 val; + int err; + + err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_NPU_VERSION, + &val, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, "failed getting NPU fw version\n"); + return err; + } + + dev_info(dev->mt76.dev, "NPU version: %0d.%d\n", + (val >> 16) & 0xffff, val & 0xffff); + + err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_PORT_TYPE, + dev->mt76.mmio.npu_type, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan PCIe port type\n"); + return err; + } + + if (is_mt7996(&dev->mt76)) + err = mt7996_npu_txrx_offload_init(dev, npu); + else + err = mt7992_npu_txrx_offload_init(dev, npu); + + if (err) + return err; + err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_TOKEN_ID_SIZE, MT7996_HW_TOKEN_SIZE, GFP_KERNEL); if (err) @@ -111,6 +239,41 @@ static int mt7996_npu_offload_init(struct mt7996_dev *dev, return 0; } +static int mt7992_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) +{ + u32 val; + int err; + + err = mt76_npu_get_msg(npu, 0, WLAN_FUNC_GET_WAIT_RXDESC_BASE, + &val, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed retrieving NPU wlan rx ring0 addr\n"); + return err; + } + writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base); + + err = mt76_npu_get_msg(npu, 1, WLAN_FUNC_GET_WAIT_RXDESC_BASE, + &val, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed retrieving NPU wlan rx ring1 addr\n"); + return err; + } + writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND1].regs->desc_base); + + err = mt76_npu_get_msg(npu, 9, WLAN_FUNC_GET_WAIT_RXDESC_BASE, + &val, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed retrieving NPU wlan rxdmad_c ring addr\n"); + return err; + } + writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_RXDMAD_C].regs->desc_base); + + return 0; +} + static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) { u32 val; @@ -125,80 +288,107 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu) } writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base); - err = mt76_npu_get_msg(npu, 1, WLAN_FUNC_GET_WAIT_RXDESC_BASE, + err = mt76_npu_get_msg(npu, 2, WLAN_FUNC_GET_WAIT_RXDESC_BASE, &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan rx ring1 addr\n"); + "failed retriving NPU wlan rx ring2 addr\n"); return err; } - writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND1].regs->desc_base); + writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2].regs->desc_base); - err = mt76_npu_get_msg(npu, 9, WLAN_FUNC_GET_WAIT_RXDESC_BASE, + /* msdu pg ring */ + err = mt76_npu_get_msg(npu, 10, WLAN_FUNC_GET_WAIT_RXDESC_BASE, &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan rxdmad_c ring addr\n"); + "failed retriving NPU wlan msdu pg ring addr\n"); return err; } - writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_RXDMAD_C].regs->desc_base); + writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND0].regs->desc_base); + + err = mt76_npu_get_msg(npu, 11, WLAN_FUNC_GET_WAIT_RXDESC_BASE, + &val, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed retriving NPU wlan msdu pg ring addr\n"); + return err; + } + writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND1].regs->desc_base); + + err = mt76_npu_get_msg(npu, 12, WLAN_FUNC_GET_WAIT_RXDESC_BASE, + &val, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed retriving NPU wlan msdu pg ring addr\n"); + return err; + } + writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND2].regs->desc_base); + + /* ind_cmd ring */ + err = mt76_npu_get_msg(npu, 8, WLAN_FUNC_GET_WAIT_RXDESC_BASE, + &val, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed retriving NPU wlan ind_cmd ring addr\n"); + return err; + } + writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_IND].regs->desc_base); return 0; } static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu) { - int i, err; + const enum mt76_band_id band_list[] = { + MT_BAND0, + is_mt7996(&dev->mt76) ? MT_BAND2 : MT_BAND1, + }; + int i, index = 0; - for (i = MT_BAND0; i < MT_BAND2; i++) { - dma_addr_t dma_addr; + BUILD_BUG_ON(ARRAY_SIZE(band_list) * 3 != + ARRAY_SIZE(dev->npu_txd_addr)); + + for (i = 0; i < ARRAY_SIZE(band_list); i++) { + int err, band = band_list[i], phy_id; u32 val; - err = mt76_npu_get_msg(npu, i + 5, + err = mt76_npu_get_msg(npu, band + 5, WLAN_FUNC_GET_WAIT_RXDESC_BASE, &val, GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, - "failed retriving NPU wlan tx ring addr\n"); + "failed retrieving NPU wlan tx ring addr\n"); return err; } - writel(val, &dev->mt76.phys[i]->q_tx[0]->regs->desc_base); - if (!dmam_alloc_coherent(dev->mt76.dma_dev, - 256 * MT7996_TX_RING_SIZE, - &dma_addr, GFP_KERNEL)) - return -ENOMEM; + phy_id = is_mt7996(&dev->mt76) ? band == MT_BAND0 ? 1 : 0 + : band; + writel(val, &dev->mt76.phys[phy_id]->q_tx[0]->regs->desc_base); - err = mt76_npu_send_msg(npu, i, + err = mt76_npu_send_msg(npu, band, WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, - dma_addr, GFP_KERNEL); + dev->npu_txd_addr[index++], GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, "failed setting NPU wlan queue buf addr\n"); return err; } - if (!dmam_alloc_coherent(dev->mt76.dma_dev, - 256 * MT7996_TX_RING_SIZE, - &dma_addr, GFP_KERNEL)) - return -ENOMEM; - - err = mt76_npu_send_msg(npu, i + 5, + err = mt76_npu_send_msg(npu, band + 5, WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, - dma_addr, GFP_KERNEL); + dev->npu_txd_addr[index++], + GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, "failed setting NPU wlan tx buf addr\n"); return err; } - if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * 1024, - &dma_addr, GFP_KERNEL)) - return -ENOMEM; - - err = mt76_npu_send_msg(npu, i + 10, + err = mt76_npu_send_msg(npu, band + 10, WLAN_FUNC_SET_WAIT_TX_BUF_SPACE_HW_BASE, - dma_addr, GFP_KERNEL); + dev->npu_txd_addr[index++], + GFP_KERNEL); if (err) { dev_warn(dev->mt76.dev, "failed setting NPU wlan tx buf base\n"); @@ -212,8 +402,9 @@ static int mt7996_npu_txd_init(struct mt7996_dev *dev, struct airoha_npu *npu) static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, struct airoha_npu *npu) { - struct mt76_queue *q = &dev->mt76.q_rx[MT_RXQ_MAIN_WA]; + int qid = is_mt7996(&dev->mt76) ? MT_RXQ_TXFREE_BAND0 : MT_RXQ_MAIN_WA; phys_addr_t phy_addr = dev->mt76.mmio.phy_addr; + struct mt76_queue *q = &dev->mt76.q_rx[qid]; int err; err = mt76_npu_send_msg(npu, 0, @@ -233,7 +424,8 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, return err; } - phy_addr += MT_RXQ_RING_BASE(MT_RXQ_MAIN_WA) + 0x20; + phy_addr += MT_RXQ_RING_BASE(qid); + phy_addr += is_mt7996(&dev->mt76) ? 0x90 : 0x20; err = mt76_npu_send_msg(npu, 10, WLAN_FUNC_SET_WAIT_PCIE_ADDR, phy_addr, GFP_KERNEL); if (err) @@ -242,11 +434,54 @@ static int mt7996_npu_rx_event_init(struct mt7996_dev *dev, return err; } +static int mt7996_npu_set_pcie_addr(struct mt7996_dev *dev, + struct airoha_npu *npu) +{ + u32 hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; + dma_addr_t dma_addr = dev->mt76.mmio.phy_addr; + int err; + + dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0) + 0x80; + err = mt76_npu_send_msg(npu, 0, WLAN_FUNC_SET_WAIT_PCIE_ADDR, + dma_addr, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan PCIe desc addr\n"); + return err; + } + + dma_addr = dev->mt76.mmio.phy_addr + hif1_ofs; + if (is_mt7996(&dev->mt76)) { + dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + 0x60; + err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_PCIE_ADDR, + dma_addr, GFP_KERNEL); + } else { + dma_addr += MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND1) + 0x90; + err = mt76_npu_send_msg(npu, 1, WLAN_FUNC_SET_WAIT_PCIE_ADDR, + dma_addr, GFP_KERNEL); + } + + if (err) + dev_warn(dev->mt76.dev, + "failed setting NPU wlan PCIe desc addr\n"); + + return err; +} + static int mt7996_npu_tx_done_init(struct mt7996_dev *dev, struct airoha_npu *npu) { int err; + /* rro ring cpu idx */ + err = mt76_npu_send_msg(npu, 15, WLAN_FUNC_SET_WAIT_PCIE_ADDR, + 0, GFP_KERNEL); + if (err) { + dev_warn(dev->mt76.dev, + "failed setting NPU wlan PCIe desc addr\n"); + return err; + } + err = mt76_npu_send_msg(npu, 2, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, 0, GFP_KERNEL); if (err) { @@ -278,40 +513,79 @@ int mt7996_npu_rx_queues_init(struct mt7996_dev *dev) &dev->mt76.q_rx[MT_RXQ_NPU1]); } -int mt7996_npu_hw_init(struct mt7996_dev *dev) +int __mt7996_npu_hw_init(struct mt7996_dev *dev) { struct airoha_npu *npu; - int i, err = 0; - - mutex_lock(&dev->mt76.mutex); + int i, err; npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); if (!npu) - goto unlock; + return 0; err = mt7996_npu_offload_init(dev, npu); if (err) - goto unlock; + return err; + + if (is_mt7996(&dev->mt76)) + err = mt7996_npu_rxd_init(dev, npu); + else + err = mt7992_npu_rxd_init(dev, npu); - err = mt7996_npu_rxd_init(dev, npu); if (err) - goto unlock; + return err; err = mt7996_npu_txd_init(dev, npu); if (err) - goto unlock; + return err; err = mt7996_npu_rx_event_init(dev, npu); if (err) - goto unlock; + return err; + + err = mt7996_npu_set_pcie_addr(dev, npu); + if (err) + return err; err = mt7996_npu_tx_done_init(dev, npu); if (err) - goto unlock; + return err; for (i = MT_RXQ_NPU0; i <= MT_RXQ_NPU1; i++) airoha_npu_wlan_enable_irq(npu, i - MT_RXQ_NPU0); -unlock: + + return 0; +} + +int mt7996_npu_hw_init(struct mt7996_dev *dev) +{ + int i, err; + + BUILD_BUG_ON(ARRAY_SIZE(dev->npu_txd_addr) % 3); + + for (i = 0; i < ARRAY_SIZE(dev->npu_txd_addr); i += 3) { + int band = i && is_mt7996(&dev->mt76) ? MT_BAND2 : MT_BAND0; + u32 size = is_mt7996(&dev->mt76) ? band == MT_BAND2 + ? MT7996_NPU_TX_RING_SIZE + : MT7996_NPU_RX_RING_SIZE / 2 + : MT7996_TX_RING_SIZE; + + if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * size, + &dev->npu_txd_addr[i], GFP_KERNEL)) + return -ENOMEM; + + if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * size, + &dev->npu_txd_addr[i + 1], + GFP_KERNEL)) + return -ENOMEM; + + if (!dmam_alloc_coherent(dev->mt76.dma_dev, 256 * 1024, + &dev->npu_txd_addr[i + 2], + GFP_KERNEL)) + return -ENOMEM; + } + + mutex_lock(&dev->mt76.mutex); + err = __mt7996_npu_hw_init(dev); mutex_unlock(&dev->mt76.mutex); return err; @@ -320,33 +594,38 @@ int mt7996_npu_hw_init(struct mt7996_dev *dev) int mt7996_npu_hw_stop(struct mt7996_dev *dev) { struct airoha_npu *npu; - int i, err; + int i, err = 0; u32 info; + mutex_lock(&dev->mt76.mutex); + npu = rcu_dereference_protected(dev->mt76.mmio.npu, &dev->mt76.mutex); if (!npu) - return 0; + goto unlock; err = mt76_npu_send_msg(npu, 4, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, 0, GFP_KERNEL); if (err) - return err; + goto unlock; for (i = 0; i < 10; i++) { err = mt76_npu_get_msg(npu, 3, WLAN_FUNC_GET_WAIT_NPU_INFO, &info, GFP_KERNEL); - if (err) - continue; + if (!err && !info) + break; - if (info) { - err = -ETIMEDOUT; - continue; - } + err = -ETIMEDOUT; + usleep_range(10000, 15000); } if (!err) err = mt76_npu_send_msg(npu, 6, WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, 0, GFP_KERNEL); + else + dev_err(dev->mt76.dev, "npu stop failed\n"); +unlock: + mutex_unlock(&dev->mt76.mutex); + return err; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index e48e0e575b64..c6379933b6c3 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -159,6 +159,9 @@ enum offs_rev { #define MT_MDP_BASE 0x820cc000 #define MT_MDP(ofs) (MT_MDP_BASE + (ofs)) +#define MT_MDP_DCR0 MT_MDP(0x800) +#define MT_MDP_DCR0_RX_HDR_TRANS_EN BIT(19) + #define MT_MDP_DCR2 MT_MDP(0x8e8) #define MT_MDP_DCR2_RX_TRANS_SHORT BIT(2) @@ -733,7 +736,15 @@ enum offs_rev { #define MT_HW_REV 0x70010204 #define MT_HW_REV1 0x8a00 +#define MT_WF_L05_RST 0x70028550 +#define MT_WF_L05_RST_WF_RST_MASK GENMASK(4, 0) + #define MT_WF_SUBSYS_RST 0x70028600 +#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST BIT(0) +#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT BIT(5) +#define MT_WF_SUBSYS_RST_BYPASS_WFDMA_SLP_PROT BIT(6) +#define MT_WF_SUBSYS_RST_BYPASS_WFDMA2_SLP_PROT BIT(16) +#define MT_WF_SUBSYS_RST_WHOLE_PATH_RST_REVERT_CYCLE GENMASK(15, 8) /* PCIE MAC */ #define MT_PCIE_MAC_BASE 0x74030000 diff --git a/drivers/net/wireless/mediatek/mt76/npu.c b/drivers/net/wireless/mediatek/mt76/npu.c index ec36975f6dc9..c4c7c0af6321 100644 --- a/drivers/net/wireless/mediatek/mt76/npu.c +++ b/drivers/net/wireless/mediatek/mt76/npu.c @@ -390,6 +390,36 @@ int mt76_npu_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, } EXPORT_SYMBOL_GPL(mt76_npu_net_setup_tc); +int mt76_npu_send_txrx_addr(struct mt76_dev *dev, int ifindex, + u32 direction, u32 i_count_addr, + u32 o_status_addr, u32 o_count_addr) +{ + struct { + __le32 dir; + __le32 in_count_addr; + __le32 out_status_addr; + __le32 out_count_addr; + } info = { + .dir = cpu_to_le32(direction), + .in_count_addr = cpu_to_le32(i_count_addr), + .out_status_addr = cpu_to_le32(o_status_addr), + .out_count_addr = cpu_to_le32(o_count_addr), + }; + struct airoha_npu *npu; + int err = -ENODEV; + + rcu_read_lock(); + npu = rcu_dereference(dev->mmio.npu); + if (npu) + err = airoha_npu_wlan_send_msg(npu, ifindex, + WLAN_FUNC_SET_WAIT_INODE_TXRX_REG_ADDR, + &info, sizeof(info), GFP_ATOMIC); + rcu_read_unlock(); + + return err; +} +EXPORT_SYMBOL_GPL(mt76_npu_send_txrx_addr); + void mt76_npu_disable_irqs(struct mt76_dev *dev) { struct airoha_npu *npu; @@ -420,10 +450,6 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type) struct airoha_npu *npu; int err = 0; - /* NPU offloading is only supported by MT7992 */ - if (!is_mt7992(dev)) - return 0; - mutex_lock(&dev->mutex); npu = airoha_npu_get(dev->dev); @@ -456,7 +482,8 @@ int mt76_npu_init(struct mt76_dev *dev, phys_addr_t phy_addr, int type) dev->mmio.phy_addr = phy_addr; dev->mmio.npu_type = type; /* NPU offloading requires HW-RRO for RX packet reordering. */ - dev->hwrro_mode = MT76_HWRRO_V3_1; + dev->hwrro_mode = is_mt7996(dev) ? MT76_HWRRO_V3 : MT76_HWRRO_V3_1; + dev->rx_token_size = 32768; rcu_assign_pointer(dev->mmio.npu, npu); rcu_assign_pointer(dev->mmio.ppe_dev, ppe_dev); diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c index ff9176cdee3d..fbc10c9657cf 100644 --- a/drivers/net/wireless/mediatek/mt76/scan.c +++ b/drivers/net/wireless/mediatek/mt76/scan.c @@ -16,9 +16,11 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) clear_bit(MT76_SCANNING, &phy->state); - if (dev->scan.chan && phy->main_chandef.chan && - !test_bit(MT76_MCU_RESET, &dev->phy.state)) + if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel && + !test_bit(MT76_MCU_RESET, &dev->phy.state)) { mt76_set_channel(phy, &phy->main_chandef, false); + mt76_offchannel_notify(phy, false); + } mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); memset(&dev->scan, 0, sizeof(dev->scan)); if (!test_bit(MT76_MCU_RESET, &dev->phy.state)) @@ -27,6 +29,10 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) 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); + cancel_delayed_work_sync(&dev->scan_work); mt76_scan_complete(dev, true); } @@ -79,6 +85,27 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) rcu_read_unlock(); } +void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan) +{ + struct mt76_phy *phy; + + 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) + goto out; + + dev->scan.beacon_received = true; + ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0); + +out: + spin_unlock(&dev->scan_lock); +} + void mt76_scan_work(struct work_struct *work) { struct mt76_dev *dev = container_of(work, struct mt76_dev, @@ -87,35 +114,60 @@ void mt76_scan_work(struct work_struct *work) 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; + if (!phy || !req) + return; + + spin_lock_bh(&dev->scan_lock); + beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received; + dev->scan.beacon_wait = false; + spin_unlock_bh(&dev->scan_lock); + + if (beacon_rx) + goto probe; + if (dev->scan.chan_idx >= req->n_channels) { mt76_scan_complete(dev, false); return; } - if (dev->scan.chan && phy->num_sta) { + if (dev->scan.chan && phy->num_sta && phy->offchannel) { dev->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++]; - cfg80211_chandef_create(&chandef, dev->scan.chan, NL80211_CHAN_HT20); - mt76_set_channel(phy, &chandef, true); + offchannel = mt76_offchannel_chandef(phy, dev->scan.chan, &chandef); - if (!req->n_ssids || - chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) + if (offchannel) + mt76_offchannel_notify(phy, true); + mt76_set_channel(phy, &chandef, offchannel); + + if (!req->n_ssids) goto out; - duration = HZ / 16; /* ~60 ms */ + 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; + spin_unlock_bh(&dev->scan_lock); + goto out; + } + +probe: + if (phy->offchannel) + duration = HZ / 16; /* ~60 ms */ local_bh_disable(); for (i = 0; i < req->n_ssids; i++) mt76_scan_send_probe(dev, &req->ssids[i]); local_bh_enable(); out: - if (dev->scan.chan) + if (dev->scan.chan && phy->offchannel) duration = max_t(int, duration, msecs_to_jiffies(req->duration + (req->duration >> 5))); diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index 9ec6d0b53a84..22f9690634c9 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -227,7 +227,9 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_sta *sta; int pending; + int i; if (!wcid || info->tx_time_est) return; @@ -235,6 +237,17 @@ mt76_tx_check_non_aql(struct mt76_dev *dev, struct mt76_wcid *wcid, pending = atomic_dec_return(&wcid->non_aql_packets); if (pending < 0) atomic_cmpxchg(&wcid->non_aql_packets, pending, 0); + + sta = wcid_to_sta(wcid); + if (!sta || pending != MT_MAX_NON_AQL_PKT - 1) + return; + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) { + if (!sta->txq[i]) + continue; + + ieee80211_schedule_txq(dev->hw, sta->txq[i]); + } } void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *skb, @@ -542,6 +555,9 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) continue; + if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) + continue; + phy = mt76_dev_phy(dev, wcid->phy_idx); if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) continue; @@ -616,7 +632,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, if ((dev->drv->drv_flags & MT_DRV_HW_MGMT_TXQ) && !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) && - !ieee80211_is_data(hdr->frame_control) && + !ieee80211_is_data_present(hdr->frame_control) && (!ieee80211_is_bufferable_mmpdu(skb) || ieee80211_is_deauth(hdr->frame_control) || head == &wcid->tx_offchannel)) @@ -644,7 +660,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, return ret; } -static void mt76_txq_schedule_pending(struct mt76_phy *phy) +void mt76_txq_schedule_pending(struct mt76_phy *phy) { LIST_HEAD(tx_list); int ret = 0; @@ -850,9 +866,15 @@ int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi) token = idr_alloc(&dev->token, *ptxwi, dev->token_start, dev->token_start + dev->token_size, GFP_ATOMIC); - if (token >= dev->token_start) + if (token >= dev->token_start) { dev->token_count++; + if ((*ptxwi)->qid == MT_TXQ_PSD) { + struct mt76_phy *mphy = mt76_dev_phy(dev, (*ptxwi)->phy_idx); + atomic_inc(&mphy->mgmt_tx_pending); + } + } + #ifdef CONFIG_NET_MEDIATEK_SOC_WED if (mtk_wed_device_active(&dev->mmio.wed) && token >= dev->mmio.wed.wlan.token_start) @@ -897,6 +919,12 @@ mt76_token_release(struct mt76_dev *dev, int token, bool *wake) if (txwi) { dev->token_count--; + if (txwi->qid == MT_TXQ_PSD) { + struct mt76_phy *mphy = mt76_dev_phy(dev, txwi->phy_idx); + if (atomic_dec_and_test(&mphy->mgmt_tx_pending)) + wake_up(&dev->tx_wait); + } + #ifdef CONFIG_NET_MEDIATEK_SOC_WED if (mtk_wed_device_active(&dev->mmio.wed) && token >= dev->mmio.wed.wlan.token_start && diff --git a/drivers/net/wireless/mediatek/mt7601u/mcu.c b/drivers/net/wireless/mediatek/mt7601u/mcu.c index 1b5cc271a9e1..bad6ca821400 100644 --- a/drivers/net/wireless/mediatek/mt7601u/mcu.c +++ b/drivers/net/wireless/mediatek/mt7601u/mcu.c @@ -403,12 +403,18 @@ mt7601u_upload_firmware(struct mt7601u_dev *dev, const struct mt76_fw *fw) return ret; } +static const char * const mt7601u_fw_paths[] = { + "mediatek/" MT7601U_FIRMWARE, + MT7601U_FIRMWARE, +}; + static int mt7601u_load_firmware(struct mt7601u_dev *dev) { const struct firmware *fw; const struct mt76_fw_header *hdr; int len, ret; u32 val; + int i; mt7601u_wr(dev, MT_USB_DMA_CFG, (MT_USB_DMA_CFG_RX_BULK_EN | MT_USB_DMA_CFG_TX_BULK_EN)); @@ -416,7 +422,14 @@ static int mt7601u_load_firmware(struct mt7601u_dev *dev) if (firmware_running(dev)) return firmware_request_cache(dev->dev, MT7601U_FIRMWARE); - ret = request_firmware(&fw, MT7601U_FIRMWARE, dev->dev); + /* Try loading firmware from multiple locations */ + fw = NULL; + for (i = 0; i < MT7601U_FIRMWARE_PATHS; i++) { + ret = request_firmware(&fw, mt7601u_fw_paths[i], dev->dev); + if (ret == 0) + break; + } + if (ret) return ret; diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.h b/drivers/net/wireless/mediatek/mt7601u/usb.h index 9fdf35970339..723025f84483 100644 --- a/drivers/net/wireless/mediatek/mt7601u/usb.h +++ b/drivers/net/wireless/mediatek/mt7601u/usb.h @@ -9,6 +9,7 @@ #include "mt7601u.h" #define MT7601U_FIRMWARE "mt7601u.bin" +#define MT7601U_FIRMWARE_PATHS ARRAY_SIZE(mt7601u_fw_paths) #define MT_VEND_REQ_MAX_RETRY 10 #define MT_VEND_REQ_TOUT_MS 300