mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 07:03:28 -04:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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) {
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -10,6 +10,15 @@ static bool mt7921_disable_clc;
|
||||
module_param_named(disable_clc, mt7921_disable_clc, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_clc, "disable CLC support");
|
||||
|
||||
static struct ieee80211_regdomain mt7921_regd_ww = {
|
||||
.n_reg_rules = 1,
|
||||
.alpha2 = "00",
|
||||
.reg_rules = {
|
||||
/* IEEE 802.11b/g, channels 1..11 */
|
||||
REG_RULE(2412 - 10, 2462 + 10, 40, 6, 20, 0),
|
||||
}
|
||||
};
|
||||
|
||||
bool mt7921_regd_clc_supported(struct mt792x_dev *dev)
|
||||
{
|
||||
if (mt7921_disable_clc ||
|
||||
@@ -33,6 +42,9 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
|
||||
np = mt76_find_power_limits_node(mdev);
|
||||
|
||||
sband = wiphy->bands[NL80211_BAND_5GHZ];
|
||||
if (!sband)
|
||||
return;
|
||||
|
||||
band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL;
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
ch = &sband->channels[i];
|
||||
@@ -71,36 +83,45 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
|
||||
enum environment_cap country_ie_env)
|
||||
int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
|
||||
enum environment_cap country_ie_env)
|
||||
{
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct ieee80211_hw *hw = mdev->hw;
|
||||
struct wiphy *wiphy = hw->wiphy;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
dev->regd_in_progress = true;
|
||||
lockdep_assert_held(&dev->mt76.mutex);
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
if (!dev->regd_change)
|
||||
goto err;
|
||||
return 0;
|
||||
|
||||
ret = mt7921_mcu_set_clc(dev, alpha2, country_ie_env);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
mt7921_regd_channel_update(wiphy, dev);
|
||||
|
||||
ret = mt76_connac_mcu_set_channel_domain(hw->priv);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
ret = mt7921_set_tx_sar_pwr(hw, NULL);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
|
||||
enum environment_cap country_ie_env)
|
||||
{
|
||||
int ret;
|
||||
|
||||
dev->regd_in_progress = true;
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
ret = __mt7921_mcu_regd_update(dev, alpha2, country_ie_env);
|
||||
mt792x_mutex_release(dev);
|
||||
|
||||
dev->regd_change = false;
|
||||
dev->regd_in_progress = false;
|
||||
wake_up(&dev->wait);
|
||||
@@ -142,10 +163,176 @@ void mt7921_regd_notifier(struct wiphy *wiphy,
|
||||
if (pm->suspended)
|
||||
return;
|
||||
|
||||
if (MT7921_REGD_SUPPORTED(&dev->phy)) {
|
||||
mt7921_regd_update(&dev->phy, req->alpha2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mt7921_mcu_regd_update(dev, req->alpha2,
|
||||
req->country_ie_env);
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
mt7921_regd_query_regdb(struct mt792x_phy *phy, char *alpha2)
|
||||
{
|
||||
struct wiphy *wiphy = phy->mt76->hw->wiphy;
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
||||
struct mt7921_clc *clc = phy->clc[MT792x_CLC_REGD];
|
||||
struct mt7921_regd_query_req *req;
|
||||
struct mt7921_regd_cc *regd_cc;
|
||||
struct sk_buff *ret_skb = NULL;
|
||||
u8 *pos, *last_pos;
|
||||
int ret = 0;
|
||||
|
||||
if (!clc)
|
||||
return NULL;
|
||||
|
||||
pos = clc->data;
|
||||
last_pos = pos + le32_to_cpu(clc->len) - sizeof(struct mt7921_clc);
|
||||
while (pos < last_pos) {
|
||||
u32 req_len = 0;
|
||||
u32 rules_len = 0;
|
||||
u32 sign_len = 4;
|
||||
u32 n_reg_rules;
|
||||
|
||||
if (pos + sizeof(*regd_cc) > last_pos)
|
||||
break;
|
||||
|
||||
regd_cc = (struct mt7921_regd_cc *)pos;
|
||||
n_reg_rules = le32_to_cpu(regd_cc->n_reg_rules);
|
||||
if (n_reg_rules > NL80211_MAX_SUPP_REG_RULES)
|
||||
break;
|
||||
|
||||
rules_len = sizeof(struct mt7921_regd_rule_header) +
|
||||
sizeof(struct mt7921_regd_rule) * n_reg_rules;
|
||||
|
||||
if (pos + sizeof(*regd_cc) + rules_len + sign_len > last_pos)
|
||||
break;
|
||||
|
||||
pos += sizeof(*regd_cc) + rules_len + sign_len;
|
||||
if (memcmp(regd_cc->alpha2, alpha2, 2))
|
||||
continue;
|
||||
|
||||
req_len = sizeof(*req) + rules_len + sign_len;
|
||||
req = kzalloc(req_len, GFP_KERNEL);
|
||||
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
req->ver = regd_cc->ver;
|
||||
req->sign_type = regd_cc->sign_type;
|
||||
req->size = cpu_to_le32(rules_len + sign_len);
|
||||
req->n_reg_rules = regd_cc->n_reg_rules;
|
||||
|
||||
memcpy(req->alpha2, regd_cc->alpha2, 2);
|
||||
memcpy(req->data, regd_cc->data, rules_len + sign_len);
|
||||
|
||||
ret = mt76_mcu_send_and_get_msg(&dev->mt76,
|
||||
MCU_CE_CMD(SET_REGD_CH),
|
||||
req, req_len, true, &ret_skb);
|
||||
|
||||
kfree(req);
|
||||
|
||||
return ret < 0 ? NULL : ret_skb;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mt7921_regd_update(struct mt792x_phy *phy, char *alpha2)
|
||||
{
|
||||
struct wiphy *wiphy = phy->mt76->hw->wiphy;
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
||||
struct mt7921_regd_rule *mt7921_rule;
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct ieee80211_regdomain *regd;
|
||||
struct ieee80211_reg_rule *rule;
|
||||
struct mt7921_regd_rule_ev *ev;
|
||||
int i, num_of_rules = 0;
|
||||
struct sk_buff *skb;
|
||||
int ret = 0;
|
||||
|
||||
if (dev->hw_full_reset)
|
||||
return 0;
|
||||
|
||||
if (!MT7921_REGD_SUPPORTED(phy))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
skb = mt7921_regd_query_regdb(phy, alpha2);
|
||||
mt792x_mutex_release(dev);
|
||||
|
||||
if (!skb) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (skb->len < sizeof(*ev) + 4) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ev = (struct mt7921_regd_rule_ev *)(skb->data + 4);
|
||||
num_of_rules = le32_to_cpu(ev->n_reg_rules);
|
||||
|
||||
if (!num_of_rules ||
|
||||
WARN_ON_ONCE(num_of_rules > NL80211_MAX_SUPP_REG_RULES)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (skb->len < struct_size(ev, reg_rule, num_of_rules) + 4) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
regd = kzalloc(struct_size(regd, reg_rules, num_of_rules), GFP_KERNEL);
|
||||
if (!regd) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_of_rules; i++) {
|
||||
mt7921_rule = &ev->reg_rule[i];
|
||||
rule = ®d->reg_rules[i];
|
||||
|
||||
rule->freq_range.start_freq_khz =
|
||||
MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->start_freq));
|
||||
rule->freq_range.end_freq_khz =
|
||||
MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->end_freq));
|
||||
rule->freq_range.max_bandwidth_khz =
|
||||
MHZ_TO_KHZ(le32_to_cpu(mt7921_rule->max_bw));
|
||||
/* not used by fw */
|
||||
rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
|
||||
rule->power_rule.max_eirp = DBM_TO_MBM(22);
|
||||
rule->flags = le32_to_cpu(mt7921_rule->flags);
|
||||
}
|
||||
|
||||
regd->n_reg_rules = num_of_rules;
|
||||
regd->dfs_region = ev->dfs_region;
|
||||
|
||||
memcpy(regd->alpha2, alpha2, 2);
|
||||
memcpy(mdev->alpha2, alpha2, 2);
|
||||
|
||||
dev->regd_change = true;
|
||||
mt7921_mcu_regd_update(dev, alpha2, ENVIRON_ANY);
|
||||
|
||||
ret = regulatory_set_wiphy_regd(wiphy, regd);
|
||||
|
||||
kfree(regd);
|
||||
err:
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
if (ret < 0)
|
||||
return regulatory_set_wiphy_regd(wiphy, &mt7921_regd_ww);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7921_regd_update);
|
||||
|
||||
static bool
|
||||
mt7921_regd_is_valid_alpha2(const char *alpha2)
|
||||
{
|
||||
@@ -183,7 +370,9 @@ int mt7921_regd_change(struct mt792x_phy *phy, char *alpha2)
|
||||
if (!memcmp(alpha2, mdev->alpha2, 2))
|
||||
return 0;
|
||||
|
||||
if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN)
|
||||
if (MT7921_REGD_SUPPORTED(phy))
|
||||
return mt7921_regd_update(phy, alpha2);
|
||||
else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN)
|
||||
return regulatory_hint(wiphy, alpha2);
|
||||
else
|
||||
return mt7921_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR);
|
||||
@@ -196,7 +385,11 @@ int mt7921_regd_init(struct mt792x_phy *phy)
|
||||
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
|
||||
if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN)
|
||||
if (MT7921_REGD_SUPPORTED(phy)) {
|
||||
wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED |
|
||||
REGULATORY_DISABLE_BEACON_HINTS;
|
||||
return mt7921_regd_update(phy, "00");
|
||||
} else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN)
|
||||
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE |
|
||||
REGULATORY_DISABLE_BEACON_HINTS;
|
||||
else
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
1098
drivers/net/wireless/mediatek/mt76/mt7925/nan.c
Normal file
1098
drivers/net/wireless/mediatek/mt76/mt7925/nan.c
Normal file
File diff suppressed because it is too large
Load Diff
421
drivers/net/wireless/mediatek/mt76/mt7925/nan.h
Normal file
421
drivers/net/wireless/mediatek/mt76/mt7925/nan.h
Normal 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
|
||||
@@ -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");
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -9,6 +9,15 @@ static bool mt7925_disable_clc;
|
||||
module_param_named(disable_clc, mt7925_disable_clc, bool, 0644);
|
||||
MODULE_PARM_DESC(disable_clc, "disable CLC support");
|
||||
|
||||
static struct ieee80211_regdomain mt7925_regd_ww = {
|
||||
.n_reg_rules = 1,
|
||||
.alpha2 = "00",
|
||||
.reg_rules = {
|
||||
/* IEEE 802.11b/g, channels 1..11 */
|
||||
REG_RULE(2412 - 10, 2462 + 10, 40, 6, 20, 0),
|
||||
}
|
||||
};
|
||||
|
||||
bool mt7925_regd_clc_supported(struct mt792x_dev *dev)
|
||||
{
|
||||
if (mt7925_disable_clc ||
|
||||
@@ -128,35 +137,37 @@ mt7925_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
|
||||
}
|
||||
}
|
||||
|
||||
int mt7925_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
|
||||
enum environment_cap country_ie_env)
|
||||
static int mt7925_mcu_apply_regd(struct mt792x_dev *dev, u8 *alpha2,
|
||||
enum environment_cap env)
|
||||
{
|
||||
struct ieee80211_hw *hw = mt76_hw(dev);
|
||||
struct wiphy *wiphy = hw->wiphy;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
dev->regd_in_progress = true;
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
if (!dev->regd_change)
|
||||
goto err;
|
||||
|
||||
ret = mt7925_mcu_set_clc(dev, alpha2, country_ie_env);
|
||||
ret = mt7925_mcu_set_clc(dev, alpha2, env);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
mt7925_regd_be_ctrl(dev, alpha2);
|
||||
mt7925_regd_channel_update(wiphy, dev);
|
||||
|
||||
ret = mt7925_mcu_set_channel_domain(hw->priv);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
ret = mt7925_set_tx_sar_pwr(hw, NULL);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
return mt7925_set_tx_sar_pwr(hw, NULL);
|
||||
}
|
||||
|
||||
err:
|
||||
int mt7925_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
|
||||
enum environment_cap country_ie_env)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
dev->regd_in_progress = true;
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
if (dev->regd_change)
|
||||
ret = mt7925_mcu_apply_regd(dev, alpha2, country_ie_env);
|
||||
mt792x_mutex_release(dev);
|
||||
dev->regd_change = false;
|
||||
dev->regd_in_progress = false;
|
||||
@@ -197,11 +208,178 @@ void mt7925_regd_notifier(struct wiphy *wiphy, struct regulatory_request *req)
|
||||
/* postpone the mcu update to resume */
|
||||
return;
|
||||
|
||||
if (MT7925_REGD_SUPPORTED(&dev->phy)) {
|
||||
mt7925_regd_update(&dev->phy, req->alpha2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mt7925_mcu_regd_update(dev, req->alpha2,
|
||||
req->country_ie_env);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct sk_buff *
|
||||
mt7925_regd_query_regdb(struct mt792x_phy *phy, char *alpha2)
|
||||
{
|
||||
struct wiphy *wiphy = phy->mt76->hw->wiphy;
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
||||
struct mt7925_clc *clc = phy->clc[MT792x_CLC_REGD];
|
||||
struct mt7925_regd_query_req *req;
|
||||
struct mt7925_regd_cc *regd_cc;
|
||||
struct sk_buff *ret_skb = NULL;
|
||||
u8 *pos, *last_pos;
|
||||
int ret = 0;
|
||||
|
||||
if (!clc)
|
||||
return NULL;
|
||||
|
||||
pos = clc->data;
|
||||
last_pos = pos + le32_to_cpu(clc->len) - sizeof(struct mt7925_clc);
|
||||
while (pos < last_pos) {
|
||||
u32 req_len = 0;
|
||||
u32 rules_len = 0;
|
||||
u32 sign_len = 4;
|
||||
u32 n_reg_rules;
|
||||
|
||||
if (pos + sizeof(*regd_cc) > last_pos)
|
||||
break;
|
||||
|
||||
regd_cc = (struct mt7925_regd_cc *)pos;
|
||||
n_reg_rules = le32_to_cpu(regd_cc->n_reg_rules);
|
||||
if (n_reg_rules > NL80211_MAX_SUPP_REG_RULES)
|
||||
break;
|
||||
|
||||
rules_len = sizeof(struct mt7925_regd_rule_header) +
|
||||
sizeof(struct mt7925_regd_rule) * n_reg_rules;
|
||||
|
||||
if (pos + sizeof(*regd_cc) + rules_len + sign_len > last_pos)
|
||||
break;
|
||||
|
||||
pos += sizeof(*regd_cc) + rules_len + sign_len;
|
||||
if (memcmp(regd_cc->alpha2, alpha2, 2))
|
||||
continue;
|
||||
|
||||
req_len = sizeof(*req) + rules_len + sign_len;
|
||||
req = kzalloc(req_len, GFP_KERNEL);
|
||||
|
||||
if (!req)
|
||||
return NULL;
|
||||
|
||||
req->tag = cpu_to_le16(0x6);
|
||||
req->len = cpu_to_le16(req_len - 4);
|
||||
req->ver = regd_cc->ver;
|
||||
req->sign_type = regd_cc->sign_type;
|
||||
req->size = cpu_to_le32(rules_len + sign_len);
|
||||
req->n_reg_rules = regd_cc->n_reg_rules;
|
||||
|
||||
memcpy(req->alpha2, regd_cc->alpha2, 2);
|
||||
memcpy(req->data, regd_cc->data, rules_len + sign_len);
|
||||
|
||||
ret = mt76_mcu_send_and_get_msg(&dev->mt76,
|
||||
MCU_UNI_CMD(SET_POWER_LIMIT),
|
||||
req, req_len, true, &ret_skb);
|
||||
kfree(req);
|
||||
|
||||
return ret < 0 ? NULL : ret_skb;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mt7925_regd_update(struct mt792x_phy *phy, char *alpha2)
|
||||
{
|
||||
struct wiphy *wiphy = phy->mt76->hw->wiphy;
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
||||
struct mt7925_regd_rule *mt7925_rule;
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
struct ieee80211_regdomain *regd;
|
||||
struct ieee80211_reg_rule *rule;
|
||||
struct mt7925_regd_rule_ev *ev;
|
||||
int i, num_of_rules = 0;
|
||||
struct sk_buff *skb;
|
||||
int ret = 0;
|
||||
|
||||
if (dev->hw_full_reset)
|
||||
return 0;
|
||||
|
||||
if (!MT7925_REGD_SUPPORTED(phy))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
mt792x_mutex_acquire(dev);
|
||||
skb = mt7925_regd_query_regdb(phy, alpha2);
|
||||
mt792x_mutex_release(dev);
|
||||
|
||||
if (!skb) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (skb->len < sizeof(*ev) + 4) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ev = (struct mt7925_regd_rule_ev *)(skb->data + 4);
|
||||
num_of_rules = le32_to_cpu(ev->n_reg_rules);
|
||||
|
||||
if (!num_of_rules ||
|
||||
WARN_ON_ONCE(num_of_rules > NL80211_MAX_SUPP_REG_RULES)) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (skb->len < struct_size(ev, reg_rule, num_of_rules) + 4) {
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
regd = kzalloc(struct_size(regd, reg_rules, num_of_rules), GFP_KERNEL);
|
||||
if (!regd) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_of_rules; i++) {
|
||||
mt7925_rule = &ev->reg_rule[i];
|
||||
rule = ®d->reg_rules[i];
|
||||
|
||||
rule->freq_range.start_freq_khz =
|
||||
MHZ_TO_KHZ(le32_to_cpu(mt7925_rule->start_freq));
|
||||
rule->freq_range.end_freq_khz =
|
||||
MHZ_TO_KHZ(le32_to_cpu(mt7925_rule->end_freq));
|
||||
rule->freq_range.max_bandwidth_khz =
|
||||
MHZ_TO_KHZ(le32_to_cpu(mt7925_rule->max_bw));
|
||||
/* not used by fw */
|
||||
rule->power_rule.max_antenna_gain = DBI_TO_MBI(6);
|
||||
rule->power_rule.max_eirp = DBM_TO_MBM(22);
|
||||
rule->flags = le32_to_cpu(mt7925_rule->flags);
|
||||
}
|
||||
|
||||
regd->n_reg_rules = num_of_rules;
|
||||
regd->dfs_region = ev->dfs_region;
|
||||
|
||||
memcpy(regd->alpha2, alpha2, 2);
|
||||
memcpy(mdev->alpha2, alpha2, 2);
|
||||
|
||||
dev->regd_change = true;
|
||||
mt7925_mcu_regd_update(dev, alpha2, ENVIRON_ANY);
|
||||
|
||||
ret = regulatory_set_wiphy_regd(wiphy, regd);
|
||||
|
||||
kfree(regd);
|
||||
err:
|
||||
dev_kfree_skb(skb);
|
||||
|
||||
if (ret < 0)
|
||||
return regulatory_set_wiphy_regd(wiphy, &mt7925_regd_ww);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7925_regd_update);
|
||||
|
||||
static bool
|
||||
mt7925_regd_is_valid_alpha2(const char *alpha2)
|
||||
{
|
||||
@@ -217,6 +395,36 @@ mt7925_regd_is_valid_alpha2(const char *alpha2)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
mt7925_regd_is_valid_channel(struct mt792x_dev *dev,
|
||||
enum nl80211_band band,
|
||||
struct ieee80211_channel *chan)
|
||||
{
|
||||
struct ieee80211_hw *hw = mt76_hw(dev);
|
||||
struct wiphy *wiphy = hw->wiphy;
|
||||
struct ieee80211_supported_band *sband;
|
||||
struct ieee80211_channel *ch;
|
||||
int i;
|
||||
|
||||
if (!chan)
|
||||
return false;
|
||||
|
||||
sband = wiphy->bands[band];
|
||||
if (!sband)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < sband->n_channels; i++) {
|
||||
ch = &sband->channels[i];
|
||||
|
||||
if (ch->hw_value == chan->hw_value &&
|
||||
((ch->flags & IEEE80211_CHAN_DISABLED) == 0))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mt7925_regd_is_valid_channel);
|
||||
|
||||
int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2)
|
||||
{
|
||||
struct wiphy *wiphy = phy->mt76->hw->wiphy;
|
||||
@@ -240,7 +448,9 @@ int mt7925_regd_change(struct mt792x_phy *phy, char *alpha2)
|
||||
if (!memcmp(alpha2, mdev->alpha2, 2))
|
||||
return 0;
|
||||
|
||||
if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) {
|
||||
if (MT7925_REGD_SUPPORTED(phy)) {
|
||||
return mt7925_regd_update(phy, alpha2);
|
||||
} else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) {
|
||||
return regulatory_hint(wiphy, alpha2);
|
||||
} else {
|
||||
return mt7925_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR);
|
||||
@@ -255,7 +465,11 @@ int mt7925_regd_init(struct mt792x_phy *phy)
|
||||
struct mt792x_dev *dev = mt792x_hw_dev(hw);
|
||||
struct mt76_dev *mdev = &dev->mt76;
|
||||
|
||||
if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) {
|
||||
if (MT7925_REGD_SUPPORTED(phy)) {
|
||||
wiphy->regulatory_flags |= REGULATORY_WIPHY_SELF_MANAGED |
|
||||
REGULATORY_DISABLE_BEACON_HINTS;
|
||||
return mt7925_regd_update(phy, "00");
|
||||
} else if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN) {
|
||||
wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE |
|
||||
REGULATORY_DISABLE_BEACON_HINTS;
|
||||
} else {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user