Merge tag 'mt76-next-2026-08-01' of https://github.com/nbd168/wireless

Felix Fietkau says:
===================
mt76 patches for 7.3

- fixes
- mt7925 NAN support
- mt7928 support
- mt7996 AP powersave improvements
===================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg
2026-08-02 18:33:31 +02:00
79 changed files with 5358 additions and 609 deletions

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -5,13 +5,15 @@
#ifndef __MT76_DMA_H
#define __MT76_DMA_H
#include <linux/regmap.h>
#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;

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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]);

View File

@@ -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;

View File

@@ -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));

View File

@@ -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

View File

@@ -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);

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 */

View File

@@ -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 |

View File

@@ -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)
{

View File

@@ -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 */

View File

@@ -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))

View File

@@ -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) {
/*

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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,

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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 = &regd->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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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:

View File

@@ -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);

View File

@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -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 <linux/if_ether.h>
#include <linux/types.h>
#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

View File

@@ -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 <deren.wu@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver");

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 = &regd->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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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 */

View File

@@ -3,6 +3,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#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;

View File

@@ -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) {

View File

@@ -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))

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,

View File

@@ -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)
{

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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);

View File

@@ -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))

View File

@@ -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:

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;