diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c index 6edcb3b8f279..28ad7bcaffd4 100644 --- a/drivers/net/wireless/mediatek/mt76/channel.c +++ b/drivers/net/wireless/mediatek/mt76/channel.c @@ -186,68 +186,74 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw, int n_vifs, enum ieee80211_chanctx_switch_mode mode) { - struct mt76_chanctx *old_ctx = (struct mt76_chanctx *)vifs->old_ctx->drv_priv; - struct mt76_chanctx *new_ctx = (struct mt76_chanctx *)vifs->new_ctx->drv_priv; - struct ieee80211_chanctx_conf *conf = vifs->new_ctx; - struct mt76_phy *old_phy = old_ctx->phy; - struct mt76_phy *phy = hw->priv; + struct ieee80211_vif_chanctx_switch *v; + struct mt76_chanctx *old_ctx, *new_ctx; + struct mt76_phy *old_phy, *phy = hw->priv; struct mt76_dev *dev = phy->dev; struct mt76_vif_link *mlink; - bool update_chan; + bool need_update[__MT_MAX_BAND] = {}; int i, ret = 0; - if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS) - phy = new_ctx->phy = dev->band_phys[conf->def.chan->band]; - else - phy = new_ctx->phy; - if (!phy) - return -EINVAL; + for (i = 0; i < n_vifs; i++) { + v = &vifs[i]; + new_ctx = (struct mt76_chanctx *)v->new_ctx->drv_priv; + if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS) + phy = new_ctx->phy = dev->band_phys[v->new_ctx->def.chan->band]; + else + phy = new_ctx->phy; - update_chan = phy->chanctx != new_ctx; - if (update_chan) { - if (dev->scan.phy == phy) - mt76_abort_scan(dev); + if (!phy) + return -EINVAL; - cancel_delayed_work_sync(&phy->mac_work); + if (need_update[phy->band_idx]) + continue; + + if (phy->chanctx != new_ctx) { + if (dev->scan.phy == phy) + mt76_abort_scan(dev); + + cancel_delayed_work_sync(&phy->mac_work); + need_update[phy->band_idx] = true; + } } mutex_lock(&dev->mutex); - if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS && - phy != old_phy && old_phy->chanctx == old_ctx) - old_phy->chanctx = NULL; - - if (update_chan) - ret = mt76_phy_update_channel(phy, vifs->new_ctx); - - if (ret) - goto out; - - if (old_phy == phy) - goto skip_link_replace; - for (i = 0; i < n_vifs; i++) { - mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf); + v = &vifs[i]; + old_ctx = (struct mt76_chanctx *)v->old_ctx->drv_priv; + old_phy = old_ctx->phy; + + new_ctx = (struct mt76_chanctx *)v->new_ctx->drv_priv; + phy = new_ctx->phy; + + if (mode == CHANCTX_SWMODE_SWAP_CONTEXTS && old_phy->chanctx && + old_phy->chanctx == old_ctx && phy != old_phy) + old_phy->chanctx = NULL; + + if (need_update[phy->band_idx]) { + ret = mt76_phy_update_channel(phy, v->new_ctx); + if (ret) + goto out; + + need_update[phy->band_idx] = false; + } + + mlink = mt76_vif_conf_link(dev, v->vif, v->link_conf); if (!mlink) continue; - dev->drv->vif_link_remove(old_phy, vifs[i].vif, - vifs[i].link_conf, mlink); + if (old_phy != phy) { + dev->drv->vif_link_remove(old_phy, v->vif, v->link_conf, + mlink); - ret = dev->drv->vif_link_add(phy, vifs[i].vif, - vifs[i].link_conf, mlink); - if (ret) - goto out; + ret = dev->drv->vif_link_add(phy, v->vif, v->link_conf, + mlink); + if (ret) + goto out; + } - } - -skip_link_replace: - for (i = 0; i < n_vifs; i++) { - mlink = mt76_vif_conf_link(dev, vifs[i].vif, vifs[i].link_conf); - if (!mlink) - continue; - - mlink->ctx = vifs->new_ctx; + mlink->ctx = v->new_ctx; if (mlink->beacon_mon_interval) WRITE_ONCE(mlink->beacon_mon_last, jiffies); } diff --git a/drivers/net/wireless/mediatek/mt76/dma.c b/drivers/net/wireless/mediatek/mt76/dma.c index 322041859217..f695a1459606 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.c +++ b/drivers/net/wireless/mediatek/mt76/dma.c @@ -186,6 +186,18 @@ mt76_dma_queue_magic_cnt_init(struct mt76_dev *dev, struct mt76_queue *q) } } +/* A hung bus (e.g. after a PCIe AER error) reads 0xffffffff from every + * register, so clamp an out-of-range index to the fallback to keep it from + * corrupting q->head/q->tail. + */ +static int +mt76_dma_read_dma_idx(struct mt76_queue *q, int fallback) +{ + u32 idx = Q_READ(q, dma_idx); + + return idx < q->ndesc ? idx : fallback; +} + static void mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) { @@ -201,7 +213,8 @@ mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) } Q_WRITE(q, desc_base, q->desc_dma); - q->head = Q_READ(q, dma_idx); + + q->head = mt76_dma_read_dma_idx(q, 0); q->tail = q->head; } @@ -419,7 +432,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) if (flush) last = -1; else - last = Q_READ(q, dma_idx); + last = mt76_dma_read_dma_idx(q, -1); while (q->queued > 0 && q->tail != last) { mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry); @@ -432,7 +445,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) } if (!flush && q->tail == last) - last = Q_READ(q, dma_idx); + last = mt76_dma_read_dma_idx(q, -1); } spin_unlock_bh(&q->cleanup_lock); @@ -534,8 +547,13 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, t->ptr = NULL; mt76_put_rxwi(dev, t); - if (drop) +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + /* the WO MCU owns the RX path only on WED v2, on newer + * versions this buf1 bit carries no drop information + */ + if (drop && dev->mmio.wed.version == 2) *drop |= !!(buf1 & MT_DMA_CTL_WO_DROP); +#endif } else { dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0], SKB_WITH_OVERHEAD(q->buf_size), @@ -595,6 +613,15 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) return NULL; +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + /* on WED v3 the M_DONE bit signals that WED is done reading + * the txfree descriptor; WED v2 does not set it + */ + else if (dev->mmio.wed.version > 2 && + mt76_queue_is_wed_tx_free(q) && + !(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_M_DONE))) + return NULL; +#endif } done: q->tail = (q->tail + 1) % q->ndesc; @@ -625,8 +652,8 @@ mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q, buf.len = skb->len; spin_lock_bh(&q->lock); - mt76_dma_add_buf(dev, q, &buf, 1, tx_info, skb, NULL); - mt76_dma_kick_queue(dev, q); + if (mt76_dma_add_buf(dev, q, &buf, 1, tx_info, skb, NULL) >= 0) + mt76_dma_kick_queue(dev, q); spin_unlock_bh(&q->lock); return 0; @@ -977,23 +1004,24 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) struct sk_buff *skb; unsigned char *data; bool check_ddone = false; - bool allow_direct = !mt76_queue_is_wed_rx(q); + bool allow_direct = !mt76_queue_is_wed_rx(q) && + !mt76_queue_is_wed_rro_rxdmad_c(q); bool more; if ((q->flags & MT_QFLAG_WED_RRO_EN) || (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && mt76_queue_is_wed_tx_free(q))) { - dma_idx = Q_READ(q, dma_idx); + dma_idx = mt76_dma_read_dma_idx(q, q->tail); check_ddone = true; } while (done < budget) { bool drop = false; - u32 info; + u32 info = 0; if (check_ddone) { if (q->tail == dma_idx) - dma_idx = Q_READ(q, dma_idx); + dma_idx = mt76_dma_read_dma_idx(q, q->tail); if (q->tail == dma_idx) break; diff --git a/drivers/net/wireless/mediatek/mt76/dma.h b/drivers/net/wireless/mediatek/mt76/dma.h index 2a0226c83f3c..7694764febe7 100644 --- a/drivers/net/wireless/mediatek/mt76/dma.h +++ b/drivers/net/wireless/mediatek/mt76/dma.h @@ -5,13 +5,15 @@ #ifndef __MT76_DMA_H #define __MT76_DMA_H +#include + #define DMA_DUMMY_DATA ((void *)~0) #define MT_RING_SIZE 0x10 #define MT_DMA_CTL_SD_LEN1 GENMASK(13, 0) #define MT_DMA_CTL_LAST_SEC1 BIT(14) -#define MT_DMA_CTL_BURST BIT(15) +#define MT_DMA_CTL_M_DONE BIT(15) #define MT_DMA_CTL_SD_LEN0 GENMASK(29, 16) #define MT_DMA_CTL_LAST_SEC0 BIT(30) #define MT_DMA_CTL_DMA_DONE BIT(31) @@ -46,73 +48,75 @@ #define MT_FCE_INFO_LEN 4 #define MT_RX_RXWI_LEN 32 +static inline bool +mt76_dma_handle_read(struct mt76_queue *q, u32 offset, u32 *val) +{ #if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) + if (q->flags & MT_QFLAG_WED) { + *val = mtk_wed_device_reg_read(q->wed, q->wed_regs + offset); + + return true; + } +#endif +#if IS_ENABLED(CONFIG_MT76_NPU) + if (q->flags & MT_QFLAG_NPU) { + struct airoha_npu *npu; + + *val = 0; + rcu_read_lock(); + npu = rcu_dereference(q->dev->mmio.npu); + if (npu) + regmap_read(npu->regmap, q->wed_regs + offset, val); + rcu_read_unlock(); + + return true; + } +#endif + + return false; +} + +static inline bool +mt76_dma_handle_write(struct mt76_queue *q, u32 offset, u32 val) +{ +#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) + if (q->flags & MT_QFLAG_WED) { + mtk_wed_device_reg_write(q->wed, q->wed_regs + offset, val); + + return true; + } +#endif +#if IS_ENABLED(CONFIG_MT76_NPU) + if (q->flags & MT_QFLAG_NPU) { + struct airoha_npu *npu; + + rcu_read_lock(); + npu = rcu_dereference(q->dev->mmio.npu); + if (npu) + regmap_write(npu->regmap, q->wed_regs + offset, val); + rcu_read_unlock(); + + return true; + } +#endif + + return false; +} #define Q_READ(_q, _field) ({ \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ u32 _val; \ - if ((_q)->flags & MT_QFLAG_WED) \ - _val = mtk_wed_device_reg_read((_q)->wed, \ - ((_q)->wed_regs + \ - _offset)); \ - else \ + if (!mt76_dma_handle_read(_q, _offset, &_val)) \ _val = readl(&(_q)->regs->_field); \ _val; \ }) #define Q_WRITE(_q, _field, _val) do { \ u32 _offset = offsetof(struct mt76_queue_regs, _field); \ - if ((_q)->flags & MT_QFLAG_WED) \ - mtk_wed_device_reg_write((_q)->wed, \ - ((_q)->wed_regs + _offset), \ - _val); \ - else \ + if (!mt76_dma_handle_write(_q, _offset, _val)) \ writel(_val, &(_q)->regs->_field); \ } while (0) -#elif IS_ENABLED(CONFIG_MT76_NPU) - -#define Q_READ(_q, _field) ({ \ - u32 _offset = offsetof(struct mt76_queue_regs, _field); \ - u32 _val = 0; \ - if ((_q)->flags & MT_QFLAG_NPU) { \ - struct airoha_npu *npu; \ - \ - rcu_read_lock(); \ - npu = rcu_dereference(q->dev->mmio.npu); \ - if (npu) \ - regmap_read(npu->regmap, \ - ((_q)->wed_regs + _offset), &_val); \ - rcu_read_unlock(); \ - } else { \ - _val = readl(&(_q)->regs->_field); \ - } \ - _val; \ -}) - -#define Q_WRITE(_q, _field, _val) do { \ - u32 _offset = offsetof(struct mt76_queue_regs, _field); \ - if ((_q)->flags & MT_QFLAG_NPU) { \ - struct airoha_npu *npu; \ - \ - rcu_read_lock(); \ - npu = rcu_dereference(q->dev->mmio.npu); \ - if (npu) \ - regmap_write(npu->regmap, \ - ((_q)->wed_regs + _offset), _val); \ - rcu_read_unlock(); \ - } else { \ - writel(_val, &(_q)->regs->_field); \ - } \ -} while (0) - -#else - -#define Q_READ(_q, _field) readl(&(_q)->regs->_field) -#define Q_WRITE(_q, _field, _val) writel(_val, &(_q)->regs->_field) - -#endif - struct mt76_desc { __le32 buf0; __le32 ctrl; diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c index 13c4e8abe281..abbe65cbcd89 100644 --- a/drivers/net/wireless/mediatek/mt76/mac80211.c +++ b/drivers/net/wireless/mediatek/mt76/mac80211.c @@ -439,8 +439,9 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw) SET_IEEE80211_DEV(hw, dev->dev); SET_IEEE80211_PERM_ADDR(hw, phy->macaddr); - wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | - NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; + wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE; + if (!phy->no_active_monitor) + wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | WIPHY_FLAG_SUPPORTS_TDLS | WIPHY_FLAG_AP_UAPSD; @@ -681,6 +682,7 @@ mt76_alloc_device(struct device *pdev, unsigned int size, dev = hw->priv; dev->hw = hw; dev->dev = pdev; + dev->init_wiphy = NULL; dev->drv = drv_ops; dev->dma_dev = pdev; @@ -779,6 +781,12 @@ int mt76_register_device(struct mt76_dev *dev, bool vht, mt76_check_sband(&dev->phy, &phy->sband_5g, NL80211_BAND_5GHZ); mt76_check_sband(&dev->phy, &phy->sband_6g, NL80211_BAND_6GHZ); + if (dev->init_wiphy) { + ret = dev->init_wiphy(dev); + if (ret) + return ret; + } + if (IS_ENABLED(CONFIG_MT76_LEDS)) { ret = mt76_led_init(phy); if (ret) @@ -886,6 +894,7 @@ static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) struct sk_buff *skb = phy->rx_amsdu[q].head; struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; struct mt76_dev *dev = phy->dev; + struct mt76_queue *rxq = &dev->q_rx[q]; phy->rx_amsdu[q].head = NULL; phy->rx_amsdu[q].tail = NULL; @@ -914,6 +923,13 @@ static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q) return; } } + + /* RRO 3.0 data queue skbs are processed and completed in the context + * of the indicator queue NAPI, which only polls its own skb list + */ + if (mt76_queue_is_wed_rro_data(rxq) && dev->hwrro_mode == MT76_HWRRO_V3) + q = MT_RXQ_RRO_IND; + __skb_queue_tail(&dev->rx_skb[q], skb); } diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c index cbfb3bbec503..7149b2f7aafd 100644 --- a/drivers/net/wireless/mediatek/mt76/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mcu.c @@ -78,15 +78,19 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb, unsigned long expires; int ret, seq; - if (mt76_is_sdio(dev)) - if (test_bit(MT76_RESET, &dev->phy.state) && atomic_read(&dev->bus_hung)) - return -EIO; - if (ret_skb) *ret_skb = NULL; mutex_lock(&dev->mcu.mutex); + if ((mt76_is_mmio(dev) && atomic_read(&dev->bus_hung)) || + (mt76_is_sdio(dev) && test_bit(MT76_RESET, &dev->phy.state) && + atomic_read(&dev->bus_hung))) { + orig_skb = skb; + ret = -EIO; + goto out; + } + if (dev->mcu_ops->mcu_skb_prepare_msg) { orig_skb = skb; ret = dev->mcu_ops->mcu_skb_prepare_msg(dev, skb, cmd, &seq); diff --git a/drivers/net/wireless/mediatek/mt76/mmio.c b/drivers/net/wireless/mediatek/mt76/mmio.c index 05d74cd7248e..73d47608bf42 100644 --- a/drivers/net/wireless/mediatek/mt76/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mmio.c @@ -35,9 +35,16 @@ static void mt76_mmio_write_copy(struct mt76_dev *dev, u32 offset, { int i; - for (i = 0; i < ALIGN(len, 4); i += 4) + for (i = 0; i + 4 <= len; i += 4) writel(get_unaligned_le32(data + i), dev->mmio.regs + offset + i); + + if (i < len) { + u8 tmp[4] = {}; + + memcpy(tmp, data + i, len - i); + writel(get_unaligned_le32(tmp), dev->mmio.regs + offset + i); + } } static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset, @@ -45,9 +52,16 @@ static void mt76_mmio_read_copy(struct mt76_dev *dev, u32 offset, { int i; - for (i = 0; i < ALIGN(len, 4); i += 4) + for (i = 0; i + 4 <= len; i += 4) put_unaligned_le32(readl(dev->mmio.regs + offset + i), data + i); + + if (i < len) { + u8 tmp[4]; + + put_unaligned_le32(readl(dev->mmio.regs + offset + i), tmp); + memcpy(data + i, tmp, len - i); + } } static int mt76_mmio_wr_rp(struct mt76_dev *dev, u32 base, diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h index 3822eb8fd88f..62b41c8bb7c0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76.h +++ b/drivers/net/wireless/mediatek/mt76/mt76.h @@ -539,6 +539,7 @@ struct mt76_hw_cap { #define MT_DRV_HW_MGMT_TXQ BIT(4) #define MT_DRV_AMSDU_OFFLOAD BIT(5) #define MT_DRV_IGNORE_TXS_FAILED BIT(6) +#define MT_DRV_HW_PS_BUFFERING BIT(7) struct mt76_driver_ops { u32 drv_flags; @@ -672,6 +673,7 @@ struct mt76_usb { u8 out_ep[__MT_EP_OUT_MAX]; u8 in_ep[__MT_EP_IN_MAX]; + void (*ctrl_timeout)(struct mt76_dev *dev, int err); bool sg_en; struct mt76u_mcu { @@ -871,6 +873,7 @@ struct mt76_phy { struct cfg80211_chan_def main_chandef; bool offchannel; bool radar_enabled; + bool no_active_monitor; struct delayed_work roc_work; struct ieee80211_vif *roc_vif; @@ -940,6 +943,9 @@ struct mt76_dev { const struct mt76_bus_ops *bus; const struct mt76_driver_ops *drv; const struct mt76_mcu_ops *mcu_ops; + + /* Optional callback to finalize wiphy state before registration. */ + int (*init_wiphy)(struct mt76_dev *dev); struct device *dev; struct device *dma_dev; @@ -1537,6 +1543,8 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw, u16 tids, int nframes, enum ieee80211_frame_release_type reason, bool more_data); +void mt76_sta_ps_transition(struct mt76_dev *dev, struct mt76_wcid *wcid, + bool ps); bool mt76_has_tx_pending(struct mt76_phy *phy); int mt76_update_channel(struct mt76_phy *phy); void mt76_update_survey(struct mt76_phy *phy); @@ -2124,6 +2132,9 @@ mt76_vif_link(struct mt76_dev *dev, struct ieee80211_vif *vif, int link_id) if (!link_id) return mlink; + if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) + return NULL; + return mt76_dereference(mvif->link[link_id], dev); } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c index 300a7f9c2ef1..acca98139f92 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/beacon.c @@ -56,6 +56,7 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, MT_TX_HW_QUEUE_BCN)); if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) { dev->beacon_check = MT7603_WATCHDOG_TIMEOUT; + dev_kfree_skb(skb); goto out; } @@ -63,6 +64,7 @@ mt7603_update_beacon_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) FIELD_PREP(MT_DMA_FQCR0_TARGET_QID, MT_TX_HW_QUEUE_BMC)); if (!mt76_poll(dev, MT_DMA_FQCR0, MT_DMA_FQCR0_BUSY, 0, 5000)) { dev->beacon_check = MT7603_WATCHDOG_TIMEOUT; + dev_kfree_skb(skb); goto out; } diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c index 3a16851524a0..477a9b7a8cf7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/dma.c @@ -39,7 +39,6 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) val = le32_to_cpu(txd[1]); idx = FIELD_GET(MT_TXD1_WLAN_IDX, val); - skb->priority = FIELD_GET(MT_TXD1_TID, val); if (idx >= MT7603_WTBL_STA - 1) goto free; @@ -72,6 +71,7 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb) hwq = MT_TX_HW_QUEUE_MGMT; } + skb->priority = tid; ieee80211_sta_set_buffered(sta, tid, true); val = le32_to_cpu(txd[0]); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c index b89db2db6573..05f7aaefaf89 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/eeprom.c @@ -142,6 +142,7 @@ static int mt7603_check_eeprom(struct mt76_dev *dev) case 0x7628: case 0x7603: case 0x7600: + case 0x7592: return 0; default: return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c index d3110eeb45d7..fa0bf9a201ce 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c @@ -235,16 +235,17 @@ void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta, sta->smps = enabled; } -void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, - bool enabled) +static void +__mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, + bool enabled, bool filter) { int idx = sta->wcid.idx; u32 addr; - spin_lock_bh(&dev->ps_lock); + lockdep_assert_held(&dev->ps_lock); if (sta->ps == enabled) - goto out; + return; mt76_wr(dev, MT_PSE_RTA, FIELD_PREP(MT_PSE_RTA_TAG_ID, idx) | @@ -255,7 +256,7 @@ void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, mt76_poll(dev, MT_PSE_RTA, MT_PSE_RTA_BUSY, 0, 5000); - if (enabled) + if (enabled && filter) mt7603_filter_tx(dev, sta->vif->idx, idx, false); addr = mt7603_wtbl1_addr(idx); @@ -264,8 +265,34 @@ void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, enabled * MT_WTBL1_W3_POWER_SAVE); mt76_clear(dev, MT_WTBL1_OR, MT_WTBL1_OR_PSM_WRITE); sta->ps = enabled; +} -out: +void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, + bool enabled) +{ + spin_lock_bh(&dev->ps_lock); + __mt7603_wtbl_set_ps(dev, sta, enabled, enabled); + spin_unlock_bh(&dev->ps_lock); +} + +void mt7603_wtbl_sta_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, bool ps) +{ + spin_lock_bh(&dev->ps_lock); + sta->ps_sleeping = ps; + __mt7603_wtbl_set_ps(dev, sta, ps, ps); + spin_unlock_bh(&dev->ps_lock); +} + +void mt7603_wtbl_restore_ps(struct mt7603_dev *dev, struct mt7603_sta *sta) +{ + spin_lock_bh(&dev->ps_lock); + /* + * Frames that are already queued for the station belong to the service + * period that has just been served, so unlike on a sleep transition + * they must not be pulled back into the PS queue. + */ + if (sta->ps_sleeping) + __mt7603_wtbl_set_ps(dev, sta, true, false); spin_unlock_bh(&dev->ps_lock); } @@ -1816,6 +1843,39 @@ mt7603_false_cca_check(struct mt7603_dev *dev) mt7603_adjust_sensitivity(dev); } +/* + * Releasing buffered frames turns off the PSE redirect for a station, since + * the released frames would otherwise be looped back into the driver PS queue + * again. mac80211 never tells us when the service period is over, so hardware + * buffering has to be re-armed here for every station that is still known to + * be asleep. Waiting for the PSD queue to drain makes sure that the released + * frames have already passed the redirect stage. + */ +static void +mt7603_mac_ps_check(struct mt7603_dev *dev) +{ + int i; + + if (dev->mphy.q_tx[MT_TXQ_PSD]->queued) + return; + + rcu_read_lock(); + for (i = 0; i < MT7603_WTBL_STA; i++) { + struct mt76_wcid *wcid = mt76_wcid_ptr(dev, i); + struct mt7603_sta *msta; + + if (!wcid || !wcid->sta) + continue; + + msta = container_of(wcid, struct mt7603_sta, wcid); + if (msta->ps || !msta->ps_sleeping) + continue; + + mt7603_wtbl_restore_ps(dev, msta); + } + rcu_read_unlock(); +} + void mt7603_mac_work(struct work_struct *work) { struct mt7603_dev *dev = container_of(work, struct mt7603_dev, @@ -1830,6 +1890,7 @@ void mt7603_mac_work(struct work_struct *work) dev->mphy.mac_work_count++; mt76_update_survey(&dev->mphy); mt7603_edcca_check(dev); + mt7603_mac_ps_check(dev); for (i = 0, idx = 0; i < 2; i++) { u32 val = mt76_rr(dev, MT_TX_AGG_CNT(i)); diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c index 0f3a7508996c..757664e9e1f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c @@ -410,7 +410,7 @@ mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) struct sk_buff_head list; mt76_stop_tx_queues(&dev->mphy, sta, true); - mt7603_wtbl_set_ps(dev, msta, ps); + mt7603_wtbl_sta_ps(dev, msta, ps); if (ps) return; @@ -423,13 +423,33 @@ mt7603_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps) mt7603_ps_tx_list(dev, &list); } -static void -mt7603_ps_set_more_data(struct sk_buff *skb) +static struct ieee80211_hdr * +mt7603_ps_skb_hdr(struct sk_buff *skb) { - struct ieee80211_hdr *hdr; + return (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; +} - hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE]; - hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); +/* + * Buffered frames can be recycled into the PS queue by mt7603_filter_tx(), so + * both bits have to be assigned, not just set. + */ +static void +mt7603_ps_set_flags(struct sk_buff *skb, bool more_data, bool eosp) +{ + struct ieee80211_hdr *hdr = mt7603_ps_skb_hdr(skb); + + if (more_data) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_MOREDATA); + else + hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); + + if (!ieee80211_is_data_qos(hdr->frame_control)) + return; + + if (eosp) + *ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_EOSP; + else + *ieee80211_get_qos_ctl(hdr) &= ~IEEE80211_QOS_CTL_EOSP; } static void @@ -442,7 +462,12 @@ mt7603_release_buffered_frames(struct ieee80211_hw *hw, struct mt7603_dev *dev = hw->priv; struct mt7603_sta *msta = (struct mt7603_sta *)sta->drv_priv; struct sk_buff_head list; - struct sk_buff *skb, *tmp; + struct sk_buff *skb, *tmp, *last; + bool eosp_null, uapsd; + unsigned long drained; + u16 pending = 0; + u8 last_tid; + int i; __skb_queue_head_init(&list); @@ -458,20 +483,58 @@ mt7603_release_buffered_frames(struct ieee80211_hw *hw, skb_set_queue_mapping(skb, MT_TXQ_PSD); __skb_unlink(skb, &msta->psq); - mt7603_ps_set_more_data(skb); __skb_queue_tail(&list, skb); nframes--; } + + skb_queue_walk(&msta->psq, skb) + pending |= BIT(skb->priority); spin_unlock_bh(&dev->ps_lock); - if (!skb_queue_empty(&list)) - ieee80211_sta_eosp(sta); + /* + * Without this, mac80211 keeps the TIM bit set for the station and + * keeps routing every service period to the driver, even though there + * is nothing left to release. + */ + drained = tids & ~pending; + for_each_set_bit(i, &drained, IEEE80211_NUM_TIDS) + ieee80211_sta_set_buffered(sta, i, false); + + last = skb_peek_tail(&list); + if (!last) { + mt76_release_buffered_frames(hw, sta, tids, nframes, reason, + more_data); + return; + } + + /* + * End the service period here instead of passing the remaining frame + * budget on to mt76_release_buffered_frames(), which would signal the + * end of the same service period a second time. + */ + uapsd = reason == IEEE80211_FRAME_RELEASE_UAPSD; + more_data |= !!(pending & tids); + + skb_queue_walk(&list, skb) + mt7603_ps_set_flags(skb, skb != last || more_data, + skb == last && uapsd); + + /* + * EOSP lives in the QoS control field, so a bufferable MMPDU cannot + * terminate a U-APSD service period on its own. In that case mac80211 + * has to append a QoS-Null frame, which ends the SP through its tx + * status. + */ + eosp_null = uapsd && + !ieee80211_is_data_qos(mt7603_ps_skb_hdr(last)->frame_control); + last_tid = __fls(tids); mt7603_ps_tx_list(dev, &list); - if (nframes) - mt76_release_buffered_frames(hw, sta, tids, nframes, reason, - more_data); + if (eosp_null) + ieee80211_send_eosp_nullfunc(sta, last_tid); + else + ieee80211_sta_eosp(sta); } static int diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h index 071bfab3af7c..5b0ecd01aad9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h +++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h @@ -80,6 +80,7 @@ struct mt7603_sta { u8 smps; u8 ps; + u8 ps_sleeping; }; struct mt7603_vif { @@ -229,6 +230,9 @@ int mt7603_wtbl_set_key(struct mt7603_dev *dev, int wcid, struct ieee80211_key_conf *key); void mt7603_wtbl_set_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, bool enabled); +void mt7603_wtbl_sta_ps(struct mt7603_dev *dev, struct mt7603_sta *sta, + bool ps); +void mt7603_wtbl_restore_ps(struct mt7603_dev *dev, struct mt7603_sta *sta); void mt7603_wtbl_set_smps(struct mt7603_dev *dev, struct mt7603_sta *sta, bool enabled); void mt7603_filter_tx(struct mt7603_dev *dev, int mac_idx, int idx, bool abort); diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c index fc619acbb40d..67f56e428d9a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c @@ -1239,11 +1239,12 @@ static int mt7615_suspend(struct ieee80211_hw *hw, cancel_delayed_work_sync(&dev->pm.ps_work); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); + cancel_delayed_work_sync(&phy->scan_work); + cancel_delayed_work_sync(&phy->mt76->mac_work); + mt7615_mutex_acquire(dev); clear_bit(MT76_STATE_RUNNING, &phy->mt76->state); - cancel_delayed_work_sync(&phy->scan_work); - cancel_delayed_work_sync(&phy->mt76->mac_work); set_bit(MT76_STATE_SUSPEND, &phy->mt76->state); ieee80211_iterate_active_interfaces(hw, diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c index 53cb1eed1e4f..0aca590f2bae 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci_mac.c @@ -68,10 +68,11 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, int pid, id; u8 *txwi = (u8 *)txwi_ptr; struct mt76_txwi_cache *t; - struct mt7615_sta *msta; + struct mt7615_sta *msta = NULL; void *txp; - msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; + if (wcid && wcid->sta) + msta = container_of(wcid, struct mt7615_sta, wcid); if (!wcid) wcid = &dev->mt76.global_wcid; diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c index f4169de939c4..9525d8062b44 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb_sdio.c @@ -187,10 +187,11 @@ int mt7663_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, struct sk_buff *skb = tx_info->skb; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_key_conf *key = info->control.hw_key; - struct mt7615_sta *msta; + struct mt7615_sta *msta = NULL; int pad, err, pktid; - msta = wcid ? container_of(wcid, struct mt7615_sta, wcid) : NULL; + if (wcid && wcid->sta) + msta = container_of(wcid, struct mt7615_sta, wcid); if (!wcid) wcid = &dev->mt76.global_wcid; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h index 2aa6078993e9..b1677ca24703 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h @@ -48,6 +48,11 @@ enum rx_pkt_type { #define MT_TXD_LEN_MSDU_LAST BIT(14) #define MT_TXD_LEN_AMSDU_LAST BIT(15) +/* PCIE part */ +#define PCIE_AER_UNC_STATUS_OFFSET 0x204 +#define PCIE_AER_UNC_MASK_OFFSET 0x208 +#define PCIE_AER_CO_STATUS_OFFSET 0x210 + enum { CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20, CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40, @@ -174,7 +179,7 @@ extern const struct wiphy_wowlan_support mt76_connac_wowlan_support; static inline bool is_connac3(struct mt76_dev *dev) { - return mt76_chip(dev) == 0x7925 || mt76_chip(dev) == 0x7927; + return mt76_chip(dev) == 0x7925 || mt76_chip(dev) == 0x7927 || mt76_chip(dev) == 0x7928; } static inline bool is_mt7925(struct mt76_dev *dev) @@ -187,6 +192,11 @@ static inline bool is_mt7927(struct mt76_dev *dev) return mt76_chip(dev) == 0x7927; } +static inline bool is_mt7928(struct mt76_dev *dev) +{ + return mt76_chip(dev) == 0x7928; +} + static inline bool is_320mhz_supported(struct mt76_dev *dev) { return mt76_chip(dev) == 0x7927; @@ -245,7 +255,8 @@ static inline bool is_mt798x(struct mt76_dev *dev) static inline bool is_mt7996(struct mt76_dev *dev) { - return mt76_chip(dev) == 0x7990; + u16 chip = mt76_chip(dev); + return chip == 0x7990 || chip == 0x7991; } static inline bool is_mt7992(struct mt76_dev *dev) @@ -295,6 +306,7 @@ static inline bool is_mt76_fw_txp(struct mt76_dev *dev) case 0x7902: case 0x7925: case 0x7927: + case 0x7928: case 0x7663: case 0x7622: return false; diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h index 247e2e7a47d8..d2d63767bfd0 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac3_mac.h @@ -18,6 +18,11 @@ enum { MT_LMAC_PSMP0, }; +enum { + TXS_FM_MPDU = 0, + TXS_FM_PPDU = 2, +}; + #define MT_CT_PARSE_LEN 72 #define MT_CT_DMA_BUF_NUM 2 @@ -236,7 +241,9 @@ enum tx_frag_idx { #define MT_TXD2_HDR_PAD GENMASK(11, 10) #define MT_TXD2_RTS BIT(9) #define MT_TXD2_OWN_MAC_MAP BIT(8) +#define MT_TXD2_OWN_MAC_MAP_V2 BIT(9) #define MT_TXD2_BF_TYPE GENMASK(6, 7) +#define MT_TXD2_BF_TYPE_V2 GENMASK(6, 8) #define MT_TXD2_FRAME_TYPE GENMASK(5, 4) #define MT_TXD2_SUB_TYPE GENMASK(3, 0) @@ -261,6 +268,7 @@ enum tx_frag_idx { #define MT_TXD5_BYPASS_TBB BIT(14) #define MT_TXD5_BYPASS_RBB BIT(13) #define MT_TXD5_BSS_COLOR_ZERO BIT(12) +#define MT_TXD5_OCUP_BY_OTHER_LNK BIT(11) #define MT_TXD5_TX_STATUS_HOST BIT(10) #define MT_TXD5_TX_STATUS_MCU BIT(9) #define MT_TXD5_TX_STATUS_FMT BIT(8) @@ -270,15 +278,19 @@ enum tx_frag_idx { #define MT_TXD6_VTA BIT(28) #define MT_TXD6_FIXED_BW BIT(25) #define MT_TXD6_BW GENMASK(24, 22) +#define MT_TXD6_BW_V2 GENMASK(25, 22) #define MT_TXD6_TX_RATE GENMASK(21, 16) #define MT_TXD6_TIMESTAMP_OFS_EN BIT(15) +#define MT_TXD6_TIMESTAMP_OFS_EN_V2 GENMASK(15, 13) #define MT_TXD6_TIMESTAMP_OFS_IDX GENMASK(14, 10) +#define MT_TXD6_TIMESTAMP_OFS_IDX_V2 GENMASK(12, 8) #define MT_TXD6_TID_ADDBA GENMASK(10, 8) #define MT_TXD6_MSDU_CNT GENMASK(9, 4) #define MT_TXD6_MSDU_CNT_V2 GENMASK(15, 10) #define MT_TXD6_DIS_MAT BIT(3) #define MT_TXD6_DAS BIT(2) #define MT_TXD6_AMSDU_CAP BIT(1) +#define MT_TXD6_MLD BIT(0) #define MT_TXD7_TXD_LEN GENMASK(31, 30) #define MT_TXD7_IP_SUM BIT(29) @@ -287,6 +299,9 @@ enum tx_frag_idx { #define MT_TXD7_CTXD BIT(26) #define MT_TXD7_CTXD_CNT GENMASK(25, 22) #define MT_TXD7_UDP_TCP_SUM BIT(15) +#define MT_TXD7_IMMEDIATE_TX BIT(14) +#define MT_TXD7_FORCE_RTS_CTS BIT(13) +#define MT_TXD7_ENABLE_ICI BIT(12) #define MT_TXD7_TX_TIME GENMASK(9, 0) #define MT_TXD9_WLAN_IDX GENMASK(23, 8) @@ -397,4 +412,31 @@ enum tx_frag_idx { #define MT_TXS7_MPDU_RETRY_BYTE_SCALE BIT(15) #define MT_TXS7_MPDU_RETRY_BYTE GENMASK(14, 0) +struct mt7928_uni_txdone_event { + __le16 tag; + __le16 len; + + u8 pid; /* HW packet ID */ + u8 status; /* TX_RESULT_xx */ + __le16 seq; /* packet sequence number */ + + u8 wcid; /* WLAN index (WTBL) */ + u8 tx_count; /* TX attempts including retries */ + __le16 tx_rate; + + u8 flag; /* TXS_WITH_ADVANCED_INFO or TXS_IS_EXIST */ + u8 tid; + u8 rsp_rate; + u8 rate_tbl_idx; /* last TX rate index from WLAN table */ + + u8 bw; /* bandwidth used for this PPDU */ + u8 tx_pwr; /* dBm */ + u8 flush_reason; + u8 rsv[1]; + + __le32 tx_delay; /* unit: 32us, UMAC TX to TX status */ + __le32 timestamp; /* local TSF at first bit of MAC header */ + __le32 applied_flags; +} __packed; + #endif /* __MT76_CONNAC3_MAC_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c index fc9f782032ef..8a8d608dd56e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c @@ -1069,6 +1069,10 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev, bw = FIELD_GET(MT_CRXV_FRAME_MODE, v2); } + /* the hardware reports NSTS; report the data NSS for STBC frames */ + if (stbc && nss > 1) + nss >>= 1; + switch (*mode) { case MT_PHY_TYPE_CCK: cck = true; @@ -1114,7 +1118,7 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev, case IEEE80211_STA_RX_BW_20: break; case IEEE80211_STA_RX_BW_40: - if (*mode & MT_PHY_TYPE_HE_EXT_SU && + if (*mode == MT_PHY_TYPE_HE_EXT_SU && (idx & MT_PRXV_TX_ER_SU_106T)) { status->bw = RATE_INFO_BW_HE_RU; status->he_ru = @@ -1152,8 +1156,6 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) return; tid = le32_get_bits(txwi[1], MT_TXD1_TID); - if (tid >= 6) /* skip VO queue */ - return; val = le32_to_cpu(txwi[2]); fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 | diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 58b0b15e4fd6..2f925d22b9aa 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -67,7 +67,8 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) || (is_connac2(dev) && addr == 0x900000) || - (is_connac3(dev) && (addr == 0x900000 || addr == 0xe0002800)) || + ((is_mt7925(dev) || is_mt7927(dev)) && (addr == 0x900000 || addr == 0xe0002800)) || + (is_mt7928(dev) && (addr == 0x900000 || addr == 0xe0002000)) || (is_mt799x(dev) && addr == 0x900000)) cmd = MCU_CMD(PATCH_START_REQ); else @@ -77,6 +78,48 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, } EXPORT_SYMBOL_GPL(mt76_connac_mcu_init_download); +int mt76_connac_cb_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get) +{ + u8 op = get ? PATCH_SEM_GET : PATCH_SEM_RELEASE; + struct { + u8 op; + u8 reserved[3]; + } req = { + .op = op, + }; + + return mt76_mcu_send_msg(dev, MCU_CMD(CB_PATCH_SEM_CONTROL), + &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_cb_mcu_patch_sem_ctrl); + +int mt76_connac_cb_mcu_start_patch(struct mt76_dev *dev) +{ + struct { + __le32 reserved; + } req = { + .reserved = 0, + }; + + return mt76_mcu_send_msg(dev, MCU_CMD(CB_PATCH_FINISH_REQ), + &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_cb_mcu_start_patch); + +int mt76_connac_cb_mcu_init_download(struct mt76_dev *dev, u32 len) +{ + struct { + __le32 addr; + __le32 len; + } req = { + .addr = 0, /* addr is meaningless for cbmcu fwdl */ + .len = cpu_to_le32(len), + }; + + return mt76_mcu_send_msg(dev, MCU_CMD(CB_PATCH_START_REQ), &req, sizeof(req), true); +} +EXPORT_SYMBOL_GPL(mt76_connac_cb_mcu_init_download); + int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy) { int len, i, n_max_channels, n_2ch = 0, n_5ch = 0, n_6ch = 0; @@ -422,6 +465,10 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb, basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); basic->aid = cpu_to_le16(link_sta->sta->aid); break; + case NL80211_IFTYPE_NAN: + case NL80211_IFTYPE_NAN_DATA: + basic->conn_type = cpu_to_le32(CONNECTION_NAN); + break; default: WARN_ON(1); break; @@ -753,7 +800,7 @@ mt76_connac_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta) HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); he->dcm_rx_max_nss = HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); - he->dcm_rx_max_nss = + he->dcm_max_ru = HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); he->pkt_ext = 2; @@ -1217,6 +1264,11 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy, case NL80211_IFTYPE_ADHOC: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); break; + case NL80211_IFTYPE_NAN: + case NL80211_IFTYPE_NAN_DATA: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_NAN); + basic_req.basic.conn_state = !enable; + break; default: WARN_ON(1); break; @@ -1627,6 +1679,11 @@ int mt76_connac_mcu_uni_add_bss(struct mt76_phy *phy, case NL80211_IFTYPE_ADHOC: basic_req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); break; + case NL80211_IFTYPE_NAN: + case NL80211_IFTYPE_NAN_DATA: + basic_req.basic.conn_type = cpu_to_le32(CONNECTION_NAN); + basic_req.basic.active = enable; + break; default: WARN_ON(1); break; @@ -3044,6 +3101,57 @@ mt76_connac_mcu_send_ram_firmware(struct mt76_dev *dev, return mt76_connac_mcu_start_firmware(dev, override, option); } +static int +mt76_connac_mcu_send_phy_ram_firmware(struct mt76_dev *dev, + const struct mt76_connac2_fw_trailer *hdr, + const u8 *data) +{ + int i, offset = 0, max_len = mt76_is_sdio(dev) ? 2048 : 4096; + u32 override = 0, option = 0; + + for (i = 0; i < hdr->n_region; i++) { + const struct mt76_connac2_fw_region *region; + u32 len, addr, mode; + int err; + + region = (const void *)((const u8 *)hdr - + (hdr->n_region - i) * sizeof(*region)); + mode = mt76_connac_mcu_gen_dl_mode(dev, region->feature_set, + true); + len = le32_to_cpu(region->len); + addr = le32_to_cpu(region->addr); + + if (region->feature_set & FW_FEATURE_NON_DL) + goto next; + + if (region->feature_set & FW_FEATURE_OVERRIDE_ADDR) + override = addr; + + err = mt76_connac_mcu_init_download(dev, addr, len, mode); + if (err) { + dev_err(dev->dev, + "The request to dowload PHY firmware failed.\n"); + return err; + } + + err = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER), + data + offset, len, max_len); + if (err) { + dev_err(dev->dev, "Failed to send PHY firmware.\n"); + return err; + } + +next: + offset += len; + } + + if (override) + option |= FW_START_OVERRIDE; + option |= FW_START_WORKING_PDA_DSP; + + return mt76_connac_mcu_start_firmware(dev, override, option); +} + int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, const char *fw_wa) { @@ -3111,6 +3219,39 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, } EXPORT_SYMBOL_GPL(mt76_connac2_load_ram); +int mt76_connac3_load_phy_ram(struct mt76_dev *dev, const char *fw_name) +{ + const struct mt76_connac2_fw_trailer *hdr; + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, fw_name, dev->dev); + if (ret) + return ret; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->dev, "Invalid PHY firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); + dev_info(dev->dev, "PHY Firmware Version: %.10s, Build Time: %.15s\n", + hdr->fw_ver, hdr->build_date); + + ret = mt76_connac_mcu_send_phy_ram_firmware(dev, hdr, fw->data); + if (ret) { + dev_err(dev->dev, "Failed to start PHY firmware\n"); + goto out; + } + +out: + release_firmware(fw); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_connac3_load_phy_ram); + static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info) { u32 mode = DL_MODE_NEED_RSP; @@ -3224,6 +3365,128 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name) } EXPORT_SYMBOL_GPL(mt76_connac2_load_patch); +int mt76_connac3_load_cb_patch(struct mt76_dev *dev, const char *fw_name) +{ + const struct mt76_connac3_multi_header_v2_sec_raw_format *sect = NULL; + const struct mt76_connac3_multi_header_v2_raw_format *hdr = NULL; + int i, ret, sem, max_len = mt76_is_sdio(dev) ? 2048 : 4096; + const struct firmware *fw = NULL; + const u8 *dl; + u32 len; + + sem = mt76_connac_cb_mcu_patch_sem_ctrl(dev, true); + switch (sem) { + case CB_PATCH_IS_DL: + return 0; + case CB_PATCH_GET_SEM_NEED_PATCH: + break; + default: + dev_err(dev->dev, "Failed to get cb patch semaphore %u\n", sem); + return -EAGAIN; + } + + ret = request_firmware(&fw, fw_name, dev->dev); + if (ret) + goto out; + + if (!fw || !fw->data || fw->size < sizeof(*hdr)) { + dev_err(dev->dev, "Invalid firmware\n"); + ret = -EINVAL; + goto out; + } + + hdr = (const void *)fw->data; + dev_info(dev->dev, "HW/SW Version: 0x%x, Pack Time: %.21s\n", + le32_to_cpu(hdr->patch_ver), hdr->pack_time); + + if (le32_to_cpu(hdr->sec_num) < 2) { + dev_err(dev->dev, "Invalid section numbers %u\n", + le32_to_cpu(hdr->sec_num)); + ret = -EINVAL; + goto out; + } + + sect = &hdr->sects[0]; + /* check the fw bin basic info */ + if (((le32_to_cpu(sect->type) & SEC_TYPE_SUBSYS_MASK) + != SEC_TYPE_SUBSYS_CBMCU) || + ((le32_to_cpu(sect->type) & SEC_TYPE_SUBSYS_SEC_MASK) + != SEC_TYPE_SUBSYS_SEC_IMG_SIGN)) { + dev_err(dev->dev, "Invalid CBMCU firmware\n"); + ret = -EINVAL; + goto out; + } + + /* download global desc + sect map + cert section */ + len = sizeof(struct mt76_connac3_multi_header_v2_raw_format) - + offsetof(struct mt76_connac3_multi_header_v2_raw_format, + global_desc_head) + + sizeof(struct mt76_connac3_multi_header_v2_sec_raw_format) * + le32_to_cpu(hdr->sec_num) + + le32_to_cpu(hdr->sects[0].size); + dl = &hdr->global_desc_head[0]; + + ret = mt76_connac_cb_mcu_init_download(dev, len); + if (ret) { + dev_err(dev->dev, "Download cb cert section request failed\n"); + goto out; + } + + ret = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER), + dl, len, max_len); + if (ret) { + dev_err(dev->dev, "Failed to send cb patch cert section\n"); + goto out; + } + + ret = mt76_connac_cb_mcu_start_patch(dev); + if (ret) { + dev_err(dev->dev, "CBMCU cert check fail\n"); + goto out; + } + + /* download cbmcu idlm */ + for (i = 1; i < le32_to_cpu(hdr->sec_num); i++) { + dl = (uint8_t *)hdr + le32_to_cpu(hdr->sects[i].offset); + len = le32_to_cpu(hdr->sects[i].size); + + ret = mt76_connac_cb_mcu_init_download(dev, len); + if (ret) { + dev_err(dev->dev, + "Download cb section %u request failed\n", i); + goto out; + } + + ret = __mt76_mcu_send_firmware(dev, MCU_CMD(FW_SCATTER), + dl, len, max_len); + if (ret) { + dev_err(dev->dev, + "Failed to send cb patch section %u\n", i); + goto out; + } + } + + ret = mt76_connac_cb_mcu_start_patch(dev); + if (ret) + dev_err(dev->dev, "Failed to start cb patch\n"); + +out: + sem = mt76_connac_cb_mcu_patch_sem_ctrl(dev, false); + switch (sem) { + case CB_PATCH_REL_SEM_SUCCESS: + break; + default: + ret = -EAGAIN; + dev_err(dev->dev, "Failed to release cb patch semaphore\n"); + break; + } + + release_firmware(fw); + + return ret; +} +EXPORT_SYMBOL_GPL(mt76_connac3_load_cb_patch); + int mt76_connac2_mcu_fill_message(struct mt76_dev *dev, struct sk_buff *skb, int cmd, int *wait_seq) { diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h index 78f633ad81a0..0ededa569e9a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h @@ -35,6 +35,12 @@ #define PATCH_SEC_ENC_SCRAMBLE_INFO_MASK GENMASK(15, 0) #define PATCH_SEC_ENC_AES_KEY_MASK GENMASK(7, 0) +#define SEC_TYPE_SUBSYS_MASK GENMASK(23, 16) +#define SEC_TYPE_SUBSYS_CBMCU BIT(16) + +#define SEC_TYPE_SUBSYS_SEC_MASK GENMASK(15, 0) +#define SEC_TYPE_SUBSYS_SEC_IMG_SIGN 0x05 + enum { FW_TYPE_DEFAULT = 0, FW_TYPE_CLC = 2, @@ -193,6 +199,25 @@ struct mt76_connac2_fw_region { u8 rsv1[14]; } __packed; +struct mt76_connac3_multi_header_v2_sec_raw_format { + __le32 type; + __le32 offset; + __le32 size; + u8 spec[52]; +} __packed; + +struct mt76_connac3_multi_header_v2_raw_format { + u8 pack_time[20]; + u8 chip_id_eco_ver[8]; + __le32 patch_ver; + u8 global_desc_head[4]; + __le32 global_subsys; + u8 rsv2[4]; + __le32 sec_num; + u8 rsv3[48]; + struct mt76_connac3_multi_header_v2_sec_raw_format sects[]; +} __packed; + struct tlv { __le16 tag; __le16 len; @@ -842,6 +867,7 @@ enum { STA_REC_HDRT = 0x28, STA_REC_EML_OP = 0x29, STA_REC_HDR_TRANS = 0x2B, + STA_REC_PS_LEAVE = 0x45, STA_REC_MAX_NUM }; @@ -876,6 +902,7 @@ enum { #define NETWORK_P2P BIT(17) #define NETWORK_IBSS BIT(18) #define NETWORK_WDS BIT(21) +#define NETWORK_NAN BIT(22) #define SCAN_FUNC_RANDOM_MAC BIT(0) #define SCAN_FUNC_RNR_SCAN BIT(3) @@ -888,6 +915,7 @@ enum { #define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS) #define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS) #define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA) +#define CONNECTION_NAN (NETWORK_NAN) #define CONN_STATE_DISCONNECT 0 #define CONN_STATE_CONNECT 1 @@ -1066,6 +1094,7 @@ enum { MCU_UNI_EVENT_IE_COUNTDOWN = 0x09, MCU_UNI_EVENT_COREDUMP = 0x0a, MCU_UNI_EVENT_BSS_BEACON_LOSS = 0x0c, + MCU_UNI_EVENT_PS_SYNC = 0x0d, MCU_UNI_EVENT_SCAN_DONE = 0x0e, MCU_UNI_EVENT_RDD_REPORT = 0x11, MCU_UNI_EVENT_ROC = 0x27, @@ -1074,6 +1103,7 @@ enum { MCU_UNI_EVENT_THERMAL = 0x35, MCU_UNI_EVENT_RSSI_MONITOR = 0x41, MCU_UNI_EVENT_NIC_CAPAB = 0x43, + MCU_UNI_EVENT_NAN = 0x56, MCU_UNI_EVENT_WED_RRO = 0x57, MCU_UNI_EVENT_PER_STA_INFO = 0x6d, MCU_UNI_EVENT_ALL_STA_INFO = 0x6e, @@ -1104,6 +1134,13 @@ enum { PATCH_REL_SEM_SUCCESS }; +enum { + CB_PATCH_GET_SEM_NEED_PATCH, + CB_PATCH_IS_DL, + CB_PATCH_NO_SEM_NEED_PATCH, + CB_PATCH_REL_SEM_SUCCESS +}; + enum { FW_STATE_INITIAL, FW_STATE_FW_DOWNLOAD, @@ -1313,6 +1350,7 @@ enum { MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40, MCU_UNI_CMD_RSSI_MONITOR = 0x41, MCU_UNI_CMD_TESTMODE_CTRL = 0x46, + MCU_UNI_CMD_NAN = 0x56, MCU_UNI_CMD_RRO = 0x57, MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58, MCU_UNI_CMD_PER_STA_INFO = 0x6d, @@ -1332,6 +1370,9 @@ enum { MCU_CMD_PATCH_START_REQ = 0x05, MCU_CMD_PATCH_FINISH_REQ = 0x07, MCU_CMD_PATCH_SEM_CONTROL = 0x10, + MCU_CMD_CB_PATCH_SEM_CONTROL = 0x30, + MCU_CMD_CB_PATCH_START_REQ = 0x31, + MCU_CMD_CB_PATCH_FINISH_REQ = 0x32, MCU_CMD_WA_PARAM = 0xc4, MCU_CMD_EXT_CID = 0xed, MCU_CMD_FW_SCATTER = 0xee, @@ -1364,6 +1405,7 @@ enum { MCU_CE_CMD_FWLOG_2_HOST = 0xc5, MCU_CE_CMD_GET_WTBL = 0xcd, MCU_CE_CMD_GET_TXPWR = 0xd0, + MCU_CE_CMD_SET_REGD_CH = 0xd1, }; enum { @@ -2019,6 +2061,9 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len, u32 mode); int mt76_connac_mcu_start_patch(struct mt76_dev *dev); int mt76_connac_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get); +int mt76_connac_cb_mcu_init_download(struct mt76_dev *dev, u32 len); +int mt76_connac_cb_mcu_start_patch(struct mt76_dev *dev); +int mt76_connac_cb_mcu_patch_sem_ctrl(struct mt76_dev *dev, bool get); int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option); void mt76_connac_mcu_build_rnr_scan_param(struct mt76_dev *mdev, @@ -2102,7 +2147,9 @@ int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index, int mt76_connac_mcu_sta_wed_update(struct mt76_dev *dev, struct sk_buff *skb); int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm, const char *fw_wa); +int mt76_connac3_load_phy_ram(struct mt76_dev *dev, const char *fw_name); int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name); +int mt76_connac3_load_cb_patch(struct mt76_dev *dev, const char *fw_name); int mt76_connac2_mcu_fill_message(struct mt76_dev *mdev, struct sk_buff *skb, int cmd, int *wait_seq); #endif /* __MT76_CONNAC_MCU_H */ diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c index 14ee5b3b94d3..21f8b1e64101 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mac.c @@ -792,6 +792,9 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, if (rxinfo & MT_RXINFO_L2PAD) pad_len += 2; + if (rxinfo & MT_RXINFO_CRCERR) + status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (rxinfo & MT_RXINFO_DECRYPT) { status->flag |= RX_FLAG_DECRYPTED; status->flag |= RX_FLAG_MMIC_STRIPPED; @@ -848,7 +851,7 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb, } } - if (WARN_ON_ONCE(len > skb->len)) + if (len > skb->len) return -EINVAL; if (pskb_trim(skb, len)) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c index 4d0854fe785b..0413b4fd2d9c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c @@ -52,23 +52,12 @@ mt7915_sys_recovery_set(struct file *file, const char __user *user_buf, struct mt7915_phy *phy = file->private_data; struct mt7915_dev *dev = phy->dev; bool band = phy->mt76->band_idx; - char buf[16]; int ret = 0; u16 val; - if (count >= sizeof(buf)) - return -EINVAL; - - if (copy_from_user(buf, user_buf, count)) - return -EFAULT; - - if (count && buf[count - 1] == '\n') - buf[count - 1] = '\0'; - else - buf[count] = '\0'; - - if (kstrtou16(buf, 0, &val)) - return -EINVAL; + ret = kstrtou16_from_user(user_buf, count, 0, &val); + if (ret) + return ret; switch (val) { /* diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c index eb92cbf1a284..fe7b29ebc0bf 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c @@ -257,7 +257,7 @@ void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev, nss = min_t(u8, min_t(u8, nss_max, nss), path); mphy->chainmask = BIT(path) - 1; - if (band) + if (band && dev->dbdc_support) mphy->chainmask <<= dev->chainshift; mphy->antenna_mask = BIT(nss) - 1; dev->chainmask |= mphy->chainmask; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c index 250c2d2479b0..ca46a203aa48 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c @@ -177,6 +177,25 @@ static const struct thermal_cooling_device_ops mt7915_thermal_ops = { .set_cur_state = mt7915_thermal_set_cur_throttle_state, }; +static int mt7915_thermal_get_temp(struct thermal_zone_device *tz, int *temp) +{ + struct mt7915_phy *phy = thermal_zone_device_priv(tz); + int val; + + mutex_lock(&phy->dev->mt76.mutex); + val = mt7915_mcu_get_temperature(phy); + mutex_unlock(&phy->dev->mt76.mutex); + if (val < 0) + return val; + + *temp = val * 1000; + return 0; +} + +static const struct thermal_zone_device_ops mt7915_tz_ops = { + .get_temp = mt7915_thermal_get_temp, +}; + static void mt7915_unregister_thermal(struct mt7915_phy *phy) { struct wiphy *wiphy = phy->mt76->hw->wiphy; @@ -213,6 +232,17 @@ static int mt7915_thermal_init(struct mt7915_phy *phy) phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP; phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP; + phy->tzone = devm_thermal_of_zone_register(phy->dev->mt76.dev, + phy->mt76->band_idx, phy, + &mt7915_tz_ops); + if (IS_ERR(phy->tzone)) { + if (PTR_ERR(phy->tzone) != -ENODEV) + dev_warn(phy->dev->mt76.dev, + "failed to register thermal zone: %ld\n", + PTR_ERR(phy->tzone)); + phy->tzone = NULL; + } + if (!IS_REACHABLE(CONFIG_HWMON)) return 0; @@ -1272,14 +1302,19 @@ int mt7915_register_device(struct mt7915_dev *dev) ret = mt7915_init_debugfs(&dev->phy); if (ret) - goto unreg_thermal; + goto unreg_ext_phy; ret = mt7915_coredump_register(dev); if (ret) - goto unreg_thermal; + goto unreg_ext_phy; return 0; +unreg_ext_phy: + if (phy2) { + mt7915_unregister_ext_phy(dev); + phy2 = NULL; + } unreg_thermal: mt7915_unregister_thermal(&dev->phy); unreg_dev: @@ -1295,6 +1330,8 @@ int mt7915_register_device(struct mt7915_dev *dev) void mt7915_unregister_device(struct mt7915_dev *dev) { cancel_work_sync(&dev->dump_work); + cancel_work_sync(&dev->reset_work); + cancel_work_sync(&dev->rc_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 334c19ab2b22..b3d4abf6a9ed 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c @@ -221,7 +221,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev) rssi[0] = to_rssi(GENMASK(7, 0), val); rssi[1] = to_rssi(GENMASK(15, 8), val); rssi[2] = to_rssi(GENMASK(23, 16), val); - rssi[3] = to_rssi(GENMASK(31, 14), val); + rssi[3] = to_rssi(GENMASK(31, 24), val); msta->ack_signal = mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); @@ -437,7 +437,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb, if (v0 & MT_PRXV_HT_AD_CODE) status->enc_flags |= RX_ENC_FLAG_LDPC; - status->chains = mphy->antenna_mask; + status->chains = mt7915_band_chainmask(phy); status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1); status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1); status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1); @@ -1292,6 +1292,7 @@ mt7915_mac_restart(struct mt7915_dev *dev) struct mt7915_phy *phy2; struct mt76_phy *ext_phy; struct mt76_dev *mdev = &dev->mt76; + bool run_main, run_ext; int i, ret; ext_phy = dev->mt76.phys[MT_BAND1]; @@ -1387,13 +1388,17 @@ mt7915_mac_restart(struct mt7915_dev *dev) mt7915_init_txpower(phy2); ret = mt7915_txbf_init(dev); - if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) { + run_main = test_and_clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); + run_ext = ext_phy && + test_and_clear_bit(MT76_STATE_RUNNING, &ext_phy->state); + + if (run_main) { ret = mt7915_run(dev->mphy.hw); if (ret) goto out; } - if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) { + if (run_ext) { ret = mt7915_run(ext_phy->hw); if (ret) goto out; @@ -1464,6 +1469,10 @@ mt7915_mac_full_reset(struct mt7915_dev *dev) mutex_unlock(&dev->mt76.mutex); + ieee80211_wake_queues(mt76_hw(dev)); + if (ext_phy) + ieee80211_wake_queues(ext_phy->hw); + ieee80211_restart_hw(mt76_hw(dev)); if (ext_phy) ieee80211_restart_hw(ext_phy->hw); @@ -1925,7 +1934,7 @@ void mt7915_mac_update_stats(struct mt7915_phy *phy) static void mt7915_mac_severe_check(struct mt7915_phy *phy) { struct mt7915_dev *dev = phy->dev; - u32 trb; + u32 trb, ple_err; if (!phy->omac_mask) return; @@ -1945,6 +1954,17 @@ static void mt7915_mac_severe_check(struct mt7915_phy *phy) phy->mt76->band_idx); phy->trb_ts = trb; + + ple_err = mt76_rr(dev, MT_SWDEF_PLE1_STATS); + if ((ple_err & MT_SWDEF_PLE1_MDP_RIOC_HANG_ERR) && + !(dev->ple1_sts & MT_SWDEF_PLE1_MDP_RIOC_HANG_ERR)) { + dev_warn(dev->mt76.dev, + "band%d: PLE error 0x%x detected, triggering L1 SER\n", + phy->mt76->band_idx, ple_err); + mt7915_mcu_set_ser(dev, SER_RECOVER, SER_SET_RECOVER_L1, + phy->mt76->band_idx); + } + dev->ple1_sts = ple_err; } void mt7915_mac_sta_rc_work(struct work_struct *work) @@ -2345,8 +2365,10 @@ void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw, } flow->tsf = le64_to_cpu(twt_agrt->twt); - if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD)) + if (mt7915_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD)) { + list_del(&flow->list); goto unlock; + } setup_cmd = TWT_SETUP_CMD_ACCEPT; dev->twt.table_mask |= BIT(table_id); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c index 51643a48ed15..a8286f8becf9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c @@ -249,7 +249,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, idx = mt76_wcid_alloc(dev->mt76.wcid_mask, mt7915_wtbl_size(dev)); if (idx < 0) { ret = -ENOSPC; - goto out; + goto err; } INIT_LIST_HEAD(&mvif->sta.rc_list); @@ -277,7 +277,17 @@ static int mt7915_add_interface(struct ieee80211_hw *hw, mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, true); rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid); + mutex_unlock(&dev->mt76.mutex); + + return 0; + +err: + dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); + phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); + mt7915_mcu_add_dev_info(phy, vif, false); out: + if (phy->monitor_vif == vif) + phy->monitor_vif = NULL; mutex_unlock(&dev->mt76.mutex); return ret; @@ -294,7 +304,6 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw, mt7915_mcu_add_bss_info(phy, vif, false); mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_DISCONNECT, false); - mt76_wcid_mask_clear(dev->mt76.wcid_mask, mvif->sta.wcid.idx); mutex_lock(&dev->mt76.mutex); mt76_testmode_reset(phy->mt76, true); @@ -310,6 +319,7 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw, mutex_lock(&dev->mt76.mutex); dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx); phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx); + mt76_wcid_mask_clear(dev->mt76.wcid_mask, mvif->sta.wcid.idx); mutex_unlock(&dev->mt76.mutex); spin_lock_bh(&dev->mt76.sta_poll_lock); @@ -493,7 +503,7 @@ static int mt7915_config(struct ieee80211_hw *hw, int radio_idx, mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN, enabled); - mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_MDP_DCR0_RX_HDR_TRANS_EN, + mt76_rmw_field(dev, MT_MDP_DCR0, MT_MDP_DCR0_RX_HDR_TRANS_EN, !dev->monitor_mask); mt76_testmode_reset(phy->mt76, true); mt76_wr(dev, MT_WF_RFCR(band), rxfilter); @@ -1128,7 +1138,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_an struct mt7915_dev *dev = mt7915_hw_dev(hw); struct mt7915_phy *phy = mt7915_hw_phy(hw); int max_nss = hweight8(hw->wiphy->available_antennas_tx); - u8 chainshift = dev->chainshift; + u8 shift = mt7915_band_chainshift(phy); u8 band = phy->mt76->band_idx; if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss) @@ -1141,13 +1151,14 @@ mt7915_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_an /* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */ if ((is_mt7916(&dev->mt76) || is_mt7981(&dev->mt76)) && band && hweight8(tx_ant) == max_nss) - phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift; + phy->mt76->chainmask = (dev->chainmask >> shift) << shift; else - phy->mt76->chainmask = tx_ant << (chainshift * band); + phy->mt76->chainmask = tx_ant << shift; mt76_set_stream_caps(phy->mt76, true); mt7915_set_stream_vht_txbf_caps(phy); mt7915_set_stream_he_caps(phy); + mt7915_mcu_set_txpower_sku(phy); mutex_unlock(&dev->mt76.mutex); @@ -1743,7 +1754,7 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw, path->mtk_wdma.wdma_idx = wed->wdma_idx; path->mtk_wdma.bss = mvif->mt76.idx; path->mtk_wdma.wcid = is_mt7915(&dev->mt76) ? msta->wcid.idx : 0x3ff; - path->mtk_wdma.queue = phy != &dev->phy; + path->mtk_wdma.queue = phy->mt76->band_idx; ctx->dev = NULL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c index e8fe86f93309..5bfe0366562f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c @@ -51,7 +51,7 @@ mt7915_mcu_get_sta_nss(u16 mcs_map) break; } - return nss - 1; + return nss ? nss - 1 : 0; } static void @@ -402,6 +402,21 @@ mt7915_mcu_rx_bcc_notify(struct mt7915_dev *dev, struct sk_buff *skb) mt7915_mcu_cca_finish, mphy->hw); } +static void +mt7915_mcu_rx_ps_sync(struct mt7915_dev *dev, struct sk_buff *skb) +{ + struct mt7915_mcu_ps_notify *p = (void *)skb->data; + struct mt76_wcid *wcid; + u16 wcid_idx; + + wcid_idx = p->wtbl_lower | (p->wtbl_higher << 8); + wcid = mt76_wcid_ptr(dev, wcid_idx); + if (!wcid || !wcid_to_sta(wcid)) + return; + + mt76_sta_ps_transition(&dev->mt76, wcid, !!p->ps_bit); +} + static void mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) { @@ -424,6 +439,9 @@ mt7915_mcu_rx_ext_event(struct mt7915_dev *dev, struct sk_buff *skb) case MCU_EXT_EVENT_BCC_NOTIFY: mt7915_mcu_rx_bcc_notify(dev, skb); break; + case MCU_EXT_EVENT_PS_SYNC: + mt7915_mcu_rx_ps_sync(dev, skb); + break; default: break; } @@ -576,9 +594,9 @@ mt7915_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif, ra->rx_streams = max_nss; ra->algo = 4; ra->train_up_rule = 2; - ra->train_up_high_thres = 110; - ra->train_up_rule_rssi = -70; - ra->low_traffic_thres = 2; + ra->train_up_high_thres = cpu_to_le16(110); + ra->train_up_rule_rssi = cpu_to_le16(-70); + ra->low_traffic_thres = cpu_to_le16(2); ra->phy_cap = cpu_to_le32(0xfdf); ra->interval = cpu_to_le32(500); ra->fast_interval = cpu_to_le32(100); @@ -902,7 +920,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta, HE_PHY(CAP3_DCM_MAX_CONST_RX_MASK, elem->phy_cap_info[3]); he->dcm_rx_max_nss = HE_PHY(CAP3_DCM_MAX_RX_NSS_2, elem->phy_cap_info[3]); - he->dcm_rx_max_nss = + he->dcm_max_ru = HE_PHY(CAP8_DCM_MAX_RU_MASK, elem->phy_cap_info[8]); he->pkt_ext = 2; @@ -1625,7 +1643,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev, cap |= STA_CAP_VHT_SGI_160; if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) cap |= STA_CAP_VHT_TX_STBC; - if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) + if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) cap |= STA_CAP_VHT_RX_STBC; if (mvif->cap.vht_ldpc && (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)) @@ -2804,7 +2822,7 @@ int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd) .center_ch = ieee80211_frequency_to_channel(freq1), .bw = mt76_connac_chan_bw(chandef), .tx_path_num = hweight16(phy->mt76->chainmask), - .rx_path = phy->mt76->chainmask >> (dev->chainshift * band), + .rx_path = mt7915_band_chainmask(phy), .band_idx = band, .channel_band = ch_band[chandef->chan->band], }; @@ -2917,8 +2935,15 @@ int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset, u8 *read_buf) return ret; res = (struct mt7915_mcu_eeprom_info *)skb->data; - if (!buf) - buf = dev->mt76.eeprom.data + le32_to_cpu(res->addr); + if (!buf) { + u32 addr = le32_to_cpu(res->addr); + + if (addr > dev->mt76.eeprom.size - MT7915_EEPROM_BLOCK_SIZE) { + dev_kfree_skb(skb); + return -EINVAL; + } + buf = dev->mt76.eeprom.data + addr; + } memcpy(buf, res->data, MT7915_EEPROM_BLOCK_SIZE); dev_kfree_skb(skb); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h index 22f73a5ed425..76e39e899797 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h @@ -54,6 +54,15 @@ struct mt7915_mcu_bcc_notify { u8 rsv; } __packed; +struct mt7915_mcu_ps_notify { + struct mt76_connac2_mcu_rxd_hdr rxd; + + u8 wtbl_lower; + u8 ps_bit; + u8 wtbl_higher; + u8 rsv; +} __packed; + struct mt7915_mcu_rdd_report { struct mt76_connac2_mcu_rxd_hdr rxd; @@ -318,9 +327,9 @@ struct bss_info_ra { u8 antenna_idx; u8 train_up_rule; u8 rsv[3]; - unsigned short train_up_high_thres; - short train_up_rule_rssi; - unsigned short low_traffic_thres; + __le16 train_up_high_thres; + __le16 train_up_rule_rssi; + __le16 low_traffic_thres; __le16 max_phyrate; __le32 phy_cap; __le32 interval; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c index 2708b1556f40..28377c964843 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c @@ -921,7 +921,8 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev, /* txwi_size = txd size + txp size */ .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ | - MT_DRV_AMSDU_OFFLOAD, + MT_DRV_AMSDU_OFFLOAD | + MT_DRV_HW_PS_BUFFERING, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h index bf1d915a3ca2..30fb119ce872 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h @@ -205,6 +205,7 @@ struct mt7915_phy { struct ieee80211_vif *monitor_vif; + struct thermal_zone_device *tzone; struct thermal_cooling_device *cdev; u8 cdev_state; u8 throttle_state; @@ -295,6 +296,7 @@ struct mt7915_dev { spinlock_t reg_lock; u32 hw_pattern; + u32 ple1_sts; bool dbdc_support; bool flash_mode; @@ -397,6 +399,24 @@ mt7915_ext_phy(struct mt7915_dev *dev) return phy->priv; } +/* without dbdc, the chainmask is stored unshifted, even if the phy is + * bound to band 1 + */ +static inline u8 mt7915_band_chainshift(struct mt7915_phy *phy) +{ + struct mt7915_dev *dev = phy->dev; + + if (!dev->dbdc_support) + return 0; + + return phy->mt76->band_idx * dev->chainshift; +} + +static inline u16 mt7915_band_chainmask(struct mt7915_phy *phy) +{ + return phy->mt76->chainmask >> mt7915_band_chainshift(phy); +} + static inline u32 mt7915_check_adie(struct mt7915_dev *dev, bool sku) { u32 mask = sku ? MT_CONNINFRA_SKU_MASK : MT_ADIE_TYPE_MASK; diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c index f6b03211a879..8007e620048b 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/pci.c @@ -135,7 +135,6 @@ static int mt7915_pci_probe(struct pci_dev *pdev, mdev = &dev->mt76; mt7915_wfsys_reset(dev); - hif2 = mt7915_pci_init_hif2(pdev); ret = mt7915_mmio_wed_init(dev, pdev, true, &irq); if (ret < 0) @@ -145,16 +144,20 @@ static int mt7915_pci_probe(struct pci_dev *pdev, hif2 = mt7915_pci_init_hif2(pdev); ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); - if (ret < 0) + if (ret < 0) { + mt7915_put_hif2(hif2); goto free_device; + } irq = pdev->irq; } ret = devm_request_irq(mdev->dev, irq, mt7915_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); - if (ret) + if (ret) { + mt7915_put_hif2(hif2); goto free_wed_or_irq_vector; + } /* master switch of PCIe tnterrupt enable */ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h index 307bf6a75674..dc7bb9a1f223 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7915/regs.h @@ -1044,6 +1044,7 @@ enum offs_rev { #define MT_SWDEF_SER_STATS MT_SWDEF(0x040) #define MT_SWDEF_PLE_STATS MT_SWDEF(0x044) #define MT_SWDEF_PLE1_STATS MT_SWDEF(0x048) +#define MT_SWDEF_PLE1_MDP_RIOC_HANG_ERR BIT(3) #define MT_SWDEF_PLE_AMSDU_STATS MT_SWDEF(0x04C) #define MT_SWDEF_PSE_STATS MT_SWDEF(0x050) #define MT_SWDEF_PSE1_STATS MT_SWDEF(0x054) diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c index 54ff6de96f3e..13fba2a061c7 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/soc.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/soc.c @@ -908,7 +908,7 @@ static void mt7986_wmac_clock_enable(struct mt7915_dev *dev, u32 adie_type) read_poll_timeout(mt76_rr, cur, !(cur & MT_SLP_CTRL_BSY_MASK), USEC_PER_MSEC, 50 * USEC_PER_MSEC, false, - dev, MT_ADIE_SLP_CTRL_CK0(0)); + dev, MT_ADIE_SLP_CTRL_CK0(1)); } mt76_wmac_spi_unlock(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c index 618a5c2bdd29..7576973f4d4e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c +++ b/drivers/net/wireless/mediatek/mt76/mt7915/testmode.c @@ -694,9 +694,7 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, { struct mt76_testmode_data *td = &mphy->test; struct mt7915_phy *phy = mphy->priv; - struct mt7915_dev *dev = phy->dev; - u32 chainmask = mphy->chainmask, changed = 0; - bool ext_phy = phy != &dev->phy; + u32 chainmask = mt7915_band_chainmask(phy), changed = 0; int i; BUILD_BUG_ON(NUM_TM_CHANGED >= 32); @@ -705,7 +703,6 @@ mt7915_tm_set_params(struct mt76_phy *mphy, struct nlattr **tb, td->state == MT76_TM_STATE_OFF) return 0; - chainmask = ext_phy ? chainmask >> dev->chainshift : chainmask; if (td->tx_antenna_mask > chainmask) return -EINVAL; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c index f7d54472da1b..e69978184f68 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c @@ -156,7 +156,7 @@ static void mt7921_mac_sta_poll(struct mt792x_dev *dev) rssi[0] = to_rssi(GENMASK(7, 0), val); rssi[1] = to_rssi(GENMASK(15, 8), val); rssi[2] = to_rssi(GENMASK(23, 16), val); - rssi[3] = to_rssi(GENMASK(31, 14), val); + rssi[3] = to_rssi(GENMASK(31, 24), val); mlink->ack_signal = mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); @@ -674,6 +674,9 @@ void mt7921_mac_reset_work(struct work_struct *work) cancel_work_sync(&pm->wake_work); for (i = 0; i < 10; i++) { + if (atomic_read(&dev->mt76.bus_hung)) + return; + mutex_lock(&dev->mt76.mutex); ret = mt792x_dev_reset(dev); mutex_unlock(&dev->mt76.mutex); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 3480205d5fb9..68a059504e83 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -802,7 +802,7 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add) out: if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ) - mt7921_mcu_regd_update(dev, dev->mt76.alpha2, dev->country_ie_env); + __mt7921_mcu_regd_update(dev, dev->mt76.alpha2, dev->country_ie_env); } int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif, diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c index 25b9437250f7..a118a301564c 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c @@ -351,8 +351,10 @@ void mt7921_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct mt76_connac2_mcu_rxd *rxd; - if (skb_linearize(skb)) + if (skb_linearize(skb)) { + dev_kfree_skb(skb); return; + } rxd = (struct mt76_connac2_mcu_rxd *)skb->data; @@ -415,7 +417,8 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) struct mt76_dev *mdev = &dev->mt76; struct mt792x_phy *phy = &dev->phy; const struct firmware *fw; - int ret, i, len, offset = 0; + size_t clc_len, fw_data_len, len, offset = 0; + int ret, i; u8 *clc_base = NULL, hw_encap = 0; dev->phy.clc_chan_conf = 0xff; @@ -441,13 +444,21 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) } hdr = (const void *)(fw->data + fw->size - sizeof(*hdr)); + if (hdr->n_region > (fw->size - sizeof(*hdr)) / sizeof(*region)) { + dev_err(mdev->dev, "Invalid firmware region table\n"); + ret = -EINVAL; + goto out; + } + fw_data_len = fw->size - sizeof(*hdr) - + hdr->n_region * sizeof(*region); + for (i = 0; i < hdr->n_region; i++) { region = (const void *)((const u8 *)hdr - (hdr->n_region - i) * sizeof(*region)); len = le32_to_cpu(region->len); /* check if we have valid buffer size */ - if (offset + len > fw->size) { + if (len > fw_data_len - offset) { dev_err(mdev->dev, "Invalid firmware region\n"); ret = -EINVAL; goto out; @@ -464,8 +475,19 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) if (!clc_base) goto out; - for (offset = 0; offset < len; offset += le32_to_cpu(clc->len)) { + for (offset = 0; offset < len; offset += clc_len) { + if (len - offset < sizeof(*clc)) { + ret = -EINVAL; + goto out; + } + clc = (const struct mt7921_clc *)(clc_base + offset); + clc_len = le32_to_cpu(clc->len); + if (clc_len < sizeof(*clc) || clc_len > len - offset || + clc->idx >= ARRAY_SIZE(phy->clc)) { + ret = -EINVAL; + goto out; + } /* do not init buf again if chip reset triggered */ if (phy->clc[clc->idx]) @@ -477,7 +499,7 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name) continue; phy->clc[clc->idx] = devm_kmemdup(mdev->dev, clc, - le32_to_cpu(clc->len), + clc_len, GFP_KERNEL); if (!phy->clc[clc->idx]) { @@ -1403,6 +1425,9 @@ int mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, /* submit all clc config */ for (i = 0; i < ARRAY_SIZE(phy->clc); i++) { + if (i == MT792x_CLC_REGD) + continue; + ret = __mt7921_mcu_set_clc(dev, alpha2, env_cap, phy->clc[i], i); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c index 7728c5ae6791..56a914aaa81e 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c @@ -286,6 +286,10 @@ static int mt7921_pci_probe(struct pci_dev *pdev, .drv_own = mt792xe_mcu_drv_pmctrl, .fw_own = mt792xe_mcu_fw_pmctrl, }; + static const struct mt792x_pcie_reg mt7921_pcie_reg = { + .imask = MT_PCIE_MAC_INT_ENABLE, + .pm = MT_PCIE_MAC_PM, + }; static const struct mt792x_irq_map irq_map = { .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, .tx = { @@ -293,6 +297,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, .mcu_complete_mask = MT_INT_TX_DONE_MCU, }, .rx = { + .all_complete_mask = MT_INT_RX_DONE_ALL, .data_complete_mask = MT_INT_RX_DONE_DATA, .wm_complete_mask = MT_INT_RX_DONE_WM, .wm2_complete_mask = MT_INT_RX_DONE_WM2, @@ -354,6 +359,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev, dev->fw_features = features; dev->hif_ops = &mt7921_pcie_ops; + dev->pcie_reg = &mt7921_pcie_reg; dev->irq_map = &irq_map; mt76_mmio_init(&dev->mt76, regs); @@ -560,7 +566,8 @@ static int mt7921_pci_resume(struct device *device) mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); mt76_connac_irq_enable(&dev->mt76, dev->irq_map->tx.all_complete_mask | - MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); + dev->irq_map->rx.all_complete_mask | + MT_INT_MCU_CMD); mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); /* put dma enabled */ @@ -600,6 +607,108 @@ static int mt7921_pci_resume(struct device *device) return err; } +static u32 mt7921_aer_rr(struct mt76_dev *mdev, u32 offset) +{ + return 0; +} + +static void mt7921_aer_wr(struct mt76_dev *mdev, u32 offset, u32 val) +{ + ; +} + +static u32 mt791_aer_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) +{ + return 0; +} + +static const struct mt76_bus_ops mt7921_aer_bus_hung_ops = { + .rr = mt7921_aer_rr, + .wr = mt7921_aer_wr, + .rmw = mt791_aer_rmw, + .type = MT76_BUS_MMIO +}; + +static void mt7921_pci_set_aer_bus_hung_ops(struct mt792x_dev *dev) +{ + if (READ_ONCE(dev->mt76.bus) == &mt7921_aer_bus_hung_ops) + return; + + atomic_set(&dev->mt76.bus_hung, true); + WRITE_ONCE(dev->mt76.bus, &mt7921_aer_bus_hung_ops); +} + +static pci_ers_result_t mt7921_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + u32 aer_unc_val = 0, aer_co_val = 0; + + dev_err(mdev->dev, "PCIE error detect state: %d\n", state); + + /* Clear SW IRQ tasklet first */ + tasklet_kill(&mdev->irq_tasklet); + + if (state == pci_channel_io_perm_failure) { + mt7921_pci_set_aer_bus_hung_ops(dev); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_read_config_dword(pdev, PCIE_AER_UNC_STATUS_OFFSET, &aer_unc_val); + pci_read_config_dword(pdev, PCIE_AER_CO_STATUS_OFFSET, &aer_co_val); + + dev_warn(mdev->dev, "PCIE_AER_UNC_STATUS_OFFSET: 0x%x\n", aer_unc_val); + dev_warn(mdev->dev, "PCIE_AER_CO_STATUS_OFFSET: 0x%x\n", aer_co_val); + + /** + * Due to this error is from link error and this AER is un-correctable, + * so can't covered by device + **/ + if (aer_unc_val != 0) { + mt7921_pci_set_aer_bus_hung_ops(dev); + return PCI_ERS_RESULT_DISCONNECT; + } + + /** + * Try to recover it when state is pci_channel_io_frozen or + * AER is correctable error + **/ + if (state == pci_channel_io_frozen || aer_co_val != 0) { + /* Disable PCIE activity first. */ + pci_disable_device(pdev); + return PCI_ERS_RESULT_NEED_RESET; + } + + return PCI_ERS_RESULT_NONE; +} + +static pci_ers_result_t mt7921_slot_reset(struct pci_dev *pdev) +{ + struct mt76_dev *mdev = pci_get_drvdata(pdev); + int ret = 0; + + ret = pci_enable_device_mem(pdev); + + if (ret) { + dev_err(mdev->dev, "pci_enable_device_mem failed: %d\n", ret); + return PCI_ERS_RESULT_DISCONNECT; + } + + pci_set_master(pdev); + pci_restore_state(pdev); + pci_save_state(pdev); + /* Also try do the vendor reset to let it more clear. */ + mt792x_reset(mdev); + + return PCI_ERS_RESULT_RECOVERED; +} + +static const struct pci_error_handlers mt7921_err_handler = { + .error_detected = mt7921_error_detected, + .slot_reset = mt7921_slot_reset, +}; + static void mt7921_pci_shutdown(struct pci_dev *pdev) { mt7921_pci_remove(pdev); @@ -614,6 +723,7 @@ static struct pci_driver mt7921_pci_driver = { .remove = mt7921_pci_remove, .shutdown = mt7921_pci_shutdown, .driver.pm = pm_sleep_ptr(&mt7921_pm_ops), + .err_handler = &mt7921_err_handler, }; module_pci_driver(mt7921_pci_driver); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c index 0db7acb3a637..98b3469ac597 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci_mac.c @@ -96,7 +96,8 @@ int mt7921e_mac_reset(struct mt792x_dev *dev) mt76_wr(dev, dev->irq_map->host_irq_enable, dev->irq_map->tx.all_complete_mask | - MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD); + dev->irq_map->rx.all_complete_mask | + MT_INT_MCU_CMD); mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); err = mt7921e_driver_own(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c index c0e2b48a50bf..4a8ea4624fee 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c @@ -10,6 +10,15 @@ static bool mt7921_disable_clc; module_param_named(disable_clc, mt7921_disable_clc, bool, 0644); MODULE_PARM_DESC(disable_clc, "disable CLC support"); +static struct ieee80211_regdomain mt7921_regd_ww = { + .n_reg_rules = 1, + .alpha2 = "00", + .reg_rules = { + /* IEEE 802.11b/g, channels 1..11 */ + REG_RULE(2412 - 10, 2462 + 10, 40, 6, 20, 0), + } +}; + bool mt7921_regd_clc_supported(struct mt792x_dev *dev) { if (mt7921_disable_clc || @@ -33,6 +42,9 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) np = mt76_find_power_limits_node(mdev); sband = wiphy->bands[NL80211_BAND_5GHZ]; + if (!sband) + return; + band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL; for (i = 0; i < sband->n_channels; i++) { ch = &sband->channels[i]; @@ -71,36 +83,45 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) } } -int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, - enum environment_cap country_ie_env) +int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) { struct mt76_dev *mdev = &dev->mt76; struct ieee80211_hw *hw = mdev->hw; struct wiphy *wiphy = hw->wiphy; - int ret = 0; + int ret; - dev->regd_in_progress = true; + lockdep_assert_held(&dev->mt76.mutex); - mt792x_mutex_acquire(dev); if (!dev->regd_change) - goto err; + return 0; ret = mt7921_mcu_set_clc(dev, alpha2, country_ie_env); if (ret < 0) - goto err; + return ret; mt7921_regd_channel_update(wiphy, dev); ret = mt76_connac_mcu_set_channel_domain(hw->priv); if (ret < 0) - goto err; + return ret; ret = mt7921_set_tx_sar_pwr(hw, NULL); - if (ret < 0) - goto err; -err: + return ret; +} + +int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) +{ + int ret; + + dev->regd_in_progress = true; + + mt792x_mutex_acquire(dev); + ret = __mt7921_mcu_regd_update(dev, alpha2, country_ie_env); mt792x_mutex_release(dev); + dev->regd_change = false; dev->regd_in_progress = false; wake_up(&dev->wait); @@ -142,10 +163,176 @@ void mt7921_regd_notifier(struct wiphy *wiphy, if (pm->suspended) return; + if (MT7921_REGD_SUPPORTED(&dev->phy)) { + mt7921_regd_update(&dev->phy, req->alpha2); + + return; + } + mt7921_mcu_regd_update(dev, req->alpha2, req->country_ie_env); } +static struct sk_buff * +mt7921_regd_query_regdb(struct mt792x_phy *phy, char *alpha2) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt7921_clc *clc = phy->clc[MT792x_CLC_REGD]; + struct mt7921_regd_query_req *req; + struct mt7921_regd_cc *regd_cc; + struct sk_buff *ret_skb = NULL; + u8 *pos, *last_pos; + int ret = 0; + + if (!clc) + return NULL; + + pos = clc->data; + last_pos = pos + le32_to_cpu(clc->len) - sizeof(struct mt7921_clc); + while (pos < last_pos) { + u32 req_len = 0; + u32 rules_len = 0; + u32 sign_len = 4; + u32 n_reg_rules; + + if (pos + sizeof(*regd_cc) > last_pos) + break; + + regd_cc = (struct mt7921_regd_cc *)pos; + n_reg_rules = le32_to_cpu(regd_cc->n_reg_rules); + if (n_reg_rules > NL80211_MAX_SUPP_REG_RULES) + break; + + rules_len = sizeof(struct mt7921_regd_rule_header) + + sizeof(struct mt7921_regd_rule) * n_reg_rules; + + if (pos + sizeof(*regd_cc) + rules_len + sign_len > last_pos) + break; + + pos += sizeof(*regd_cc) + rules_len + sign_len; + if (memcmp(regd_cc->alpha2, alpha2, 2)) + continue; + + req_len = sizeof(*req) + rules_len + sign_len; + req = kzalloc(req_len, GFP_KERNEL); + + if (!req) + return NULL; + + req->ver = regd_cc->ver; + req->sign_type = regd_cc->sign_type; + req->size = cpu_to_le32(rules_len + sign_len); + req->n_reg_rules = regd_cc->n_reg_rules; + + memcpy(req->alpha2, regd_cc->alpha2, 2); + memcpy(req->data, regd_cc->data, rules_len + sign_len); + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_CE_CMD(SET_REGD_CH), + req, req_len, true, &ret_skb); + + kfree(req); + + return ret < 0 ? NULL : ret_skb; + } + + return NULL; +} + +int mt7921_regd_update(struct mt792x_phy *phy, char *alpha2) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt7921_regd_rule *mt7921_rule; + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_regdomain *regd; + struct ieee80211_reg_rule *rule; + struct mt7921_regd_rule_ev *ev; + int i, num_of_rules = 0; + struct sk_buff *skb; + int ret = 0; + + if (dev->hw_full_reset) + return 0; + + if (!MT7921_REGD_SUPPORTED(phy)) + return -EOPNOTSUPP; + + mt792x_mutex_acquire(dev); + skb = mt7921_regd_query_regdb(phy, alpha2); + mt792x_mutex_release(dev); + + if (!skb) { + ret = -EINVAL; + goto err; + } + + if (skb->len < sizeof(*ev) + 4) { + ret = -EINVAL; + goto err; + } + + ev = (struct mt7921_regd_rule_ev *)(skb->data + 4); + num_of_rules = le32_to_cpu(ev->n_reg_rules); + + if (!num_of_rules || + WARN_ON_ONCE(num_of_rules > NL80211_MAX_SUPP_REG_RULES)) { + ret = -EINVAL; + goto err; + } + + if (skb->len < struct_size(ev, reg_rule, num_of_rules) + 4) { + ret = -EINVAL; + goto err; + } + + regd = kzalloc(struct_size(regd, reg_rules, num_of_rules), GFP_KERNEL); + if (!regd) { + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < num_of_rules; i++) { + mt7921_rule = &ev->reg_rule[i]; + rule = ®d->reg_rules[i]; + + rule->freq_range.start_freq_khz = + MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->start_freq)); + rule->freq_range.end_freq_khz = + MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->end_freq)); + rule->freq_range.max_bandwidth_khz = + MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->max_bw)); + /* not used by fw */ + rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); + rule->power_rule.max_eirp = DBM_TO_MBM(22); + rule->flags = le32_to_cpu(mt7921_rule->flags); + } + + regd->n_reg_rules = num_of_rules; + regd->dfs_region = ev->dfs_region; + + memcpy(regd->alpha2, alpha2, 2); + memcpy(mdev->alpha2, alpha2, 2); + + dev->regd_change = true; + mt7921_mcu_regd_update(dev, alpha2, ENVIRON_ANY); + + ret = regulatory_set_wiphy_regd(wiphy, regd); + + kfree(regd); +err: + dev_kfree_skb(skb); + + if (ret < 0) + return regulatory_set_wiphy_regd(wiphy, &mt7921_regd_ww); + + return ret; +} +EXPORT_SYMBOL_GPL(mt7921_regd_update); + static bool mt7921_regd_is_valid_alpha2(const char *alpha2) { @@ -183,7 +370,9 @@ int mt7921_regd_change(struct mt792x_phy *phy, char *alpha2) if (!memcmp(alpha2, mdev->alpha2, 2)) return 0; - if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) + if (MT7921_REGD_SUPPORTED(phy)) + return mt7921_regd_update(phy, alpha2); + else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) return regulatory_hint(wiphy, alpha2); else return mt7921_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR); @@ -196,7 +385,11 @@ int mt7921_regd_init(struct mt792x_phy *phy) struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt76_dev *mdev = &dev->mt76; - if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) + if (MT7921_REGD_SUPPORTED(phy)) { + wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED | + REGULATORY_DISABLE_BEACON_HINTS; + return mt7921_regd_update(phy, "00"); + } else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE | REGULATORY_DISABLE_BEACON_HINTS; else diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h index 571f31629e9e..d4223ba8fbd5 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h @@ -4,16 +4,67 @@ #ifndef __MT7921_REGD_H #define __MT7921_REGD_H -struct mt792x_dev; -struct wiphy; -struct regulatory_request; +#include "mt7921.h" + +struct mt7921_regd_rule_header { + u8 alpha2[2]; + u8 dfs_region; + u8 rsv[13]; +}; + +struct mt7921_regd_rule { + __le32 start_freq; + __le32 end_freq; + __le32 max_bw; + __le32 eirp; + __le32 flags; + u8 rsv[12]; +}; + +struct mt7921_regd_cc { + u8 alpha2[2]; + u8 ver; + u8 rsv; + __le32 n_reg_rules; + u8 sign_type; + u8 rsv1[7]; + u8 data[]; +}; + +struct mt7921_regd_rule_ev { + __le16 tag; + __le16 len; + __le32 n_reg_rules; + u8 dfs_region; + u8 rsv[15]; + struct mt7921_regd_rule reg_rule[]; +}; + +struct mt7921_regd_query_req { + u8 ver; + u8 sign_type; + u8 rsv1[2]; + __le32 size; + u8 alpha2[2]; + u8 rsv2[2]; + __le32 n_reg_rules; + u8 rsv3[64]; + u8 data[]; +}; + +#define MT7921_REGD_SUPPORTED(phy) \ + (((phy)->chip_cap & MT792x_CHIP_CAP_REGD_EN) && \ + (phy)->clc[MT792x_CLC_REGD]) int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap country_ie_env); +int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env); void mt7921_regd_notifier(struct wiphy *wiphy, struct regulatory_request *request); bool mt7921_regd_clc_supported(struct mt792x_dev *dev); int mt7921_regd_change(struct mt792x_phy *phy, char *alpha2); int mt7921_regd_init(struct mt792x_phy *phy); +int mt7921_regd_update(struct mt792x_phy *phy, char *alpha2); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h index 4d9eaf1e0692..75b4e81c7224 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7921/regs.h @@ -78,4 +78,9 @@ #define MT_WTBL_UPDATE_WLAN_IDX GENMASK(9, 0) #define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12) +#define MT_PCIE_MAC_BASE 0x10000 +#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) +#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) +#define MT_PCIE_MAC_PM MT_PCIE_MAC(0x194) + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile index 8f1078ce3231..f9dcc0bba393 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/Makefile +++ b/drivers/net/wireless/mediatek/mt76/mt7925/Makefile @@ -4,7 +4,7 @@ obj-$(CONFIG_MT7925_COMMON) += mt7925-common.o obj-$(CONFIG_MT7925E) += mt7925e.o obj-$(CONFIG_MT7925U) += mt7925u.o -mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o +mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o mt7925-common-$(CONFIG_NL80211_TESTMODE) += testmode.o mt7925e-y := pci.o pci_mac.o pci_mcu.o mt7925u-y := usb.o diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c index e85b0d104fbe..cd22fcc021b1 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c @@ -137,10 +137,18 @@ static int mt7925_init_hardware(struct mt792x_dev *dev) set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); for (i = 0; i < MT792x_MCU_INIT_RETRY_COUNT; i++) { + if (atomic_read(&dev->mt76.bus_hung)) { + ret = -EIO; + break; + } + ret = __mt7925_init_hardware(dev); if (!ret) break; + if (atomic_read(&dev->mt76.bus_hung)) + break; + mt792x_init_reset(dev); } @@ -152,6 +160,33 @@ static int mt7925_init_hardware(struct mt792x_dev *dev) return 0; } +static int mt7925_init_nan_cap(struct mt76_dev *mdev) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + const struct ieee80211_sta_he_cap *he_cap; + struct ieee80211_supported_band *sband; + struct wiphy *wiphy = mdev->hw->wiphy; + + if (!(dev->fw_features & MT792x_FW_CAP_NAN)) + return 0; + + sband = wiphy->bands[NL80211_BAND_2GHZ]; + if (sband) + wiphy->nan_capa.phy.ht = sband->ht_cap; + + sband = wiphy->bands[NL80211_BAND_5GHZ]; + if (sband) + wiphy->nan_capa.phy.vht = sband->vht_cap; + + sband = wiphy->bands[NL80211_BAND_2GHZ]; + he_cap = sband ? ieee80211_get_he_iftype_cap(sband, NL80211_IFTYPE_NAN) + : NULL; + if (he_cap) + wiphy->nan_capa.phy.he = *he_cap; + + return 0; +} + static void mt7925_init_work(struct work_struct *work) { struct mt792x_dev *dev = container_of(work, struct mt792x_dev, @@ -172,6 +207,8 @@ static void mt7925_init_work(struct work_struct *work) return; } + dev->mt76.init_wiphy = mt7925_init_nan_cap; + ret = mt76_register_device(&dev->mt76, true, mt76_rates, ARRAY_SIZE(mt76_rates)); if (ret) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c index 6b0cd1996ecb..101f571b027f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c @@ -12,10 +12,17 @@ bool mt7925_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask) { - mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX, + u32 wtbl_update; + + if (is_mt7928(&dev->mt76)) + wtbl_update = MT7928_WTBL_UPDATE; + else + wtbl_update = MT7925_WTBL_UPDATE; + + mt76_rmw(dev, wtbl_update, MT_WTBL_UPDATE_WLAN_IDX, FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, idx) | mask); - return mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, + return mt76_poll(dev, wtbl_update, MT_WTBL_UPDATE_BUSY, 0, 5000); } @@ -145,7 +152,7 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev) rssi[0] = to_rssi(GENMASK(7, 0), val); rssi[1] = to_rssi(GENMASK(15, 8), val); rssi[2] = to_rssi(GENMASK(23, 16), val); - rssi[3] = to_rssi(GENMASK(31, 14), val); + rssi[3] = to_rssi(GENMASK(31, 24), val); mlink->ack_signal = mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi); @@ -159,10 +166,17 @@ void mt7925_mac_set_fixed_rate_table(struct mt792x_dev *dev, { u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx; - mt76_wr(dev, MT_WTBL_ITDR0, rate_idx); - /* use wtbl spe idx */ - mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); - mt76_wr(dev, MT_WTBL_ITCR, ctrl); + if (is_mt7928(&dev->mt76)) { + mt76_wr(dev, MT7928_WTBL_ITDR0, rate_idx); + /* use wtbl spe idx */ + mt76_wr(dev, MT7928_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); + mt76_wr(dev, MT7928_WTBL_ITCR, ctrl); + } else { + mt76_wr(dev, MT_WTBL_ITDR0, rate_idx); + /* use wtbl spe idx */ + mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL); + mt76_wr(dev, MT_WTBL_ITCR, ctrl); + } } /* The HW does not translate the mac header to 802.3 for mesh point */ @@ -705,6 +719,9 @@ mt7925_mac_write_txwi_80211(struct mt76_dev *dev, __le32 *txwi, txwi[2] |= cpu_to_le32(val); + if (is_mt7928(dev) && ieee80211_is_mgmt(hdr->frame_control)) + txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU); + txwi[3] |= cpu_to_le32(FIELD_PREP(MT_TXD3_BCM, multicast)); if (ieee80211_is_beacon(fc)) txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT); @@ -808,7 +825,11 @@ 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 (is_mt7928(dev)) + val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT_V2, 1); + else + val = MT_TXD6_DAS | FIELD_PREP(MT_TXD6_MSDU_CNT, 1); + if (vif && (!ieee80211_vif_is_mld(vif) || (q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))) val |= MT_TXD6_DIS_MAT; @@ -836,6 +857,10 @@ mt7925_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi, } txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx)); + + if (is_mt7928(dev)) + txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_BW_V2, 8)); + txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE); } } @@ -916,7 +941,6 @@ mt7925_mac_add_txs_skb(struct mt792x_dev *dev, struct mt76_wcid *wcid, goto out_no_skb; txs = le32_to_cpu(txs_data[0]); - info = IEEE80211_SKB_CB(skb); if (!(txs & MT_TXS0_ACK_ERROR_MASK)) info->flags |= IEEE80211_TX_STAT_ACK; @@ -1033,17 +1057,192 @@ mt7925_mac_add_txs_skb(struct mt792x_dev *dev, struct mt76_wcid *wcid, return !!skb; } -void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data) +static bool +mt7928_mac_add_txs_skb_msg(struct mt792x_dev *dev, struct mt76_wcid *wcid, + int pid, struct mt7928_uni_txdone_event *pevt) { + struct mt76_sta_stats *stats = &wcid->stats; + struct ieee80211_supported_band *sband; + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_tx_info *info; + struct sk_buff_head list; + u32 txrate, mode, stbc; + struct rate_info rate; + struct mt76_phy *mphy; + struct sk_buff *skb; + bool cck = false; + + mt76_tx_status_lock(mdev, &list); + skb = mt76_tx_status_skb_get(mdev, wcid, pid, &list); + if (!skb) + goto out_no_skb; + + info = IEEE80211_SKB_CB(skb); + if (!pevt->status) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.ampdu_len = 1; + info->status.ampdu_ack_len = !!(info->flags & + IEEE80211_TX_STAT_ACK); + + info->status.rates[0].idx = -1; + + txrate = le16_to_cpu(pevt->tx_rate); + + rate.mcs = FIELD_GET(MT_TX_RATE_IDX, txrate); + rate.nss = FIELD_GET(MT_TX_RATE_NSS, txrate) + 1; + stbc = FIELD_GET(MT_TX_RATE_STBC, txrate); + + if (stbc && rate.nss > 1) + rate.nss >>= 1; + + if (rate.nss - 1 < ARRAY_SIZE(stats->tx_nss)) + stats->tx_nss[rate.nss - 1]++; + if (rate.mcs < ARRAY_SIZE(stats->tx_mcs)) + stats->tx_mcs[rate.mcs]++; + + mode = FIELD_GET(MT_TX_RATE_MODE, txrate); + switch (mode) { + case MT_PHY_TYPE_CCK: + cck = true; + fallthrough; + case MT_PHY_TYPE_OFDM: + mphy = mt76_dev_phy(mdev, wcid->phy_idx); + + if (mphy->chandef.chan->band == NL80211_BAND_5GHZ) + sband = &mphy->sband_5g.sband; + else if (mphy->chandef.chan->band == NL80211_BAND_6GHZ) + sband = &mphy->sband_6g.sband; + else + sband = &mphy->sband_2g.sband; + + rate.mcs = mt76_get_rate(mphy->dev, sband, rate.mcs, cck); + rate.legacy = sband->bitrates[rate.mcs].bitrate; + break; + case MT_PHY_TYPE_HT: + case MT_PHY_TYPE_HT_GF: + if (rate.mcs > 31) + goto out; + + rate.flags = RATE_INFO_FLAGS_MCS; + if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI) + rate.flags |= RATE_INFO_FLAGS_SHORT_GI; + break; + case MT_PHY_TYPE_VHT: + if (rate.mcs > 9) + goto out; + + rate.flags = RATE_INFO_FLAGS_VHT_MCS; + break; + case MT_PHY_TYPE_HE_SU: + case MT_PHY_TYPE_HE_EXT_SU: + case MT_PHY_TYPE_HE_TB: + case MT_PHY_TYPE_HE_MU: + if (rate.mcs > 11) + goto out; + + rate.he_gi = wcid->rate.he_gi; + rate.he_dcm = FIELD_GET(MT_TX_RATE_DCM, txrate); + rate.flags = RATE_INFO_FLAGS_HE_MCS; + break; + case MT_PHY_TYPE_EHT_SU: + case MT_PHY_TYPE_EHT_TRIG: + case MT_PHY_TYPE_EHT_MU: + if (rate.mcs > 13) + goto out; + + rate.eht_gi = wcid->rate.eht_gi; + rate.flags = RATE_INFO_FLAGS_EHT_MCS; + break; + default: + goto out; + } + + stats->tx_mode[mode]++; + + switch (pevt->bw) { + case IEEE80211_STA_RX_BW_160: + rate.bw = RATE_INFO_BW_160; + stats->tx_bw[3]++; + break; + case IEEE80211_STA_RX_BW_80: + rate.bw = RATE_INFO_BW_80; + stats->tx_bw[2]++; + break; + case IEEE80211_STA_RX_BW_40: + rate.bw = RATE_INFO_BW_40; + stats->tx_bw[1]++; + break; + default: + rate.bw = RATE_INFO_BW_20; + stats->tx_bw[0]++; + break; + } + wcid->rate = rate; + +out: + mt76_tx_status_skb_done(mdev, skb, &list); + +out_no_skb: + mt76_tx_status_unlock(mdev, &list); + + return !!skb; +} + +void mt7928_mac_add_txs_msg(struct mt792x_dev *dev, + void *evt) +{ + struct mt7928_uni_txdone_event *done_evt; struct mt792x_link_sta *mlink = NULL; struct mt76_wcid *wcid; - __le32 *txs_data = data; u16 wcidx; u8 pid; - if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1) + done_evt = (struct mt7928_uni_txdone_event *)evt; + wcidx = done_evt->wcid; + pid = done_evt->pid; + + if (pid < MT_PACKET_ID_FIRST) return; + if (wcidx >= MT792x_WTBL_SIZE) + return; + + rcu_read_lock(); + + wcid = mt76_wcid_ptr(dev, wcidx); + if (!wcid) + goto out; + + mlink = container_of(wcid, struct mt792x_link_sta, wcid); + + mt7928_mac_add_txs_skb_msg(dev, wcid, pid, done_evt); + if (!wcid->sta) + goto out; + + mt76_wcid_add_poll(&dev->mt76, &mlink->wcid); + +out: + rcu_read_unlock(); +} + +void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data) +{ + struct mt792x_link_sta *mlink = NULL; + __le32 *txs_data = data; + struct mt76_wcid *wcid; + u8 pid, txs_fm; + u16 wcidx; + + txs_fm = le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT); + + if (is_mt7928(&dev->mt76)) { + if (txs_fm != TXS_FM_MPDU && txs_fm != TXS_FM_PPDU) + return; + } else if (txs_fm > 1) { + return; + } + wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID); pid = le32_get_bits(txs_data[3], MT_TXS3_PID); @@ -1317,15 +1516,22 @@ void mt7925_mac_reset_work(struct work_struct *work) struct mt76_connac_pm *pm = &dev->pm; int i, ret; + if (atomic_read(&dev->mt76.bus_hung)) + return; + dev_dbg(dev->mt76.dev, "chip reset\n"); dev->hw_full_reset = true; ieee80211_stop_queues(hw); cancel_delayed_work_sync(&dev->mphy.mac_work); cancel_delayed_work_sync(&pm->ps_work); + cancel_delayed_work_sync(&dev->mlo_pm_work); cancel_work_sync(&pm->wake_work); for (i = 0; i < 10; i++) { + if (test_bit(MT76_REMOVED, &dev->mphy.state)) + goto out; + mutex_lock(&dev->mt76.mutex); ret = mt792x_dev_reset(dev); mutex_unlock(&dev->mt76.mutex); @@ -1334,6 +1540,9 @@ void mt7925_mac_reset_work(struct work_struct *work) break; } + if (atomic_read(&dev->mt76.bus_hung)) + return; + if (i == 10) dev_err(dev->mt76.dev, "chip reset failed\n"); @@ -1345,8 +1554,12 @@ void mt7925_mac_reset_work(struct work_struct *work) ieee80211_scan_completed(dev->mphy.hw, &info); } +out: dev->hw_full_reset = false; pm->suspended = false; + if (test_bit(MT76_REMOVED, &dev->mphy.state)) + return; + ieee80211_wake_queues(hw); ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL, @@ -1434,6 +1647,10 @@ int mt7925_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, if (!wcid) wcid = &dev->mt76.global_wcid; + err = skb_cow_head(skb, MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE); + if (err) + return err; + if (sta) { struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.h b/drivers/net/wireless/mediatek/mt76/mt7925/mac.h index 83ea9021daea..567d072cba02 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.h @@ -14,7 +14,14 @@ static inline u32 mt7925_mac_wtbl_lmac_addr(struct mt792x_dev *dev, u16 wcid, u8 dw) { - mt76_wr(dev, MT_WTBLON_TOP_WDUCR, + u32 wdu_cr; + + if (is_mt7928(&dev->mt76)) + wdu_cr = MT7928_WTBLON_TOP_WDUCR; + else + wdu_cr = MT7925_WTBLON_TOP_WDUCR; + + mt76_wr(dev, wdu_cr, FIELD_PREP(MT_WTBLON_TOP_WDUCR_GROUP, (wcid >> 7))); return MT_WTBL_LMAC_OFFS(wcid, dw); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c index 2b6cc8e253c0..84b55f008b3d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c @@ -11,6 +11,7 @@ #include "regd.h" #include "mcu.h" #include "mac.h" +#include "nan.h" static void mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band, @@ -187,19 +188,21 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band, eht_cap_elem->phy_cap_info[0] |= IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ; + val = (sts > 3) ? sts - 1 : 3; + eht_cap_elem->phy_cap_info[0] |= - u8_encode_bits(u8_get_bits(sts - 1, BIT(0)), + u8_encode_bits(u8_get_bits(val, BIT(0)), IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK); eht_cap_elem->phy_cap_info[1] = - u8_encode_bits(u8_get_bits(sts - 1, GENMASK(2, 1)), + u8_encode_bits(u8_get_bits(val, GENMASK(2, 1)), IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) | - u8_encode_bits(sts - 1, + u8_encode_bits(val, IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK); if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76)) eht_cap_elem->phy_cap_info[1] |= - u8_encode_bits(sts - 1, + u8_encode_bits(val, IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK); eht_cap_elem->phy_cap_info[2] = @@ -412,7 +415,8 @@ static int mt7925_mac_link_bss_add(struct mt792x_dev *dev, 0 : mconf->mt76.idx % MT76_CONNAC_MAX_WMM_SETS; mconf->mt76.link_idx = hweight16(mvif->valid_links); - if (mvif->phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) + if (mvif->phy->mt76->chandef.chan && + mvif->phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ) mconf->mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL + 4; else mconf->mt76.basic_rates_idx = MT792x_BASIC_RATES_TBL; @@ -474,12 +478,32 @@ mt7925_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) INIT_WORK(&mvif->csa_work, mt7925_csa_work); timer_setup(&mvif->csa_timer, mt792x_csa_timer, 0); + if (vif->type == NL80211_IFTYPE_NAN) + dev->nan_vif = vif; out: mt792x_mutex_release(dev); return ret; } +static void +mt7925_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt792x_bss_conf *mconf; + + mt792x_mutex_acquire(dev); + + if (dev->nan_vif == vif) + dev->nan_vif = NULL; + + mconf = mt792x_link_conf_to_mconf(&vif->bss_conf); + mt792x_mac_link_bss_remove(dev, mconf, &mvif->sta.deflink); + + mt792x_mutex_release(dev); +} + static void mt7925_roc_iter(void *priv, u8 *mac, struct ieee80211_vif *vif) { @@ -1217,20 +1241,37 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev, int mt7925_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif, struct ieee80211_sta *sta, enum mt76_sta_event ev) { + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); struct ieee80211_link_sta *link_sta = &sta->deflink; - if (ev != MT76_STA_EVENT_ASSOC) - return 0; + switch (ev) { + case MT76_STA_EVENT_ASSOC: + if (ieee80211_vif_is_mld(vif)) { + struct mt792x_sta *msta = + (struct mt792x_sta *)sta->drv_priv; - if (ieee80211_vif_is_mld(vif)) { - struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + link_sta = mt792x_sta_to_link_sta(vif, sta, + msta->deflink_id); + mt7925_mac_set_links(mdev, vif); + } - link_sta = mt792x_sta_to_link_sta(vif, sta, msta->deflink_id); - mt7925_mac_set_links(mdev, vif); + mt7925_mac_link_sta_assoc(mdev, vif, link_sta); + break; + case MT76_STA_EVENT_AUTHORIZE: + if (vif->type == NL80211_IFTYPE_NAN_DATA) { + int ret; + + mt792x_mutex_acquire(dev); + ret = mt792x_nan_map_sta_rec(mdev, vif, sta); + mt792x_mutex_release(dev); + + return ret; + } + break; + default: + break; } - mt7925_mac_link_sta_assoc(mdev, vif, link_sta); - return 0; } EXPORT_SYMBOL_GPL(mt7925_mac_sta_event); @@ -1357,6 +1398,36 @@ void mt7925_mac_sta_remove(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; + /* Release NAN peer record before tearing down the STA. */ + if (vif->type == NL80211_IFTYPE_NAN || + vif->type == NL80211_IFTYPE_NAN_DATA) { + int ret = mt792x_nan_set_peer_rec(mdev, sta); + + if (ret) + dev_err(mdev->dev, + "NAN: failed to deactivate peer record: %d\n", + ret); + } + + /* Release NDP context ID for NAN_DATA sta. */ + if (vif->type == NL80211_IFTYPE_NAN_DATA) { + struct ieee80211_sta *nmi_sta; + + rcu_read_lock(); + nmi_sta = rcu_dereference(sta->nmi); + if (nmi_sta) { + struct mt792x_sta *nmi_msta = + (struct mt792x_sta *)nmi_sta->drv_priv; + + if (msta->nan_sched.ndp_ctx_assigned) { + clear_bit(msta->nan_sched.ndp_ctx_id, + &nmi_msta->nan_sched.ndp_ctx_bitmap); + msta->nan_sched.ndp_ctx_assigned = false; + } + } + rcu_read_unlock(); + } + if (ieee80211_vif_is_mld(vif)) { mt7925_mac_sta_remove_links(dev, vif, sta, msta->valid_links); mt7925_mcu_del_dev(mdev, vif); @@ -1493,7 +1564,7 @@ void mt7925_scan_work(struct work_struct *work) while (true) { struct sk_buff *skb; struct tlv *tlv; - int tlv_len; + u32 tlv_len; spin_lock_bh(&phy->dev->mt76.lock); skb = __skb_dequeue(&phy->scan_event_list); @@ -1506,7 +1577,7 @@ void mt7925_scan_work(struct work_struct *work) tlv = (struct tlv *)skb->data; tlv_len = skb->len; - while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { + mt7925_for_each_tlv(tlv, tlv_len) { struct mt7925_mcu_scan_chinfo_event *evt; switch (le16_to_cpu(tlv->tag)) { @@ -1519,6 +1590,9 @@ void mt7925_scan_work(struct work_struct *work) } break; case UNI_EVENT_SCAN_DONE_CHNLINFO: + if (le16_to_cpu(tlv->len) < sizeof(*tlv) + sizeof(*evt)) + break; + evt = (struct mt7925_mcu_scan_chinfo_event *)tlv->data; mt7925_regd_change(phy, evt->alpha2); @@ -1530,9 +1604,6 @@ void mt7925_scan_work(struct work_struct *work) default: break; } - - tlv_len -= le16_to_cpu(tlv->len); - tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); } dev_kfree_skb(skb); @@ -1640,6 +1711,7 @@ static int mt7925_suspend(struct ieee80211_hw *hw, cancel_delayed_work_sync(&phy->mt76->mac_work); cancel_delayed_work_sync(&dev->pm.ps_work); + cancel_delayed_work_sync(&dev->mlo_pm_work); mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt792x_mutex_acquire(dev); @@ -1827,9 +1899,15 @@ static int mt7925_set_sar_specs(struct ieee80211_hw *hw, int err; mt792x_mutex_acquire(dev); - err = mt7925_set_tx_sar_pwr(hw, sar); - mt792x_mutex_release(dev); + err = mt7925_mcu_set_clc(dev, dev->mt76.alpha2, + dev->country_ie_env); + if (err < 0) + goto out; + err = mt7925_set_tx_sar_pwr(hw, sar); + +out: + mt792x_mutex_release(dev); return err; } @@ -2062,6 +2140,11 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw, } mt792x_mutex_release(dev); + + if (vif->type == NL80211_IFTYPE_NAN && + changed & BSS_CHANGED_NAN_LOCAL_SCHED) { + mt7925_nan_local_sched_changed(dev, vif); + } } static void mt7925_link_info_changed(struct ieee80211_hw *hw, @@ -2484,19 +2567,165 @@ static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw, } } +static int mt7925_start_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf) +{ + struct ieee80211_bss_conf *link_conf = &vif->bss_conf; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct ieee80211_channel *chan; + int err = 0; + + mt792x_mutex_acquire(dev); + + chan = conf->band_cfgs[NL80211_BAND_2GHZ].chan; + if (!chan) { + err = -EINVAL; + goto out; + } + + cfg80211_chandef_create(&link_conf->chanreq.oper, chan, + NL80211_CHAN_NO_HT); + + err = mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, + NULL, true); + if (err < 0) + goto out; + + dev->nan_vif = vif; + + err = mt7925_nan_set_nmi_addr(dev, vif->addr); + if (err) + goto rollback_bss; + + err = mt7925_nan_enable(vif, dev, conf); + if (err) + goto rollback_bss; + + goto out; + +rollback_bss: + dev->nan_vif = NULL; + mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false); + +out: + mt792x_mutex_release(dev); + + return err; +} + +static int mt7925_stop_nan(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) +{ + struct ieee80211_bss_conf *link_conf = &vif->bss_conf; + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err, ret; + + mt792x_mutex_acquire(dev); + + err = mt7925_nan_disable(vif, dev); + + ret = mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, + NULL, false); + if (!err) + err = ret; + + if (dev->nan_vif == vif) + dev->nan_vif = NULL; + + mt792x_mutex_release(dev); + + return err; +} + +static int mt7925_nan_change_conf(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct cfg80211_nan_conf *conf, + u32 changes) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err = 0; + + mt792x_mutex_acquire(dev); + + err = mt7925_nan_change_configure(vif, dev, conf); + + mt792x_mutex_release(dev); + + return err; +} + +static int mt7925_nan_peer_sched_changed(struct ieee80211_hw *hw, + struct ieee80211_sta *sta) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + int err = 0; + + mt792x_mutex_acquire(dev); + + err = mt792x_nan_set_peer_schedule(dev, sta); + + mt792x_mutex_release(dev); + + return err; +} + +static void mt7925_sta_pre_rcu_remove(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt76_phy *phy = hw->priv; + struct mt76_dev *dev = phy->dev; + struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; + + mutex_lock(&dev->mutex); + spin_lock_bh(&dev->status_lock); + + if (ieee80211_vif_is_mld(vif)) { + struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + unsigned long valid = mvif->valid_links; + struct mt792x_link_sta *mlink; + unsigned int link_id; + + for_each_set_bit(link_id, &valid, IEEE80211_MLD_MAX_NUM_LINKS) { + mlink = mt792x_sta_to_link(msta, link_id); + if (!mlink || !mlink->wcid.sta) + continue; + if (mlink->wcid.idx < ARRAY_SIZE(dev->wcid)) + rcu_assign_pointer(dev->wcid[mlink->wcid.idx], + NULL); + } + } else { + rcu_assign_pointer(dev->wcid[wcid->idx], NULL); + } + + spin_unlock_bh(&dev->status_lock); + mutex_unlock(&dev->mutex); +} + +static void mt7925_stop(struct ieee80211_hw *hw, bool suspend) +{ + struct mt792x_dev *dev = mt792x_hw_dev(hw); + + cancel_delayed_work_sync(&dev->mlo_pm_work); + + mt792x_stop(hw, suspend); +} + const struct ieee80211_ops mt7925_ops = { .tx = mt792x_tx, .start = mt7925_start, - .stop = mt792x_stop, + .stop = mt7925_stop, .add_interface = mt7925_add_interface, - .remove_interface = mt792x_remove_interface, + .remove_interface = mt7925_remove_interface, .config = mt7925_config, .conf_tx = mt7925_conf_tx, .configure_filter = mt7925_configure_filter, .start_ap = mt7925_start_ap, .stop_ap = mt7925_stop_ap, .sta_state = mt76_sta_state, - .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove, + .sta_pre_rcu_remove = mt7925_sta_pre_rcu_remove, .set_key = mt7925_set_key, .sta_set_decap_offload = mt7925_sta_set_decap_offload, #if IS_ENABLED(CONFIG_IPV6) @@ -2553,6 +2782,10 @@ const struct ieee80211_ops mt7925_ops = { .channel_switch = mt7925_channel_switch, .abort_channel_switch = mt7925_abort_channel_switch, .channel_switch_rx_beacon = mt7925_channel_switch_rx_beacon, + .start_nan = mt7925_start_nan, + .stop_nan = mt7925_stop_nan, + .nan_change_conf = mt7925_nan_change_conf, + .nan_peer_sched_changed = mt7925_nan_peer_sched_changed, }; 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 cb265a6fc7ad..fa29c486a455 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c @@ -7,9 +7,17 @@ #include "regd.h" #include "mcu.h" #include "mac.h" +#include "nan.h" #define MT_STA_BFER BIT(0) #define MT_STA_BFEE BIT(1) +#define MT7925_WOW_PATTERN_NEW_FW_DATE "20260414153105" + +static bool mt7925_vif_is_nan(struct ieee80211_vif *vif) +{ + return vif->type == NL80211_IFTYPE_NAN || + vif->type == NL80211_IFTYPE_NAN_DATA; +} int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, struct sk_buff *skb, int seq) @@ -26,18 +34,30 @@ int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, } rxd = (struct mt7925_mcu_rxd *)skb->data; - if (seq != rxd->seq) - return -EAGAIN; + if (seq != rxd->seq) { + if (!is_mt7928(mdev)) + return -EAGAIN; + else if (is_mt7928(mdev) && + cmd != MCU_CMD(CB_PATCH_SEM_CONTROL) && + cmd != MCU_CMD(CB_PATCH_FINISH_REQ)) + return -EAGAIN; + } if (cmd == MCU_CMD(PATCH_SEM_CONTROL) || cmd == MCU_CMD(PATCH_FINISH_REQ)) { skb_pull(skb, sizeof(*rxd) - 4); ret = *skb->data; + } else if (is_mt7928(mdev) && + (cmd == MCU_CMD(CB_PATCH_SEM_CONTROL) || + cmd == MCU_CMD(CB_PATCH_FINISH_REQ))) { + skb_pull(skb, sizeof(*rxd) - 4); + ret = *skb->data; } else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) || cmd == MCU_UNI_CMD(BSS_INFO_UPDATE) || cmd == MCU_UNI_CMD(STA_REC_UPDATE) || cmd == MCU_UNI_CMD(OFFLOAD) || - cmd == MCU_UNI_CMD(SUSPEND)) { + cmd == MCU_UNI_CMD(SUSPEND) || + cmd == MCU_UNI_CMD(NAN)) { struct mt7925_mcu_uni_event *event; skb_pull(skb, sizeof(*rxd)); @@ -210,6 +230,23 @@ mt7925_connac_mcu_set_wow_ctrl(struct mt76_phy *phy, struct ieee80211_vif *vif, sizeof(req), true); } +static bool mt7925_mcu_wow_pattern_old_tlv(struct mt76_dev *dev) +{ + const char *fw_version = dev->hw->wiphy->fw_version; + const char *build_date = strrchr(fw_version, '-'); + + if (!is_mt7925(dev)) + return false; + + if (!build_date) + return false; + + build_date++; + + return strncmp(build_date, MT7925_WOW_PATTERN_NEW_FW_DATE, + strlen(MT7925_WOW_PATTERN_NEW_FW_DATE)) < 0; +} + static int mt7925_mcu_set_wow_pattern(struct mt76_dev *dev, struct ieee80211_vif *vif, @@ -219,6 +256,8 @@ mt7925_mcu_set_wow_pattern(struct mt76_dev *dev, struct mt76_vif_link *mvif = (struct mt76_vif_link *)vif->drv_priv; struct mt7925_wow_pattern_tlv *tlv; struct sk_buff *skb; + int tlv_len; + bool old_tlv; struct { u8 bss_idx; u8 pad[3]; @@ -226,14 +265,18 @@ mt7925_mcu_set_wow_pattern(struct mt76_dev *dev, .bss_idx = mvif->idx, }; - skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(hdr) + sizeof(*tlv)); + old_tlv = mt7925_mcu_wow_pattern_old_tlv(dev); + tlv_len = old_tlv ? sizeof(struct mt7925_wow_pattern_tlv) : + MT7925_WOW_PATTERN_TLV_V2_SIZE; + + skb = mt76_mcu_msg_alloc(dev, NULL, sizeof(hdr) + tlv_len); if (!skb) return -ENOMEM; skb_put_data(skb, &hdr, sizeof(hdr)); - tlv = (struct mt7925_wow_pattern_tlv *)skb_put(skb, sizeof(*tlv)); + tlv = (struct mt7925_wow_pattern_tlv *)skb_put_zero(skb, tlv_len); tlv->tag = cpu_to_le16(UNI_SUSPEND_WOW_PATTERN); - tlv->len = cpu_to_le16(sizeof(*tlv)); + tlv->len = cpu_to_le16(tlv_len); tlv->bss_idx = 0xF; tlv->data_len = pattern->pattern_len; tlv->enable = enable; @@ -366,16 +409,18 @@ mt7925_mcu_uni_hif_ctrl_event(struct mt792x_dev *dev, struct sk_buff *skb) tlv = (struct tlv *)skb->data; tlv_len = skb->len; - while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { + mt7925_for_each_tlv(tlv, tlv_len) { switch (le16_to_cpu(tlv->tag)) { case UNI_EVENT_HIF_CTRL_BASIC: + if (le16_to_cpu(tlv->len) < + sizeof(struct mt7925_mcu_hif_ctrl_basic_tlv)) + break; + mt7925_mcu_handle_hif_ctrl_basic(dev, tlv); break; default: break; } - tlv_len -= le16_to_cpu(tlv->len); - tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); } } @@ -383,22 +428,24 @@ static void mt7925_mcu_uni_roc_event(struct mt792x_dev *dev, struct sk_buff *skb) { struct tlv *tlv; - int i = 0; + u32 tlv_len; skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + tlv = (struct tlv *)skb->data; + tlv_len = skb->len; - while (i < skb->len) { - tlv = (struct tlv *)(skb->data + i); - + mt7925_for_each_tlv(tlv, tlv_len) { switch (le16_to_cpu(tlv->tag)) { case UNI_EVENT_ROC_GRANT: + if (le16_to_cpu(tlv->len) < + sizeof(struct mt7925_roc_grant_tlv)) + break; + mt7925_mcu_roc_handle_grant(dev, tlv); break; case UNI_EVENT_ROC_GRANT_SUB_LINK: break; } - - i += le16_to_cpu(tlv->len); } } @@ -426,6 +473,7 @@ mt7925_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb) u8 rsv[3]; u8 data[]; } __packed * txs; + struct mt7928_uni_txdone_event *evt; struct tlv *tlv; u32 tlv_len; @@ -433,8 +481,34 @@ mt7925_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb) tlv = (struct tlv *)skb->data; tlv_len = skb->len; - while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { + mt7925_for_each_tlv(tlv, tlv_len) { switch (le16_to_cpu(tlv->tag)) { + case UNI_EVENT_TX_DONE_MSG: + if (!is_mt7928(&dev->mt76)) + break; + + if (le16_to_cpu(tlv->len) < sizeof(*evt)) + break; + + evt = (struct mt7928_uni_txdone_event *)tlv; + if (evt->status) { + dev_info(dev->mt76.dev, + "TxDone: pid=%u status=%#x sn=%#x wcid=%u " + "cnt=%u rate=%#x flag=%#x tid=%u pwr=%u " + "rsp_rate=%#x rate_idx=%u bw=%u flush=%#x " + "delay=%#x ts=%#x flags=%#x\n", + evt->pid, evt->status, + le16_to_cpu(evt->seq), evt->wcid, + evt->tx_count, le16_to_cpu(evt->tx_rate), + evt->flag, evt->tid, evt->tx_pwr, + evt->rsp_rate, evt->rate_tbl_idx, + evt->bw, evt->flush_reason, + le32_to_cpu(evt->tx_delay), + le32_to_cpu(evt->timestamp), + le32_to_cpu(evt->applied_flags)); + } + mt7928_mac_add_txs_msg(dev, evt); + break; case UNI_EVENT_TX_DONE_RAW: txs = (struct mt7925_mcu_txs_event *)tlv->data; mt7925_mac_add_txs(dev, txs->data); @@ -442,8 +516,6 @@ mt7925_mcu_tx_done_event(struct mt792x_dev *dev, struct sk_buff *skb) default: break; } - tlv_len -= le16_to_cpu(tlv->len); - tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); } } @@ -480,10 +552,13 @@ mt7925_mcu_rssi_monitor_event(struct mt792x_dev *dev, struct sk_buff *skb) tlv = (struct tlv *)skb->data; tlv_len = skb->len; - while (tlv_len > 0 && le16_to_cpu(tlv->len) <= tlv_len) { + mt7925_for_each_tlv(tlv, tlv_len) { switch (le16_to_cpu(tlv->tag)) { case UNI_EVENT_RSSI_MONITOR_INFO: - event = (struct mt7925_uni_rssi_monitor_event *)skb->data; + if (le16_to_cpu(tlv->len) < sizeof(*event)) + break; + + event = (struct mt7925_uni_rssi_monitor_event *)tlv; ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw, IEEE80211_IFACE_ITER_RESUME_ALL, mt7925_mcu_rssi_monitor_iter, @@ -492,8 +567,6 @@ mt7925_mcu_rssi_monitor_event(struct mt792x_dev *dev, struct sk_buff *skb) default: break; } - tlv_len -= le16_to_cpu(tlv->len); - tlv = (struct tlv *)((char *)(tlv) + le16_to_cpu(tlv->len)); } } @@ -631,6 +704,9 @@ mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev, dev->fw_assert = true; mt76_connac_mcu_coredump_event(&dev->mt76, skb, &dev->coredump); return; + case MCU_UNI_EVENT_NAN: + mt7925_nan_mcu_event(dev, skb); + break; default: break; } @@ -1546,7 +1622,8 @@ int mt7925_mcu_set_eeprom(struct mt792x_dev *dev) .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE), .len = cpu_to_le16(sizeof(req) - 4), .buffer_mode = EE_MODE_EFUSE, - .format = EE_FORMAT_WHOLE + .format = EE_FORMAT_WHOLE, + .buf_len = 0 }; return mt76_mcu_send_and_get_msg(&dev->mt76, MCU_UNI_CMD(EFUSE_CTRL), @@ -1835,9 +1912,20 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb, tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy)); phy = (struct sta_rec_phy *)tlv; - phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, - chandef->chan->band, - link_sta); + + if (mt7925_vif_is_nan(vif)) { + enum nl80211_band band = chandef->chan ? chandef->chan->band + : NL80211_BAND_2GHZ; + phy->phy_type = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_ERP; + phy->phy_type |= mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, + band, + link_sta); + } else { + phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif, + chandef->chan->band, + link_sta); + } + phy->basic_rate = cpu_to_le16((u16)link_conf->basic_rates); if (link_sta->ht_cap.ht_supported) { af = link_sta->ht_cap.ampdu_factor; @@ -1910,11 +1998,15 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, mconf = mt792x_vif_to_link(mvif, link_sta->link_id); chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def : &link_conf->chanreq.oper; - band = chandef->chan->band; tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra_info)); ra_info = (struct sta_rec_ra_info *)tlv; + if (mt7925_vif_is_nan(vif)) + band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ; + else + band = chandef->chan->band; + supp_rates = link_sta->supp_rates[band]; if (band == NL80211_BAND_2GHZ) supp_rates = FIELD_PREP(RA_LEGACY_OFDM, supp_rates >> 4) | @@ -2174,6 +2266,8 @@ int mt7925_get_txpwr_info(struct mt792x_dev *dev, u8 band_idx, struct mt7925_txp int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, bool enable) { + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct ieee80211_chanctx_conf *ctx = mvif->bss_conf.mt76.ctx; struct { struct { u8 band_idx; @@ -2196,6 +2290,15 @@ int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif, }, }; + if (is_mt7927(&dev->mt76)) { + struct ieee80211_channel *chan; + + chan = ctx ? ctx->def.chan : mvif->phy->mt76->chandef.chan; + + if (chan) + req.hdr.band_idx = mt7927_band_idx(chan->band); + } + return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(SNIFFER), &req, sizeof(req), true); } @@ -2255,6 +2358,9 @@ int mt7925_mcu_config_sniffer(struct mt792x_vif *vif, }, }; + if (is_mt7927(mphy->dev)) + req.hdr.band_idx = mt7927_band_idx(chandef->chan->band); + if (chandef->chan->band < ARRAY_SIZE(ch_band)) req.tlv.ch_band = ch_band[chandef->chan->band]; if (chandef->width < ARRAY_SIZE(ch_width)) @@ -2364,11 +2470,18 @@ void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy, { struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &link_conf->chanreq.oper; - int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2; - enum nl80211_band band = chandef->chan->band; struct bss_rlm_tlv *req; + enum nl80211_band band; + int freq1, freq2; struct tlv *tlv; + if (WARN_ON_ONCE(!chandef || !chandef->chan)) + return; + + freq1 = chandef->center_freq1; + freq2 = chandef->center_freq2; + band = chandef->chan->band; + tlv = mt76_connac_mcu_add_tlv(skb, UNI_BSS_INFO_RLM, sizeof(*req)); req = (struct bss_rlm_tlv *)tlv; req->control_channel = chandef->chan->hw_value; @@ -2506,8 +2619,8 @@ mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, enum nl80211_band band, struct ieee80211_link_sta *link_sta) { - struct ieee80211_he_6ghz_capa *he_6ghz_capa; - const struct ieee80211_sta_eht_cap *eht_cap; + struct ieee80211_he_6ghz_capa *he_6ghz_capa = NULL; + const struct ieee80211_sta_eht_cap *eht_cap = NULL; __le16 capa = 0; u8 mode = 0; @@ -2515,11 +2628,18 @@ mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, he_6ghz_capa = &link_sta->he_6ghz_capa; eht_cap = &link_sta->eht_cap; } else { + const struct ieee80211_sta_he_cap *he_cap; struct ieee80211_supported_band *sband; sband = phy->hw->wiphy->bands[band]; - capa = ieee80211_get_he_6ghz_capa(sband, vif->type); - he_6ghz_capa = (struct ieee80211_he_6ghz_capa *)&capa; + + he_cap = (band == NL80211_BAND_6GHZ) ? + ieee80211_get_he_iftype_cap(sband, vif->type) : NULL; + + if (he_cap) { + capa = ieee80211_get_he_6ghz_capa(sband, vif->type); + he_6ghz_capa = (struct ieee80211_he_6ghz_capa *)&capa; + } eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type); } @@ -2547,6 +2667,29 @@ mt7925_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif, return mode; } +static void +mt7925_mcu_bss_basic_tlv_nan(struct mt76_phy *phy, + struct ieee80211_vif *vif, + struct ieee80211_link_sta *link_sta, + struct mt76_connac_bss_basic_tlv *basic_req) +{ + u8 mode_2g, mode_5g; + + mode_2g = mt7925_get_phy_mode_ext(phy, vif, NL80211_BAND_2GHZ, + link_sta); + mode_5g = mt7925_get_phy_mode_ext(phy, vif, NL80211_BAND_5GHZ, + link_sta); + basic_req->phymode_ext = mode_2g | mode_5g; + + basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_ERP_INDEX); + + mode_2g = mt76_connac_get_phy_mode(phy, vif, NL80211_BAND_2GHZ, + link_sta); + mode_5g = mt76_connac_get_phy_mode(phy, vif, NL80211_BAND_5GHZ, + link_sta); + basic_req->phymode = (mode_2g | mode_5g) & ~PHY_MODE_B; +} + static void mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *link_conf, @@ -2561,7 +2704,7 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &link_conf->chanreq.oper; - enum nl80211_band band = chandef->chan->band; + enum nl80211_band band = NL80211_BAND_2GHZ; struct mt76_connac_bss_basic_tlv *basic_req; struct tlv *tlv; int conn_type; @@ -2574,16 +2717,25 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, mconf->mt76.omac_idx; basic_req->hw_bss_idx = idx; - basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, - link_sta); + if (mt7925_vif_is_nan(vif)) { + mt7925_mcu_bss_basic_tlv_nan(phy, vif, link_sta, basic_req); + } else { + band = chandef->chan->band; + basic_req->phymode_ext = mt7925_get_phy_mode_ext(phy, vif, band, + link_sta); - if (band == NL80211_BAND_2GHZ) - basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_ERP_INDEX); - else - basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_OFDM_INDEX); + if (band == NL80211_BAND_2GHZ) + basic_req->nonht_basic_phy = + cpu_to_le16(PHY_TYPE_ERP_INDEX); + else + basic_req->nonht_basic_phy = + cpu_to_le16(PHY_TYPE_OFDM_INDEX); + + memcpy(basic_req->bssid, link_conf->bssid, ETH_ALEN); + basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, + link_sta); + } - memcpy(basic_req->bssid, link_conf->bssid, ETH_ALEN); - 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(bmc_tx_wlan_idx); @@ -2616,6 +2768,11 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb, basic_req->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC); basic_req->active = true; break; + case NL80211_IFTYPE_NAN: + case NL80211_IFTYPE_NAN_DATA: + basic_req->conn_type = cpu_to_le32(CONNECTION_NAN); + basic_req->active = enable; + break; default: WARN_ON(1); break; @@ -2674,10 +2831,11 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, struct ieee80211_chanctx_conf *ctx, struct ieee80211_bss_conf *link_conf) { + struct ieee80211_vif *vif = link_conf->vif; struct cfg80211_chan_def *chandef = ctx ? &ctx->def : &link_conf->chanreq.oper; struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf); - enum nl80211_band band = chandef->chan->band; + enum nl80211_band band = NL80211_BAND_2GHZ; struct mt76_vif_link *mvif = &mconf->mt76; struct bss_rate_tlv *bmc; struct tlv *tlv; @@ -2688,6 +2846,11 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy, bmc = (struct bss_rate_tlv *)tlv; + if (mt7925_vif_is_nan(vif)) + band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ; + else + band = chandef->chan->band; + if (band == NL80211_BAND_2GHZ) bmc->basic_rate = cpu_to_le16(HR_DSSS_ERP_BASIC_RATE); else @@ -3002,11 +3165,11 @@ mt7925_mcu_build_scan_ie_tlv(struct mt76_dev *mdev, struct ieee80211_scan_ies *scan_ies) { u32 max_len = sizeof(struct scan_ie_tlv) + MT76_CONNAC_SCAN_IE_LEN; + u32 ies_len, alloc_len; struct scan_ie_tlv *ie; enum nl80211_band i; struct tlv *tlv; const u8 *ies; - u16 ies_len; for (i = 0; i <= NL80211_BAND_6GHZ; i++) { if (i == NL80211_BAND_60GHZ) @@ -3018,11 +3181,16 @@ mt7925_mcu_build_scan_ie_tlv(struct mt76_dev *mdev, if (!ies || !ies_len) continue; - if (ies_len > max_len) + if (is_mt7928(mdev)) + alloc_len = ALIGN(sizeof(*ie) + ies_len, 4); + else + alloc_len = sizeof(*ie) + ies_len; + + if (alloc_len > max_len) return; tlv = mt76_connac_mcu_add_tlv(skb, UNI_SCAN_IE, - sizeof(*ie) + ies_len); + alloc_len); ie = (struct scan_ie_tlv *)tlv; memcpy(ie->ies, ies, ies_len); @@ -3040,7 +3208,7 @@ mt7925_mcu_build_scan_ie_tlv(struct mt76_dev *mdev, break; } - max_len -= (sizeof(*ie) + ies_len); + max_len -= alloc_len; } } @@ -3541,7 +3709,8 @@ int mt7925_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2, /* submit all clc config */ for (i = 0; i < ARRAY_SIZE(phy->clc); i++) { - if (i == MT792x_CLC_BE_CTRL) + if (i == MT792x_CLC_BE_CTRL || + i == MT792x_CLC_REGD) continue; ret = __mt7925_mcu_set_clc(dev, alpha2, env_cap, @@ -3829,7 +3998,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(msg_len); + tx_power_tlv->len = cpu_to_le16(msg_len - 4); 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 293f173b23dd..11f9eac13ffc 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h @@ -175,6 +175,27 @@ enum connac3_mcu_cipher_type { CONNAC3_CIPHER_GCMP_256 = 12, }; +enum DMASHDL_GROUP_IDX { + DMASHDL_GROUP_0 = 0, + DMASHDL_GROUP_1, + DMASHDL_GROUP_2, + DMASHDL_GROUP_3, + DMASHDL_GROUP_4, + DMASHDL_GROUP_5, + DMASHDL_GROUP_6, + DMASHDL_GROUP_7, + DMASHDL_GROUP_8, + DMASHDL_GROUP_9, + DMASHDL_GROUP_10, + DMASHDL_GROUP_11, + DMASHDL_GROUP_12, + DMASHDL_GROUP_13, + DMASHDL_GROUP_14, + DMASHDL_GROUP_15, + DMASHDL_GROUP_NUM, + DMASHDL_LITE_GROUP_NUM = 64 +}; + struct mt7925_mcu_scan_chinfo_event { u8 nr_chan; u8 alpha2[3]; @@ -587,6 +608,9 @@ struct mt7925_wow_pattern_tlv { u8 rsv[4]; }; +#define MT7925_WOW_PATTERN_TLV_V2_SIZE \ + (offsetof(struct mt7925_wow_pattern_tlv, rsv) + 3) + struct roc_acquire_tlv { __le16 tag; __le16 len; @@ -675,6 +699,25 @@ mt7925_mcu_get_cipher(int cipher) } } +static inline bool +mt7925_mcu_tlv_valid(struct tlv *tlv, u32 rem) +{ + u16 len; + + if (rem < sizeof(*tlv)) + return false; + + len = le16_to_cpu(tlv->len); + + /* a length below the header size would not advance the cursor */ + return len >= sizeof(*tlv) && len <= rem; +} + +#define mt7925_for_each_tlv(tlv, rem) \ + for (; mt7925_mcu_tlv_valid(tlv, rem); \ + (rem) -= le16_to_cpu((tlv)->len), \ + (tlv) = (struct tlv *)((u8 *)(tlv) + le16_to_cpu((tlv)->len))) + int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable); int mt7925_mcu_hw_scan(struct mt76_phy *phy, struct ieee80211_vif *vif, struct ieee80211_scan_request *scan_req); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h index 4cc259418afc..321e732347f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h @@ -15,6 +15,7 @@ #define MT7925_RX_RING_SIZE 1536 #define MT7925_RX_MCU_RING_SIZE 512 +#define MT7928_RX_MCU_WA_RING_SIZE 512 #define MT7925_EEPROM_SIZE 3584 #define MT7925_TOKEN_SIZE 8192 @@ -139,6 +140,13 @@ enum mt7927_rxq_id { MT7927_RXQ_DATA2 = 7, }; +enum mt7928_rxq_id { + MT7928_RXQ_BAND0, + MT7928_RXQ_BAND1 = 2, + MT7928_RXQ_MCU_WM = 3, + MT7928_RXQ_MCU_WM2 = 1, /* for tx done */ +}; + enum { MODE_OPEN = 0, MODE_SHARED = 1, @@ -346,6 +354,7 @@ int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd, int mt7925e_mac_reset(struct mt792x_dev *dev); int mt7925e_mcu_init(struct mt792x_dev *dev); void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data); +void mt7928_mac_add_txs_msg(struct mt792x_dev *dev, void *evt); void mt7925_set_runtime_pm(struct mt792x_dev *dev); void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac, struct ieee80211_vif *vif); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.c b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c new file mode 100644 index 000000000000..d260e803d056 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.c @@ -0,0 +1,1098 @@ +// SPDX-License-Identifier: BSD-3-Clause-Clear +/* Copyright (C) 2025-2026 MediaTek Inc. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mt7925.h" +#include "mcu.h" +#include "nan.h" +#include "regd.h" + +static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev, + struct mt7925_nan_enable_req_tlv *req, + struct cfg80211_nan_conf *conf) +{ + struct ieee80211_channel *chan; + u32 ch5g = 0; + + chan = conf->band_cfgs[NL80211_BAND_5GHZ].chan; + + if (!chan) + return; + + if (!mt7925_regd_is_valid_channel(dev, NL80211_BAND_5GHZ, chan)) + return; + + req->config_support_5g = 1; + req->support_5g_val = 1; + req->config_5g_channel = 1; + + if (chan->hw_value == NAN_5G_LOW_DISC_CHANNEL) + ch5g |= BIT(0); + else if (chan->hw_value == NAN_5G_HIGH_DISC_CHANNEL) + ch5g |= BIT(1); + + req->channel_5g_val = cpu_to_le32(ch5g); +} + +static void mt7925_nan_set_2g_support(struct mt7925_nan_enable_req_tlv *req, + struct cfg80211_nan_conf *conf) +{ + if (!conf->band_cfgs[NL80211_BAND_2GHZ].chan) + return; + + req->config_2dot4g_support = 1; + req->support_2dot4g_val = 1; +} + +static void mt7925_nan_set_cluster_id(struct mt7925_nan_enable_req_tlv *req, + const u8 *cluster_id) +{ + if (!cluster_id) + return; + + req->cluster_high = cpu_to_le16(cluster_id[4] | cluster_id[5] << 8); + req->cluster_low = cpu_to_le16((u16)cluster_id[3]); +} + +static void mt7925_nan_set_dw_interval(struct mt7925_nan_enable_req_tlv *req, + struct cfg80211_nan_conf *conf) +{ + if (conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval > 0) { + req->config_dw.config_2dot4g_dw_band = 1; + req->config_dw.dw_2dot4g_interval_val = + cpu_to_le32(conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval); + } + + if (conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval > 0) { + req->config_dw.config_5g_dw_band = 1; + req->config_dw.dw_5g_interval_val = + cpu_to_le32(conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval); + } +} + +static void mt7925_nan_set_disc_beacon(struct mt7925_nan_enable_req_tlv *req, + struct cfg80211_nan_conf *conf) +{ + if (conf->discovery_beacon_interval > 0) { + req->config_2dot4g_beacons = true; + req->beacon_2dot4g_val = conf->discovery_beacon_interval; + } +} + +static void mt7925_nan_set_rssi_thresholds(struct mt7925_nan_enable_req_tlv *req, + struct cfg80211_nan_conf *conf) +{ + if (conf->band_cfgs[NL80211_BAND_2GHZ].chan) { + req->config_2dot4g_rssi_close = 1; + req->rssi_close_2dot4g_val = + abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close); + req->config_2dot4g_rssi_middle = 1; + req->rssi_middle_2dot4g_val = + abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle); + } + + if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) { + req->config_5g_rssi_close = 1; + req->rssi_close_5g_val = + abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close); + req->config_5g_rssi_middle = 1; + req->rssi_middle_5g_val = + abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle); + } +} + +static void mt7925_nan_set_scan_params(struct mt7925_nan_enable_req_tlv *req, + struct cfg80211_nan_conf *conf) +{ + req->scan_params_val.scan_period[0] = + cpu_to_le16(conf->scan_period < 255 ? conf->scan_period : 255); + req->scan_params_val.dwell_time[0] = + conf->scan_dwell_time < 255 ? conf->scan_dwell_time : 255; +} + +static u16 +mt7925_nan_avail_attr_ctrl(const struct ieee80211_nan_sched_cfg *sched) +{ + if (sched->avail_blob_len < NAN_AVAIL_ATTR_CTRL_OFFSET + 2) + return 0; + + return sched->avail_blob[NAN_AVAIL_ATTR_CTRL_OFFSET] | + sched->avail_blob[NAN_AVAIL_ATTR_CTRL_OFFSET + 1] << 8; +} + +static void +mt7925_nan_update_conf(struct mt792x_vif *mvif, + const struct cfg80211_nan_conf *conf) +{ + mvif->nan.conf.master_pref = conf->master_pref; + mvif->nan.conf.bands = conf->bands; + mvif->nan.conf.discovery_beacon_interval = + conf->discovery_beacon_interval; + mvif->nan.conf.enable_dw_notification = + conf->enable_dw_notification; + + memcpy(mvif->nan.conf.cluster_id, conf->cluster_id, ETH_ALEN); +} + +int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr) +{ + struct mt76_dev *mdev; + struct { + u8 rsv[4]; + struct mt7925_nan_nmi_addr_tlv nmi_addr_tlv; + } nmi_cmd = { + .rsv = { 0 }, + .nmi_addr_tlv = { + .tag = cpu_to_le16(NAN_UNI_CMD_CHANGE_NMI_ADDRESS), + .len = cpu_to_le16(sizeof(struct mt7925_nan_nmi_addr_tlv)), + }, + }; + int ret; + + if (!dev || !addr) + return -EINVAL; + + if (is_zero_ether_addr(addr) || is_multicast_ether_addr(addr)) { + dev_err(dev->mt76.dev, "NAN: invalid NMI address %pM\n", addr); + return -EINVAL; + } + + mdev = &dev->mt76; + memcpy(nmi_cmd.nmi_addr_tlv.nmi_addr, addr, ETH_ALEN); + + ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nmi_cmd, + sizeof(nmi_cmd), true); + + return ret; +} + +int mt7925_nan_enable(struct ieee80211_vif *vif, + struct mt792x_dev *dev, + struct cfg80211_nan_conf *conf) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt76_dev *mdev = &dev->mt76; + struct { + u8 rsv[4]; + struct mt7925_nan_enable_req_tlv nan_req_tlv; + } nan_cmd = { + .rsv = { 0 }, + .nan_req_tlv = { + .tag = cpu_to_le16(NAN_UNI_CMD_ENABLE_REQUEST), + .len = cpu_to_le16(sizeof(struct mt7925_nan_enable_req_tlv)), + .config_random_factor_force = 0, + .random_factor_force_val = 0, + .config_hop_count_force = 0, + .hop_count_force_val = 0, + }, + }; + struct mt7925_nan_enable_req_tlv *p_nan_req_tlv = &nan_cmd.nan_req_tlv; + int ret; + + if (!vif || !dev || !conf) + return -EINVAL; + + p_nan_req_tlv->master_pref = conf->master_pref; + + mt7925_nan_set_2g_support(p_nan_req_tlv, conf); + mt7925_nan_set_5g_channel(dev, p_nan_req_tlv, conf); + mt7925_nan_set_cluster_id(p_nan_req_tlv, conf->cluster_id); + mt7925_nan_set_dw_interval(p_nan_req_tlv, conf); + mt7925_nan_set_disc_beacon(p_nan_req_tlv, conf); + mt7925_nan_set_rssi_thresholds(p_nan_req_tlv, conf); + mt7925_nan_set_scan_params(p_nan_req_tlv, conf); + + mt7925_nan_update_conf(mvif, conf); + + ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true); + + return ret; +} + +int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev) +{ + struct mt76_dev *mdev = &dev->mt76; + struct { + u8 rsv[4]; + struct tlv nan_dis_tlv; + } nan_cmd = { + .rsv = { 0 }, + .nan_dis_tlv = { + .tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST), + .len = cpu_to_le16(sizeof(struct tlv)), + }, + }; + + if (!dev) + return -EINVAL; + + return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true); +} + +static int +mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref) +{ + struct mt7925_nan_master_preference_tlv *mp_tlv = NULL; + struct tlv *tlv = NULL; + + if (!skb) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_MASTER_PREFERENCE, + sizeof(struct mt7925_nan_master_preference_tlv)); + if (!tlv) + return -ENOMEM; + + mp_tlv = (struct mt7925_nan_master_preference_tlv *)tlv; + + if (master_pref > NAN_MAX_MASTER_PREFERENCE) + return 0; + + mp_tlv->master_preference = master_pref; + + return 0; +} + +static int +mt7925_nan_dw_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf) +{ + struct mt7925_nan_dw_interval_tlv *dw_tlv = NULL; + struct tlv *tlv = NULL; + u16 interval; + + if (!skb || !conf) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_DW_INTERVAL, + sizeof(struct mt7925_nan_dw_interval_tlv)); + + if (!tlv) + return -ENOMEM; + + dw_tlv = (struct mt7925_nan_dw_interval_tlv *)tlv; + + /* Set DW interval for 2.4GHz and 5GHz bands if available */ + if (conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval > 0) { + dw_tlv->dw_interval = conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval; + } else if (conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval > 0) { + dw_tlv->dw_interval = conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval; + } else { + /* Fallback to a default value or log a warning */ + dw_tlv->dw_interval = NAN_DEFAULT_DW_INTERVAL; + } + + /* Validate and set NAN Discovery Beacon Interval */ + interval = conf->discovery_beacon_interval > 0 ? + conf->discovery_beacon_interval : + NAN_DEFAULT_DISC_BCN_INTERVAL; + + dw_tlv->disc_bcn_interval = cpu_to_le16(interval); + + return 0; +} + +static int +mt7925_nan_cluster_id_tlv(struct sk_buff *skb, const u8 *cluster_id) +{ + struct mt7925_nan_cluster_id_tlv *cluster_tlv = NULL; + struct tlv *tlv = NULL; + + if (!skb || !cluster_id) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_CLUSTER_ID, + sizeof(struct mt7925_nan_cluster_id_tlv)); + + if (!tlv) + return -ENOMEM; + + cluster_tlv = (struct mt7925_nan_cluster_id_tlv *)tlv; + + memcpy(cluster_tlv->cluster_id, cluster_id, ETH_ALEN); + + return 0; +} + +static int +mt7925_nan_sync_rssi_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf) +{ + struct mt7925_nan_sync_rssi_tlv *rssi_tlv = NULL; + struct tlv *tlv = NULL; + + if (!skb || !conf) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_SET_SYNC_RSSI, + sizeof(struct mt7925_nan_sync_rssi_tlv)); + + if (!tlv) + return -ENOMEM; + + rssi_tlv = (struct mt7925_nan_sync_rssi_tlv *)tlv; + + if (conf->band_cfgs[NL80211_BAND_2GHZ].chan) { + rssi_tlv->rssi_close_2g = + conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close; + rssi_tlv->rssi_middle_2g = + conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle; + } + + if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) { + rssi_tlv->rssi_close_5g = + conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close; + rssi_tlv->rssi_middle_5g = + conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle; + } + + return 0; +} + +int mt7925_nan_change_configure(struct ieee80211_vif *vif, + struct mt792x_dev *dev, + struct cfg80211_nan_conf *conf) +{ + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + struct mt7925_nan_common_hdr *hdr = NULL; + struct mt76_dev *mdev = &dev->mt76; + struct sk_buff *skb = NULL; + + if (!vif || !dev || !conf) + return -EINVAL; + + skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_CONF_MAX_SIZE); + if (!skb) + return -ENOMEM; + + hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + + if (mt7925_nan_mp_tlv(skb, conf->master_pref) || + mt7925_nan_dw_tlv(skb, conf) || + mt7925_nan_cluster_id_tlv(skb, conf->cluster_id) || + mt7925_nan_sync_rssi_tlv(skb, conf)) { + dev_kfree_skb(skb); + return -ENOMEM; + } + + mt7925_nan_update_conf(mvif, conf); + + return mt76_mcu_skb_send_msg(mdev, skb, + MCU_UNI_CMD(NAN), true); +} + +static void +mt7925_nan_handle_dw_ind(struct mt792x_dev *dev, struct tlv *tlv) +{ + struct ieee80211_channel *chan; + struct nan_rpt_dw_evt *evt; + struct wireless_dev *wdev; + u16 len, channel, dw_num; + struct mt792x_vif *mvif; + enum nl80211_band band; + int freq; + + if (!dev || !tlv) + return; + + len = le16_to_cpu(tlv->len); + if (len < sizeof(*tlv) + sizeof(*evt)) { + dev_warn(dev->mt76.dev, + "nan: short dw event tlv len=%u\n", len); + return; + } + + if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) + return; + + wdev = ieee80211_vif_to_wdev(dev->nan_vif); + if (!wdev) + return; + + mvif = (struct mt792x_vif *)dev->nan_vif->drv_priv; + if (!mvif->nan.conf.enable_dw_notification) + return; + + evt = (struct nan_rpt_dw_evt *)tlv->data; + channel = le16_to_cpu(evt->channel); + dw_num = le16_to_cpu(evt->dw_num); + + band = channel > 13 ? NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; + freq = ieee80211_channel_to_frequency(channel, band); + chan = ieee80211_get_channel(dev->mt76.hw->wiphy, freq); + if (!chan) { + dev_dbg(dev->mt76.dev, + "nan: no channel for dw end event ch=%u dw=%u\n", + channel, dw_num); + return; + } + + cfg80211_next_nan_dw_notif(wdev, chan, GFP_KERNEL); +} + +static void +mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv) +{ + u8 cluster_id[ETH_ALEN] __aligned(2) = {0x50, 0x6f, 0x9a, 0x01, 0x00, 0x00}; + struct mt7925_nan_de_event *de_evt = NULL; + u16 len; + + if (!dev || !tlv) { + if (dev) + dev_warn(dev->mt76.dev, "nan: failed to parse TLV\n"); + return; + } + + len = le16_to_cpu(tlv->len); + if (len < sizeof(*tlv) + sizeof(*de_evt)) { + dev_warn(dev->mt76.dev, + "nan: short de_event tlv len=%u\n", len); + return; + } + + de_evt = (struct mt7925_nan_de_event *)tlv->data; + if (!de_evt) { + dev_warn(dev->mt76.dev, "nan: missing DE event payload\n"); + return; + } + + if (de_evt->event_type == NAN_EVENT_ID_DISC_MAC_ADDR) + return; + + memcpy(cluster_id, de_evt->cluster_id, ETH_ALEN); + + dev_dbg(dev->mt76.dev, "nan: evt=%u cluster=%pM\n", + de_evt->event_type, de_evt->cluster_id); + + if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER) + return; + + if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) { + dev_warn(dev->mt76.dev, "nan: joined-cluster event but NAN not started\n"); + return; + } + + dev_dbg(dev->mt76.dev, "nan: anchor_master_rank=%*phN\n", + NAN_ANCHOR_MASTER_RANK_NUM, de_evt->anchor_master_rank); + + dev_dbg(dev->mt76.dev, "nan: own_nmi=%pM master_nmi=%pM\n", + de_evt->own_nmi, de_evt->master_nmi); + + ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL); +} + +void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb) +{ + struct tlv *tlv; + u32 tlv_len; + + if (!dev || !skb) + return; + + if (skb->len < sizeof(struct mt7925_mcu_rxd) + 4) + return; + + skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4); + tlv = (struct tlv *)skb->data; + tlv_len = skb->len; + + while (tlv_len >= sizeof(*tlv)) { + u16 len = le16_to_cpu(tlv->len); + + if (len < sizeof(*tlv) || len > tlv_len) + break; + + switch (le16_to_cpu(tlv->tag)) { + case NAN_UNI_EVENT_ID_DE_EVENT_IND: + mt7925_nan_mcu_handle_de_event(dev, tlv); + break; + case NAN_UNI_EVENT_REPORT_DW_END: + mt7925_nan_handle_dw_ind(dev, tlv); + break; + default: + break; + } + + tlv_len -= len; + tlv = (struct tlv *)((u8 *)tlv + len); + } +} + +static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif) +{ + struct mt7925_nan_avail_ctrl_tlv *avail_ctrl_tlv; + struct ieee80211_nan_sched_cfg *sched; + struct tlv *tlv; + u8 seq_id = 0; + u16 ctrl = 0; + + if (!skb || !vif) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL, + sizeof(struct mt7925_nan_avail_ctrl_tlv)); + + if (!tlv) + return -ENOMEM; + + sched = &vif->cfg.nan_sched; + + ctrl = mt7925_nan_avail_attr_ctrl(sched); + if (sched->avail_blob_len >= NAN_AVAIL_ATTR_CTRL_OFFSET + 2) + seq_id = sched->avail_blob[NAN_AVAIL_SEQ_ID_OFFSET]; + + avail_ctrl_tlv = (struct mt7925_nan_avail_ctrl_tlv *)tlv; + avail_ctrl_tlv->avail_ctrl = + cpu_to_le16(ctrl & NAN_AVAIL_CTRL_CHECK_FOR_CHANGED); + avail_ctrl_tlv->seq_id = seq_id; + + return 0; +} + +static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif, + struct mt7925_nan_ch_timeline *ch_list) +{ + struct ieee80211_nan_channel **slots = vif->cfg.nan_sched.schedule; + struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv; + u32 num_channels = 0; + u32 i, j; + + for (i = 0; i < ARRAY_SIZE(mvif->nan.local_sched); i++) { + struct cfg80211_chan_def *slot_chan = &mvif->nan.local_sched[i]; + struct ieee80211_nan_channel *slot = slots[i]; + bool is_found = false; + + if (slot && !IS_ERR(slot) && slot->chanctx_conf) { + *slot_chan = slot->chanctx_conf->def; + } else { + memset(slot_chan, 0, sizeof(*slot_chan)); + continue; + } + + for (j = 0; j < num_channels; j++) { + u32 raw = le32_to_cpu(ch_list[j].ch_info); + + if (FIELD_GET(NAN_CH_CTRL_PRIMARY_CH, raw) == + slot_chan->chan->hw_value) { + u32 map = le32_to_cpu(ch_list[j].avail_map[0]); + + ch_list[j].avail_map[0] = cpu_to_le32(map | BIT(i)); + le32_add_cpu(&ch_list[j].num, 1); + is_found = true; + break; + } + } + + if (!is_found && num_channels < NAN_TIMELINE_MGMT_CHNL_LIST_NUM) { + ch_list[num_channels].ch_info = + cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_OP_CLASS, + slot->channel_entry[0]) | + FIELD_PREP(NAN_CH_CTRL_PRIMARY_CH, + slot_chan->chan->hw_value)); + ch_list[num_channels].avail_map[0] = cpu_to_le32(BIT(i)); + le32_add_cpu(&ch_list[num_channels].num, 1); + ch_list[num_channels].is_valid++; + num_channels++; + } + } + + return num_channels; +} + +static int mt7925_nan_avail_tlv(struct sk_buff *skb, + struct ieee80211_vif *vif) +{ + struct mt7925_nan_avail_entry_tlv *avail_tlv; + struct ieee80211_nan_sched_cfg *sched; + struct tlv *tlv; + u16 ctrl = 0; + + if (!skb || !vif) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_AVAILABILITY, + sizeof(struct mt7925_nan_avail_entry_tlv)); + + if (!tlv) + return -ENOMEM; + + sched = &vif->cfg.nan_sched; + + ctrl = mt7925_nan_avail_attr_ctrl(sched); + + avail_tlv = (struct mt7925_nan_avail_entry_tlv *)tlv; + avail_tlv->map_id = ctrl & NAN_AVAIL_CTRL_MAPID; + avail_tlv->is_cond_avail = false; + avail_tlv->timeline_idx = 0; + + mt7925_nan_slot_to_bitmap(vif, avail_tlv->ch_list); + + avail_tlv->is_multi_map = false; + + return 0; +} + +void mt7925_nan_local_sched_changed(struct mt792x_dev *dev, + struct ieee80211_vif *vif) +{ + struct mt7925_nan_common_hdr *hdr; + struct mt76_dev *mdev; + bool deferred; + struct sk_buff *skb; + int ret = -ENOMEM; + + if (!dev || !vif) + return; + + mdev = &dev->mt76; + deferred = vif->cfg.nan_sched.deferred; + + mt792x_mutex_acquire(dev); + + skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_AVAIL_MAX_SIZE); + if (!skb) + goto out; + + hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + + if (mt7925_nan_avail_ctrl_tlv(skb, vif) || + mt7925_nan_avail_tlv(skb, vif)) { + dev_kfree_skb(skb); + goto out; + } + + ret = mt76_mcu_skb_send_msg(mdev, skb, + MCU_UNI_CMD(NAN), true); +out: + mt792x_mutex_release(dev); + + if (deferred) { + if (ret) + dev_err(mdev->dev, + "NAN: local schedule update failed: %d\n", + ret); + + ieee80211_nan_sched_update_done(vif); + } +} + +static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb, + struct ieee80211_sta *sta, + struct mt792x_sta *msta, + u8 is_activate) +{ + struct mt7925_nan_sched_manage_peer_rec_tlv *peer_rec_tlv; + struct tlv *tlv; + + if (!skb || !sta || !msta) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD, + sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv)); + + if (!tlv) + return -ENOMEM; + + peer_rec_tlv = (struct mt7925_nan_sched_manage_peer_rec_tlv *)tlv; + peer_rec_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx); + peer_rec_tlv->is_activate = is_activate; + memcpy(peer_rec_tlv->nmi_addr, sta->addr, ETH_ALEN); + + return 0; +} + +static u8 mt7925_nan_get_supported_bands(struct mt792x_vif *mvif) +{ + struct wiphy *wiphy; + u8 bands = 0; + + if (!mvif || !mvif->phy) + return BIT(NAN_SUPPORTED_BAND_ID_2P4G); + + wiphy = mvif->phy->mt76->hw->wiphy; + if (wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ)) + bands |= BIT(NAN_SUPPORTED_BAND_ID_2P4G); + if (wiphy->nan_supported_bands & BIT(NL80211_BAND_5GHZ)) + bands |= BIT(NAN_SUPPORTED_BAND_ID_5G); + + return bands ?: BIT(NAN_SUPPORTED_BAND_ID_2P4G); +} + +static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb, + struct ieee80211_sta *sta, + struct mt792x_sta *msta) +{ + struct mt7925_nan_sched_update_peer_cap_tlv *peer_cap_tlv; + struct ieee80211_nan_peer_sched *sched; + enum nl80211_band band; + struct tlv *tlv; + u16 primary_ch; + u32 i; + + if (!skb || !sta || !msta) + return -EINVAL; + + sched = sta->nan_sched; + if (!sched) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_PEER_CAPABILITY, + sizeof(struct mt7925_nan_sched_update_peer_cap_tlv)); + + if (!tlv) + return -ENOMEM; + + peer_cap_tlv = (struct mt7925_nan_sched_update_peer_cap_tlv *)tlv; + peer_cap_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx); + peer_cap_tlv->supported_bands = + mt7925_nan_get_supported_bands(msta->vif); + peer_cap_tlv->max_chnl_switch_time = cpu_to_le16(sched->max_chan_switch); + + for (i = 0; i < sched->n_channels; i++) { + if (!sched->channels[i].chanctx_conf) + continue; + + band = sched->channels[i].chanctx_conf->def.chan->band; + primary_ch = + sched->channels[i].chanctx_conf->def.chan->hw_value; + + if (band == NL80211_BAND_2GHZ) + peer_cap_tlv->peer_supported_bands |= + BIT(NAN_SUPPORTED_BN_2G); + else if (primary_ch >= UNII1_LOWER_BOUND && + primary_ch <= UNII1_UPPER_BOUND) + peer_cap_tlv->peer_supported_bands |= + BIT(NAN_SUPPORTED_BN_5G_LOW); + else if (primary_ch >= UNII3_LOWER_BOUND && + primary_ch <= UNII3_UPPER_BOUND) + peer_cap_tlv->peer_supported_bands |= + BIT(NAN_SUPPORTED_BN_5G_HIGH); + } + + return 0; +} + +static void +mt7925_nan_fill_crb_committed(struct mt7925_nan_sched_update_crb_tlv *crb_tlv, + struct ieee80211_vif *vif, + struct ieee80211_nan_peer_sched *sched) +{ + struct ieee80211_nan_sched_cfg *local_sched; + u8 local_map_id; + u32 m, slot; + + if (!vif || !sched) + return; + + local_sched = &vif->cfg.nan_sched; + local_map_id = mt7925_nan_avail_attr_ctrl(local_sched) & + NAN_AVAIL_CTRL_MAPID; + + for (m = 0; m < CFG80211_NAN_MAX_PEER_MAPS && + m < NAN_TIMELINE_MGMT_SIZE; m++) { + struct mt7925_nan_sched_timeline *tl = + &crb_tlv->comm_faw_timeline[m]; + struct ieee80211_nan_peer_map *map = &sched->maps[m]; + u32 avail_map = 0; + + if (map->map_id == CFG80211_NAN_INVALID_MAP_ID) + continue; + + tl->map_id = map->map_id; + tl->local_map_id = local_map_id; + + for (slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; + slot++) { + struct ieee80211_nan_channel *local_ch; + struct ieee80211_nan_channel *peer_ch; + + local_ch = local_sched->schedule[slot]; + peer_ch = map->slots[slot]; + + if (!local_ch || !local_ch->chanctx_conf || + !peer_ch || !peer_ch->chanctx_conf) + continue; + + if (local_ch->chanctx_conf != peer_ch->chanctx_conf) + continue; + + avail_map |= BIT(slot); + } + + tl->avail_map[0] = cpu_to_le32(avail_map); + } +} + +static int mt7925_nan_update_crb_tlv(struct sk_buff *skb, + struct ieee80211_sta *sta, + struct mt792x_sta *msta) +{ + struct mt7925_nan_sched_update_crb_tlv *crb_tlv; + struct tlv *tlv; + + if (!skb || !sta || !msta) + return -EINVAL; + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_CRB, + sizeof(struct mt7925_nan_sched_update_crb_tlv)); + + if (!tlv) + return -ENOMEM; + + crb_tlv = (struct mt7925_nan_sched_update_crb_tlv *)tlv; + crb_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx); + crb_tlv->flags = NAN_CRB_USE_DATA_PATH; + crb_tlv->is_use_ranging = false; + crb_tlv->comm_ndc_ctrl.is_valid = false; + + mt7925_nan_fill_crb_committed(crb_tlv, msta->vif->phy->dev->nan_vif, + sta->nan_sched); + + return 0; +} + +int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev, + struct ieee80211_sta *sta) +{ + struct mt7925_nan_common_hdr *hdr; + bool idx_allocated = false; + struct mt792x_sta *msta; + struct mt792x_nan *nan; + struct mt76_dev *mdev; + struct sk_buff *skb; + int ret; + + if (!dev || !sta) + return -EINVAL; + + mdev = &dev->mt76; + + skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_PEER_MAX_SIZE); + if (!skb) + return -ENOMEM; + + hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + + msta = (struct mt792x_sta *)sta->drv_priv; + nan = &msta->vif->nan; + + /* Allocate connection index on first call for this peer */ + if (!msta->nan_sched.idx_assigned) { + int idx = find_first_zero_bit(&nan->conn_bitmap, + NAN_MAX_CONN_CFG); + if (idx >= NAN_MAX_CONN_CFG) { + dev_kfree_skb(skb); + return -ENOSPC; + } + + set_bit(idx, &nan->conn_bitmap); + msta->nan_sched.sch_idx = idx; + msta->nan_sched.idx_assigned = true; + idx_allocated = true; + + if (mt7925_nan_peer_rec_tlv(skb, sta, msta, true) || + mt7925_nan_peer_cap_tlv(skb, sta, msta)) { + ret = -ENOMEM; + goto free_skb; + } + } + + if (mt7925_nan_update_crb_tlv(skb, sta, msta)) { + ret = -ENOMEM; + goto free_skb; + } + + ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true); + if (ret && idx_allocated) + goto clear_idx; + + return ret; + +free_skb: + dev_kfree_skb(skb); + if (!idx_allocated) + return ret; + +clear_idx: + clear_bit(msta->nan_sched.sch_idx, &nan->conn_bitmap); + msta->nan_sched.idx_assigned = false; + + return ret; +} + +int mt792x_nan_set_peer_rec(struct mt76_dev *mdev, + struct ieee80211_sta *sta) +{ + struct mt7925_nan_common_hdr *hdr; + struct mt792x_sta *msta; + struct mt792x_nan *nan; + struct sk_buff *skb; + int ret; + + if (!mdev || !sta) + return -EINVAL; + + skb = mt76_mcu_msg_alloc(mdev, NULL, + sizeof(struct mt7925_nan_common_hdr) + + sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv)); + if (!skb) + return -ENOMEM; + + hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + + msta = (struct mt792x_sta *)sta->drv_priv; + nan = &msta->vif->nan; + + if (!msta->nan_sched.idx_assigned) { + dev_kfree_skb(skb); + return 0; + } + + if (mt7925_nan_peer_rec_tlv(skb, sta, msta, false)) { + dev_kfree_skb(skb); + return -ENOMEM; + } + + ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true); + if (ret) + return ret; + + clear_bit(msta->nan_sched.sch_idx, &nan->conn_bitmap); + msta->nan_sched.idx_assigned = false; + + return 0; +} + +int mt792x_nan_map_sta_rec(struct mt76_dev *mdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta) +{ + struct mt7925_nan_sched_map_sta_rec_tlv *map_tlv; + struct mt7925_nan_common_hdr *hdr; + struct ieee80211_sta *nmi_sta; + struct mt792x_sta *nmi_msta; + struct mt792x_vif *mvif; + struct mt792x_sta *msta; + u8 nmi_addr[ETH_ALEN]; + struct sk_buff *skb; + int ndp_ctx_id = 0; + int ret = -ENOMEM; + struct mt792x_dev *dev; + struct tlv *tlv; + + if (!mdev || !vif || !sta) + return -EINVAL; + + dev = container_of(mdev, struct mt792x_dev, mt76); + msta = (struct mt792x_sta *)sta->drv_priv; + mvif = (struct mt792x_vif *)vif->drv_priv; + + rcu_read_lock(); + nmi_sta = rcu_dereference(sta->nmi); + if (!nmi_sta) { + rcu_read_unlock(); + dev_err(mdev->dev, "NAN: NMI sta not found for NDI sta %pM\n", + sta->addr); + return -EINVAL; + } + + memcpy(nmi_addr, nmi_sta->addr, ETH_ALEN); + nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv; + + if (!nmi_msta->nan_sched.idx_assigned) { + if (!nmi_sta->nan_sched) { + rcu_read_unlock(); + dev_err(mdev->dev, + "NAN: peer schedule missing for NDI sta %pM\n", + sta->addr); + return -EAGAIN; + } + + rcu_read_unlock(); + ret = mt792x_nan_set_peer_schedule(dev, nmi_sta); + if (ret) + return ret; + + rcu_read_lock(); + nmi_sta = rcu_dereference(sta->nmi); + if (!nmi_sta) { + rcu_read_unlock(); + dev_err(mdev->dev, + "NAN: NMI sta not found for NDI sta %pM\n", + sta->addr); + return -EINVAL; + } + + nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv; + } + + ndp_ctx_id = find_first_zero_bit(&nmi_msta->nan_sched.ndp_ctx_bitmap, + NAN_MAX_NDP_CXT); + if (ndp_ctx_id >= NAN_MAX_NDP_CXT) { + rcu_read_unlock(); + return -ENOSPC; + } + + set_bit(ndp_ctx_id, &nmi_msta->nan_sched.ndp_ctx_bitmap); + rcu_read_unlock(); + + msta->nan_sched.ndp_ctx_id = ndp_ctx_id; + msta->nan_sched.ndp_ctx_assigned = true; + + skb = mt76_mcu_msg_alloc(mdev, NULL, + sizeof(struct mt7925_nan_common_hdr) + + sizeof(struct mt7925_nan_sched_map_sta_rec_tlv)); + if (!skb) + goto clear_ndp_ctx; + + hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr)); + memset(hdr, 0, sizeof(*hdr)); + + tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_MAP_STA_RECORD, + sizeof(struct mt7925_nan_sched_map_sta_rec_tlv)); + if (!tlv) { + dev_kfree_skb(skb); + ret = -ENOMEM; + goto clear_ndp_ctx; + } + + map_tlv = (struct mt7925_nan_sched_map_sta_rec_tlv *)tlv; + memcpy(map_tlv->nmi_addr, nmi_addr, ETH_ALEN); + map_tlv->sta_rec_idx = msta->deflink.wcid.idx; + map_tlv->ndp_ctx_id = ndp_ctx_id; + map_tlv->role_idx = cpu_to_le32(mvif->bss_conf.mt76.idx); + memcpy(map_tlv->ndi_addr, vif->addr, ETH_ALEN); + + ret = mt76_mcu_skb_send_msg(mdev, skb, + MCU_UNI_CMD(NAN), true); + if (ret) + goto clear_ndp_ctx; + + return 0; + +clear_ndp_ctx: + rcu_read_lock(); + nmi_sta = rcu_dereference(sta->nmi); + if (nmi_sta) { + nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv; + clear_bit(msta->nan_sched.ndp_ctx_id, + &nmi_msta->nan_sched.ndp_ctx_bitmap); + } + rcu_read_unlock(); + msta->nan_sched.ndp_ctx_assigned = false; + + return ret ?: -ENOMEM; +} diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/nan.h b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h new file mode 100644 index 000000000000..f55730e25f46 --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/mt7925/nan.h @@ -0,0 +1,421 @@ +/* SPDX-License-Identifier: BSD-3-Clause-Clear */ +/* Copyright (C) 2025-2026 MediaTek Inc. */ + +#ifndef __MT7925_NAN_H +#define __MT7925_NAN_H + +#include +#include + +#include "../mt76_connac_mcu.h" + +#define NAN_MAX_SOCIAL_CHANNELS 3 +#define NAN_ANCHOR_MASTER_RANK_NUM 8 +#define NAN_5G_LOW_DISC_CHANNEL 44 +#define NAN_5G_HIGH_DISC_CHANNEL 149 +#define NAN_MAX_MASTER_PREFERENCE 255 +#define NAN_DEFAULT_DW_INTERVAL 1 +#define NAN_DEFAULT_DISC_BCN_INTERVAL 100 +#define NAN_TOTAL_DW 16 +#define NAN_SUPPORTED_2G_FAW_CH_NUM 4 +#define NAN_SUPPORTED_5G_FAW_CH_NUM 4 +#define NAN_TIMELINE_MGMT_SIZE 2 +#define NAN_TIMELINE_MGMT_CHNL_LIST_NUM \ + ((NAN_SUPPORTED_2G_FAW_CH_NUM + \ + NAN_SUPPORTED_5G_FAW_CH_NUM) / NAN_TIMELINE_MGMT_SIZE) +#define NAN_NUM_AVAIL_DB 2 +#define NAN_NDC_ATTRIBUTE_ID_LENGTH 6 +#define NAN_MAX_CONN_CFG 8 +#define NAN_MAX_NDP_CXT 4 + +#define MT7925_NAN_CONF_MAX_SIZE \ + (sizeof(struct mt7925_nan_common_hdr) + \ + sizeof(struct mt7925_nan_master_preference_tlv) + \ + sizeof(struct mt7925_nan_dw_interval_tlv) + \ + sizeof(struct mt7925_nan_cluster_id_tlv) + \ + sizeof(struct mt7925_nan_sync_rssi_tlv)) + +#define MT7925_NAN_AVAIL_MAX_SIZE \ + (sizeof(struct mt7925_nan_common_hdr) + \ + sizeof(struct mt7925_nan_avail_ctrl_tlv) + \ + sizeof(struct mt7925_nan_avail_entry_tlv)) + +#define MT7925_NAN_PEER_MAX_SIZE \ + (sizeof(struct mt7925_nan_common_hdr) + \ + sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv) + \ + sizeof(struct mt7925_nan_sched_update_peer_cap_tlv) + \ + sizeof(struct mt7925_nan_sched_update_crb_tlv)) + +/* NAN Availability Attribute */ +#define NAN_AVAIL_ATTR_ID_OFFSET 0 +#define NAN_AVAIL_ATTR_LEN_OFFSET 1 +#define NAN_AVAIL_SEQ_ID_OFFSET 3 +#define NAN_AVAIL_ATTR_CTRL_OFFSET 4 + +/* NAN Availability Attribute - Attribute Control Field */ +#define NAN_AVAIL_CTRL_MAPID GENMASK(3, 0) +#define NAN_AVAIL_CTRL_COMMIT_CHANGED BIT(4) +#define NAN_AVAIL_CTRL_POTN_CHANGED BIT(5) +#define NAN_AVAIL_CTRL_PUBLIC_AVAIL_CHANGED BIT(6) +#define NAN_AVAIL_CTRL_NDC_CHANGED BIT(7) +#define NAN_AVAIL_CTRL_CHECK_FOR_CHANGED GENMASK(7, 4) + +#define UNII1_LOWER_BOUND 36 +#define UNII1_UPPER_BOUND 50 +#define UNII3_LOWER_BOUND 149 +#define UNII3_UPPER_BOUND 165 + +enum nan_uni_cmd_tag { + NAN_UNI_CMD_SET_MASTER_PREFERENCE = 0, + NAN_UNI_CMD_ENABLE_REQUEST = 7, + NAN_UNI_CMD_DISABLE_REQUEST = 8, + NAN_UNI_CMD_UPDATE_AVAILABILITY = 9, + NAN_UNI_CMD_UPDATE_CRB = 10, + NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD = 12, + NAN_UNI_CMD_MAP_STA_RECORD = 13, + NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL = 20, + NAN_UNI_CMD_UPDATE_PEER_CAPABILITY = 21, + NAN_UNI_CMD_CHANGE_NMI_ADDRESS = 24, + NAN_UNI_CMD_SET_DW_INTERVAL = 26, + NAN_UNI_CMD_SET_SYNC_RSSI = 39, + NAN_UNI_CMD_SET_CLUSTER_ID = 40, + NAN_UNI_CMD_KEY_MANAGEMENT = 53, +}; + +enum nan_uni_event_tag { + NAN_UNI_EVENT_ID_DE_EVENT_IND = 19, + NAN_UNI_EVENT_REPORT_DW_END = 60, +}; + +enum nan_disc_event_type { + NAN_EVENT_ID_DISC_MAC_ADDR = 0, + NAN_EVENT_ID_JOINED_CLUSTER = 2, +}; + +/* NAN 4.0 Table 79. Device Capability attribute format, Supported Bands */ +enum nan_supported_bands { + NAN_SUPPORTED_BAND_ID_2P4G = 2, + NAN_SUPPORTED_BAND_ID_5G = 4, + NAN_PROPRIETARY_BAND_ID_6G = 6, + NAN_SUPPORTED_BAND_ID_6G = 7, +}; + +enum nan_peer_supported_bands { + NAN_SUPPORTED_BN_2G = 0, + NAN_SUPPORTED_BN_5G_LOW, + NAN_SUPPORTED_BN_5G_HIGH, + NAN_SUPPORTED_BN_6G, + NAN_SUPPORTED_BN_NUM +}; + +#define NAN_CH_CTRL_OP_CLASS GENMASK(15, 8) +#define NAN_CH_CTRL_PRIMARY_CH GENMASK(23, 16) + +#define NAN_CRB_USE_DATA_PATH BIT(0) +#define NAN_CRB_AVAIL_6G_FORMAT GENMASK(2, 1) + +struct mt7925_nan_social_ch_scan_params { + u8 dwell_time[NAN_MAX_SOCIAL_CHANNELS]; + __le16 scan_period[NAN_MAX_SOCIAL_CHANNELS]; +} __packed; + +/* Firmware-reported NAN device information */ +struct nan_dev_info_evt { + u8 is_enabled; + u8 my_addr[ETH_ALEN]; + u8 en_fw_election; + __le32 nan_dev_role; + __le32 nan_dev_state; + u8 mst_preference; + u8 random_factor; + u8 cnt_hop; + u8 cluster_id[ETH_ALEN]; + u8 anchor_mst_addr[ETH_ALEN]; + u8 am_preference; + u8 am_random_factor; + u8 parent_mac[ETH_ALEN]; + u8 parent_am_preference; + u8 parent_am_factor; + __le32 ambtt; + __le32 tsf[2]; + u8 pn_igtk[6]; + u8 pn_bigtk[6]; +}; + +/* Firmware NAN discovery window event */ +struct nan_rpt_dw_evt { + struct nan_dev_info_evt device_info; + __le32 expected_tsf_h; + __le32 expected_tsf_l; + __le32 actual_tsf_h; + __le32 actual_tsf_l; + __le16 channel; + __le16 dw_num; +}; + +struct mt7925_nan_conf_dw { + u8 config_2dot4g_dw_band; + __le32 dw_2dot4g_interval_val; + + u8 config_5g_dw_band; + __le32 dw_5g_interval_val; +} __packed; + +struct mt7925_nan_enable_req_tlv { + __le16 tag; + __le16 len; + + u8 master_pref; + __le16 cluster_low; + __le16 cluster_high; + + u8 config_support_5g; + u8 support_5g_val; + + u8 config_sid_beacon; + u8 sid_beacon_val; + + u8 config_2dot4g_rssi_close; + u8 rssi_close_2dot4g_val; + u8 config_2dot4g_rssi_middle; + u8 rssi_middle_2dot4g_val; + + u8 config_2dot4g_rssi_proximity; + u8 rssi_proximity_2dot4g_val; + u8 config_hop_count_limit; + u8 hop_count_limit_val; + + u8 config_2dot4g_support; + u8 support_2dot4g_val; + + u8 config_2dot4g_beacons; + u8 beacon_2dot4g_val; + + u8 config_2dot4g_sdf; + u8 sdf_2dot4g_val; + + u8 config_5g_beacons; + u8 beacon_5g_val; + + u8 config_5g_sdf; + u8 sdf_5g_val; + + u8 config_5g_rssi_close; + u8 rssi_close_5g_val; + + u8 config_5g_rssi_middle; + u8 rssi_middle_5g_val; + + u8 config_5g_rssi_close_proximity; + u8 rssi_close_proximity_5g_val; + + u8 config_rssi_window_size; + u8 rssi_window_size_val; + + u8 config_oui; + __le32 oui_val; + + u8 config_intf_addr; + u8 intf_addr_val[ETH_ALEN]; + + u8 config_cluster_attribute_val; + + u8 config_scan_params; + struct mt7925_nan_social_ch_scan_params scan_params_val; + + u8 config_random_factor_force; + u8 random_factor_force_val; + + u8 config_hop_count_force; + u8 hop_count_force_val; + + u8 config_24g_channel; + __le32 channel_24g_val; + + u8 config_5g_channel; + __le32 channel_5g_val; + + struct mt7925_nan_conf_dw config_dw; + + u8 config_disc_mac_addr_randomization; + __le32 disc_mac_addr_rand_interval_sec; + + u8 discovery_indication_cfg; + + u8 config_subscribe_sid_beacon; + __le32 subscribe_sid_beacon_val; + + u8 enable_log_slot_statistics; +} __packed __aligned(4); + +struct mt7925_nan_common_hdr { + u8 reserved[4]; +}; + +struct mt7925_nan_master_preference_tlv { + __le16 tag; + __le16 len; + u8 master_preference; + u8 reserved[3]; +} __packed __aligned(4); + +struct mt7925_nan_dw_interval_tlv { + __le16 tag; + __le16 len; + u8 dw_interval; + u8 vendor_ioctl; + __le16 disc_bcn_interval; +} __packed __aligned(4); + +struct mt7925_nan_cluster_id_tlv { + __le16 tag; + __le16 len; + u8 cluster_id[ETH_ALEN]; + u8 reserved[2]; +} __packed __aligned(4); + +struct mt7925_nan_sync_rssi_tlv { + __le16 tag; + __le16 len; + s8 rssi_close_2g; + s8 rssi_middle_2g; + s8 rssi_close_5g; + s8 rssi_middle_5g; +} __packed __aligned(4); + +struct mt7925_nan_de_event { + u8 event_type; + u8 cluster_id[ETH_ALEN]; + u8 anchor_master_rank[NAN_ANCHOR_MASTER_RANK_NUM]; + u8 own_nmi[ETH_ALEN]; + u8 master_nmi[ETH_ALEN]; +}; + +struct mt7925_nan_nmi_addr_tlv { + __le16 tag; + __le16 len; + u8 nmi_addr[ETH_ALEN]; +} __packed __aligned(4); + +struct mt7925_nan_avail_ctrl_tlv { + __le16 tag; + __le16 len; + __le16 avail_ctrl; + u8 seq_id; + u8 reserved[1]; +} __packed __aligned(4); + +struct mt7925_nan_ch_timeline { + u8 is_valid; + u8 reserved[3]; + + __le32 ch_info; + + __le32 num; + __le32 avail_map[NAN_TOTAL_DW]; +}; + +struct mt7925_nan_avail_entry_tlv { + __le16 tag; + __le16 len; + u8 map_id; + u8 is_cond_avail; + u8 timeline_idx; + u8 is_multi_map; + + struct mt7925_nan_ch_timeline ch_list[NAN_TIMELINE_MGMT_CHNL_LIST_NUM]; +} __packed __aligned(4); + +struct mt7925_nan_sched_manage_peer_rec_tlv { + __le16 tag; + __le16 len; + __le32 sch_idx; + u8 is_activate; + u8 nmi_addr[ETH_ALEN]; + u8 reserved[1]; +} __packed __aligned(4); + +struct mt7925_nan_sched_update_peer_cap_tlv { + __le16 tag; + __le16 len; + __le32 sch_idx; + u8 supported_bands; + __le16 max_chnl_switch_time; + u8 peer_supported_bands; +} __packed __aligned(4); + +struct mt7925_nan_sched_timeline { + u8 map_id; + u8 local_map_id; + u8 reserved[2]; + union { + __le32 avail_map[NAN_TOTAL_DW]; + u8 avail_block[NAN_TOTAL_DW * 4]; + }; +}; + +struct mt7925_nan_sched_faw_ndc_timeline { + __le32 avail_map[NAN_TOTAL_DW]; +}; + +struct mt7925_nan_sched_ndc_ctrl { + u8 is_valid; + u8 ndc_id[NAN_NDC_ATTRIBUTE_ID_LENGTH]; + u8 ndc_idx; + struct mt7925_nan_sched_timeline timeline[NAN_NUM_AVAIL_DB]; +}; + +struct mt7925_nan_sched_update_crb_tlv { + __le16 tag; + __le16 len; + __le32 sch_idx; + u8 flags; + u8 is_use_ranging; + u8 reserved[2]; + struct mt7925_nan_sched_timeline comm_ranging_timeline[NAN_TIMELINE_MGMT_SIZE]; + struct mt7925_nan_sched_timeline comm_faw_timeline[NAN_TIMELINE_MGMT_SIZE]; + struct mt7925_nan_sched_ndc_ctrl comm_ndc_ctrl; + struct mt7925_nan_sched_faw_ndc_timeline faw_ndc_timeline[NAN_TIMELINE_MGMT_SIZE]; +} __packed __aligned(4); + +struct mt7925_nan_sched_map_sta_rec_tlv { + __le16 tag; + __le16 len; + u8 nmi_addr[ETH_ALEN]; + u8 sta_rec_idx; + u8 ndp_ctx_id; + + __le32 role_idx; + u8 ndi_addr[ETH_ALEN]; + u8 reserved[2]; +} __packed __aligned(4); + +int mt7925_nan_enable(struct ieee80211_vif *vif, + struct mt792x_dev *dev, + struct cfg80211_nan_conf *conf); + +int mt7925_nan_disable(struct ieee80211_vif *vif, + struct mt792x_dev *dev); + +int mt7925_nan_change_configure(struct ieee80211_vif *vif, + struct mt792x_dev *dev, + struct cfg80211_nan_conf *conf); + +void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb); + +int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr); + +void mt7925_nan_local_sched_changed(struct mt792x_dev *dev, + struct ieee80211_vif *vif); + +int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev, + struct ieee80211_sta *sta); + +int mt792x_nan_set_peer_rec(struct mt76_dev *mdev, + struct ieee80211_sta *sta); + +int mt792x_nan_map_sta_rec(struct mt76_dev *mdev, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta); + +#endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c index ea64303283ed..02ef09dd797d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c @@ -22,6 +22,10 @@ static const struct pci_device_id mt7925_pci_device_table[] = { .driver_data = (kernel_ulong_t)MT7927_FIRMWARE_WM }, { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0738), .driver_data = (kernel_ulong_t)MT7927_FIRMWARE_WM }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7928), + .driver_data = (kernel_ulong_t)MT7928_FIRMWARE_WM }, + { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7935), + .driver_data = (kernel_ulong_t)MT7928_FIRMWARE_WM }, { }, }; @@ -43,13 +47,14 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev) if (dev->phy.chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN) wiphy_rfkill_stop_polling(hw->wiphy); + cancel_work_sync(&dev->reset_work); cancel_work_sync(&dev->init_work); mt76_unregister_device(&dev->mt76); mt76_for_each_q_rx(&dev->mt76, i) napi_disable(&dev->mt76.napi[i]); cancel_delayed_work_sync(&pm->ps_work); + cancel_delayed_work_sync(&dev->mlo_pm_work); cancel_work_sync(&pm->wake_work); - cancel_work_sync(&dev->reset_work); mt7925_tx_token_put(dev); __mt792x_mcu_drv_pmctrl(dev); @@ -110,7 +115,7 @@ static u32 mt7925_reg_map_l2(struct mt792x_dev *dev, u32 addr) static u32 __mt7925_reg_addr(struct mt792x_dev *dev, u32 addr) { - static const struct mt76_connac_reg_map fixed_map[] = { + static const struct mt76_connac_reg_map default_fixed_map[] = { { 0x830c0000, 0x000000, 0x0001000 }, /* WF_MCU_BUS_CR_REMAP */ { 0x54000000, 0x002000, 0x0001000 }, /* WFDMA PCIE0 MCU DMA0 */ { 0x55000000, 0x003000, 0x0001000 }, /* WFDMA PCIE0 MCU DMA1 */ @@ -161,17 +166,112 @@ static u32 __mt7925_reg_addr(struct mt792x_dev *dev, u32 addr) { 0x7c060000, 0x0e0000, 0x0010000 }, /* CONN_INFRA, conn_host_csr_top */ { 0x7c000000, 0x0f0000, 0x0010000 }, /* CONN_INFRA */ { 0x70020000, 0x1f0000, 0x0010000 }, /* Reserved for CBTOP, can't switch */ - { 0x7c500000, 0x060000, 0x2000000 }, /* remap */ + { 0x7c500000, 0x060000, 0x200000 }, /* remap */ { 0x0, 0x0, 0x0 } /* End */ }; - int i; + /* The remap table was ordered from highest to lowest frequency + * to improve lookup efficiency. + */ + static const struct mt76_connac_reg_map mt7928_fixed_map[] = { + {0x54000000, 0x002000, 0x01000}, /* WFDMA_0 (PCIE0 MCU DMA0) */ + {0x55000000, 0x003000, 0x01000}, /* WFDMA_1 (PCIE0 MCU DMA1) */ + {0x57000000, 0x005000, 0x01000}, /* WFDMA_3 (MCU wrap CR) */ + {0x58000000, 0x006000, 0x01000}, /* WFDMA_4 (PCIE1 MCU DMA0) */ + {0x59000000, 0x007000, 0x01000}, /* WFDMA_5 (PCIE1 MCU DMA1) */ + {0x56000000, 0x004000, 0x01000}, /* WFDMA_2 (Reserved) */ + {0x820D0000, 0x030000, 0x10000}, /* WF_LMAC_TOP (WF_WTBLON) */ + {0x820C4000, 0x0A8000, 0x04000}, /* WF_LMAC_TOP (WF_UWTBL) */ + {0x820C0000, 0x008000, 0x04000}, /* WF_UMAC_TOP (PLE) */ + {0x820C8000, 0x00C000, 0x02000}, /* WF_UMAC_TOP (PSE) */ + {0x820CC000, 0x00E000, 0x02000}, /* WF_UMAC_TOP (PP) */ + {0x820F0000, 0x0A0000, 0x00400}, /* WF_LMAC_TOP (WF_CFG) */ + {0x820F1000, 0x0A0600, 0x00200}, /* WF_LMAC_TOP (WF_TRB) */ + {0x820F2000, 0x0A0800, 0x00400}, /* WF_LMAC_TOP (WF_AGG) */ + {0x820F3000, 0x0A0C00, 0x00400}, /* WF_LMAC_TOP (WF_ARB) */ + {0x820F4000, 0x0A1000, 0x00400}, /* WF_LMAC_TOP (WF_TMAC) */ + {0x820F5000, 0x0A1400, 0x00800}, /* WF_LMAC_TOP (WF_RMAC) */ + {0x820F7000, 0x0A1E00, 0x00200}, /* WF_LMAC_TOP (WF_DMA) */ + {0x820F9000, 0x0A3400, 0x00200}, /* WF_LMAC_TOP (WF_WTBLOFF) */ + {0x820FA000, 0x0A4000, 0x00200}, /* WF_LMAC_TOP (WF_ETBF) */ + {0x820FB000, 0x0A4200, 0x00400}, /* WF_LMAC_TOP (WF_LPON) */ + {0x820FC000, 0x0A4600, 0x00200}, /* WF_LMAC_TOP (WF_INT) */ + {0x820FD000, 0x0A4800, 0x00800}, /* WF_LMAC_TOP (WF_MIB) */ + {0x820E0000, 0x020000, 0x00400}, /* WF_LMAC_TOP (WF_CFG) */ + {0x820E1000, 0x020400, 0x00200}, /* WF_LMAC_TOP (WF_TRB) */ + {0x820E2000, 0x020800, 0x00400}, /* WF_LMAC_TOP (WF_AGG) */ + {0x820E3000, 0x020C00, 0x00400}, /* WF_LMAC_TOP (WF_ARB) */ + {0x820E4000, 0x021000, 0x00400}, /* WF_LMAC_TOP (WF_TMAC) */ + {0x820E5000, 0x021400, 0x00800}, /* WF_LMAC_TOP (WF_RMAC) */ + {0x820CE000, 0x021C00, 0x00200}, /* WF_LMAC_TOP (WF_SEC) */ + {0x820E7000, 0x021E00, 0x00200}, /* WF_LMAC_TOP (WF_DMA) */ + {0x820CF000, 0x022000, 0x01000}, /* WF_LMAC_TOP (WF_PF) */ + {0x820E9000, 0x023400, 0x00200}, /* WF_LMAC_TOP (WF_WTBLOFF) */ + {0x820EA000, 0x024000, 0x00200}, /* WF_LMAC_TOP (WF_ETBF) */ + {0x820EB000, 0x024200, 0x00400}, /* WF_LMAC_TOP (WF_LPON) */ + {0x820EC000, 0x024600, 0x00200}, /* WF_LMAC_TOP (WF_INT) */ + {0x820ED000, 0x024800, 0x00800}, /* WF_LMAC_TOP (WF_MIB) */ + {0x820CA000, 0x026000, 0x02000}, /* WF_LMAC_TOP (WF_MUCOP) */ + {0x7C500000, 0x060000, 0x200000}, /* remap */ + {0x7C000000, 0x0F0000, 0x10000}, /* CONN_INFRA (off2on) */ + {0x7C060000, 0x0E0000, 0x10000}, /* remap MT_CONN_ON_LPCTL and MT_CONN_ON_MISC */ + {0x20060000, 0x0E0000, 0x10000}, /* CONN_INFRA conn_host_csr_top */ + {0x7C010000, 0x100000, 0x10000}, /* CONN_INFRA (gpio clkgen cfg) */ + {0x7C050000, 0x1A0000, 0x10000}, /* CONN_INFRA SYSRAM */ + {0x7C080000, 0x190000, 0x10000}, /* CONN_INFRA (coex, pta) */ + {0x7C070000, 0x180000, 0x10000}, /* CONN_INFRA Semaphore */ + {0x7C040000, 0x170000, 0x10000}, /* CONN_INFRA (bus, afe) */ + {0x7C026000, 0x0D6000, 0x0019C}, /* remap DMASHL TOP */ + {0x20020000, 0x0D0000, 0x0C000}, /* CONN_INFRA wf_dma_host_side_cr */ + {0x200B0000, 0x050000, 0x10000}, /* CONN_INFRA conn_von_sysram */ + {0x20090000, 0x150000, 0x08000}, /* CONN_INFRA von_connsys_s0-s7 */ + {0x7C098000, 0x158000, 0x08000}, /* CONN_INFRA von_connsys_hclk_s0-s7 */ + {0x20030000, 0x160000, 0x10000}, /* CONN_INFRA CCIF */ + {0x70000000, 0x1E0000, 0x10000}, /* CONN_INFRA CONN2AP */ + {0x830C0000, 0x000000, 0x01000}, /* WF_MCU_BUS_CR_REMAP */ + {0x81020000, 0x0C0000, 0x10000}, /* WF_TOP_MISC_ON */ + {0x80020000, 0x0B0000, 0x10000}, /* WF_TOP_MISC_OFF */ + {0x81040000, 0x120000, 0x01000}, /* WF_MCU_CFG_ON */ + {0x00400000, 0x080000, 0x10000}, /* WF_MCU_SYSRAM */ + {0x00410000, 0x090000, 0x10000}, /* WF_MCU_SYSRAM (Common driver) */ + {0x88000000, 0x140000, 0x10000}, /* WF_MCU_CFG_LS */ + {0x80010000, 0x124000, 0x01000}, /* WF_AXIDMA */ + {0x81050000, 0x121000, 0x01000}, /* WF_MCU_EINT */ + {0x81060000, 0x122000, 0x01000}, /* WF_MCU_GPT */ + {0x81070000, 0x123000, 0x01000}, /* WF_MCU_WDT */ + {0x830A0000, 0x040000, 0x10000}, /* WF_PHY_MAP0 */ + {0x83090000, 0x060000, 0x10000}, /* WF_PHY_MAP2 */ + {0x83000000, 0x110000, 0x10000}, /* WF_PHY_MAP3 */ + {0x83010000, 0x130000, 0x10000}, /* WF_PHY_MAP4 */ + {0x81030000, 0x0AE000, 0x00100}, /* WFSYS_AON */ + {0x81031000, 0x0AE100, 0x00100}, /* WFSYS_AON */ + {0x81032000, 0x0AE200, 0x00100}, /* WFSYS_AON */ + {0x81033000, 0x0AE300, 0x00100}, /* WFSYS_AON */ + {0x81034000, 0x0AE400, 0x00100}, /* WFSYS_AON */ + {0xE0400000, 0x070000, 0x10000}, /* WF_UMCA_SYSRAM */ + {0x70010000, 0x1C0000, 0x10000}, /* CB Infra1 */ + {0x70020000, 0x1F0000, 0x10000}, /* Reserved for CBTOP, can't switch */ + {0x74040000, 0x1D0000, 0x10000}, /* CB PCIe (cbtop remap) */ + {0x18010000, 0x100000, 0x10000}, /* remap MT_HW_EMI_CTRL */ + {0x00000000, 0x000000, 0x00000}, /* END */ + }; + const struct mt76_connac_reg_map *fixed_map; + size_t array_size; + u32 i; if (addr < 0x200000) return addr; mt7925_reg_remap_restore(dev); - for (i = 0; i < ARRAY_SIZE(fixed_map); i++) { + if (is_mt7928(&dev->mt76)) { + fixed_map = mt7928_fixed_map; + array_size = ARRAY_SIZE(mt7928_fixed_map); + } else { + fixed_map = default_fixed_map; + array_size = ARRAY_SIZE(default_fixed_map); + } + + for (i = 0; i < array_size; i++) { u32 ofs; if (addr < fixed_map[i].phys) @@ -252,6 +352,27 @@ static const struct mt792x_dma_layout mt7927_dma_layout = { MT_RX_DATA_RING_BASE), }; +static const struct mt792x_dma_layout mt7928_dma_layout = { + .tx_data0 = mt792x_dma_ring(MT7925_TXQ_BAND0, + MT7925_TX_RING_SIZE, + MT_TX_RING_BASE), + .tx_mcu = mt792x_dma_ring(MT7925_TXQ_MCU_WM, + MT7925_TX_MCU_RING_SIZE, + MT_TX_RING_BASE), + .tx_fwdl = mt792x_dma_ring(MT7925_TXQ_FWDL, + MT7925_TX_FWDL_RING_SIZE, + MT_TX_RING_BASE), + .tx_done = mt792x_dma_ring(MT7928_RXQ_MCU_WM2, + MT7928_RX_MCU_WA_RING_SIZE, + MT_RX_EVENT_RING_BASE), + .rx_mcu = mt792x_dma_ring(MT7928_RXQ_MCU_WM, + MT7925_RX_MCU_RING_SIZE, + MT_RX_EVENT_RING_BASE), + .rx_data = mt792x_dma_ring(MT7928_RXQ_BAND0, + MT7925_RX_RING_SIZE, + MT_RX_DATA_RING_BASE), +}; + static int mt7927_dma_init(struct mt792x_dev *dev) { int ret; @@ -279,11 +400,62 @@ static int mt7927_dma_init(struct mt792x_dev *dev) return mt792x_dma_enable(dev); } +static void mt7928_dma_shdl_lite_init(struct mt792x_dev *dev) +{ + u32 addr, idx, grp1_5_quota, grp15_quota; + u32 q2group[8] = { + 0x04000000, /* AC00->G0,..., AC03->G4 */ + 0x04010101, /* AC10->G1,..., AC13->G4 */ + 0x04020202, /* AC20->G2,..., AC23->G4 */ + 0x04030303, /* AC30->G3,..., AC33->G4 */ + 0x00000005, /* ALTX->G5,BMC->G0,BCN->G0 */ + 0x00000005, /* TGID=1 ALTX->G5 */ + 0x00000000, /* NAF/NBCN/FIXFID -> G0 */ + 0x00000005, /* TGID=2 ALTX->G5 */ + }; + + /* RST */ + mt76_wr(dev, MT_DMASHDL_LITE_MAIN_CONTROL, MT_DMASHDL_LITE_MAIN_CONTROL_SW_RST); + /* pse page size 0x10, ple page size 0x7e0 */ + mt76_wr(dev, MT_DMASHDL_LITE_PAGE_SIZE, + FIELD_PREP(MT_DMASHDL_LITE_PSE_PAGE_SIZE_MASK, 0x10) | + FIELD_PREP(MT_DMASHDL_LITE_PLE_PAGE_SIZE_MASK, 0x7e0)); + /* pse max page 8, ple max page 1 */ + mt76_wr(dev, MT_DMASHDL_LITE_PKT_MAX_SIZE, + FIELD_PREP(MT_DMASHDL_LITE_PSE_PKT_MAX_SIZE_MASK, 8) | + FIELD_PREP(MT_DMASHDL_LITE_PLE_PKT_MAX_SIZE_MASK, 1)); + /* SN/UDF check */ + mt76_wr(dev, MT_DMASHDL_LITE_GROUP_SN_CHK0, 0xffffffff); + mt76_wr(dev, MT_DMASHDL_LITE_GROUP_SN_CHK1, 0xffffffff); + mt76_wr(dev, MT_DMASHDL_LITE_GROUP_UDF_CHK0, 0xffffffff); + mt76_wr(dev, MT_DMASHDL_LITE_GROUP_UDF_CHK1, 0xffffffff); + /* q mapping */ + for (addr = MT_DMASHDL_LITE_Q_MAPPING0, idx = 0; + idx < ARRAY_SIZE(q2group); + idx++, addr += 4) + mt76_wr(dev, addr, q2group[idx]); + /* refill, set 0 to enable group 0,1,2,3,4,5 & 15 */ + mt76_wr(dev, MT_DMASHDL_LITE_GROUP_DISABLE0, 0xffff7fc0); + mt76_wr(dev, MT_DMASHDL_LITE_GROUP_DISABLE1, 0xffffffff); + /* max/min quota */ + grp1_5_quota = FIELD_PREP(MT_DMASHDL_LITE_GROUP_MAX_QUOTA_MASK, 0x3f0) | + FIELD_PREP(MT_DMASHDL_LITE_GROUP_MIN_QUOTA_MASK, 0x10); + grp15_quota = FIELD_PREP(MT_DMASHDL_LITE_GROUP_MAX_QUOTA_MASK, 0x30); + + for (addr = MT_DMASHDL_LITE_GROUP0_QUOTA, idx = 0; + idx < DMASHDL_LITE_GROUP_NUM; + idx++, addr += 4) + mt76_wr(dev, addr, (idx <= 5) ? grp1_5_quota : + ((idx == 15) ? grp15_quota : 0)); +} + static int mt7925_dma_init(struct mt792x_dev *dev) { int ret; + const struct mt792x_dma_layout *layout = + is_mt7928(&dev->mt76) ? &mt7928_dma_layout : &mt7925_dma_layout; - ret = mt792x_dma_alloc_queues(dev, &mt7925_dma_layout); + ret = mt792x_dma_alloc_queues(dev, layout); if (ret) return ret; @@ -291,6 +463,9 @@ static int mt7925_dma_init(struct mt792x_dev *dev) if (ret < 0) return ret; + if (is_mt7928(&dev->mt76)) + mt7928_dma_shdl_lite_init(dev); + netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi, mt792x_poll_tx); napi_enable(&dev->mt76.tx_napi); @@ -298,6 +473,30 @@ static int mt7925_dma_init(struct mt792x_dev *dev) return mt792x_dma_enable(dev); } +static const struct mt792x_pcie_reg mt7925_pcie_reg = { + .imask = MT7925_PCIE_MAC_INT_ENABLE, + .pm = MT7925_PCIE_MAC_PM, +}; + +static const struct mt792x_pcie_reg mt7928_pcie_reg = { + .imask = MT7928_PCIE_MAC_INT_ENABLE, + .pm = MT7928_PCIE_MAC_PM, +}; + +static const struct mt792x_irq_map mt7925_irq_map = { + .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, + .tx = { + .all_complete_mask = MT_INT_TX_DONE_ALL, + .mcu_complete_mask = MT_INT_TX_DONE_MCU, + }, + .rx = { + .all_complete_mask = MT7925_INT_RX_DONE_ALL, + .data_complete_mask = MT7925_INT_RX_DONE_DATA, + .wm_complete_mask = MT7925_INT_RX_DONE_WM, + .wm2_complete_mask = MT_INT_RX_DONE_WM2, + }, +}; + static const struct mt792x_irq_map mt7927_irq_map = { .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, .tx = { @@ -305,11 +504,27 @@ static const struct mt792x_irq_map mt7927_irq_map = { .mcu_complete_mask = MT_INT_TX_DONE_MCU, }, .rx = { - .data_complete_mask = MT7927_RX_DONE_INT_ENA4, - .wm_complete_mask = MT7927_RX_DONE_INT_ENA6, - .wm2_complete_mask = MT7927_RX_DONE_INT_ENA7, + .all_complete_mask = MT7927_INT_RX_DONE_ALL, + .data_complete_mask = MT7927_INT_RX_DONE_DATA, + .wm_complete_mask = MT7927_INT_RX_DONE_WM, + .wm2_complete_mask = MT7927_INT_RX_DONE_WM2, }, }; + +static const struct mt792x_irq_map mt7928_irq_map = { + .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, + .tx = { + .all_complete_mask = MT_INT_TX_DONE_ALL, + .mcu_complete_mask = MT_INT_TX_DONE_MCU, + }, + .rx = { + .all_complete_mask = MT7928_INT_RX_DONE_ALL, + .data_complete_mask = MT7928_INT_RX_DONE_DATA, + .wm_complete_mask = MT7928_INT_RX_DONE_WM, + .wm2_complete_mask = MT_INT_RX_DONE_WM2, + }, +}; + static int mt7925_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -339,22 +554,11 @@ static int mt7925_pci_probe(struct pci_dev *pdev, .drv_own = mt792xe_mcu_drv_pmctrl, .fw_own = mt792xe_mcu_fw_pmctrl, }; - static const struct mt792x_irq_map irq_map = { - .host_irq_enable = MT_WFDMA0_HOST_INT_ENA, - .tx = { - .all_complete_mask = MT_INT_TX_DONE_ALL, - .mcu_complete_mask = MT_INT_TX_DONE_MCU, - }, - .rx = { - .data_complete_mask = HOST_RX_DONE_INT_ENA2, - .wm_complete_mask = HOST_RX_DONE_INT_ENA0, - }, - }; - struct ieee80211_ops *ops; + bool is_mt7927_hw, is_mt7928_hw; struct mt76_bus_ops *bus_ops; + struct ieee80211_ops *ops; struct mt792x_dev *dev; struct mt76_dev *mdev; - bool is_mt7927_hw; u8 features; int ret; u16 cmd; @@ -378,12 +582,17 @@ static int mt7925_pci_probe(struct pci_dev *pdev, if (ret < 0) return ret; - ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); - if (ret) - goto err_free_pci_vec; - is_mt7927_hw = (pdev->device == 0x6639 || pdev->device == 0x7927 || pdev->device == 0x0738); + is_mt7928_hw = (pdev->device == 0x7928 || pdev->device == 0x7935); + + if (is_mt7928_hw) + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(34)); + else + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + + if (ret) + goto err_free_pci_vec; /* MT7927: ASPM L1 causes unreliable WFDMA register access */ if (mt7925_disable_aspm || is_mt7927_hw) @@ -407,7 +616,18 @@ static int mt7925_pci_probe(struct pci_dev *pdev, dev = container_of(mdev, struct mt792x_dev, mt76); dev->fw_features = features; dev->hif_ops = &mt7925_pcie_ops; - dev->irq_map = is_mt7927_hw ? &mt7927_irq_map : &irq_map; + dev->pcie_reg = &mt7925_pcie_reg; + + if (is_mt7928_hw) { + dev->pcie_reg = &mt7928_pcie_reg; + dev->irq_map = &mt7928_irq_map; + mdev->rev = 0x7928 << 16; + } else if (is_mt7927_hw) { + dev->irq_map = &mt7927_irq_map; + } else { + dev->irq_map = &mt7925_irq_map; + } + mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]); tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev); @@ -430,6 +650,9 @@ static int mt7925_pci_probe(struct pci_dev *pdev, if (!mt7925_disable_aspm && mt76_pci_aspm_supported(pdev)) dev->aspm_supported = true; + if (is_mt7928(&dev->mt76)) + dev->skip_wpdma_reinit = true; + ret = __mt792x_mcu_fw_pmctrl(dev); if (ret) goto err_free_dev; @@ -448,6 +671,11 @@ static int mt7925_pci_probe(struct pci_dev *pdev, "MT7927 raw CHIPID=0x%04x, forcing chip=0x7927\n", mt76_chip(mdev)); mdev->rev = (0x7927 << 16) | (mdev->rev & 0xff); + } else if (is_mt7928_hw && mt76_chip(mdev) != 0x7928) { + dev_info(mdev->dev, + "MT7928 raw CHIPID=0x%04x, forcing chip=0x7928\n", + mt76_chip(mdev)); + mdev->rev = (0x7928 << 16) | (mdev->rev & 0xff); } mt76_rmw_field(dev, MT_HW_EMI_CTL, MT_HW_EMI_CTL_SLPPROT_EN, 1); @@ -456,9 +684,8 @@ static int mt7925_pci_probe(struct pci_dev *pdev, if (ret) goto err_free_dev; - mt76_wr(dev, irq_map.host_irq_enable, 0); - - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + mt76_wr(dev, dev->irq_map->host_irq_enable, 0); + mt76_wr(dev, dev->pcie_reg->imask, 0xff); ret = devm_request_irq(mdev->dev, pdev->irq, mt792x_irq_handler, IRQF_SHARED, KBUILD_MODNAME, dev); @@ -467,7 +694,7 @@ static int mt7925_pci_probe(struct pci_dev *pdev, if (is_mt7927(&dev->mt76)) ret = mt7927_dma_init(dev); - else if (is_mt7925(&dev->mt76)) + else if (is_mt7925(&dev->mt76) || is_mt7928(&dev->mt76)) ret = mt7925_dma_init(dev); else ret = -EINVAL; @@ -498,8 +725,8 @@ static void mt7925_pci_remove(struct pci_dev *pdev) struct mt76_dev *mdev = pci_get_drvdata(pdev); struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); - mt7925e_unregister_device(dev); set_bit(MT76_REMOVED, &mdev->phy.state); + mt7925e_unregister_device(dev); devm_free_irq(&pdev->dev, pdev->irq, dev); mt76_free_device(&dev->mt76); pci_free_irq_vectors(pdev); @@ -517,6 +744,7 @@ static int mt7925_pci_suspend(struct device *device) dev->hif_resumed = false; flush_work(&dev->reset_work); cancel_delayed_work_sync(&pm->ps_work); + cancel_delayed_work_sync(&dev->mlo_pm_work); cancel_work_sync(&pm->wake_work); mt7925_roc_abort_sync(dev); @@ -559,8 +787,7 @@ static int mt7925_pci_suspend(struct device *device) /* disable interrupt */ mt76_wr(dev, dev->irq_map->host_irq_enable, 0); - - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); + mt76_wr(dev, dev->pcie_reg->imask, 0x0); synchronize_irq(pdev->irq); tasklet_kill(&mdev->irq_tasklet); @@ -610,12 +837,10 @@ static int _mt7925_pci_resume(struct device *device, bool restore) mt792x_wpdma_reinit_cond(dev); /* enable interrupt */ - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + mt76_wr(dev, dev->pcie_reg->imask, 0xff); mt76_connac_irq_enable(&dev->mt76, dev->irq_map->tx.all_complete_mask | - dev->irq_map->rx.data_complete_mask | - dev->irq_map->rx.wm_complete_mask | - dev->irq_map->rx.wm2_complete_mask | + dev->irq_map->rx.all_complete_mask | MT_INT_MCU_CMD); mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); @@ -702,6 +927,10 @@ MODULE_FIRMWARE(MT7925_FIRMWARE_WM); MODULE_FIRMWARE(MT7925_ROM_PATCH); MODULE_FIRMWARE(MT7927_FIRMWARE_WM); MODULE_FIRMWARE(MT7927_ROM_PATCH); +MODULE_FIRMWARE(MT7928_FIRMWARE_WM); +MODULE_FIRMWARE(MT7928_ROM_PATCH); +MODULE_FIRMWARE(MT7928_CB_ROM_PATCH); +MODULE_FIRMWARE(MT7928_PHY_RAM); MODULE_AUTHOR("Deren Wu "); MODULE_AUTHOR("Lorenzo Bianconi "); MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver"); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c index 97683949a305..8477d21abc66 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c @@ -78,7 +78,7 @@ int mt7925e_mac_reset(struct mt792x_dev *dev) mt76_connac_free_pending_tx_skbs(&dev->pm, NULL); mt76_wr(dev, dev->irq_map->host_irq_enable, 0); - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); + mt76_wr(dev, dev->pcie_reg->imask, 0x0); set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); @@ -119,11 +119,9 @@ int mt7925e_mac_reset(struct mt792x_dev *dev) mt76_wr(dev, dev->irq_map->host_irq_enable, dev->irq_map->tx.all_complete_mask | - dev->irq_map->rx.data_complete_mask | - dev->irq_map->rx.wm_complete_mask | - dev->irq_map->rx.wm2_complete_mask | + dev->irq_map->rx.all_complete_mask | MT_INT_MCU_CMD); - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + mt76_wr(dev, dev->pcie_reg->imask, 0xff); err = mt792xe_mcu_fw_pmctrl(dev); if (err) diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c index 6cceff88c656..72707eddc3db 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mcu.c @@ -43,7 +43,7 @@ int mt7925e_mcu_init(struct mt792x_dev *dev) if (err) return err; - mt76_rmw_field(dev, MT_PCIE_MAC_PM, MT_PCIE_MAC_PM_L0S_DIS, 1); + mt76_rmw_field(dev, dev->pcie_reg->pm, MT_PCIE_MAC_PM_L0S_DIS, 1); err = mt7925_run_firmware(dev); diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c index 16f56ee879d4..f4beb7f52043 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/regd.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regd.c @@ -9,6 +9,15 @@ static bool mt7925_disable_clc; module_param_named(disable_clc, mt7925_disable_clc, bool, 0644); MODULE_PARM_DESC(disable_clc, "disable CLC support"); +static struct ieee80211_regdomain mt7925_regd_ww = { + .n_reg_rules = 1, + .alpha2 = "00", + .reg_rules = { + /* IEEE 802.11b/g, channels 1..11 */ + REG_RULE(2412 - 10, 2462 + 10, 40, 6, 20, 0), + } +}; + bool mt7925_regd_clc_supported(struct mt792x_dev *dev) { if (mt7925_disable_clc || @@ -128,35 +137,37 @@ mt7925_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev) } } -int mt7925_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, - enum environment_cap country_ie_env) +static int mt7925_mcu_apply_regd(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap env) { struct ieee80211_hw *hw = mt76_hw(dev); struct wiphy *wiphy = hw->wiphy; - int ret = 0; + int ret; - dev->regd_in_progress = true; - - mt792x_mutex_acquire(dev); - if (!dev->regd_change) - goto err; - - ret = mt7925_mcu_set_clc(dev, alpha2, country_ie_env); + ret = mt7925_mcu_set_clc(dev, alpha2, env); if (ret < 0) - goto err; + return ret; mt7925_regd_be_ctrl(dev, alpha2); mt7925_regd_channel_update(wiphy, dev); ret = mt7925_mcu_set_channel_domain(hw->priv); if (ret < 0) - goto err; + return ret; - ret = mt7925_set_tx_sar_pwr(hw, NULL); - if (ret < 0) - goto err; + return mt7925_set_tx_sar_pwr(hw, NULL); +} -err: +int mt7925_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, + enum environment_cap country_ie_env) +{ + int ret = 0; + + dev->regd_in_progress = true; + + mt792x_mutex_acquire(dev); + if (dev->regd_change) + ret = mt7925_mcu_apply_regd(dev, alpha2, country_ie_env); mt792x_mutex_release(dev); dev->regd_change = false; dev->regd_in_progress = false; @@ -197,11 +208,178 @@ void mt7925_regd_notifier(struct wiphy *wiphy, struct regulatory_request *req) /* postpone the mcu update to resume */ return; + if (MT7925_REGD_SUPPORTED(&dev->phy)) { + mt7925_regd_update(&dev->phy, req->alpha2); + + return; + } + mt7925_mcu_regd_update(dev, req->alpha2, req->country_ie_env); return; } +static struct sk_buff * +mt7925_regd_query_regdb(struct mt792x_phy *phy, char *alpha2) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt7925_clc *clc = phy->clc[MT792x_CLC_REGD]; + struct mt7925_regd_query_req *req; + struct mt7925_regd_cc *regd_cc; + struct sk_buff *ret_skb = NULL; + u8 *pos, *last_pos; + int ret = 0; + + if (!clc) + return NULL; + + pos = clc->data; + last_pos = pos + le32_to_cpu(clc->len) - sizeof(struct mt7925_clc); + while (pos < last_pos) { + u32 req_len = 0; + u32 rules_len = 0; + u32 sign_len = 4; + u32 n_reg_rules; + + if (pos + sizeof(*regd_cc) > last_pos) + break; + + regd_cc = (struct mt7925_regd_cc *)pos; + n_reg_rules = le32_to_cpu(regd_cc->n_reg_rules); + if (n_reg_rules > NL80211_MAX_SUPP_REG_RULES) + break; + + rules_len = sizeof(struct mt7925_regd_rule_header) + + sizeof(struct mt7925_regd_rule) * n_reg_rules; + + if (pos + sizeof(*regd_cc) + rules_len + sign_len > last_pos) + break; + + pos += sizeof(*regd_cc) + rules_len + sign_len; + if (memcmp(regd_cc->alpha2, alpha2, 2)) + continue; + + req_len = sizeof(*req) + rules_len + sign_len; + req = kzalloc(req_len, GFP_KERNEL); + + if (!req) + return NULL; + + req->tag = cpu_to_le16(0x6); + req->len = cpu_to_le16(req_len - 4); + req->ver = regd_cc->ver; + req->sign_type = regd_cc->sign_type; + req->size = cpu_to_le32(rules_len + sign_len); + req->n_reg_rules = regd_cc->n_reg_rules; + + memcpy(req->alpha2, regd_cc->alpha2, 2); + memcpy(req->data, regd_cc->data, rules_len + sign_len); + + ret = mt76_mcu_send_and_get_msg(&dev->mt76, + MCU_UNI_CMD(SET_POWER_LIMIT), + req, req_len, true, &ret_skb); + kfree(req); + + return ret < 0 ? NULL : ret_skb; + } + + return NULL; +} + +int mt7925_regd_update(struct mt792x_phy *phy, char *alpha2) +{ + struct wiphy *wiphy = phy->mt76->hw->wiphy; + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt7925_regd_rule *mt7925_rule; + struct mt76_dev *mdev = &dev->mt76; + struct ieee80211_regdomain *regd; + struct ieee80211_reg_rule *rule; + struct mt7925_regd_rule_ev *ev; + int i, num_of_rules = 0; + struct sk_buff *skb; + int ret = 0; + + if (dev->hw_full_reset) + return 0; + + if (!MT7925_REGD_SUPPORTED(phy)) + return -EOPNOTSUPP; + + mt792x_mutex_acquire(dev); + skb = mt7925_regd_query_regdb(phy, alpha2); + mt792x_mutex_release(dev); + + if (!skb) { + ret = -EINVAL; + goto err; + } + + if (skb->len < sizeof(*ev) + 4) { + ret = -EINVAL; + goto err; + } + + ev = (struct mt7925_regd_rule_ev *)(skb->data + 4); + num_of_rules = le32_to_cpu(ev->n_reg_rules); + + if (!num_of_rules || + WARN_ON_ONCE(num_of_rules > NL80211_MAX_SUPP_REG_RULES)) { + ret = -EINVAL; + goto err; + } + + if (skb->len < struct_size(ev, reg_rule, num_of_rules) + 4) { + ret = -EINVAL; + goto err; + } + + regd = kzalloc(struct_size(regd, reg_rules, num_of_rules), GFP_KERNEL); + if (!regd) { + ret = -ENOMEM; + goto err; + } + + for (i = 0; i < num_of_rules; i++) { + mt7925_rule = &ev->reg_rule[i]; + rule = ®d->reg_rules[i]; + + rule->freq_range.start_freq_khz = + MHZ_TO_KHZ(le32_to_cpu(mt7925_rule->start_freq)); + rule->freq_range.end_freq_khz = + MHZ_TO_KHZ(le32_to_cpu(mt7925_rule->end_freq)); + rule->freq_range.max_bandwidth_khz = + MHZ_TO_KHZ(le32_to_cpu(mt7925_rule->max_bw)); + /* not used by fw */ + rule->power_rule.max_antenna_gain = DBI_TO_MBI(6); + rule->power_rule.max_eirp = DBM_TO_MBM(22); + rule->flags = le32_to_cpu(mt7925_rule->flags); + } + + regd->n_reg_rules = num_of_rules; + regd->dfs_region = ev->dfs_region; + + memcpy(regd->alpha2, alpha2, 2); + memcpy(mdev->alpha2, alpha2, 2); + + dev->regd_change = true; + mt7925_mcu_regd_update(dev, alpha2, ENVIRON_ANY); + + ret = regulatory_set_wiphy_regd(wiphy, regd); + + kfree(regd); +err: + dev_kfree_skb(skb); + + if (ret < 0) + return regulatory_set_wiphy_regd(wiphy, &mt7925_regd_ww); + + return ret; +} +EXPORT_SYMBOL_GPL(mt7925_regd_update); + static bool mt7925_regd_is_valid_alpha2(const char *alpha2) { @@ -217,6 +395,36 @@ mt7925_regd_is_valid_alpha2(const char *alpha2) return false; } +bool +mt7925_regd_is_valid_channel(struct mt792x_dev *dev, + enum nl80211_band band, + struct ieee80211_channel *chan) +{ + struct ieee80211_hw *hw = mt76_hw(dev); + struct wiphy *wiphy = hw->wiphy; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int i; + + if (!chan) + return false; + + sband = wiphy->bands[band]; + if (!sband) + return false; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + if (ch->hw_value == chan->hw_value && + ((ch->flags & IEEE80211_CHAN_DISABLED) == 0)) + return true; + } + + return false; +} +EXPORT_SYMBOL_GPL(mt7925_regd_is_valid_channel); + int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2) { struct wiphy *wiphy = phy->mt76->hw->wiphy; @@ -240,7 +448,9 @@ int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2) if (!memcmp(alpha2, mdev->alpha2, 2)) return 0; - if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) { + if (MT7925_REGD_SUPPORTED(phy)) { + return mt7925_regd_update(phy, alpha2); + } else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) { return regulatory_hint(wiphy, alpha2); } else { return mt7925_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR); @@ -255,7 +465,11 @@ int mt7925_regd_init(struct mt792x_phy *phy) struct mt792x_dev *dev = mt792x_hw_dev(hw); struct mt76_dev *mdev = &dev->mt76; - if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) { + if (MT7925_REGD_SUPPORTED(phy)) { + wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED | + REGULATORY_DISABLE_BEACON_HINTS; + return mt7925_regd_update(phy, "00"); + } else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) { wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE | REGULATORY_DISABLE_BEACON_HINTS; } else { diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regd.h b/drivers/net/wireless/mediatek/mt76/mt7925/regd.h index 0767f078862e..65ef2b140f51 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/regd.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regd.h @@ -6,13 +6,70 @@ #include "mt7925.h" +struct mt7925_regd_rule_header { + u8 alpha2[2]; + u8 dfs_region; + u8 rsv[13]; +}; + +struct mt7925_regd_rule { + __le32 start_freq; + __le32 end_freq; + __le32 max_bw; + __le32 eirp; + __le32 flags; + u8 rsv[12]; +}; + +struct mt7925_regd_cc { + u8 alpha2[2]; + u8 ver; + u8 rsv; + __le32 n_reg_rules; + u8 sign_type; + u8 rsv1[7]; + u8 data[]; +}; + +struct mt7925_regd_rule_ev { + __le16 tag; + __le16 len; + __le32 n_reg_rules; + u8 dfs_region; + u8 rsv[15]; + struct mt7925_regd_rule reg_rule[]; +}; + +struct mt7925_regd_query_req { + u8 rsv[4]; + __le16 tag; + __le16 len; + u8 ver; + u8 sign_type; + u8 rsv1[2]; + __le32 size; + u8 alpha2[2]; + u8 rsv2[2]; + __le32 n_reg_rules; + u8 rsv3[64]; + u8 data[]; +}; + +#define MT7925_REGD_SUPPORTED(phy) \ + (((phy)->chip_cap & MT792x_CHIP_CAP_REGD_EN) && \ + (phy)->clc[MT792x_CLC_REGD]) + int mt7925_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2, enum environment_cap country_ie_env); void mt7925_regd_be_ctrl(struct mt792x_dev *dev, u8 *alpha2); void mt7925_regd_notifier(struct wiphy *wiphy, struct regulatory_request *req); bool mt7925_regd_clc_supported(struct mt792x_dev *dev); +int mt7925_regd_update(struct mt792x_phy *phy, char *alpha2); int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2); +bool mt7925_regd_is_valid_channel(struct mt792x_dev *dev, + enum nl80211_band band, + struct ieee80211_channel *chan); int mt7925_regd_init(struct mt792x_phy *phy); #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h index 24985bba1b90..ab6c33b4a180 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7925/regs.h @@ -43,11 +43,25 @@ #define HOST_TX_DONE_INT_ENA17 BIT(27) /* WFDMA interrupt */ -#define MT_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA2 -#define MT_INT_RX_DONE_WM HOST_RX_DONE_INT_ENA0 #define MT_INT_RX_DONE_WM2 HOST_RX_DONE_INT_ENA1 -#define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_DATA | \ - MT_INT_RX_DONE_WM | \ + +#define MT7925_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA2 +#define MT7925_INT_RX_DONE_WM HOST_RX_DONE_INT_ENA0 +#define MT7925_INT_RX_DONE_ALL (MT7925_INT_RX_DONE_DATA | \ + MT7925_INT_RX_DONE_WM | \ + MT_INT_RX_DONE_WM2) + +#define MT7927_INT_RX_DONE_DATA MT7927_RX_DONE_INT_ENA4 +#define MT7927_INT_RX_DONE_WM MT7927_RX_DONE_INT_ENA6 +#define MT7927_INT_RX_DONE_WM2 MT7927_RX_DONE_INT_ENA7 +#define MT7927_INT_RX_DONE_ALL (MT7927_INT_RX_DONE_DATA | \ + MT7927_INT_RX_DONE_WM | \ + MT7927_INT_RX_DONE_WM2) + +#define MT7928_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA0 +#define MT7928_INT_RX_DONE_WM HOST_RX_DONE_INT_ENA3 +#define MT7928_INT_RX_DONE_ALL (MT7928_INT_RX_DONE_DATA | \ + MT7928_INT_RX_DONE_WM | \ MT_INT_RX_DONE_WM2) #define MT_INT_TX_DONE_MCU_WM (HOST_TX_DONE_INT_ENA15 | \ @@ -74,19 +88,52 @@ #define MT_HIF_REMAP_BASE_L1 0x130000 #define MT_HIF_REMAP_L2 0x0120 -#if IS_ENABLED(CONFIG_MT76_DEV) -#define MT_HIF_REMAP_BASE_L2 (0x7c500000 - (0x7c000000 - 0x18000000)) -#else #define MT_HIF_REMAP_BASE_L2 0x18500000 -#endif #define MT_WFSYS_SW_RST_B 0x7c000140 -#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x370) +#define MT7925_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x370) +#define MT7928_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x400) #define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(4, 0) -#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x380) +#define MT7925_WTBL_UPDATE MT_WTBLON_TOP(0x380) +#define MT7928_WTBL_UPDATE MT_WTBLON_TOP(0x410) #define MT_WTBL_UPDATE_WLAN_IDX GENMASK(11, 0) #define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(14) +#define MT7928_WTBL_ITCR MT_WTBLON_TOP(0x440) +#define MT7928_WTBL_ITDR0 MT_WTBLON_TOP(0x448) +#define MT7928_WTBL_ITDR1 MT_WTBLON_TOP(0x44c) + +#define MT7925_PCIE_MAC_BASE 0x10000 +#define MT7925_PCIE_MAC(ofs) (MT7925_PCIE_MAC_BASE + (ofs)) +#define MT7925_PCIE_MAC_INT_ENABLE MT7925_PCIE_MAC(0x188) +#define MT7925_PCIE_MAC_PM MT7925_PCIE_MAC(0x194) + +#define MT7928_PCIE_MAC_BASE 0x74040000 +#define MT7928_PCIE_MAC(ofs) (MT7928_PCIE_MAC_BASE + (ofs)) +#define MT7928_PCIE_MAC_INT_ENABLE MT7928_PCIE_MAC(0x188) +#define MT7928_PCIE_MAC_PM MT7928_PCIE_MAC(0x194) + +#define MT_DMASHDL_LITE_BASE 0x20026200 +#define MT_DMASHDL_LITE(ofs) (MT_DMASHDL_LITE_BASE + (ofs)) +#define MT_DMASHDL_LITE_MAIN_CONTROL MT_DMASHDL_LITE(0x004) +#define MT_DMASHDL_LITE_MAIN_CONTROL_SW_RST BIT(18) +#define MT_DMASHDL_LITE_PAGE_SIZE MT_DMASHDL_LITE(0x008) +#define MT_DMASHDL_LITE_PLE_PAGE_SIZE_MASK GENMASK(12, 0) +#define MT_DMASHDL_LITE_PSE_PAGE_SIZE_MASK GENMASK(28, 16) +#define MT_DMASHDL_LITE_PKT_MAX_SIZE MT_DMASHDL_LITE(0x00c) +#define MT_DMASHDL_LITE_PLE_PKT_MAX_SIZE_MASK GENMASK(12, 0) +#define MT_DMASHDL_LITE_PSE_PKT_MAX_SIZE_MASK GENMASK(28, 16) +#define MT_DMASHDL_LITE_GROUP_DISABLE0 MT_DMASHDL_LITE(0x010) +#define MT_DMASHDL_LITE_GROUP_DISABLE1 MT_DMASHDL_LITE(0x014) +#define MT_DMASHDL_LITE_GROUP_SN_CHK0 MT_DMASHDL_LITE(0x018) +#define MT_DMASHDL_LITE_GROUP_SN_CHK1 MT_DMASHDL_LITE(0x01c) +#define MT_DMASHDL_LITE_GROUP_UDF_CHK0 MT_DMASHDL_LITE(0x020) +#define MT_DMASHDL_LITE_GROUP_UDF_CHK1 MT_DMASHDL_LITE(0x024) +#define MT_DMASHDL_LITE_Q_MAPPING0 MT_DMASHDL_LITE(0x028) +#define MT_DMASHDL_LITE_GROUP0_QUOTA MT_DMASHDL_LITE(0x100) +#define MT_DMASHDL_LITE_GROUP_MIN_QUOTA_MASK GENMASK(12, 0) +#define MT_DMASHDL_LITE_GROUP_MAX_QUOTA_MASK GENMASK(28, 16) + #endif diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c index e9f58492bf7d..1757023ea70d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c @@ -81,6 +81,13 @@ static int mt7925u_mac_reset(struct mt792x_dev *dev) { int err; + if (atomic_read(&dev->mt76.bus_hung)) + return 0; + + mt792xu_reset_on_bus_error(dev); + if (atomic_read(&dev->mt76.bus_hung)) + return 0; + mt76_txq_schedule_all(&dev->mphy); mt76_worker_disable(&dev->mt76.tx_worker); @@ -269,6 +276,7 @@ static int mt7925u_suspend(struct usb_interface *intf, pm_message_t state) pm->suspended = true; dev->hif_resumed = false; flush_work(&dev->reset_work); + cancel_delayed_work_sync(&dev->mlo_pm_work); mt76_connac_mcu_set_hif_suspend(&dev->mt76, true, false); ret = wait_event_timeout(dev->wait, diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h index 70073b43af54..9efc251cb745 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x.h @@ -23,17 +23,19 @@ #define MT792x_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ #define MT792x_FW_TAG_FEATURE 4 +#define MT792x_FW_CAP_NAN BIT(5) #define MT792x_FW_CAP_CNM BIT(7) #define MT792x_CHIP_CAP_CLC_EVT_EN BIT(0) #define MT792x_CHIP_CAP_RSSI_NOTIFY_EVT_EN BIT(1) #define MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN BIT(3) #define MT792x_CHIP_CAP_11D_EN BIT(4) +#define MT792x_CHIP_CAP_REGD_EN BIT(5) #define MT792x_CHIP_CAP_MLO_EN BIT(8) #define MT792x_CHIP_CAP_MLO_EML_EN BIT(9) /* NOTE: used to map mt76_rates. idx may change if firmware expands table */ -#define MT792x_BASIC_RATES_TBL 11 +#define MT792x_BASIC_RATES_TBL 14 #define MT792x_WATCHDOG_TIME (HZ / 4) @@ -47,6 +49,7 @@ #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 MT7927_FIRMWARE_WM "mediatek/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin" +#define MT7928_FIRMWARE_WM "mediatek/mt7928/WIFI_RAM_CODE_MT7935_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" @@ -54,6 +57,10 @@ #define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin" #define MT7925_ROM_PATCH "mediatek/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin" #define MT7927_ROM_PATCH "mediatek/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin" +#define MT7928_ROM_PATCH "mediatek/mt7928/WIFI_MT7935_PATCH_MCU_1_1_hdr.bin" + +#define MT7928_CB_ROM_PATCH "mediatek/mt7928/CBMCU_CODE_MT7935_1_1.bin" +#define MT7928_PHY_RAM "mediatek/mt7928/WIFI_MT7935_PHY_RAM_CODE_1_1.bin" #define MT792x_SDIO_HDR_TX_BYTES GENMASK(15, 0) #define MT792x_SDIO_HDR_PKT_TYPE GENMASK(17, 16) @@ -77,6 +84,7 @@ enum { MT792x_CLC_POWER, MT792x_CLC_POWER_EXT, MT792x_CLC_BE_CTRL, + MT792x_CLC_REGD, MT792x_CLC_MAX_NUM, }; @@ -115,6 +123,20 @@ struct mt792x_link_sta { struct ieee80211_link_sta *pri_link; }; +struct mt792x_sta_nan_sched { + /* protects NAN peer schedule state */ + u16 committed_dw; + u32 sch_idx; + bool idx_assigned; + unsigned long ndp_ctx_bitmap; + bool ndp_ctx_assigned; + u8 ndp_ctx_id; /* assigned NDP context ID (for NDI sta) */ + struct { + u8 map_id; + struct cfg80211_chan_def chans[CFG80211_NAN_SCHED_NUM_TIME_SLOTS]; + } maps[CFG80211_NAN_MAX_PEER_MAPS]; +}; + struct mt792x_sta { struct mt792x_link_sta deflink; /* must be first */ struct mt792x_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -123,6 +145,9 @@ struct mt792x_sta { u16 valid_links; u8 deflink_id; + + /* NAN peer schedule */ + struct mt792x_sta_nan_sched nan_sched; }; DECLARE_EWMA(rssi, 10, 8); @@ -139,6 +164,25 @@ struct mt792x_bss_conf { unsigned int link_id; }; +struct mt792x_nan_conf { + u8 master_pref; + u8 bands; + u8 cluster_id[ETH_ALEN]; + u32 discovery_beacon_interval; + bool enable_dw_notification; +}; + +struct mt792x_nan { + struct mt792x_nan_conf conf; + + /* Scheduler */ + struct cfg80211_chan_def local_sched[CFG80211_NAN_SCHED_NUM_TIME_SLOTS]; + u32 seq_id; + + /* Connection index bitmap, up to NAN_MAX_CONN_CFG peers */ + unsigned long conn_bitmap; +}; + struct mt792x_vif { struct mt792x_bss_conf bss_conf; /* must be first */ struct mt792x_bss_conf __rcu *link_conf[IEEE80211_MLD_MAX_NUM_LINKS]; @@ -153,6 +197,8 @@ struct mt792x_vif { struct work_struct csa_work; struct timer_list csa_timer; + + struct mt792x_nan nan; }; struct mt792x_phy { @@ -200,6 +246,7 @@ struct mt792x_irq_map { u32 mcu_complete_mask; } tx; struct { + u32 all_complete_mask; u32 data_complete_mask; u32 wm_complete_mask; u32 wm2_complete_mask; @@ -216,6 +263,7 @@ struct mt792x_dma_layout { struct mt792x_dma_ring tx_data0; struct mt792x_dma_ring tx_mcu; struct mt792x_dma_ring tx_fwdl; + struct mt792x_dma_ring tx_done; struct mt792x_dma_ring rx_data; struct mt792x_dma_ring rx_mcu; }; @@ -237,6 +285,11 @@ struct mt792x_hif_ops { int (*fw_own)(struct mt792x_dev *dev); }; +struct mt792x_pcie_reg { + u32 imask; + u32 pm; +}; + struct mt792x_dev { union { /* must be first */ struct mt76_dev mt76; @@ -259,6 +312,7 @@ struct mt792x_dev { bool hif_idle:1; bool hif_resumed:1; bool regd_change:1; + bool skip_wpdma_reinit:1; wait_queue_head_t wait; struct work_struct init_work; @@ -272,6 +326,7 @@ struct mt792x_dev { struct mt76_connac_coredump coredump; const struct mt792x_hif_ops *hif_ops; const struct mt792x_irq_map *irq_map; + const struct mt792x_pcie_reg *pcie_reg; struct work_struct ipv6_ns_work; struct delayed_work mlo_pm_work; @@ -283,6 +338,10 @@ struct mt792x_dev { u32 backup_l2; struct ieee80211_chanctx_conf *new_ctx; + + struct ieee80211_vif *nan_vif; + const struct ieee80211_iface_combination *iface_combinations; + int n_iface_combinations; }; static inline struct mt792x_bss_conf * @@ -486,6 +545,8 @@ static inline char *mt792x_ram_name(struct mt792x_dev *dev) return MT7925_FIRMWARE_WM; case 0x7927: return MT7927_FIRMWARE_WM; + case 0x7928: + return MT7928_FIRMWARE_WM; default: return MT7921_FIRMWARE_WM; } @@ -504,11 +565,33 @@ static inline char *mt792x_patch_name(struct mt792x_dev *dev) return MT7925_ROM_PATCH; case 0x7927: return MT7927_ROM_PATCH; + case 0x7928: + return MT7928_ROM_PATCH; default: return MT7921_ROM_PATCH; } } +static inline char *mt792x_cb_patch_name(struct mt792x_dev *dev) +{ + switch (mt76_chip(&dev->mt76)) { + case 0x7928: + return MT7928_CB_ROM_PATCH; + default: + return NULL; + } +} + +static inline char *mt792x_phy_ram_name(struct mt792x_dev *dev) +{ + switch (mt76_chip(&dev->mt76)) { + case 0x7928: + return MT7928_PHY_RAM; + default: + return NULL; + } +} + int mt792x_load_firmware(struct mt792x_dev *dev); /* usb */ diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c index b50825eccdaf..0ad33f74c228 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c @@ -3,6 +3,7 @@ #include #include +#include #include "mt792x.h" #include "dma.h" @@ -60,7 +61,41 @@ static const struct ieee80211_iface_limit if_limits_chanctx_scc[] = { } }; -static const struct ieee80211_iface_combination if_comb_chanctx[] = { +static const struct ieee80211_iface_limit if_limits_nan_mcc[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_NAN), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_NAN_DATA), + }, +}; + +static const struct ieee80211_iface_limit if_limits_nan_scc[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_NAN), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_NAN_DATA), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_combination if_comb_chanctx_base[] = { { .limits = if_limits_chanctx_mcc, .n_limits = ARRAY_SIZE(if_limits_chanctx_mcc), @@ -77,6 +112,60 @@ static const struct ieee80211_iface_combination if_comb_chanctx[] = { } }; +static const struct ieee80211_iface_combination if_comb_chanctx_nan[] = { + { + .limits = if_limits_nan_mcc, + .n_limits = ARRAY_SIZE(if_limits_nan_mcc), + .max_interfaces = MT792x_MAX_INTERFACES, + .num_different_channels = 2, + .beacon_int_infra_match = false, + }, + { + .limits = if_limits_nan_scc, + .n_limits = ARRAY_SIZE(if_limits_nan_scc), + .max_interfaces = MT792x_MAX_INTERFACES, + .num_different_channels = 1, + .beacon_int_infra_match = false, + }, +}; + +static int mt792x_setup_iface_combinations(struct mt792x_dev *dev, + struct wiphy *wiphy) +{ + const bool cnm = !!(dev->fw_features & MT792x_FW_CAP_CNM); + const bool nan = !!(dev->fw_features & MT792x_FW_CAP_NAN); + const int n_base = ARRAY_SIZE(if_comb_chanctx_base); + const int n_nan = ARRAY_SIZE(if_comb_chanctx_nan); + struct ieee80211_iface_combination *comb; + + if (!cnm) { + dev->iface_combinations = if_comb; + dev->n_iface_combinations = ARRAY_SIZE(if_comb); + return 0; + } + + /* CNM enabled, NAN optional */ + if (!nan) { + dev->iface_combinations = if_comb_chanctx_base; + dev->n_iface_combinations = ARRAY_SIZE(if_comb_chanctx_base); + return 0; + } + + /* CNM + NAN: dynamically build base + nan list */ + comb = devm_kcalloc(&wiphy->dev, n_base + n_nan, sizeof(*comb), + GFP_KERNEL); + if (!comb) + return -ENOMEM; + + memcpy(comb, if_comb_chanctx_base, sizeof(if_comb_chanctx_base)); + memcpy(comb + n_base, if_comb_chanctx_nan, sizeof(if_comb_chanctx_nan)); + + dev->iface_combinations = comb; + dev->n_iface_combinations = n_base + n_nan; + + return 0; +} + void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control, struct sk_buff *skb) { @@ -663,6 +752,7 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) struct mt792x_phy *phy = mt792x_hw_phy(hw); struct mt792x_dev *dev = phy->dev; struct wiphy *wiphy = hw->wiphy; + int err; hw->queues = 4; if (dev->has_eht) { @@ -683,15 +773,17 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) hw->vif_data_size = sizeof(struct mt792x_vif); hw->chanctx_data_size = sizeof(struct mt792x_chanctx); - if (dev->fw_features & MT792x_FW_CAP_CNM) { + if (dev->fw_features & MT792x_FW_CAP_CNM) wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - wiphy->iface_combinations = if_comb_chanctx; - wiphy->n_iface_combinations = ARRAY_SIZE(if_comb_chanctx); - } else { + else wiphy->flags &= ~WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; - wiphy->iface_combinations = if_comb; - wiphy->n_iface_combinations = ARRAY_SIZE(if_comb); - } + + err = mt792x_setup_iface_combinations(dev, wiphy); + if (err) + return err; + + wiphy->iface_combinations = dev->iface_combinations; + wiphy->n_iface_combinations = dev->n_iface_combinations; wiphy->flags &= ~(WIPHY_FLAG_IBSS_RSN | WIPHY_FLAG_4ADDR_AP | WIPHY_FLAG_4ADDR_STATION); wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | @@ -699,6 +791,22 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_DEVICE); + + if ((dev->fw_features & MT792x_FW_CAP_CNM) && + (dev->fw_features & MT792x_FW_CAP_NAN)) { + wiphy->interface_modes |= BIT(NL80211_IFTYPE_NAN) | + BIT(NL80211_IFTYPE_NAN_DATA); + wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ) | + BIT(NL80211_BAND_5GHZ); + wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC | + WIPHY_NAN_FLAGS_USERSPACE_DE; + wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK; + wiphy->nan_capa.n_antennas = 0x22; + wiphy->nan_capa.max_channel_switch_time = 12; + wiphy->nan_capa.dev_capabilities = NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED; + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SECURE_NAN); + } + wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN; wiphy->max_scan_ssids = 4; wiphy->max_sched_scan_plan_interval = @@ -712,6 +820,7 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR | NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR; + phy->mt76->no_active_monitor = true; wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_LEGACY); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT); @@ -719,12 +828,16 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS); ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS); ieee80211_hw_set(hw, HAS_RATE_CONTROL); ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD); ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD); - ieee80211_hw_set(hw, WANT_MONITOR_VIF); + if (is_mt7927(&dev->mt76)) + ieee80211_hw_set(hw, NO_VIRTUAL_MONITOR); + else + ieee80211_hw_set(hw, WANT_MONITOR_VIF); ieee80211_hw_set(hw, SUPPORTS_PS); ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS); ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW); @@ -985,6 +1098,15 @@ int mt792x_load_firmware(struct mt792x_dev *dev) dev_warn(dev->mt76.dev, "MCU is not ready for firmware download\n"); + if (is_mt7928(&dev->mt76)) { + dev_info(dev->mt76.dev, "Loading CB firmware patch: %s\n", + mt792x_cb_patch_name(dev)); + ret = mt76_connac3_load_cb_patch(&dev->mt76, mt792x_cb_patch_name(dev)); + if (ret) + return ret; + } + + dev_info(dev->mt76.dev, "Loading firmware patch: %s\n", mt792x_patch_name(dev)); ret = mt76_connac2_load_patch(&dev->mt76, mt792x_patch_name(dev)); if (ret) return ret; @@ -996,6 +1118,12 @@ int mt792x_load_firmware(struct mt792x_dev *dev) ret = __mt792x_mcu_drv_pmctrl(dev); } + if (is_mt7928(&dev->mt76)) { + ret = mt76_connac3_load_phy_ram(&dev->mt76, mt792x_phy_ram_name(dev)); + if (ret) + return ret; + } + ret = mt76_connac2_load_ram(&dev->mt76, mt792x_ram_name(dev), NULL); 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 fc326447c792..e74b95fdc767 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c @@ -39,9 +39,7 @@ void mt792x_irq_tasklet(unsigned long data) trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); - mask |= intr & (irq_map->rx.data_complete_mask | - irq_map->rx.wm_complete_mask | - irq_map->rx.wm2_complete_mask); + mask |= intr & irq_map->rx.all_complete_mask; if (intr & dev->irq_map->tx.mcu_complete_mask) mask |= dev->irq_map->tx.mcu_complete_mask; @@ -124,6 +122,17 @@ int mt792x_dma_alloc_queues(struct mt792x_dev *dev, if (ret) return ret; + /* tx done */ + if (layout->tx_done.ring_base) { + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA], + layout->tx_done.qid, + layout->tx_done.n_desc, + MT_RX_BUF_SIZE, + layout->tx_done.ring_base); + if (ret) + return ret; + } + /* rx event */ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU], layout->rx_mcu.qid, @@ -197,9 +206,38 @@ static void mt7927_wfdma_setup(struct mt792x_dev *dev) mt76_set(dev, MT_WFDMA0_INT_TX_PRI, 0x7F00); } +static void mt7928_dma_prefetch_setup(struct mt792x_dev *dev) +{ + /* rx ring */ + mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0000, 0x8)); + mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x0080, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x00c0, 0x8)); + mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x0140, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING4_EXT_CTRL, PREFETCH(0x0180, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING5_EXT_CTRL, PREFETCH(0x01c0, 0x4)); + mt76_wr(dev, MT_WFDMA0_RX_RING6_EXT_CTRL, PREFETCH(0x0200, 0x4)); + /* tx ring */ + mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x0240, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x0340, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x0440, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0540, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING4_EXT_CTRL, PREFETCH(0x0640, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING5_EXT_CTRL, PREFETCH(0x0740, 0x10)); + mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0840, 0x4)); + mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0880, 0x4)); +} + +static void mt7928_wfdma_setup(struct mt792x_dev *dev) +{ + mt76_wr(dev, MT_WFDMA0_INT_RX_PRI, 0); + mt76_wr(dev, MT_WFDMA0_INT_TX_PRI, 0); +} + static void mt792x_dma_prefetch(struct mt792x_dev *dev) { - if (is_mt7927(&dev->mt76)) { + if (is_mt7928(&dev->mt76)) { + mt7928_dma_prefetch_setup(dev); + } else if (is_mt7927(&dev->mt76)) { mt7927_dma_prefetch_setup(dev); } else if (is_mt7925(&dev->mt76)) { mt7925_dma_prefetch_setup(dev); @@ -241,32 +279,69 @@ static void mt792x_dma_prefetch(struct mt792x_dev *dev) int mt792x_dma_enable(struct mt792x_dev *dev) { - /* configure perfetch settings */ + u32 addr; + + /* configure prefetch settings */ mt792x_dma_prefetch(dev); /* reset dma idx */ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0); - if (is_mt7925(&dev->mt76)) + if (is_mt7925(&dev->mt76) || is_mt7928(&dev->mt76)) mt76_wr(dev, MT_WFDMA0_RST_DRX_PTR, ~0); /* configure delay interrupt */ mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0); - mt76_set(dev, MT_WFDMA0_GLO_CFG, - MT_WFDMA0_GLO_CFG_TX_WB_DDONE | - MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | - MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | - MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | - FIELD_PREP(MT_WFDMA0_GLO_CFG_DMA_SIZE, 3) | - MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK | - MT_WFDMA0_GLO_CFG_RX_WB_DDONE | - MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + if (is_mt7928(&dev->mt76)) { + mt76_wr(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_WB_DDONE | + MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | + MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + FIELD_PREP(MT_WFDMA0_GLO_CFG_DMA_SIZE, 1) | + MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK | + MT_WFDMA0_GLO_CFG_RX_WB_DDONE | + MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | + MT_WFDMA0_GLO_CFG_ADDR_EXT_EN | + MT_WFDMA0_GLO_CFG_CSR_LBK_RX_Q_SEL_EN); + /* set rxq threshold to 2 */ + for (addr = MT_WFDMA0_WPDMA_PAUSE_RXQ_TH10; + addr <= MT_WFDMA0_WPDMA_PAUSE_RXQ_TH76; + addr += 4) { + mt76_wr(dev, addr, + FIELD_PREP(MT_WFDMA0_WPDMA_PAUSE_RXQ_THXX_L_TH_MASK, 2) | + FIELD_PREP(MT_WFDMA0_WPDMA_PAUSE_RXQ_THXX_H_TH_MASK, 2)); + } + mt76_wr(dev, MT_WFDMA0_GLO_CFG_EXT0, + MT_WFDMA0_GLO_CFG_EXT0_CSR_MEM_ARB_LOCK_EN | + MT_WFDMA0_GLO_CFG_EXT0_CSR_TX_DMASHDL_LITE_EN | + MT_WFDMA0_GLO_CFG_EXT0_CSR_RX_WB_KEEP_RSVD | + MT_WFDMA0_GLO_CFG_EXT0_CSR_BID_CHECK_BYPASS_EN | + MT_WFDMA0_GLO_CFG_EXT0_CSR_RX_INFO_WB_EN | + MT_WFDMA0_GLO_CFG_EXT0_CSR_AXI_AWUSER_LOCK_EN | + FIELD_PREP(MT_WFDMA0_GLO_CFG_EXT0_CSR_MAX_PREFETCH_CNT_MASK, 3) | + FIELD_PREP(MT_WFDMA0_GLO_CFG_EXT0_CSR_MEM_BST_SIZE_MASK, 3) | + FIELD_PREP(MT_WFDMA0_GLO_CFG_EXT0_CSR_AXI_AW_OUTSTANDING_NUM_MASK, + 8)); + } else { + mt76_set(dev, MT_WFDMA0_GLO_CFG, + MT_WFDMA0_GLO_CFG_TX_WB_DDONE | + MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN | + MT_WFDMA0_GLO_CFG_CLK_GAT_DIS | + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | + FIELD_PREP(MT_WFDMA0_GLO_CFG_DMA_SIZE, 3) | + MT_WFDMA0_GLO_CFG_FIFO_DIS_CHECK | + MT_WFDMA0_GLO_CFG_RX_WB_DDONE | + MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN | + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); + } mt76_set(dev, MT_WFDMA0_GLO_CFG, MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN); - if (is_mt7927(&dev->mt76)) + if (is_mt7928(&dev->mt76)) + mt7928_wfdma_setup(dev); + else if (is_mt7927(&dev->mt76)) mt7927_wfdma_setup(dev); else if (is_mt7925(&dev->mt76)) mt7925_wfdma_setup(dev); @@ -276,9 +351,7 @@ int mt792x_dma_enable(struct mt792x_dev *dev) /* enable interrupts for TX/RX rings */ mt76_connac_irq_enable(&dev->mt76, dev->irq_map->tx.all_complete_mask | - dev->irq_map->rx.data_complete_mask | - dev->irq_map->rx.wm2_complete_mask | - dev->irq_map->rx.wm_complete_mask | + dev->irq_map->rx.all_complete_mask | MT_INT_MCU_CMD); mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE); @@ -345,11 +418,15 @@ int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev) struct mt76_connac_pm *pm = &dev->pm; int err; + if (dev->skip_wpdma_reinit) + return 0; + /* check if the wpdma must be reinitialized */ if (mt792x_dma_need_reinit(dev)) { /* disable interrutpts */ mt76_wr(dev, dev->irq_map->host_irq_enable, 0); - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0); + if (dev->pcie_reg) + mt76_wr(dev, dev->pcie_reg->imask, 0x0); err = mt792x_wpdma_reset(dev, false); if (err) { @@ -358,7 +435,8 @@ int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev) } /* enable interrutpts */ - mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff); + if (dev->pcie_reg) + mt76_wr(dev, dev->pcie_reg->imask, 0xff); pm->stats.lp_wake++; } @@ -388,7 +466,7 @@ int mt792x_dma_disable(struct mt792x_dev *dev, bool force) /* disable dmashdl */ mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0, - MT_WFDMA0_CSR_TX_DMASHDL_ENABLE); + MT_WFDMA0_GLO_CFG_EXT0_CSR_TX_DMASHDL_EN); mt76_set(dev, MT_DMASHDL_SW_CONTROL, MT_DMASHDL_DMASHDL_BYPASS); if (force) { diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h index 4cd5b33b640e..3587f61e098a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h @@ -331,11 +331,29 @@ #define MT_INT_MCU_CMD MCU2HOST_SW_INT_ENA #define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c) +#define MT_WFDMA0_WPDMA_PAUSE_RXQ_TH10 MT_WFDMA0(0x260) +#define MT_WFDMA0_WPDMA_PAUSE_RXQ_TH32 MT_WFDMA0(0x264) +#define MT_WFDMA0_WPDMA_PAUSE_RXQ_TH54 MT_WFDMA0(0x268) +#define MT_WFDMA0_WPDMA_PAUSE_RXQ_TH76 MT_WFDMA0(0x26c) +#define MT_WFDMA0_WPDMA_PAUSE_RXQ_THXX_L_TH_MASK GENMASK(11, 0) +#define MT_WFDMA0_WPDMA_PAUSE_RXQ_THXX_H_TH_MASK GENMASK(27, 16) + #define MT_WFDMA0_RST_DRX_PTR MT_WFDMA0(0x280) #define MT_WFDMA0_INT_RX_PRI MT_WFDMA0(0x298) #define MT_WFDMA0_INT_TX_PRI MT_WFDMA0(0x29c) #define MT_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0) -#define MT_WFDMA0_CSR_TX_DMASHDL_ENABLE BIT(6) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_MEM_ARB_LOCK_EN BIT(4) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_TX_DMASHDL_EN BIT(6) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_TX_DMASHDL_LITE_EN BIT(7) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_RX_WB_KEEP_RSVD BIT(10) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_BID_CHECK_BYPASS_EN BIT(22) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_RX_INFO_WB_EN BIT(23) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_AXI_AWUSER_LOCK_EN BIT(29) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_MAX_PREFETCH_CNT_MASK GENMASK(1, 0) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_MEM_BST_SIZE_MASK GENMASK(3, 2) +#define MT_WFDMA0_GLO_CFG_EXT0_CSR_AXI_AW_OUTSTANDING_NUM_MASK GENMASK(27, 24) + +#define MT_WFDMA0_GLO_CFG_EXT1 MT_WFDMA0(0x2b4) #define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0) #define MT_WFDMA0_TX_RING0_EXT_CTRL MT_WFDMA0(0x600) @@ -375,7 +393,6 @@ #define MT_WFDMA_PREFETCH_CFG1 MT_WFDMA_EXT_CSR(0xf4) #define MT_WFDMA_PREFETCH_CFG2 MT_WFDMA_EXT_CSR(0xf8) #define MT_WFDMA_PREFETCH_CFG3 MT_WFDMA_EXT_CSR(0xfc) -#define MT_WFDMA0_GLO_CFG_EXT1 MT_WFDMA0(0x2b4) #define MT_SWDEF_BASE 0x41f200 #define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs)) @@ -415,10 +432,6 @@ #define MT_HW_EMI_CTL 0x18011100 #define MT_HW_EMI_CTL_SLPPROT_EN BIT(1) -#define MT_PCIE_MAC_BASE 0x10000 -#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs)) -#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188) -#define MT_PCIE_MAC_PM MT_PCIE_MAC(0x194) #define MT_PCIE_MAC_PM_L0S_DIS BIT(8) #define MT_DMA_SHDL(ofs) (0x7c026000 + (ofs)) diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c index 910132e94956..850f6b2cfc4a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c +++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c @@ -11,6 +11,9 @@ #include "mt792x.h" #include "mt76_connac2_mac.h" +#define MT792X_USB_TX_TIMEOUT_LIMIT 50000 +#define MT792X_USB_UDMA_IDLE_TIMEOUT 1000 + static int mt792xu_read32(struct mt76_dev *dev, u32 addr, void *buf) { return __mt76u_vendor_request(dev, MT_VEND_READ_EXT, @@ -31,10 +34,75 @@ static void mt792xu_reset_work(struct work_struct *work) atomic_set(&dev->usb_reset_pending, 0); } +static void mt792xu_queue_usb_reset(struct mt792x_dev *dev, int err) +{ + if (!atomic_xchg(&dev->usb_reset_pending, 1)) { + dev_warn(dev->mt76.dev, + "USB transport access failed (%d), queueing device reset\n", + err); + + schedule_work(&dev->usb_reset_work); + } +} + +static u32 mt792xu_bus_hung_rr(struct mt76_dev *mdev, u32 offset) +{ + return 0; +} + +static void mt792xu_bus_hung_wr(struct mt76_dev *mdev, u32 offset, u32 val) +{ +} + +static u32 mt792xu_bus_hung_rmw(struct mt76_dev *mdev, u32 offset, + u32 mask, u32 val) +{ + return 0; +} + +static void mt792xu_bus_hung_write_copy(struct mt76_dev *mdev, u32 offset, + const void *data, int len) +{ +} + +static void mt792xu_bus_hung_read_copy(struct mt76_dev *mdev, u32 offset, + void *data, int len) +{ + memset(data, 0, len); +} + +static const struct mt76_bus_ops mt792xu_bus_hung_ops = { + .rr = mt792xu_bus_hung_rr, + .wr = mt792xu_bus_hung_wr, + .rmw = mt792xu_bus_hung_rmw, + .write_copy = mt792xu_bus_hung_write_copy, + .read_copy = mt792xu_bus_hung_read_copy, + .type = MT76_BUS_USB, +}; + +static void mt792xu_set_bus_hung(struct mt792x_dev *dev) +{ + atomic_set(&dev->mt76.bus_hung, true); + + if (READ_ONCE(dev->mt76.bus) == &mt792xu_bus_hung_ops) + return; + + WRITE_ONCE(dev->mt76.bus, &mt792xu_bus_hung_ops); +} + +static void mt792xu_ctrl_timeout(struct mt76_dev *mdev, int err) +{ + struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76); + + mt792xu_set_bus_hung(dev); + mt792xu_queue_usb_reset(dev, err); +} + void mt792xu_reset_work_init(struct mt792x_dev *dev) { INIT_WORK(&dev->usb_reset_work, mt792xu_reset_work); atomic_set(&dev->usb_reset_pending, 0); + dev->mt76.usb.ctrl_timeout = mt792xu_ctrl_timeout; } EXPORT_SYMBOL_GPL(mt792xu_reset_work_init); @@ -62,26 +130,23 @@ EXPORT_SYMBOL_GPL(mt792xu_check_bus); int mt792xu_reset_on_bus_error(struct mt792x_dev *dev) { - int err = 0; + int err; - if (!atomic_read(&dev->mt76.bus_hung)) - err = mt792xu_check_bus(dev); + /* Once hung, the no-op bus ops stay installed until the queued USB + * reset re-probes the device. Do not clear bus_hung here, or the caller + * would run a full reset over dropped register I/O and report success. + */ + if (atomic_read(&dev->mt76.bus_hung)) + return -EIO; + err = mt792xu_check_bus(dev); if (err) { - atomic_set(&dev->mt76.bus_hung, true); - - if (!atomic_xchg(&dev->usb_reset_pending, 1)) { - dev_warn(dev->mt76.dev, - "USB transport access failed (%d), queueing device reset\n", - err); - - schedule_work(&dev->usb_reset_work); - } + mt792xu_set_bus_hung(dev); + mt792xu_queue_usb_reset(dev, err); return err; } - atomic_set(&dev->mt76.bus_hung, false); return 0; } EXPORT_SYMBOL_GPL(mt792xu_reset_on_bus_error); @@ -169,9 +234,9 @@ EXPORT_SYMBOL_GPL(mt792xu_mcu_power_on); static void mt792xu_cleanup(struct mt792x_dev *dev) { clear_bit(MT76_STATE_INITIALIZED, &dev->mphy.state); - mt792xu_wfsys_reset(dev); skb_queue_purge(&dev->mt76.mcu.res_q); mt76u_queues_deinit(&dev->mt76); + mt792xu_wfsys_reset(dev); } static u32 mt792xu_uhw_rr(struct mt76_dev *dev, u32 addr) @@ -281,6 +346,23 @@ 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); } +static void mt792xu_wait_udma_idle(struct mt792x_dev *dev) +{ + u32 mask = MT_WL_RX_BUSY | MT_WL_TX_BUSY; + u32 val; + + mt76_set(dev, MT_UDMA_WLCFG_0, MT_WL_RX_FLUSH); + + if (mt76_poll_msec(dev, MT_UDMA_WLCFG_0, mask, 0, + MT792X_USB_UDMA_IDLE_TIMEOUT)) + return; + + val = mt76_rr(dev, MT_UDMA_WLCFG_0); + + dev_warn(dev->mt76.dev, + "UDMA busy before WFSYS reset: WLCFG0=0x%08x\n", val); +} + struct mt792xu_wfsys_desc { u32 rst_reg; u32 done_reg; @@ -319,6 +401,10 @@ int mt792xu_dma_init(struct mt792x_dev *dev, bool resume) mt76_set(dev, MT_UDMA_WLCFG_0, MT_WL_RX_EN | MT_WL_TX_EN | MT_WL_RX_MPSZ_PAD0 | MT_TICK_1US_EN); + mt76_rmw(dev, MT_UDMA_WLCFG_1, MT_WL_TX_TMOUT_LMT, + FIELD_PREP(MT_WL_TX_TMOUT_LMT, + MT792X_USB_TX_TIMEOUT_LIMIT)); + mt76_set(dev, MT_UDMA_WLCFG_0, MT_WL_TX_TMOUT_FUNC_EN); mt76_clear(dev, MT_UDMA_WLCFG_0, MT_WL_RX_AGG_TO | MT_WL_RX_AGG_LMT); mt76_clear(dev, MT_UDMA_WLCFG_1, MT_WL_RX_AGG_PKT_LMT); @@ -344,6 +430,10 @@ int mt792xu_wfsys_reset(struct mt792x_dev *dev) u32 val; int i; + if (atomic_read(&dev->mt76.bus_hung)) + return -EIO; + + mt792xu_wait_udma_idle(dev); mt792xu_epctl_rst_opt(dev, false); val = mt792xu_uhw_rr(&dev->mt76, desc->rst_reg); @@ -408,13 +498,27 @@ void mt792xu_disconnect(struct usb_interface *usb_intf) { struct mt792x_dev *dev = usb_get_intfdata(usb_intf); - mt792xu_reset_work_cleanup(dev); - cancel_work_sync(&dev->init_work); - if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) + if (!dev) return; + set_bit(MT76_RESET, &dev->mphy.state); + set_bit(MT76_MCU_RESET, &dev->mphy.state); + clear_bit(MT76_STATE_RUNNING, &dev->mphy.state); + wake_up(&dev->mt76.mcu.wait); + skb_queue_purge(&dev->mt76.mcu.res_q); + + cancel_work_sync(&dev->reset_work); + cancel_work_sync(&dev->init_work); + mt76_worker_disable(&dev->mt76.tx_worker); + mt792xu_reset_work_cleanup(dev); + if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) { + set_bit(MT76_REMOVED, &dev->mphy.state); + return; + } + mt76_unregister_device(&dev->mt76); mt792xu_cleanup(dev); + set_bit(MT76_REMOVED, &dev->mphy.state); usb_set_intfdata(usb_intf, NULL); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c index ac05f7d75d63..ec33521db564 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c @@ -150,6 +150,12 @@ mt7996_eeprom_check_or_use_default(struct mt7996_dev *dev, bool use_default) goto out; } + if (fw->size < MT7996_EEPROM_SIZE) { + dev_err(dev->mt76.dev, "Invalid default bin size\n"); + ret = -EINVAL; + goto out; + } + if (!use_default && mt7996_eeprom_variant_valid(dev, fw->data)) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c index d6f9aa1ab52d..fb635a092584 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c @@ -34,7 +34,6 @@ 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 = { @@ -47,7 +46,6 @@ static const struct ieee80211_iface_combination if_comb_global_7992 = { 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[] = { @@ -463,6 +461,8 @@ mt7996_init_wiphy_band(struct ieee80211_hw *hw, struct mt7996_phy *phy) radio->n_freq_range = 1; radio->iface_combinations = &if_comb; radio->n_iface_combinations = 1; + memcpy(dev->radio_addrs[n_radios].addr, phy->mt76->macaddr, ETH_ALEN); + hw->wiphy->n_addresses++; hw->wiphy->n_radio++; wiphy->available_antennas_rx |= phy->mt76->chainmask; @@ -505,6 +505,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) wiphy->n_iface_combinations = 1; wiphy->radio = dev->radios; + wiphy->addresses = dev->radio_addrs; wiphy->reg_notifier = mt7996_regd_notifier; wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH | @@ -524,6 +525,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER); + wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL); if (mt7996_eeprom_has_background_radar(dev) && (!mdev->dev->of_node || @@ -559,6 +561,9 @@ mt7996_mac_init_band(struct mt7996_dev *dev, u8 band) { u32 mask, set; + if (!mt7996_band_valid(dev, band)) + return; + /* clear estimated value of EIFS for Rx duration & OBSS time */ mt76_wr(dev, MT_WF_RMAC_RSVD0(band), MT_WF_RMAC_RSVD0_EIFS_CLR); @@ -590,6 +595,9 @@ mt7996_mac_init_band(struct mt7996_dev *dev, u8 band) * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set. */ mt76_set(dev, MT_AGG_ACR4(band), MT_AGG_ACR_PPDU_TXS2H); + + if (!is_mt7996(&dev->mt76)) + mt7996_mcu_set_bssid_mapping_addr(&dev->mt76, band); } static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev) @@ -1561,7 +1569,6 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band, struct ieee80211_sta_eht_cap *eht_cap = &data->eht_cap; struct ieee80211_eht_cap_elem_fixed *eht_cap_elem = &eht_cap->eht_cap_elem; struct ieee80211_eht_mcs_nss_supp *eht_nss = &eht_cap->eht_mcs_nss_supp; - enum nl80211_chan_width width = phy->mt76->chandef.width; int nss = hweight8(phy->mt76->antenna_mask); int sts = hweight16(phy->mt76->chainmask); u8 val; @@ -1637,11 +1644,16 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band, u8_encode_bits(u8_get_bits(1, GENMASK(1, 0)), IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK); - val = width == NL80211_CHAN_WIDTH_320 ? 0xf : - width == NL80211_CHAN_WIDTH_160 ? 0x7 : - width == NL80211_CHAN_WIDTH_80 ? 0x3 : 0x1; - eht_cap_elem->phy_cap_info[6] = - u8_encode_bits(val, IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK); + eht_cap_elem->phy_cap_info[6] = IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK; + if (band != NL80211_BAND_6GHZ) { + eht_cap_elem->phy_cap_info[6] &= + ~IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_320MHZ; + + if (band != NL80211_BAND_5GHZ) + eht_cap_elem->phy_cap_info[6] &= + ~(IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_160MHZ | + IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_80MHZ); + } val = u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_RX) | u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_TX); @@ -1799,6 +1811,8 @@ void mt7996_unregister_device(struct mt7996_dev *dev) { cancel_work_sync(&dev->dump_work); cancel_work_sync(&dev->wed_rro.work); + cancel_work_sync(&dev->reset_work); + cancel_work_sync(&dev->rc_work); mt7996_unregister_phy(mt7996_phy3(dev)); mt7996_unregister_phy(mt7996_phy2(dev)); mt7996_unregister_thermal(&dev->phy); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c index 0eebc8182ca9..1cba381a78b8 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c @@ -166,7 +166,7 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev) rssi[0] = to_rssi(GENMASK(7, 0), val); rssi[1] = to_rssi(GENMASK(15, 8), val); rssi[2] = to_rssi(GENMASK(23, 16), val); - rssi[3] = to_rssi(GENMASK(31, 14), val); + rssi[3] = to_rssi(GENMASK(31, 24), val); mlink = rcu_dereference(msta->vif->mt76.link[wcid->link_id]); if (mlink) { @@ -294,6 +294,10 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev, dcm = FIELD_GET(MT_PRXV_DCM, v2); bw = FIELD_GET(MT_PRXV_FRAME_MODE, v2); + /* the hardware reports NSTS; report the data NSS for STBC frames */ + if (stbc && nss > 1) + nss >>= 1; + switch (*mode) { case MT_PHY_TYPE_CCK: cck = true; @@ -349,7 +353,7 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev, case IEEE80211_STA_RX_BW_20: break; case IEEE80211_STA_RX_BW_40: - if (*mode & MT_PHY_TYPE_HE_EXT_SU && + if (*mode == MT_PHY_TYPE_HE_EXT_SU && (idx & MT_PRXV_TX_ER_SU_106T)) { status->bw = RATE_INFO_BW_HE_RU; status->he_ru = @@ -441,7 +445,13 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, memset(status, 0, sizeof(*status)); band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1); + if (!mt7996_band_valid(dev, band_idx)) + return -EINVAL; + mphy = dev->mt76.phys[band_idx]; + if (!mphy) + return -EINVAL; + phy = mphy->priv; status->phy_idx = mphy->band_idx; @@ -854,6 +864,33 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi, txwi[6] |= cpu_to_le32(MT_TXD6_DIS_MAT); } +/* The WLAN_IDX in the TXD and TXP must belong to the primary or secondary + * link of an MLD station; any other link id can make the firmware spin when + * that link is in powersave. Completion events carry the same index, so the + * wcid used for status tracking and accounting must match it + */ +struct mt76_wcid *mt7996_get_tx_wcid(struct mt76_wcid *wcid) +{ + struct mt7996_sta_link *msta_link; + struct mt7996_sta *msta; + + if (!wcid->sta) + return wcid; + + msta_link = container_of(wcid, struct mt7996_sta_link, wcid); + msta = msta_link->sta; + + if (!msta || wcid->link_id == msta->seclink_id || + wcid->link_id == msta->deflink_id) + return wcid; + + msta_link = mt7996_sta_link(msta, msta->deflink_id); + if (msta_link) + return &msta_link->wcid; + + return wcid; +} + void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, @@ -1030,6 +1067,11 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, IEEE80211_TX_CTRL_MLO_LINK); } + /* non-MLD frames are LINK_UNSPECIFIED; use the wcid's own link */ + if (link_id == IEEE80211_LINK_UNSPECIFIED && + wcid != &dev->mt76.global_wcid) + link_id = wcid->link_id; + if (link_id != wcid->link_id && link_id != IEEE80211_LINK_UNSPECIFIED) { if (msta) { struct mt7996_sta_link *msta_link = @@ -1086,6 +1128,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, tx_info->buf[1].len, DMA_TO_DEVICE); } + wcid = mt7996_get_tx_wcid(wcid); + pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb); memset(txwi_ptr, 0, MT_TXD_SIZE); /* Transmit non qos data by 802.11 header and need to fill txd by host*/ @@ -1212,8 +1256,6 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta, return; tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; - if (tid >= 6) /* skip VO queue */ - return; if (is_8023) { fc = IEEE80211_FTYPE_DATA | @@ -1239,6 +1281,30 @@ mt7996_tx_check_aggr(struct ieee80211_link_sta *link_sta, clear_bit(tid, &wcid->ampdu_state); } +static void +mt7996_txp_skb_unmap(struct mt76_dev *mdev, struct mt76_txwi_cache *t) +{ + u8 *txwi_ptr = mt76_get_txwi_ptr(mdev, t); + __le32 *txwi = (__le32 *)txwi_ptr; + __le32 *txp; + dma_addr_t addr; + u32 val; + + if (!(le32_to_cpu(txwi[7]) & MT_TXD7_MAC_TXD)) { + mt76_connac_txp_skb_unmap(mdev, t); + return; + } + + txp = (__le32 *)(txwi_ptr + MT_TXD_SIZE); + val = le32_to_cpu(txp[3]); + addr = le32_to_cpu(txp[2]); +#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT + addr |= (dma_addr_t)FIELD_GET(MT_TXP3_DMA_ADDR_H, val) << 32; +#endif + dma_unmap_single(mdev->dma_dev, addr, FIELD_GET(MT_TXP_BUF_LEN, val), + DMA_TO_DEVICE); +} + static void mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t, struct ieee80211_link_sta *link_sta, @@ -1248,7 +1314,7 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t, __le32 *txwi; u16 wcid_idx; - mt76_connac_txp_skb_unmap(mdev, t); + mt7996_txp_skb_unmap(mdev, t); if (!t->skb) goto out; @@ -2383,6 +2449,7 @@ mt7996_mac_reset_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) rcu_assign_pointer(mvif->link[i], NULL); kfree_rcu(mlink, rcu_head); } + mvif->valid_links = 0; rcu_read_unlock(); } @@ -2396,6 +2463,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) dev->recovery.hw_full_reset = true; + set_bit(MT76_MCU_RESET, &dev->mphy.state); wake_up(&dev->mt76.mcu.wait); ieee80211_stop_queues(hw); @@ -2416,12 +2484,14 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) mt7996_for_each_phy(dev, phy) phy->omac_mask = 0; + dev->mld_idx_mask = 0; + dev->mld_remap_idx_mask = 0; ieee80211_iterate_stations_atomic(hw, mt7996_mac_reset_sta_iter, dev); + mt76_reset_device(&dev->mt76); ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_SKIP_SDATA_NOT_IN_DRIVER, mt7996_mac_reset_vif_iter, dev); - mt76_reset_device(&dev->mt76); INIT_LIST_HEAD(&dev->sta_rc_list); INIT_LIST_HEAD(&dev->twt_list); @@ -2445,6 +2515,8 @@ mt7996_mac_full_reset(struct mt7996_dev *dev) mutex_unlock(&dev->mt76.mutex); + ieee80211_wake_queues(mt76_hw(dev)); + ieee80211_restart_hw(mt76_hw(dev)); } @@ -2500,8 +2572,8 @@ void mt7996_mac_reset_work(struct work_struct *work) set_bit(MT76_RESET, &dev->mphy.state); set_bit(MT76_MCU_RESET, &dev->mphy.state); - mt76_abort_scan(&dev->mt76); wake_up(&dev->mt76.mcu.wait); + mt76_abort_scan(&dev->mt76); cancel_work_sync(&dev->wed_rro.work); mt7996_for_each_phy(dev, phy) { @@ -2510,6 +2582,8 @@ void mt7996_mac_reset_work(struct work_struct *work) cancel_delayed_work_sync(&phy->mt76->mac_work); } + mutex_lock(&dev->mt76.mutex); + mt76_worker_disable(&dev->mt76.tx_worker); mt76_for_each_q_rx(&dev->mt76, i) { if (mtk_wed_device_active(&dev->mt76.mmio.wed) && @@ -2527,8 +2601,6 @@ void mt7996_mac_reset_work(struct work_struct *work) } napi_disable(&dev->mt76.tx_napi); - mutex_lock(&dev->mt76.mutex); - mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED); if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) { @@ -3146,6 +3218,12 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw, struct mt7996_twt_flow *flow; u8 flowid, table_id, exp; + /* the firmware does not support iTWT agreements with MLD peers, and + * driver TWT state is only tracked on the default link + */ + if (sta->mlo) + goto out; + if (mt7996_mac_check_twt_req(twt)) goto out; diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c index afbcc8c7b18b..e218856b0c45 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c @@ -372,7 +372,8 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif, CONN_STATE_PORT_SECURE, true); rcu_assign_pointer(dev->mt76.wcid[idx], &msta_link->wcid); - ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); + if (!mlink->wcid->offchannel) + ieee80211_iter_keys(mphy->hw, vif, mt7996_key_iter, &it); if (!mlink->wcid->offchannel) { if (vif->txq && @@ -605,6 +606,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw, unsigned int link_id; int i; + mutex_lock(&dev->mt76.mutex); + /* Remove all active links */ for_each_set_bit(link_id, &rem_links, IEEE80211_MLD_MAX_NUM_LINKS) { struct mt7996_vif_link *link; @@ -621,6 +624,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw, mt7996_vif_link_destroy(phy, link, vif, NULL); } + mutex_unlock(&dev->mt76.mutex); + ieee80211_iterate_active_interfaces_mtx(hw, 0, mt7996_remove_iter, &rdata); mt76_vif_cleanup(&dev->mt76, vif); @@ -1202,15 +1207,9 @@ void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, mt76_wcid_cleanup(&dev->mt76, &msta_link->wcid); 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); - phy = __mt7996_phy(dev, msta_link->wcid.phy_idx); - if (phy) - phy->mt76->num_sta--; - if (msta->deflink_id == link_id) { msta->deflink_id = IEEE80211_LINK_UNSPECIFIED; if (msta->seclink_id == link_id) { @@ -1236,6 +1235,12 @@ void mt7996_mac_sta_remove_link(struct mt7996_dev *dev, } if (flush) { + struct mt7996_phy *phy = + __mt7996_phy(dev, msta_link->wcid.phy_idx); + + if (phy) + phy->mt76->num_sta--; + 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); @@ -1510,20 +1515,26 @@ static void mt7996_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif = info->control.vif; struct mt7996_vif *mvif = vif ? (void *)vif->drv_priv : NULL; struct mt76_wcid *wcid = &dev->mt76.global_wcid; + u8 deflink_id = IEEE80211_LINK_UNSPECIFIED; u8 link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK); rcu_read_lock(); + if (msta) + deflink_id = msta->deflink_id; + else if (mvif) + deflink_id = mvif->mt76.deflink_id; + + /* the primary link is unset until the first link has been added */ + if (deflink_id >= IEEE80211_MLD_MAX_NUM_LINKS) + deflink_id = 0; + /* Use primary link_id if the value from mac80211 is set to * IEEE80211_LINK_UNSPECIFIED. */ - if (link_id == IEEE80211_LINK_UNSPECIFIED) { - if (msta) - link_id = msta->deflink_id; - else if (mvif) - link_id = mvif->mt76.deflink_id; - } + if (link_id == IEEE80211_LINK_UNSPECIFIED) + link_id = deflink_id; if (vif && ieee80211_vif_is_mld(vif)) { struct ieee80211_bss_conf *link_conf; @@ -1533,7 +1544,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, link_sta = rcu_dereference(sta->link[link_id]); if (!link_sta) - link_sta = rcu_dereference(sta->link[msta->deflink_id]); + link_sta = rcu_dereference(sta->link[deflink_id]); if (link_sta) { memcpy(hdr->addr1, link_sta->addr, ETH_ALEN); @@ -1579,7 +1590,7 @@ static void mt7996_tx(struct ieee80211_hw *hw, if (msta_link) wcid = &msta_link->wcid; } - mt76_tx(mphy, control->sta, wcid, skb); + mt76_tx(mphy, control->sta, mt7996_get_tx_wcid(wcid), skb); unlock: rcu_read_unlock(); } @@ -1883,8 +1894,6 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw, sinfo->txrate.flags = txrate->flags; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); } - sinfo->txrate.flags = txrate->flags; - sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE); sinfo->tx_failed = msta_link->wcid.stats.tx_failed; sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED); @@ -2029,6 +2038,14 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw, continue; mt7996_mcu_wtbl_update_hdr_trans(dev, vif, link, msta_link); + + /* HW cannot derive the BSSID from 4-address non-AMSDU frames, + * so PS exit is missed on links other than the setup link. + * Let the firmware wake those links instead. + */ + if (enabled && msta->deflink_id != link_id && + is_mt7996(&dev->mt76)) + mt7996_mcu_ps_leave(dev, link, msta_link); } mutex_unlock(&dev->mt76.mutex); @@ -2436,6 +2453,23 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw, return 0; } +#if defined(CONFIG_NET_MEDIATEK_SOC_WED) || defined(CONFIG_MT7996_NPU) +static int +mt7996_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct net_device *netdev, enum tc_setup_type type, + void *type_data) +{ +#ifdef CONFIG_NET_MEDIATEK_SOC_WED + struct mt7996_dev *dev = mt7996_hw_dev(hw); + + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) + return mt76_wed_net_setup_tc(hw, vif, netdev, type, + type_data); +#endif + return mt76_npu_net_setup_tc(hw, vif, netdev, type, type_data); +} +#endif + static int mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 old_links, u16 new_links, @@ -2460,6 +2494,7 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif, idx = get_free_idx(dev->mld_remap_idx_mask, 0, 15) - 1; if (idx < 0) { + dev->mld_idx_mask &= ~BIT_ULL(mvif->mld_group_idx); ret = -ENOSPC; goto out; } @@ -2562,10 +2597,8 @@ const struct ieee80211_ops mt7996_ops = { #endif .set_radar_background = mt7996_set_radar_background, .net_fill_forward_path = mt7996_net_fill_forward_path, -#ifdef CONFIG_NET_MEDIATEK_SOC_WED - .net_setup_tc = mt76_wed_net_setup_tc, -#elif defined(CONFIG_MT7996_NPU) - .net_setup_tc = mt76_npu_net_setup_tc, +#if defined(CONFIG_NET_MEDIATEK_SOC_WED) || defined(CONFIG_MT7996_NPU) + .net_setup_tc = mt7996_net_setup_tc, #endif .change_vif_links = mt7996_change_vif_links, .change_sta_links = mt7996_mac_sta_change_links, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c index 2e83f4b79c87..cd7587ce5b8a 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c @@ -826,6 +826,89 @@ mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb) } } +static void +mt7996_mcu_ps_transition(struct mt7996_dev *dev, u16 wcid_idx, bool ps) +{ + struct mt76_wcid *wcid; + + wcid = mt76_wcid_ptr(dev, wcid_idx); + if (!wcid || !wcid_to_sta(wcid)) + return; + + mt76_sta_ps_transition(&dev->mt76, wcid, ps); +} + +static void +mt7996_mcu_rx_ps_sync(struct mt7996_dev *dev, struct sk_buff *skb) +{ + struct mt7996_mcu_ps_sync_event *event = (void *)skb->data; + struct tlv *tlv; + int len; + + if (skb->len < sizeof(*event)) + return; + + skb_pull(skb, sizeof(*event)); + + len = skb->len; + while (len >= sizeof(*tlv)) { + u16 tag, tag_len; + + tlv = (struct tlv *)skb->data; + tag = le16_to_cpu(tlv->tag); + tag_len = le16_to_cpu(tlv->len); + /* a tag_len below the header size would not advance the buffer */ + if (tag_len < sizeof(*tlv) || tag_len > len) + break; + + switch (tag) { + case UNI_PS_CLIENT_INFO: { + struct mt7996_mcu_ps_client_info *info = (void *)tlv; + + if (tag_len < sizeof(*info)) + break; + + mt7996_mcu_ps_transition(dev, + le16_to_cpu(info->wlan_idx), + info->ps_bit); + break; + } + case UNI_PS_MULTI_CLIENT_INFO: { + struct mt7996_mcu_ps_multi_client_info *info = (void *)tlv; + u16 cnt; + int i; + + if (tag_len < sizeof(*info)) + break; + + cnt = min_t(u16, le16_to_cpu(info->sta_cnt), + (tag_len - sizeof(*info)) / sizeof(info->sta_ps_info[0])); + for (i = 0; i < cnt; i++) { + u16 entry = le16_to_cpu(info->sta_ps_info[i]); + + mt7996_mcu_ps_transition(dev, + FIELD_GET(MT7996_PS_MULTI_WCID, entry), + !!(entry & MT7996_PS_MULTI_PS_BIT)); + } + break; + } + case UNI_PS_MULTI_CLIENT_INFO_BITMAP: { + u8 *bitmap = tlv->data; + int bitmap_len = tag_len - sizeof(*tlv); + int i; + + for (i = 0; i < bitmap_len * 8; i++) + mt7996_mcu_ps_transition(dev, i, + !!(bitmap[i / 8] & BIT(i % 8))); + break; + } + } + + skb_pull(skb, tag_len); + len -= tag_len; + } +} + static void mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) { @@ -847,6 +930,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb) case MCU_UNI_EVENT_WED_RRO: mt7996_mcu_wed_rro_event(dev, skb); break; + case MCU_UNI_EVENT_PS_SYNC: + mt7996_mcu_rx_ps_sync(dev, skb); + break; default: break; } @@ -1044,43 +1130,6 @@ mt7996_mcu_bss_sec_tlv(struct sk_buff *skb, struct mt76_vif_link *mlink) sec->cipher = mlink->cipher; } -static int -mt7996_mcu_muar_config(struct mt7996_dev *dev, struct mt76_vif_link *mlink, - const u8 *addr, bool bssid, bool enable) -{ -#define UNI_MUAR_ENTRY 2 - u32 idx = mlink->omac_idx - REPEATER_BSSID_START; - struct { - struct { - u8 band; - u8 __rsv[3]; - } hdr; - - __le16 tag; - __le16 len; - - bool smesh; - u8 bssid; - u8 index; - u8 entry_add; - u8 addr[ETH_ALEN]; - u8 __rsv[2]; - } __packed req = { - .hdr.band = mlink->band_idx, - .tag = cpu_to_le16(UNI_MUAR_ENTRY), - .len = cpu_to_le16(sizeof(req) - sizeof(req.hdr)), - .smesh = false, - .index = idx * 2 + bssid, - .entry_add = true, - }; - - if (enable) - memcpy(req.addr, addr, ETH_ALEN); - - return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REPT_MUAR), &req, - sizeof(req), true); -} - static void mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct mt7996_phy *phy) { @@ -1210,11 +1259,6 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, struct mt7996_dev *dev = phy->dev; struct sk_buff *skb; - if (mlink->omac_idx >= REPEATER_BSSID_START) { - mt7996_mcu_muar_config(dev, mlink, link_conf->addr, false, enable); - mt7996_mcu_muar_config(dev, mlink, link_conf->bssid, true, enable); - } - skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, mlink, MT7996_BSS_UPDATE_MAX_SIZE); if (IS_ERR(skb)) @@ -2483,7 +2527,7 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev, cap |= STA_CAP_VHT_SGI_160; if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC) cap |= STA_CAP_VHT_TX_STBC; - if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1) + if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_MASK) cap |= STA_CAP_VHT_RX_STBC; if ((vif->type != NL80211_IFTYPE_AP || link_conf->vht_ldpc) && (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC)) @@ -2996,9 +3040,6 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy, struct ieee80211_vif *vif, }, }; - if (mlink->omac_idx >= REPEATER_BSSID_START) - return mt7996_mcu_muar_config(dev, mlink, link_conf->addr, false, enable); - memcpy(data.tlv.omac_addr, link_conf->addr, ETH_ALEN); return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(DEV_INFO_UPDATE), &data, sizeof(data), true); @@ -4023,6 +4064,9 @@ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy, struct mt7996_dev *dev = phy->dev; int err, region, rdd_idx = mt7996_get_rdd_idx(phy, true); + if (rdd_idx < 0) + return -EINVAL; + if (!chandef) { /* disable offchain */ err = mt7996_mcu_rdd_cmd(dev, RDD_STOP, rdd_idx, 0); if (err) @@ -4352,11 +4396,18 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *buf, u32 buf_l event = (struct mt7996_mcu_eeprom_access_event *)skb->data; if (event->valid) { u32 ret_len = le32_to_cpu(event->eeprom.ext_eeprom.data_len); + u32 block = mode == EEPROM_MODE_EXT ? MT7996_EXT_EEPROM_BLOCK_SIZE : + MT7996_EEPROM_BLOCK_SIZE; addr = le32_to_cpu(event->addr); - if (!buf) + if (!buf) { + if (addr > dev->mt76.eeprom.size - block) { + dev_kfree_skb(skb); + return -EINVAL; + } buf = (u8 *)dev->mt76.eeprom.data + addr; + } switch (mode) { case EEPROM_MODE_EFUSE: @@ -4438,21 +4489,31 @@ int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap) return ret; /* fixed field */ + if (skb->len < 4) { + dev_kfree_skb(skb); + return -EINVAL; + } skb_pull(skb, 4); buf = skb->data; - while (buf - skb->data < skb->len) { + while (buf - skb->data + sizeof(struct tlv) <= skb->len) { struct tlv *tlv = (struct tlv *)buf; + u16 tlv_len = le16_to_cpu(tlv->len); + + if (tlv_len < sizeof(*tlv) || + tlv_len > skb->len - (buf - skb->data)) + break; switch (le16_to_cpu(tlv->tag)) { case UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION: - *cap = le32_to_cpu(*(__le32 *)(buf + sizeof(*tlv))); + if (tlv_len >= sizeof(*tlv) + sizeof(__le32)) + *cap = le32_to_cpu(*(__le32 *)(buf + sizeof(*tlv))); break; default: break; } - buf += le16_to_cpu(tlv->len); + buf += tlv_len; } dev_kfree_skb(skb); @@ -5029,6 +5090,32 @@ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev, &req, sizeof(req), true); } +int mt7996_mcu_set_bssid_mapping_addr(struct mt76_dev *dev, u8 band_idx) +{ + enum { + BSSID_MAPPING_ADDR1, + BSSID_MAPPING_ADDR2, + BSSID_MAPPING_ADDR3, + }; + struct { + u8 band_idx; + u8 _rsv1[3]; + + __le16 tag; + __le16 len; + u8 addr; + u8 _rsv2[3]; + } __packed req = { + .band_idx = band_idx, + .tag = cpu_to_le16(UNI_BAND_CONFIG_BSSID_MAPPING_ADDR), + .len = cpu_to_le16(sizeof(req) - 4), + .addr = BSSID_MAPPING_ADDR1, + }; + + return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(BAND_CONFIG), + &req, sizeof(req), true); +} + int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val) { struct { @@ -5145,6 +5232,24 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); } +int mt7996_mcu_ps_leave(struct mt7996_dev *dev, struct mt7996_vif_link *link, + struct mt7996_sta_link *msta_link) +{ + struct sk_buff *skb; + + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76, + &msta_link->wcid, + MT7996_STA_UPDATE_MAX_SIZE); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + mt76_connac_mcu_add_tlv(skb, STA_REC_PS_LEAVE, + sizeof(struct sta_rec_ps_leave)); + + return mt76_mcu_skb_send_msg(&dev->mt76, skb, + MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); +} + int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx, u16 rate_idx, bool beacon) { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h index 8902e16508b7..74b70fb6da3d 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h @@ -293,6 +293,39 @@ enum { UNI_WED_RRO_BA_SESSION_DELETE, }; +struct mt7996_mcu_ps_sync_event { + struct mt7996_mcu_rxd rxd; + + u8 bss_idx; + u8 __rsv[3]; +} __packed; + +struct mt7996_mcu_ps_client_info { + __le16 tag; + __le16 len; + u8 ps_bit; + u8 __rsv; + __le16 wlan_idx; + u8 buffer_size; + u8 __rsv2[3]; +} __packed; + +struct mt7996_mcu_ps_multi_client_info { + __le16 tag; + __le16 len; + __le16 sta_cnt; + __le16 sta_ps_info[]; +} __packed; + +#define MT7996_PS_MULTI_WCID GENMASK(10, 0) +#define MT7996_PS_MULTI_PS_BIT BIT(15) + +enum { + UNI_PS_CLIENT_INFO = 0, + UNI_PS_MULTI_CLIENT_INFO = 1, + UNI_PS_MULTI_CLIENT_INFO_BITMAP = 2, +}; + struct mt7996_mcu_thermal_notify { struct mt7996_mcu_rxd rxd; @@ -680,6 +713,12 @@ struct sta_rec_hdr_trans { u8 mesh; } __packed; +struct sta_rec_ps_leave { + __le16 tag; + __le16 len; + u8 __rsv[4]; +} __packed; + struct sta_rec_mld_setup { __le16 tag; __le16 len; @@ -917,7 +956,7 @@ enum { #define MT7996_BEACON_UPDATE_SIZE (sizeof(struct bss_req_hdr) + \ sizeof(struct bss_bcn_content_tlv) + \ 4 + MT_TXD_SIZE + \ - sizeof(struct bss_bcn_cntdwn_tlv) + \ + sizeof(struct bss_bcn_cntdwn_tlv) * 2 + \ sizeof(struct bss_bcn_mbss_tlv)) #define MT7996_MAX_BSS_OFFLOAD_SIZE 2048 #define MT7996_MAX_BEACON_SIZE (MT7996_MAX_BSS_OFFLOAD_SIZE - \ @@ -927,6 +966,7 @@ enum { UNI_BAND_CONFIG_RADIO_ENABLE, UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08, UNI_BAND_CONFIG_MAC_ENABLE_CTRL = 0x0c, + UNI_BAND_CONFIG_BSSID_MAPPING_ADDR = 0x12, }; enum { diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c index d9780bb425a7..fbfbb96a742f 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c @@ -17,6 +17,8 @@ static bool wed_enable; module_param(wed_enable, bool, 0644); +#define INVALID_REG_ADDR 0xffffffff + static const struct __base mt7996_reg_base[] = { [WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } }, [WF_ARB_BASE] = { { 0x820e3000, 0x820f3000, 0x830e3000 } }, @@ -54,6 +56,14 @@ static const u32 mt7996_offs[] = { [MIB_BSCR7] = 0x9e8, [MIB_BSCR17] = 0xa10, [MIB_TRDR1] = 0xa28, + [MIB_TSCR0] = 0x6b0, + [MIB_TSCR1] = 0x6b4, + [MIB_TSCR2] = 0x6b8, + [MIB_TSCR3] = 0x6bc, + [MIB_TSCR4] = 0x6c0, + [MIB_TSCR5] = 0x6c4, + [MIB_TSCR6] = 0x6c8, + [MIB_TSCR7] = 0x6d0, [HIF_REMAP_L1] = 0x24, [HIF_REMAP_BASE_L1] = 0x130000, [HIF_REMAP_L2] = 0x1b4, @@ -91,6 +101,14 @@ static const u32 mt7992_offs[] = { [MIB_BSCR7] = 0xae4, [MIB_BSCR17] = 0xb0c, [MIB_TRDR1] = 0xb24, + [MIB_TSCR0] = 0x6b0, + [MIB_TSCR1] = 0x6b4, + [MIB_TSCR2] = 0x6b8, + [MIB_TSCR3] = 0x6bc, + [MIB_TSCR4] = 0x6c0, + [MIB_TSCR5] = 0x6c4, + [MIB_TSCR6] = 0x6c8, + [MIB_TSCR7] = 0x6d0, [HIF_REMAP_L1] = 0x8, [HIF_REMAP_BASE_L1] = 0x40000, [HIF_REMAP_L2] = 0x1b4, @@ -128,6 +146,14 @@ static const u32 mt7990_offs[] = { [MIB_BSCR7] = 0xbd4, [MIB_BSCR17] = 0xbfc, [MIB_TRDR1] = 0xc14, + [MIB_TSCR0] = 0x750, + [MIB_TSCR1] = 0x754, + [MIB_TSCR2] = 0x758, + [MIB_TSCR3] = 0x75c, + [MIB_TSCR4] = 0x760, + [MIB_TSCR5] = 0x764, + [MIB_TSCR6] = 0x768, + [MIB_TSCR7] = 0x770, [HIF_REMAP_L1] = 0x8, [HIF_REMAP_BASE_L1] = 0x40000, [HIF_REMAP_L2] = 0x1b8, @@ -334,7 +360,7 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr) return dev->reg.map[i].mapped + ofs; } - return 0; + return INVALID_REG_ADDR; } static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr) @@ -366,7 +392,7 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset, { u32 addr = __mt7996_reg_addr(dev, offset); - if (addr) { + if (addr != INVALID_REG_ADDR) { memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len); return; } @@ -382,7 +408,7 @@ static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); u32 addr = __mt7996_reg_addr(dev, offset), val; - if (addr) + if (addr != INVALID_REG_ADDR) return dev->bus_ops->rr(mdev, addr); spin_lock_bh(&dev->reg_lock); @@ -397,7 +423,7 @@ static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); u32 addr = __mt7996_reg_addr(dev, offset); - if (addr) { + if (addr != INVALID_REG_ADDR) { dev->bus_ops->wr(mdev, addr, val); return; } @@ -412,7 +438,7 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76); u32 addr = __mt7996_reg_addr(dev, offset); - if (addr) + if (addr != INVALID_REG_ADDR) return dev->bus_ops->rmw(mdev, addr, mask, val); spin_lock_bh(&dev->reg_lock); @@ -464,8 +490,8 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, if (!wed_enable) return 0; - dev->mt76.hwrro_mode = is_mt7996(&dev->mt76) ? MT76_HWRRO_V3 - : MT76_HWRRO_V3_1; + if (hif2 && !mtk_wed_device_active(&dev->mt76.mmio.wed)) + return 0; hif1_ofs = dev->hif2 ? MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0) : 0; @@ -491,23 +517,16 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + MT_TXQ_RING_BASE(0) + MT7996_TXQ_BAND2 * MT_RING_SIZE; - if (mt7996_has_hwrro(dev)) { - if (is_mt7996(&dev->mt76)) { - wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; - wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + - MT_RXQ_RING_BASE(0) + - MT7996_RXQ_TXFREE2 * MT_RING_SIZE; - } else { - wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_BAND1_EXT) - 1; - wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + - MT_RXQ_RING_BASE(0) + - MT7996_RXQ_MCU_WA_EXT * MT_RING_SIZE; - } - } else { + if (is_mt7996(&dev->mt76)) { + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + MT_RXQ_RING_BASE(0) + - MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; + MT7996_RXQ_TXFREE2 * MT_RING_SIZE; + } else { + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_BAND1_EXT) - 1; + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_MCU_WA_EXT * MT_RING_SIZE; } wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG; @@ -518,7 +537,7 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.id = MT7996_DEVICE_ID_2; wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; } else { - wed->wlan.hw_rro = mt7996_has_hwrro(dev); + wed->wlan.hw_rro = true; wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + @@ -571,23 +590,15 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; if (is_mt7996(&dev->mt76)) { - if (mt7996_has_hwrro(dev)) { - wed->wlan.wpdma_txfree = wed->wlan.phy_base + - MT_RXQ_RING_BASE(0) + - MT7996_RXQ_TXFREE0 * MT_RING_SIZE; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; - } else { - wed->wlan.wpdma_txfree = wed->wlan.phy_base + - MT_RXQ_RING_BASE(0) + - MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; - wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; - } + wed->wlan.wpdma_txfree = wed->wlan.phy_base + + MT_RXQ_RING_BASE(0) + + MT7996_RXQ_TXFREE0 * MT_RING_SIZE; + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; } else { wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; } - dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt; if (dev->hif2 && is_mt7992(&dev->mt76)) wed->wlan.id = 0x7992; @@ -610,9 +621,14 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, wed->wlan.reset_complete = mt76_wed_reset_complete; } - if (mtk_wed_device_attach(wed)) { - dev->mt76.hwrro_mode = MT76_HWRRO_OFF; + if (mtk_wed_device_attach(wed)) return 0; + + if (!hif2) { + dev->mt76.hwrro_mode = is_mt7996(&dev->mt76) ? MT76_HWRRO_V3 + : MT76_HWRRO_V3_1; + dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + + wed->wlan.rx_npkt; } *irq = wed->irq; @@ -822,7 +838,8 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev, .link_data_size = sizeof(struct mt7996_vif_link), .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_AMSDU_OFFLOAD | - MT_DRV_HW_MGMT_TXQ, + MT_DRV_HW_MGMT_TXQ | + MT_DRV_HW_PS_BUFFERING, .survey_flags = SURVEY_INFO_TIME_TX | SURVEY_INFO_TIME_RX | SURVEY_INFO_TIME_BSS_RX, diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h index 0d6488522ba7..2a0cdb56f822 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h @@ -411,6 +411,7 @@ struct mt7996_dev { struct mt7996_phy *radio_phy[MT7996_MAX_RADIOS]; struct wiphy_radio radios[MT7996_MAX_RADIOS]; struct wiphy_radio_freq_range radio_freqs[MT7996_MAX_RADIOS]; + struct mac_address radio_addrs[MT7996_MAX_RADIOS]; struct mt7996_hif *hif2; struct mt7996_reg_desc reg; @@ -771,6 +772,7 @@ int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *li 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_set_bssid_mapping_addr(struct mt76_dev *dev, u8 band_idx); int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch); int mt7996_mcu_get_temperature(struct mt7996_phy *phy); int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state); @@ -871,6 +873,7 @@ bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask); void mt7996_mac_reset_counters(struct mt7996_phy *phy); void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy); void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band); +struct mt76_wcid *mt7996_get_tx_wcid(struct mt76_wcid *wcid); void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_key_conf *key, int pid, @@ -925,6 +928,8 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, struct ieee80211_vif *vif, struct mt7996_vif_link *link, struct mt7996_sta_link *msta_link); +int mt7996_mcu_ps_leave(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, @@ -941,10 +946,6 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, bool hif2, int *irq); u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); -#ifdef CONFIG_MTK_DEBUG -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); diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h index c6379933b6c3..8ff78cf6eb04 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h +++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h @@ -64,6 +64,14 @@ enum offs_rev { MIB_BSCR7, MIB_BSCR17, MIB_TRDR1, + MIB_TSCR0, + MIB_TSCR1, + MIB_TSCR2, + MIB_TSCR3, + MIB_TSCR4, + MIB_TSCR5, + MIB_TSCR6, + MIB_TSCR7, HIF_REMAP_L1, HIF_REMAP_BASE_L1, HIF_REMAP_L2, @@ -250,9 +258,9 @@ enum offs_rev { #define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR7)) #define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR17)) -#define MT_MIB_TSCR5(_band) MT_WF_MIB(_band, 0x6c4) -#define MT_MIB_TSCR6(_band) MT_WF_MIB(_band, 0x6c8) -#define MT_MIB_TSCR7(_band) MT_WF_MIB(_band, 0x6d0) +#define MT_MIB_TSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_TSCR5)) +#define MT_MIB_TSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_TSCR6)) +#define MT_MIB_TSCR7(_band) MT_WF_MIB(_band, __OFFS(MIB_TSCR7)) #define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR1)) /* rx mpdu counter, full 32 bits */ @@ -268,14 +276,14 @@ enum offs_rev { #define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR36)) /* tx ampdu cnt, full 32 bits */ -#define MT_MIB_TSCR0(_band) MT_WF_MIB(_band, 0x6b0) -#define MT_MIB_TSCR2(_band) MT_WF_MIB(_band, 0x6b8) +#define MT_MIB_TSCR0(_band) MT_WF_MIB(_band, __OFFS(MIB_TSCR0)) +#define MT_MIB_TSCR2(_band) MT_WF_MIB(_band, __OFFS(MIB_TSCR2)) /* counts all mpdus in ampdu, regardless of success */ -#define MT_MIB_TSCR3(_band) MT_WF_MIB(_band, 0x6bc) +#define MT_MIB_TSCR3(_band) MT_WF_MIB(_band, __OFFS(MIB_TSCR3)) /* counts all successfully tx'd mpdus in ampdu */ -#define MT_MIB_TSCR4(_band) MT_WF_MIB(_band, 0x6c0) +#define MT_MIB_TSCR4(_band) MT_WF_MIB(_band, __OFFS(MIB_TSCR4)) /* rx ampdu count, 32-bit */ #define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR27)) @@ -299,7 +307,7 @@ enum offs_rev { #define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR1)) /* rx blockack count, 32 bits */ -#define MT_MIB_TSCR1(_band) MT_WF_MIB(_band, 0x6b4) +#define MT_MIB_TSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_TSCR1)) #define MT_MIB_BTSCR0(_band) MT_WF_MIB(_band, 0x5e0) #define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR5)) diff --git a/drivers/net/wireless/mediatek/mt76/scan.c b/drivers/net/wireless/mediatek/mt76/scan.c index 7fe1b1fbb699..3594b599662d 100644 --- a/drivers/net/wireless/mediatek/mt76/scan.c +++ b/drivers/net/wireless/mediatek/mt76/scan.c @@ -11,15 +11,24 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort) .aborted = abort, }; + lockdep_assert_held(&dev->mutex); + if (!phy) return; clear_bit(MT76_SCANNING, &phy->state); - if (dev->scan.chan && phy->main_chandef.chan && phy->offchannel && + /* Re-program the operating channel even when the scan never left it: + * any channel set during the scan ran with MT76_SCANNING held, which + * left DFS radar detection disabled + */ + if (phy->main_chandef.chan && !test_bit(MT76_MCU_RESET, &dev->phy.state)) { - mt76_set_channel(phy, &phy->main_chandef, false); - mt76_offchannel_notify(phy, false); + bool offchannel = phy->offchannel; + + __mt76_set_channel(phy, &phy->main_chandef, false); + if (offchannel) + mt76_offchannel_notify(phy, false); } mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink); memset(&dev->scan, 0, sizeof(dev->scan)); @@ -34,7 +43,10 @@ void mt76_abort_scan(struct mt76_dev *dev) spin_unlock_bh(&dev->scan_lock); cancel_delayed_work_sync(&dev->scan_work); + + mutex_lock(&dev->mutex); mt76_scan_complete(dev, true); + mutex_unlock(&dev->mutex); } EXPORT_SYMBOL_GPL(mt76_abort_scan); @@ -48,6 +60,7 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) struct mt76_phy *phy = dev->scan.phy; struct ieee80211_tx_info *info; struct sk_buff *skb; + u8 link_id; skb = ieee80211_probereq_get(phy->hw, vif->addr, ssid->ssid, ssid->ssid_len, req->ie_len); @@ -77,6 +90,10 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid) info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE; info->control.flags |= IEEE80211_TX_CTRL_DONT_USE_RATE_MASK; + link_id = mvif->wcid ? mvif->wcid->link_id : IEEE80211_LINK_UNSPECIFIED; + info->control.flags &= ~IEEE80211_TX_CTRL_MLO_LINK; + info->control.flags |= u32_encode_bits(link_id, IEEE80211_TX_CTRL_MLO_LINK); + mt76_tx(phy, NULL, mvif->wcid, skb); out: @@ -127,7 +144,9 @@ void mt76_scan_work(struct work_struct *work) goto probe; if (dev->scan.chan_idx >= req->n_channels) { + mutex_lock(&dev->mutex); mt76_scan_complete(dev, false); + mutex_unlock(&dev->mutex); return; } @@ -206,6 +225,7 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif, dev->scan.vif = vif; dev->scan.phy = phy; dev->scan.mlink = mlink; + set_bit(MT76_SCANNING, &phy->state); ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, 0); out: diff --git a/drivers/net/wireless/mediatek/mt76/sdio.c b/drivers/net/wireless/mediatek/mt76/sdio.c index 8bae77c761be..ba5f123f7e39 100644 --- a/drivers/net/wireless/mediatek/mt76/sdio.c +++ b/drivers/net/wireless/mediatek/mt76/sdio.c @@ -519,6 +519,10 @@ mt76s_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, enum mt76_txq_id qid, struct sk_buff *skb, struct mt76_wcid *wcid, struct ieee80211_sta *sta) { + struct ieee80211_tx_status status = { + .sta = sta, + }; + struct mt76_tx_info tx_info = { .skb = skb, }; @@ -531,8 +535,13 @@ mt76s_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q, skb->prev = skb->next = NULL; err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info); - if (err < 0) + if (err < 0) { + status.skb = tx_info.skb; + spin_lock_bh(&dev->rx_lock); + ieee80211_tx_status_ext(dev->hw, &status); + spin_unlock_bh(&dev->rx_lock); return err; + } q->entry[q->head].skb = tx_info.skb; q->entry[q->head].buf_sz = len; diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c index f96d9c471853..3707ee19e4ae 100644 --- a/drivers/net/wireless/mediatek/mt76/tx.c +++ b/drivers/net/wireless/mediatek/mt76/tx.c @@ -267,6 +267,21 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff * wcid = __mt76_wcid_ptr(dev, wcid_idx); mt76_tx_check_non_aql(dev, wcid, skb); + if (wcid && (dev->drv->drv_flags & MT_DRV_HW_PS_BUFFERING) && + test_bit(MT_WCID_FLAG_PS, &wcid->flags)) { + struct ieee80211_sta *sta = wcid_to_sta(wcid); + + if (sta) { + struct ieee80211_hw *hw = mt76_phy_hw(dev, wcid->phy_idx); + int i; + + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + if (sta->txq[i]) + ieee80211_schedule_txq(hw, sta->txq[i]); + mt76_worker_schedule(&dev->tx_worker); + } + } + #ifdef CONFIG_NL80211_TESTMODE if (mt76_is_testmode_skb(dev, skb, &hw)) { struct mt76_phy *phy = hw->priv; @@ -324,10 +339,6 @@ __mt76_tx_queue_skb(struct mt76_phy *phy, int qid, struct sk_buff *skb, if (idx < 0 || !sta) return idx; - wcid = (struct mt76_wcid *)sta->drv_priv; - if (!wcid->sta) - return idx; - q->entry[idx].wcid = wcid->idx; if (!non_aql) @@ -401,16 +412,23 @@ mt76_txq_dequeue(struct mt76_phy *phy, struct mt76_txq *mtxq) static void mt76_queue_ps_skb(struct mt76_phy *phy, struct ieee80211_sta *sta, - struct sk_buff *skb, bool last) + struct sk_buff *skb, bool last, + enum ieee80211_frame_release_type reason) { struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; info->control.flags |= IEEE80211_TX_CTRL_PS_RESPONSE; - if (last) + if (last) { info->flags |= IEEE80211_TX_STATUS_EOSP | IEEE80211_TX_CTL_REQ_TX_STATUS; + if (reason == IEEE80211_FRAME_RELEASE_UAPSD && + ieee80211_is_data_qos(hdr->frame_control)) + *ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_EOSP; + } + mt76_skb_set_moredata(skb, !last); __mt76_tx_queue_skb(phy, MT_TXQ_PSD, skb, wcid, sta, NULL); } @@ -443,14 +461,15 @@ mt76_release_buffered_frames(struct ieee80211_hw *hw, struct ieee80211_sta *sta, nframes--; if (last_skb) - mt76_queue_ps_skb(phy, sta, last_skb, false); + mt76_queue_ps_skb(phy, sta, last_skb, false, + reason); last_skb = skb; } while (nframes); } if (last_skb) { - mt76_queue_ps_skb(phy, sta, last_skb, true); + mt76_queue_ps_skb(phy, sta, last_skb, true, reason); dev->queue_ops->kick(dev, hwq); } else { ieee80211_sta_eosp(sta); @@ -480,8 +499,12 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q, bool stop = false; int idx; - if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) - return 0; + if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) { + if (!(dev->drv->drv_flags & MT_DRV_HW_PS_BUFFERING)) + return 0; + if (ieee80211_txq_aql_pending(phy->hw, txq)) + return 0; + } if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) return 0; @@ -501,6 +524,9 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q, if (idx < 0) return idx; + if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) + goto out; + do { if (test_bit(MT76_RESET, &phy->state) || phy->offchannel) break; @@ -526,6 +552,7 @@ mt76_txq_send_burst(struct mt76_phy *phy, struct mt76_queue *q, n_frames++; } while (1); +out: spin_lock(&q->lock); dev->queue_ops->kick(dev, q); spin_unlock(&q->lock); @@ -552,10 +579,7 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) mtxq = (struct mt76_txq *)txq->drv_priv; wcid = __mt76_wcid_ptr(dev, mtxq->wcid); - if (!wcid || test_bit(MT_WCID_FLAG_PS, &wcid->flags)) - continue; - - if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) + if (!wcid) continue; phy = mt76_dev_phy(dev, wcid->phy_idx); @@ -563,6 +587,24 @@ mt76_txq_schedule_list(struct mt76_phy *phy, enum mt76_txq_id qid) continue; q = phy->q_tx[qid]; + + if (test_bit(MT_WCID_FLAG_PS, &wcid->flags)) { + if (!(dev->drv->drv_flags & MT_DRV_HW_PS_BUFFERING)) + continue; + + if (!mt76_txq_stopped(q)) + n_frames = mt76_txq_send_burst(phy, q, mtxq, wcid); + + ieee80211_return_txq(phy->hw, txq, false); + + if (unlikely(n_frames < 0)) + return n_frames; + ret += n_frames; + continue; + } + + if (atomic_read(&wcid->non_aql_packets) >= MT_MAX_NON_AQL_PKT) + continue; if (dev->queue_ops->tx_cleanup && q->queued + 2 * MT_TXQ_FREE_THR >= q->ndesc) { dev->queue_ops->tx_cleanup(dev, q, false); @@ -635,6 +677,7 @@ mt76_txq_schedule_pending_wcid(struct mt76_phy *phy, struct mt76_wcid *wcid, !ieee80211_is_data_present(hdr->frame_control) && (!ieee80211_is_bufferable_mmpdu(skb) || ieee80211_is_deauth(hdr->frame_control) || + ieee80211_is_disassoc(hdr->frame_control) || head == &wcid->tx_offchannel)) qid = MT_TXQ_PSD; @@ -686,8 +729,8 @@ void mt76_txq_schedule_pending(struct mt76_phy *phy) ret = mt76_txq_schedule_pending_wcid(phy, wcid, &wcid->tx_pending); spin_lock(&phy->tx_lock); - if (!skb_queue_empty(&wcid->tx_pending) && - !skb_queue_empty(&wcid->tx_offchannel) && + if ((!skb_queue_empty(&wcid->tx_pending) || + !skb_queue_empty(&wcid->tx_offchannel)) && list_empty(&wcid->tx_list)) list_add_tail(&wcid->tx_list, &phy->tx_list); } @@ -768,6 +811,33 @@ void mt76_stop_tx_queues(struct mt76_phy *phy, struct ieee80211_sta *sta, } EXPORT_SYMBOL_GPL(mt76_stop_tx_queues); +void mt76_sta_ps_transition(struct mt76_dev *dev, struct mt76_wcid *wcid, + bool ps) +{ + struct ieee80211_sta *sta; + struct ieee80211_hw *hw; + int i; + + if (ps) { + set_bit(MT_WCID_FLAG_PS, &wcid->flags); + mt76_worker_schedule(&dev->tx_worker); + return; + } + + clear_bit(MT_WCID_FLAG_PS, &wcid->flags); + + sta = wcid_to_sta(wcid); + if (!sta) + return; + + hw = mt76_phy_hw(dev, wcid->phy_idx); + for (i = 0; i < ARRAY_SIZE(sta->txq); i++) + if (sta->txq[i]) + ieee80211_schedule_txq(hw, sta->txq[i]); + mt76_worker_schedule(&dev->tx_worker); +} +EXPORT_SYMBOL_GPL(mt76_sta_ps_transition); + void mt76_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *txq) { struct mt76_phy *phy = hw->priv; diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c index d9638a9b749b..a9af3aa6b80a 100644 --- a/drivers/net/wireless/mediatek/mt76/usb.c +++ b/drivers/net/wireless/mediatek/mt76/usb.c @@ -30,6 +30,8 @@ int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, for (i = 0; i < MT_VEND_REQ_MAX_RETRY; i++) { if (test_bit(MT76_REMOVED, &dev->phy.state)) return -EIO; + if (dev->usb.ctrl_timeout && atomic_read(&dev->bus_hung)) + return -EIO; ret = usb_control_msg(udev, pipe, req, req_type, val, offset, buf, len, MT_VEND_REQ_TOUT_MS); @@ -42,6 +44,15 @@ int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type, dev_err(dev->dev, "vendor request req:%02x off:%04x failed:%d\n", req, offset, ret); + + if (dev->usb.ctrl_timeout) { + atomic_set(&dev->bus_hung, true); + dev_err(dev->dev, "vendor request req:%02x off:%04x timed out, marking bus hung\n", + req, offset); + dev->usb.ctrl_timeout(dev, ret); + return ret; + } + return ret; } EXPORT_SYMBOL_GPL(__mt76u_vendor_request); @@ -580,7 +591,11 @@ static void mt76u_complete_rx(struct urb *urb) q->head = (q->head + 1) % q->ndesc; q->queued++; - mt76_worker_schedule(&dev->usb.rx_worker); + + if (q == &dev->q_rx[MT_RXQ_MAIN]) + napi_schedule(&dev->napi[MT_RXQ_MAIN]); + else + mt76_worker_schedule(&dev->usb.rx_worker); out: spin_unlock_irqrestore(&q->lock, flags); } @@ -618,11 +633,23 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q) } mt76u_submit_rx_buf(dev, qid, urb); } - if (qid == MT_RXQ_MAIN) { - local_bh_disable(); - mt76_rx_poll_complete(dev, MT_RXQ_MAIN, NULL); - local_bh_enable(); - } +} + +/* Threaded NAPI poll for the MAIN RX queue: drain URBs, build skbs, resubmit, + * then deliver through napi_gro_receive() and let napi_complete() flush GRO. + */ +static int mt76u_napi_poll(struct napi_struct *napi, int budget) +{ + struct mt76_dev *dev = mt76_priv(napi->dev); + + rcu_read_lock(); + mt76u_process_rx_queue(dev, &dev->q_rx[MT_RXQ_MAIN]); + mt76_rx_poll_complete(dev, MT_RXQ_MAIN, napi); + rcu_read_unlock(); + + napi_complete(napi); + + return 0; } static void mt76u_rx_worker(struct mt76_worker *w) @@ -632,8 +659,13 @@ static void mt76u_rx_worker(struct mt76_worker *w) int i; rcu_read_lock(); - mt76_for_each_q_rx(dev, i) + mt76_for_each_q_rx(dev, i) { + /* MT_RXQ_MAIN is serviced by the threaded NAPI poll */ + if (i == MT_RXQ_MAIN) + continue; + mt76u_process_rx_queue(dev, &dev->q_rx[i]); + } rcu_read_unlock(); } @@ -731,6 +763,13 @@ void mt76u_stop_rx(struct mt76_dev *dev) for (j = 0; j < q->ndesc; j++) usb_poison_urb(q->entry[j].urb); } + + /* The MAIN queue napi stays enabled for the device lifetime. The URBs + * are now poisoned, so mt76u_complete_rx() can no longer reschedule it; + * just drain any in-flight poll before the caller frees or resets. + */ + if (dev->napi_dev) + napi_synchronize(&dev->napi[MT_RXQ_MAIN]); } EXPORT_SYMBOL_GPL(mt76u_stop_rx); @@ -1051,6 +1090,13 @@ void mt76u_queues_deinit(struct mt76_dev *dev) mt76u_stop_rx(dev); mt76u_stop_tx(dev); + if (dev->napi_dev) { + napi_disable(&dev->napi[MT_RXQ_MAIN]); + netif_napi_del(&dev->napi[MT_RXQ_MAIN]); + free_netdev(dev->napi_dev); + dev->napi_dev = NULL; + } + mt76u_free_rx(dev); mt76u_free_tx(dev); } @@ -1078,6 +1124,7 @@ int __mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, { struct usb_device *udev = interface_to_usbdev(intf); struct mt76_usb *usb = &dev->usb; + struct mt76_dev **priv; int err; INIT_WORK(&usb->stat_work, mt76u_tx_status_data); @@ -1115,6 +1162,20 @@ int __mt76u_init(struct mt76_dev *dev, struct usb_interface *intf, sched_set_fifo_low(usb->rx_worker.task); sched_set_fifo_low(usb->status_worker.task); + /* threaded NAPI on a dummy netdev (reusing mt76_dev's napi_dev/napi[]) + * services the MAIN RX queue and gives the RX path GRO + */ + dev->napi_dev = alloc_netdev_dummy(sizeof(struct mt76_dev *)); + if (!dev->napi_dev) + return -ENOMEM; + + priv = netdev_priv(dev->napi_dev); + *priv = dev; + strscpy(dev->napi_dev->name, "mt76u-rx", sizeof(dev->napi_dev->name)); + dev->napi_dev->threaded = 1; + netif_napi_add(dev->napi_dev, &dev->napi[MT_RXQ_MAIN], mt76u_napi_poll); + napi_enable(&dev->napi[MT_RXQ_MAIN]); + return 0; } EXPORT_SYMBOL_GPL(__mt76u_init); diff --git a/drivers/net/wireless/mediatek/mt76/wed.c b/drivers/net/wireless/mediatek/mt76/wed.c index ed657d952de2..f210a0c57d81 100644 --- a/drivers/net/wireless/mediatek/mt76/wed.c +++ b/drivers/net/wireless/mediatek/mt76/wed.c @@ -33,10 +33,15 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size) { struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; struct mt76_dev *dev = mt76_wed_to_dev(wed); - struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; struct mt76_txwi_cache *t = NULL; + struct mt76_queue *q; int i; + if (wed->version == 2 && dev->phy.band_idx) + q = &dev->q_rx[MT_RXQ_BAND1]; + else + q = &dev->q_rx[MT_RXQ_MAIN]; + for (i = 0; i < size; i++) { dma_addr_t addr; u32 offset;