Merge tag 'mt76-for-kvalo-2023-02-03' of https://github.com/nbd168/wireless

mt76 patches for 6.3

- fixes
- mt7996 cleanups
- switch to page pool allocator
- mt7996 eht support
- WED reset support
This commit is contained in:
Kalle Valo
2023-02-13 14:38:27 +02:00
49 changed files with 1338 additions and 649 deletions

View File

@@ -1,6 +1,7 @@
# SPDX-License-Identifier: GPL-2.0-only
config MT76_CORE
tristate
select PAGE_POOL
config MT76_LEDS
bool

View File

@@ -165,7 +165,7 @@ mt76_free_pending_txwi(struct mt76_dev *dev)
local_bh_enable();
}
static void
void
mt76_free_pending_rxwi(struct mt76_dev *dev)
{
struct mt76_txwi_cache *t;
@@ -173,11 +173,12 @@ mt76_free_pending_rxwi(struct mt76_dev *dev)
local_bh_disable();
while ((t = __mt76_get_rxwi(dev)) != NULL) {
if (t->ptr)
skb_free_frag(t->ptr);
mt76_put_page_pool_buf(t->ptr, false);
kfree(t);
}
local_bh_enable();
}
EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi);
static void
mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q)
@@ -218,8 +219,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
if ((q->flags & MT_QFLAG_WED) &&
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) {
if (mt76_queue_is_wed_rx(q)) {
txwi = mt76_get_rxwi(dev);
if (!txwi)
return -ENOMEM;
@@ -401,8 +401,7 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
if (info)
*info = le32_to_cpu(desc->info);
if ((q->flags & MT_QFLAG_WED) &&
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX) {
if (mt76_queue_is_wed_rx(q)) {
u32 token = FIELD_GET(MT_DMA_CTL_TOKEN,
le32_to_cpu(desc->buf1));
struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token);
@@ -410,9 +409,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
if (!t)
return NULL;
dma_unmap_single(dev->dma_dev, t->dma_addr,
SKB_WITH_OVERHEAD(q->buf_size),
DMA_FROM_DEVICE);
dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr,
SKB_WITH_OVERHEAD(q->buf_size),
page_pool_get_dma_dir(q->page_pool));
buf = t->ptr;
t->dma_addr = 0;
@@ -429,9 +428,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
} else {
buf = e->buf;
e->buf = NULL;
dma_unmap_single(dev->dma_dev, e->dma_addr[0],
SKB_WITH_OVERHEAD(q->buf_size),
DMA_FROM_DEVICE);
dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0],
SKB_WITH_OVERHEAD(q->buf_size),
page_pool_get_dma_dir(q->page_pool));
}
return buf;
@@ -583,11 +582,11 @@ free_skb:
}
static int
mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
bool allow_direct)
{
int len = SKB_WITH_OVERHEAD(q->buf_size);
int frames = 0, offset = q->buf_offset;
dma_addr_t addr;
int frames = 0;
if (!q->ndesc)
return 0;
@@ -595,26 +594,25 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
spin_lock_bh(&q->lock);
while (q->queued < q->ndesc - 1) {
enum dma_data_direction dir;
struct mt76_queue_buf qbuf;
void *buf = NULL;
dma_addr_t addr;
int offset;
void *buf;
buf = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC);
buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
if (!buf)
break;
addr = dma_map_single(dev->dma_dev, buf, len, DMA_FROM_DEVICE);
if (unlikely(dma_mapping_error(dev->dma_dev, addr))) {
skb_free_frag(buf);
break;
}
addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset;
dir = page_pool_get_dma_dir(q->page_pool);
dma_sync_single_for_device(dev->dma_dev, addr, len, dir);
qbuf.addr = addr + offset;
qbuf.len = len - offset;
qbuf.addr = addr + q->buf_offset;
qbuf.len = len - q->buf_offset;
qbuf.skip_unmap = false;
if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) {
dma_unmap_single(dev->dma_dev, addr, len,
DMA_FROM_DEVICE);
skb_free_frag(buf);
mt76_put_page_pool_buf(buf, allow_direct);
break;
}
frames++;
@@ -628,14 +626,17 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
return frames;
}
static int
mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
{
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
struct mtk_wed_device *wed = &dev->mmio.wed;
int ret, type, ring;
u8 flags = q->flags;
u8 flags;
if (!q || !q->ndesc)
return -EINVAL;
flags = q->flags;
if (!mtk_wed_device_active(wed))
q->flags &= ~MT_QFLAG_WED;
@@ -647,7 +648,7 @@ mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
switch (type) {
case MT76_WED_Q_TX:
ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, false);
ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, reset);
if (!ret)
q->wed_regs = wed->tx_ring[ring].reg_base;
break;
@@ -655,7 +656,7 @@ mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
/* WED txfree queue needs ring to be initialized before setup */
q->flags = 0;
mt76_dma_queue_reset(dev, q);
mt76_dma_rx_fill(dev, q);
mt76_dma_rx_fill(dev, q, false);
q->flags = flags;
ret = mtk_wed_device_txfree_ring_setup(wed, q->regs);
@@ -663,7 +664,7 @@ mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
q->wed_regs = wed->txfree_ring.reg_base;
break;
case MT76_WED_Q_RX:
ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, false);
ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, reset);
if (!ret)
q->wed_regs = wed->rx_ring[ring].reg_base;
break;
@@ -676,6 +677,7 @@ mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
return 0;
#endif
}
EXPORT_SYMBOL_GPL(mt76_dma_wed_setup);
static int
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
@@ -702,7 +704,11 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
if (!q->entry)
return -ENOMEM;
ret = mt76_dma_wed_setup(dev, q);
ret = mt76_create_page_pool(dev, q);
if (ret)
return ret;
ret = mt76_dma_wed_setup(dev, q, false);
if (ret)
return ret;
@@ -715,7 +721,6 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
static void
mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
{
struct page *page;
void *buf;
bool more;
@@ -723,21 +728,21 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
return;
spin_lock_bh(&q->lock);
do {
buf = mt76_dma_dequeue(dev, q, true, NULL, NULL, &more, NULL);
if (!buf)
break;
skb_free_frag(buf);
mt76_put_page_pool_buf(buf, false);
} while (1);
if (q->rx_head) {
dev_kfree_skb(q->rx_head);
q->rx_head = NULL;
}
spin_unlock_bh(&q->lock);
if (!q->rx_page.va)
return;
page = virt_to_page(q->rx_page.va);
__page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
memset(&q->rx_page, 0, sizeof(q->rx_page));
}
static void
@@ -753,14 +758,13 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);
mt76_dma_rx_cleanup(dev, q);
mt76_dma_sync_idx(dev, q);
mt76_dma_rx_fill(dev, q);
if (!q->rx_head)
return;
dev_kfree_skb(q->rx_head);
q->rx_head = NULL;
/* reset WED rx queues */
mt76_dma_wed_setup(dev, q, true);
if (q->flags != MT_WED_Q_TXFREE) {
mt76_dma_sync_idx(dev, q);
mt76_dma_rx_fill(dev, q, false);
}
}
static void
@@ -777,7 +781,7 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
skb_add_rx_frag(skb, nr_frags, page, offset, len, q->buf_size);
} else {
skb_free_frag(data);
mt76_put_page_pool_buf(data, true);
}
if (more)
@@ -850,6 +854,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
goto free_frag;
skb_reserve(skb, q->buf_offset);
skb_mark_for_recycle(skb);
*(u32 *)skb->cb = info;
@@ -865,10 +870,10 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
continue;
free_frag:
skb_free_frag(data);
mt76_put_page_pool_buf(data, true);
}
mt76_dma_rx_fill(dev, q);
mt76_dma_rx_fill(dev, q, true);
return done;
}
@@ -908,10 +913,12 @@ mt76_dma_init(struct mt76_dev *dev,
snprintf(dev->napi_dev.name, sizeof(dev->napi_dev.name), "%s",
wiphy_name(dev->hw->wiphy));
dev->napi_dev.threaded = 1;
init_completion(&dev->mmio.wed_reset);
init_completion(&dev->mmio.wed_reset_complete);
mt76_for_each_q_rx(dev, i) {
netif_napi_add(&dev->napi_dev, &dev->napi[i], poll);
mt76_dma_rx_fill(dev, &dev->q_rx[i]);
mt76_dma_rx_fill(dev, &dev->q_rx[i], false);
napi_enable(&dev->napi[i]);
}
@@ -961,8 +968,9 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
struct mt76_queue *q = &dev->q_rx[i];
netif_napi_del(&dev->napi[i]);
if (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags))
mt76_dma_rx_cleanup(dev, q);
mt76_dma_rx_cleanup(dev, q);
page_pool_destroy(q->page_pool);
}
mt76_free_pending_txwi(dev);

View File

@@ -56,5 +56,6 @@ enum mt76_mcu_evt_type {
int mt76_dma_rx_poll(struct napi_struct *napi, int budget);
void mt76_dma_attach(struct mt76_dev *dev);
void mt76_dma_cleanup(struct mt76_dev *dev);
int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset);
#endif

View File

@@ -138,6 +138,7 @@ mt76_find_power_limits_node(struct mt76_dev *dev)
{
struct device_node *np = dev->dev->of_node;
const char *const region_names[] = {
[NL80211_DFS_UNSET] = "ww",
[NL80211_DFS_ETSI] = "etsi",
[NL80211_DFS_FCC] = "fcc",
[NL80211_DFS_JP] = "jp",

View File

@@ -4,6 +4,7 @@
*/
#include <linux/sched.h>
#include <linux/of.h>
#include <net/page_pool.h>
#include "mt76.h"
#define CHAN2G(_idx, _freq) { \
@@ -556,6 +557,47 @@ void mt76_unregister_phy(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_unregister_phy);
int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
{
struct page_pool_params pp_params = {
.order = 0,
.flags = PP_FLAG_PAGE_FRAG,
.nid = NUMA_NO_NODE,
.dev = dev->dma_dev,
};
int idx = q - dev->q_rx;
switch (idx) {
case MT_RXQ_MAIN:
case MT_RXQ_BAND1:
case MT_RXQ_BAND2:
pp_params.pool_size = 256;
break;
default:
pp_params.pool_size = 16;
break;
}
if (mt76_is_mmio(dev)) {
/* rely on page_pool for DMA mapping */
pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
pp_params.dma_dir = DMA_FROM_DEVICE;
pp_params.max_len = PAGE_SIZE;
pp_params.offset = 0;
}
q->page_pool = page_pool_create(&pp_params);
if (IS_ERR(q->page_pool)) {
int err = PTR_ERR(q->page_pool);
q->page_pool = NULL;
return err;
}
return 0;
}
EXPORT_SYMBOL_GPL(mt76_create_page_pool);
struct mt76_dev *
mt76_alloc_device(struct device *pdev, unsigned int size,
const struct ieee80211_ops *ops,
@@ -1658,7 +1700,7 @@ u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx)
EXPORT_SYMBOL_GPL(mt76_calculate_default_rate);
void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
struct mt76_sta_stats *stats)
struct mt76_sta_stats *stats, bool eht)
{
int i, ei = wi->initial_stat_idx;
u64 *data = wi->data;
@@ -1674,17 +1716,37 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_EXT_SU];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_TB];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_HE_MU];
if (eht) {
data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_SU];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_TRIG];
data[ei++] += stats->tx_mode[MT_PHY_TYPE_EHT_MU];
}
for (i = 0; i < ARRAY_SIZE(stats->tx_bw); i++)
for (i = 0; i < (ARRAY_SIZE(stats->tx_bw) - !eht); i++)
data[ei++] += stats->tx_bw[i];
for (i = 0; i < 12; i++)
for (i = 0; i < (eht ? 14 : 12); i++)
data[ei++] += stats->tx_mcs[i];
wi->worker_stat_count = ei - wi->initial_stat_idx;
}
EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
{
#ifdef CONFIG_PAGE_POOL_STATS
struct page_pool_stats stats = {};
int i;
mt76_for_each_q_rx(dev, i)
page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
page_pool_ethtool_stats_get(data, &stats);
*index += page_pool_ethtool_stats_get_count();
#endif
}
EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
{
struct ieee80211_hw *hw = phy->hw;

View File

@@ -202,7 +202,7 @@ struct mt76_queue {
dma_addr_t desc_dma;
struct sk_buff *rx_head;
struct page_frag_cache rx_page;
struct page_pool *page_pool;
};
struct mt76_mcu_ops {
@@ -264,12 +264,15 @@ enum mt76_phy_type {
MT_PHY_TYPE_HE_EXT_SU,
MT_PHY_TYPE_HE_TB,
MT_PHY_TYPE_HE_MU,
__MT_PHY_TYPE_HE_MAX,
MT_PHY_TYPE_EHT_SU = 13,
MT_PHY_TYPE_EHT_TRIG,
MT_PHY_TYPE_EHT_MU,
__MT_PHY_TYPE_MAX,
};
struct mt76_sta_stats {
u64 tx_mode[__MT_PHY_TYPE_HE_MAX];
u64 tx_bw[4]; /* 20, 40, 80, 160 */
u64 tx_mode[__MT_PHY_TYPE_MAX];
u64 tx_bw[5]; /* 20, 40, 80, 160, 320 */
u64 tx_nss[4]; /* 1, 2, 3, 4 */
u64 tx_mcs[16]; /* mcs idx */
u64 tx_bytes;
@@ -291,7 +294,7 @@ enum mt76_wcid_flags {
MT_WCID_FLAG_HDR_TRANS,
};
#define MT76_N_WCIDS 544
#define MT76_N_WCIDS 1088
/* stored in ieee80211_tx_info::hw_queue */
#define MT_TX_HW_QUEUE_PHY GENMASK(3, 2)
@@ -413,6 +416,7 @@ enum {
MT76_STATE_SUSPEND,
MT76_STATE_ROC,
MT76_STATE_PM,
MT76_STATE_WED_RESET,
};
struct mt76_hw_cap {
@@ -591,6 +595,8 @@ struct mt76_mmio {
u32 irqmask;
struct mtk_wed_device wed;
struct completion wed_reset;
struct completion wed_reset_complete;
};
struct mt76_rx_status {
@@ -888,7 +894,6 @@ extern struct ieee80211_rate mt76_rates[12];
#define mt76_mcu_restart(dev, ...) (dev)->mt76.mcu_ops->mcu_restart(&((dev)->mt76))
#define __mt76_mcu_restart(dev, ...) (dev)->mcu_ops->mcu_restart((dev))
#define mt76_set(dev, offset, val) mt76_rmw(dev, offset, 0, val)
#define mt76_clear(dev, offset, val) mt76_rmw(dev, offset, val, 0)
@@ -909,10 +914,11 @@ bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
#define mt76_poll(dev, ...) __mt76_poll(&((dev)->mt76), __VA_ARGS__)
bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
int timeout);
#define mt76_poll_msec(dev, ...) __mt76_poll_msec(&((dev)->mt76), __VA_ARGS__)
bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
int timeout, int kick);
#define __mt76_poll_msec(...) ____mt76_poll_msec(__VA_ARGS__, 10)
#define mt76_poll_msec(dev, ...) ____mt76_poll_msec(&((dev)->mt76), __VA_ARGS__, 10)
#define mt76_poll_msec_tick(dev, ...) ____mt76_poll_msec(&((dev)->mt76), __VA_ARGS__)
void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs);
void mt76_pci_disable_aspm(struct pci_dev *pdev);
@@ -1269,6 +1275,7 @@ mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb)
void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
void mt76_put_rxwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
struct mt76_txwi_cache *mt76_get_rxwi(struct mt76_dev *dev);
void mt76_free_pending_rxwi(struct mt76_dev *dev);
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
struct napi_struct *napi);
void mt76_rx_poll_complete(struct mt76_dev *dev, enum mt76_rxq_id q,
@@ -1311,8 +1318,9 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout);
}
void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index);
void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
struct mt76_sta_stats *stats);
struct mt76_sta_stats *stats, bool eht);
int mt76_skb_adjust_pad(struct sk_buff *skb, int pad);
int __mt76u_vendor_request(struct mt76_dev *dev, u8 req, u8 req_type,
u16 val, u16 offset, void *buf, size_t len);
@@ -1409,6 +1417,12 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
struct mt76_power_limits *dest,
s8 target_power);
static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q)
{
return (q->flags & MT_QFLAG_WED) &&
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX;
}
struct mt76_txwi_cache *
mt76_token_release(struct mt76_dev *dev, int token, bool *wake);
int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi);
@@ -1416,6 +1430,25 @@ void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);
struct mt76_txwi_cache *mt76_rx_token_release(struct mt76_dev *dev, int token);
int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr,
struct mt76_txwi_cache *r, dma_addr_t phys);
int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q);
static inline void mt76_put_page_pool_buf(void *buf, bool allow_direct)
{
struct page *page = virt_to_head_page(buf);
page_pool_put_full_page(page->pp, page, allow_direct);
}
static inline void *
mt76_get_page_pool_buf(struct mt76_queue *q, u32 *offset, u32 size)
{
struct page *page;
page = page_pool_dev_alloc_frag(q->page_pool, offset, size);
if (!page)
return NULL;
return page_address(page) + *offset;
}
static inline void mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked)
{

View File

@@ -221,7 +221,6 @@ int mt7603_mcu_init(struct mt7603_dev *dev)
.headroom = sizeof(struct mt7603_mcu_txd),
.mcu_skb_send_msg = mt7603_mcu_skb_send_msg,
.mcu_parse_response = mt7603_mcu_parse_response,
.mcu_restart = mt7603_mcu_restart,
};
dev->mt76.mcu_ops = &mt7603_mcu_ops;
@@ -230,7 +229,7 @@ int mt7603_mcu_init(struct mt7603_dev *dev)
void mt7603_mcu_exit(struct mt7603_dev *dev)
{
__mt76_mcu_restart(&dev->mt76);
mt7603_mcu_restart(&dev->mt76);
skb_queue_purge(&dev->mt76.mcu.res_q);
}

View File

@@ -1692,7 +1692,6 @@ int mt7615_mcu_init(struct mt7615_dev *dev)
.headroom = sizeof(struct mt7615_mcu_txd),
.mcu_skb_send_msg = mt7615_mcu_send_message,
.mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
};
int ret;
@@ -1732,7 +1731,7 @@ EXPORT_SYMBOL_GPL(mt7615_mcu_init);
void mt7615_mcu_exit(struct mt7615_dev *dev)
{
__mt76_mcu_restart(&dev->mt76);
mt7615_mcu_restart(&dev->mt76);
mt7615_mcu_set_fw_ctrl(dev);
skb_queue_purge(&dev->mt76.mcu.res_q);
}

View File

@@ -137,7 +137,6 @@ int mt7663s_mcu_init(struct mt7615_dev *dev)
.tailroom = MT_USB_TAIL_SIZE,
.mcu_skb_send_msg = mt7663s_mcu_send_message,
.mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
.mcu_rr = mt76_connac_mcu_reg_rr,
.mcu_wr = mt76_connac_mcu_reg_wr,
};

View File

@@ -69,7 +69,6 @@ int mt7663u_mcu_init(struct mt7615_dev *dev)
.tailroom = MT_USB_TAIL_SIZE,
.mcu_skb_send_msg = mt7663u_mcu_send_message,
.mcu_parse_response = mt7615_mcu_parse_response,
.mcu_restart = mt7615_mcu_restart,
};
int ret;

View File

@@ -42,6 +42,7 @@ enum {
CMD_CBW_10MHZ,
CMD_CBW_5MHZ,
CMD_CBW_8080MHZ,
CMD_CBW_320MHZ,
CMD_HE_MCS_BW80 = 0,
CMD_HE_MCS_BW160,
@@ -239,6 +240,7 @@ static inline u8 mt76_connac_chan_bw(struct cfg80211_chan_def *chandef)
[NL80211_CHAN_WIDTH_10] = CMD_CBW_10MHZ,
[NL80211_CHAN_WIDTH_20] = CMD_CBW_20MHZ,
[NL80211_CHAN_WIDTH_20_NOHT] = CMD_CBW_20MHZ,
[NL80211_CHAN_WIDTH_320] = CMD_CBW_320MHZ,
};
if (chandef->width >= ARRAY_SIZE(width_to_bw))
@@ -370,6 +372,9 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
enum mt76_txq_id qid, u32 changed);
u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
struct ieee80211_vif *vif,
bool beacon, bool mcast);
bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
__le32 *txs_data);
bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,

View File

@@ -267,9 +267,9 @@ int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,
}
EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues);
static u16
mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif,
bool beacon, bool mcast)
u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
struct ieee80211_vif *vif,
bool beacon, bool mcast)
{
u8 mode = 0, band = mphy->chandef.chan->band;
int rateidx = 0, mcast_rate;
@@ -319,6 +319,7 @@ out:
return FIELD_PREP(MT_TX_RATE_IDX, rateidx) |
FIELD_PREP(MT_TX_RATE_MODE, mode);
}
EXPORT_SYMBOL_GPL(mt76_connac2_mac_tx_rate_val);
static void
mt76_connac2_mac_write_txwi_8023(__le32 *txwi, struct sk_buff *skb,

View File

@@ -1329,6 +1329,40 @@ u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode);
u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
enum nl80211_band band)
{
const struct ieee80211_sta_eht_cap *eht_cap;
struct ieee80211_supported_band *sband;
u8 mode = 0;
if (band == NL80211_BAND_6GHZ)
mode |= PHY_MODE_AX_6G;
sband = phy->hw->wiphy->bands[band];
eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type);
if (!eht_cap || !eht_cap->has_eht)
return mode;
switch (band) {
case NL80211_BAND_6GHZ:
mode |= PHY_MODE_BE_6G;
break;
case NL80211_BAND_5GHZ:
mode |= PHY_MODE_BE_5G;
break;
case NL80211_BAND_2GHZ:
mode |= PHY_MODE_BE_24G;
break;
default:
break;
}
return mode;
}
EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode_ext);
const struct ieee80211_sta_he_cap *
mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif)
{
@@ -1341,6 +1375,18 @@ mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif)
}
EXPORT_SYMBOL_GPL(mt76_connac_get_he_phy_cap);
const struct ieee80211_sta_eht_cap *
mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif)
{
enum nl80211_band band = phy->chandef.chan->band;
struct ieee80211_supported_band *sband;
sband = phy->hw->wiphy->bands[band];
return ieee80211_get_eht_iftype_cap(sband, vif->type);
}
EXPORT_SYMBOL_GPL(mt76_connac_get_eht_phy_cap);
#define DEFAULT_HE_PE_DURATION 4
#define DEFAULT_HE_DURATION_RTS_THRES 1023
static void

View File

@@ -793,6 +793,7 @@ enum {
STA_REC_PHY = 0x15,
STA_REC_HE_6G = 0x17,
STA_REC_HE_V2 = 0x19,
STA_REC_EHT = 0x22,
STA_REC_HDRT = 0x28,
STA_REC_HDR_TRANS = 0x2B,
STA_REC_MAX_NUM
@@ -882,12 +883,16 @@ enum {
#define PHY_MODE_AX_5G BIT(7)
#define PHY_MODE_AX_6G BIT(0) /* phymode_ext */
#define PHY_MODE_BE_24G BIT(1)
#define PHY_MODE_BE_5G BIT(2)
#define PHY_MODE_BE_6G BIT(3)
#define MODE_CCK BIT(0)
#define MODE_OFDM BIT(1)
#define MODE_HT BIT(2)
#define MODE_VHT BIT(3)
#define MODE_HE BIT(4)
#define MODE_EHT BIT(5)
#define STA_CAP_WMM BIT(0)
#define STA_CAP_SGI_20 BIT(4)
@@ -1171,6 +1176,7 @@ enum {
MCU_EXT_CMD_GET_MIB_INFO = 0x5a,
MCU_EXT_CMD_TXDPD_CAL = 0x60,
MCU_EXT_CMD_CAL_CACHE = 0x67,
MCU_EXT_CMD_RED_ENABLE = 0x68,
MCU_EXT_CMD_SET_RADAR_TH = 0x7c,
MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d,
MCU_EXT_CMD_MWDS_SUPPORT = 0x80,
@@ -1198,7 +1204,8 @@ enum {
MCU_UNI_CMD_REPT_MUAR = 0x09,
MCU_UNI_CMD_WSYS_CONFIG = 0x0b,
MCU_UNI_CMD_REG_ACCESS = 0x0d,
MCU_UNI_CMD_POWER_CREL = 0x0f,
MCU_UNI_CMD_CHIP_CONFIG = 0x0e,
MCU_UNI_CMD_POWER_CTRL = 0x0f,
MCU_UNI_CMD_RX_HDR_TRANS = 0x12,
MCU_UNI_CMD_SER = 0x13,
MCU_UNI_CMD_TWT = 0x14,
@@ -1238,6 +1245,7 @@ enum {
MCU_CE_CMD_TEST_CTRL = 0x01,
MCU_CE_CMD_START_HW_SCAN = 0x03,
MCU_CE_CMD_SET_PS_PROFILE = 0x05,
MCU_CE_CMD_SET_RX_FILTER = 0x0a,
MCU_CE_CMD_SET_CHAN_DOMAIN = 0x0f,
MCU_CE_CMD_SET_BSS_CONNECTED = 0x16,
MCU_CE_CMD_SET_BSS_ABORT = 0x17,
@@ -1730,7 +1738,7 @@ mt76_connac_mcu_gen_dl_mode(struct mt76_dev *dev, u8 feature_set, bool is_wa)
}
#define to_wcid_lo(id) FIELD_GET(GENMASK(7, 0), (u16)id)
#define to_wcid_hi(id) FIELD_GET(GENMASK(9, 8), (u16)id)
#define to_wcid_hi(id) FIELD_GET(GENMASK(10, 8), (u16)id)
static inline void
mt76_connac_mcu_get_wlan_idx(struct mt76_dev *dev, struct mt76_wcid *wcid,
@@ -1866,8 +1874,12 @@ void mt76_connac_mcu_reg_wr(struct mt76_dev *dev, u32 offset, u32 val);
const struct ieee80211_sta_he_cap *
mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif);
const struct ieee80211_sta_eht_cap *
mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif);
u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
enum nl80211_band band, struct ieee80211_sta *sta);
u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
enum nl80211_band band);
int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
struct mt76_connac_sta_key_conf *sta_key_conf,

View File

@@ -148,6 +148,7 @@ static int mt76x0u_load_firmware(struct mt76x02_dev *dev)
mt76_wr(dev, MT_USB_DMA_CFG, val);
ret = mt76x0u_upload_firmware(dev, hdr);
mt76x02_set_ethtool_fwver(dev, hdr);
release_firmware(fw);
mt76_wr(dev, MT_FCE_PSE_CTRL, 1);

View File

@@ -559,9 +559,32 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
return 0;
}
static void mt7915_dma_wed_reset(struct mt7915_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
if (!test_bit(MT76_STATE_WED_RESET, &dev->mphy.state))
return;
complete(&mdev->mmio.wed_reset);
if (!wait_for_completion_timeout(&dev->mt76.mmio.wed_reset_complete,
3 * HZ))
dev_err(dev->mt76.dev, "wed reset complete timeout\n");
}
static void
mt7915_dma_reset_tx_queue(struct mt7915_dev *dev, struct mt76_queue *q)
{
mt76_queue_reset(dev, q);
if (mtk_wed_device_active(&dev->mt76.mmio.wed))
mt76_dma_wed_setup(&dev->mt76, q, true);
}
int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
{
struct mt76_phy *mphy_ext = dev->mt76.phys[MT_BAND1];
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
int i;
/* clean up hw queues */
@@ -581,28 +604,40 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
if (force)
mt7915_wfsys_reset(dev);
if (mtk_wed_device_active(wed))
mtk_wed_device_dma_reset(wed);
mt7915_dma_disable(dev, force);
mt7915_dma_wed_reset(dev);
/* reset hw queues */
for (i = 0; i < __MT_TXQ_MAX; i++) {
mt76_queue_reset(dev, dev->mphy.q_tx[i]);
mt7915_dma_reset_tx_queue(dev, dev->mphy.q_tx[i]);
if (mphy_ext)
mt76_queue_reset(dev, mphy_ext->q_tx[i]);
mt7915_dma_reset_tx_queue(dev, mphy_ext->q_tx[i]);
}
for (i = 0; i < __MT_MCUQ_MAX; i++)
mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
mt76_for_each_q_rx(&dev->mt76, i)
mt76_for_each_q_rx(&dev->mt76, i) {
if (dev->mt76.q_rx[i].flags == MT_WED_Q_TXFREE)
continue;
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
}
mt76_tx_status_check(&dev->mt76, true);
mt7915_dma_enable(dev);
mt76_for_each_q_rx(&dev->mt76, i)
mt76_queue_rx_reset(dev, i);
if (mtk_wed_device_active(wed) && is_mt7915(&dev->mt76))
mt76_rmw(dev, MT_WFDMA0_EXT0_CFG, MT_WFDMA0_EXT0_RXWB_KEEP,
MT_WFDMA0_EXT0_RXWB_KEEP);
mt7915_dma_enable(dev);
return 0;
}

View File

@@ -33,11 +33,14 @@ static int mt7915_check_eeprom(struct mt7915_dev *dev)
u8 *eeprom = dev->mt76.eeprom.data;
u16 val = get_unaligned_le16(eeprom);
#define CHECK_EEPROM_ERR(match) (match ? 0 : -EINVAL)
switch (val) {
case 0x7915:
return CHECK_EEPROM_ERR(is_mt7915(&dev->mt76));
case 0x7916:
return CHECK_EEPROM_ERR(is_mt7916(&dev->mt76));
case 0x7986:
return 0;
return CHECK_EEPROM_ERR(is_mt7986(&dev->mt76));
default:
return -EINVAL;
}

View File

@@ -38,8 +38,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160) |
BIT(NL80211_CHAN_WIDTH_80P80),
BIT(NL80211_CHAN_WIDTH_160),
}
};
@@ -83,9 +82,23 @@ static ssize_t mt7915_thermal_temp_store(struct device *dev,
mutex_lock(&phy->dev->mt76.mutex);
val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 60, 130);
if ((i - 1 == MT7915_CRIT_TEMP_IDX &&
val > phy->throttle_temp[MT7915_MAX_TEMP_IDX]) ||
(i - 1 == MT7915_MAX_TEMP_IDX &&
val < phy->throttle_temp[MT7915_CRIT_TEMP_IDX])) {
dev_err(phy->dev->mt76.dev,
"temp1_max shall be greater than temp1_crit.");
return -EINVAL;
}
phy->throttle_temp[i - 1] = val;
mutex_unlock(&phy->dev->mt76.mutex);
ret = mt7915_mcu_set_thermal_protect(phy);
if (ret)
return ret;
return count;
}
@@ -131,11 +144,11 @@ mt7915_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
u8 throttling = MT7915_THERMAL_THROTTLE_MAX - state;
int ret;
if (state > MT7915_CDEV_THROTTLE_MAX)
if (state > MT7915_CDEV_THROTTLE_MAX) {
dev_err(phy->dev->mt76.dev,
"please specify a valid throttling state\n");
return -EINVAL;
if (phy->throttle_temp[0] > phy->throttle_temp[1])
return 0;
}
if (state == phy->cdev_state)
return 0;
@@ -164,7 +177,7 @@ static void mt7915_unregister_thermal(struct mt7915_phy *phy)
struct wiphy *wiphy = phy->mt76->hw->wiphy;
if (!phy->cdev)
return;
return;
sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
thermal_cooling_device_unregister(phy->cdev);
@@ -198,11 +211,10 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
return PTR_ERR(hwmon);
/* initialize critical/maximum high temperature */
phy->throttle_temp[0] = 110;
phy->throttle_temp[1] = 120;
phy->throttle_temp[MT7915_CRIT_TEMP_IDX] = MT7915_CRIT_TEMP;
phy->throttle_temp[MT7915_MAX_TEMP_IDX] = MT7915_MAX_TEMP;
return mt7915_mcu_set_thermal_throttling(phy,
MT7915_THERMAL_THROTTLE_MAX);
return 0;
}
static void mt7915_led_set_config(struct led_classdev *led_cdev,
@@ -394,11 +406,6 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
phy->mt76->sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
if (!dev->dbdc_support)
phy->mt76->sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_SHORT_GI_160 |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
} else {
phy->mt76->sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
@@ -834,13 +841,9 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_phy *phy,
int sts = hweight8(phy->mt76->chainmask);
u8 c, sts_160 = sts;
/* Can do 1/2 of STS in 160Mhz mode for mt7915 */
if (is_mt7915(&dev->mt76)) {
if (!dev->dbdc_support)
sts_160 /= 2;
else
sts_160 = 0;
}
/* mt7915 doesn't support bw160 */
if (is_mt7915(&dev->mt76))
sts_160 = 0;
#ifdef CONFIG_MAC80211_MESH
if (vif == NL80211_IFTYPE_MESH_POINT)
@@ -894,9 +897,6 @@ mt7915_set_stream_he_txbf_caps(struct mt7915_phy *phy,
elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
/* num_snd_dim
* for mt7915, max supported sts is 2 for bw > 80MHz and 0 if dbdc
*/
c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
sts - 1);
if (sts_160)
@@ -944,15 +944,10 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
int i, idx = 0, nss = hweight8(phy->mt76->antenna_mask);
u16 mcs_map = 0;
u16 mcs_map_160 = 0;
u8 nss_160;
u8 nss_160 = nss;
if (!is_mt7915(&dev->mt76))
nss_160 = nss;
else if (!dev->dbdc_support)
/* Can do 1/2 of NSS streams in 160Mhz mode for mt7915 */
nss_160 = nss / 2;
else
/* Can't do 160MHz with mt7915 dbdc */
/* Can't do 160MHz with mt7915 */
if (is_mt7915(&dev->mt76))
nss_160 = 0;
for (i = 0; i < 8; i++) {
@@ -1002,8 +997,7 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
else if (nss_160)
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
else
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G;
@@ -1075,12 +1069,11 @@ mt7915_init_he_caps(struct mt7915_phy *phy, enum nl80211_band band,
break;
}
memset(he_mcs, 0, sizeof(*he_mcs));
he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map_160);
he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map_160);
he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map_160);
he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map_160);
mt7915_set_stream_he_txbf_caps(phy, he_cap, i);
@@ -1172,7 +1165,6 @@ static void mt7915_stop_hardware(struct mt7915_dev *dev)
mt7986_wmac_disable(dev);
}
int mt7915_register_device(struct mt7915_dev *dev)
{
struct mt7915_phy *phy2;

View File

@@ -256,8 +256,7 @@ mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q,
if (!msta || !msta->vif)
return;
if (!(q->flags & MT_QFLAG_WED) ||
FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) != MT76_WED_Q_RX)
if (!mt76_queue_is_wed_rx(q))
return;
if (!(info & MT_DMA_INFO_PPE_VLD))
@@ -1061,9 +1060,6 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
u16 wcidx;
u8 pid;
if (le32_get_bits(txs_data[0], MT_TXS0_TXS_FORMAT) > 1)
return;
wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
@@ -1582,6 +1578,12 @@ void mt7915_mac_reset_work(struct work_struct *work)
if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
return;
if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
mtk_wed_device_stop(&dev->mt76.mmio.wed);
if (!is_mt7986(&dev->mt76))
mt76_wr(dev, MT_INT_WED_MASK_CSR, 0);
}
ieee80211_stop_queues(mt76_hw(dev));
if (ext_phy)
ieee80211_stop_queues(ext_phy->hw);

View File

@@ -57,6 +57,17 @@ int mt7915_run(struct ieee80211_hw *hw)
mt7915_mac_enable_nf(dev, phy->mt76->band_idx);
}
ret = mt7915_mcu_set_thermal_throttling(phy,
MT7915_THERMAL_THROTTLE_MAX);
if (ret)
goto out;
ret = mt7915_mcu_set_thermal_protect(phy);
if (ret)
goto out;
ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b,
phy->mt76->band_idx);
if (ret)
@@ -1280,19 +1291,22 @@ void mt7915_get_et_strings(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u32 sset, u8 *data)
{
if (sset == ETH_SS_STATS)
memcpy(data, *mt7915_gstrings_stats,
sizeof(mt7915_gstrings_stats));
if (sset != ETH_SS_STATS)
return;
memcpy(data, *mt7915_gstrings_stats, sizeof(mt7915_gstrings_stats));
data += sizeof(mt7915_gstrings_stats);
page_pool_ethtool_stats_get_strings(data);
}
static
int mt7915_get_et_sset_count(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, int sset)
{
if (sset == ETH_SS_STATS)
return MT7915_SSTATS_LEN;
if (sset != ETH_SS_STATS)
return 0;
return 0;
return MT7915_SSTATS_LEN + page_pool_ethtool_stats_get_count();
}
static void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
@@ -1303,7 +1317,7 @@ static void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
if (msta->vif->mt76.idx != wi->idx)
return;
mt76_ethtool_worker(wi, &msta->wcid.stats);
mt76_ethtool_worker(wi, &msta->wcid.stats, false);
}
static
@@ -1320,7 +1334,7 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,
};
struct mib_stats *mib = &phy->mib;
/* See mt7915_ampdu_stat_read_phy, etc */
int i, ei = 0;
int i, ei = 0, stats_size;
mutex_lock(&dev->mt76.mutex);
@@ -1401,9 +1415,12 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,
return;
ei += wi.worker_stat_count;
if (ei != MT7915_SSTATS_LEN)
dev_err(dev->mt76.dev, "ei: %d MT7915_SSTATS_LEN: %d",
ei, (int)MT7915_SSTATS_LEN);
mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei);
stats_size = MT7915_SSTATS_LEN + page_pool_ethtool_stats_get_count();
if (ei != stats_size)
dev_err(dev->mt76.dev, "ei: %d size: %d", ei, stats_size);
}
static void

View File

@@ -2117,7 +2117,7 @@ static int mt7915_load_firmware(struct mt7915_dev *dev)
/* make sure fw is download state */
if (mt7915_firmware_state(dev, false)) {
/* restart firmware once */
__mt76_mcu_restart(&dev->mt76);
mt76_connac_mcu_restart(&dev->mt76);
ret = mt7915_firmware_state(dev, false);
if (ret) {
dev_err(dev->mt76.dev,
@@ -2291,6 +2291,53 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
sizeof(req), true);
}
static int mt7915_red_set_watermark(struct mt7915_dev *dev)
{
#define RED_GLOBAL_TOKEN_WATERMARK 2
struct {
__le32 args[3];
u8 cmd;
u8 version;
u8 __rsv1[4];
__le16 len;
__le16 high_mark;
__le16 low_mark;
u8 __rsv2[12];
} __packed req = {
.args[0] = cpu_to_le32(MCU_WA_PARAM_RED_SETTING),
.cmd = RED_GLOBAL_TOKEN_WATERMARK,
.len = cpu_to_le16(sizeof(req) - sizeof(req.args)),
.high_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256),
.low_mark = cpu_to_le16(MT7915_HW_TOKEN_SIZE - 256 - 1536),
};
return mt76_mcu_send_msg(&dev->mt76, MCU_WA_PARAM_CMD(SET), &req,
sizeof(req), false);
}
static int mt7915_mcu_set_red(struct mt7915_dev *dev, bool enabled)
{
#define RED_DISABLE 0
#define RED_BY_WA_ENABLE 2
int ret;
u32 red_type = enabled ? RED_BY_WA_ENABLE : RED_DISABLE;
__le32 req = cpu_to_le32(red_type);
if (enabled) {
ret = mt7915_red_set_watermark(dev);
if (ret < 0)
return ret;
}
ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(RED_ENABLE), &req,
sizeof(req), false);
if (ret < 0)
return ret;
return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
MCU_WA_PARAM_RED, enabled, 0);
}
int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
{
int ret;
@@ -2339,8 +2386,7 @@ int mt7915_mcu_init_firmware(struct mt7915_dev *dev)
if (ret)
return ret;
return mt7915_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
MCU_WA_PARAM_RED, 0, 0);
return mt7915_mcu_set_red(dev, mtk_wed_device_active(&dev->mt76.mmio.wed));
}
int mt7915_mcu_init(struct mt7915_dev *dev)
@@ -2349,7 +2395,6 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
.headroom = sizeof(struct mt76_connac2_mcu_txd),
.mcu_skb_send_msg = mt7915_mcu_send_message,
.mcu_parse_response = mt7915_mcu_parse_response,
.mcu_restart = mt76_connac_mcu_restart,
};
dev->mt76.mcu_ops = &mt7915_mcu_ops;
@@ -2359,16 +2404,17 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
void mt7915_mcu_exit(struct mt7915_dev *dev)
{
__mt76_mcu_restart(&dev->mt76);
mt76_connac_mcu_restart(&dev->mt76);
if (mt7915_firmware_state(dev, false)) {
dev_err(dev->mt76.dev, "Failed to exit mcu\n");
return;
goto out;
}
mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN);
if (dev->hif2)
mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1),
MT_TOP_LPCR_HOST_FW_OWN);
out:
skb_queue_purge(&dev->mt76.mcu.res_q);
}
@@ -3077,6 +3123,29 @@ int mt7915_mcu_get_temperature(struct mt7915_phy *phy)
}
int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
{
struct mt7915_dev *dev = phy->dev;
struct mt7915_mcu_thermal_ctrl req = {
.band_idx = phy->mt76->band_idx,
.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG,
};
int level, ret;
/* set duty cycle and level */
for (level = 0; level < 4; level++) {
req.duty.duty_level = level;
req.duty.duty_cycle = state;
state /= 2;
ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
&req, sizeof(req), false);
if (ret)
return ret;
}
return 0;
}
int mt7915_mcu_set_thermal_protect(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
struct {
@@ -3089,29 +3158,18 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
} __packed req = {
.ctrl = {
.band_idx = phy->mt76->band_idx,
.type.protect_type = 1,
.type.trigger_type = 1,
},
};
int level;
int ret;
if (!state) {
req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE;
goto out;
}
req.ctrl.ctrl_id = THERMAL_PROTECT_DISABLE;
ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
&req, sizeof(req.ctrl), false);
/* set duty cycle and level */
for (level = 0; level < 4; level++) {
int ret;
req.ctrl.ctrl_id = THERMAL_PROTECT_DUTY_CONFIG;
req.ctrl.duty.duty_level = level;
req.ctrl.duty.duty_cycle = state;
state /= 2;
ret = mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
&req, sizeof(req.ctrl), false);
if (ret)
return ret;
}
if (ret)
return ret;
/* set high-temperature trigger threshold */
req.ctrl.ctrl_id = THERMAL_PROTECT_ENABLE;
@@ -3120,10 +3178,6 @@ int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state)
req.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
req.sustain_time = cpu_to_le16(10);
out:
req.ctrl.type.protect_type = 1;
req.ctrl.type.trigger_type = 1;
return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_PROT),
&req, sizeof(req), false);
}

View File

@@ -278,6 +278,7 @@ enum {
MCU_WA_PARAM_PDMA_RX = 0x04,
MCU_WA_PARAM_CPU_UTIL = 0x0b,
MCU_WA_PARAM_RED = 0x0e,
MCU_WA_PARAM_RED_SETTING = 0x40,
};
enum mcu_mmps_mode {

View File

@@ -4,10 +4,12 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/rtnetlink.h>
#include <linux/pci.h>
#include "mt7915.h"
#include "mac.h"
#include "mcu.h"
#include "../trace.h"
#include "../dma.h"
@@ -594,13 +596,9 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed)
static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
{
struct mt7915_dev *dev;
u32 length;
int i;
dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
length = SKB_DATA_ALIGN(NET_SKB_PAD + wed->wlan.rx_size +
sizeof(struct skb_shared_info));
for (i = 0; i < dev->mt76.rx_token_size; i++) {
struct mt76_txwi_cache *t;
@@ -608,52 +606,50 @@ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
if (!t || !t->ptr)
continue;
dma_unmap_single(dev->mt76.dma_dev, t->dma_addr,
wed->wlan.rx_size, DMA_FROM_DEVICE);
__free_pages(virt_to_page(t->ptr), get_order(length));
mt76_put_page_pool_buf(t->ptr, false);
t->ptr = NULL;
mt76_put_rxwi(&dev->mt76, t);
}
mt76_free_pending_rxwi(&dev->mt76);
}
static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
{
struct mtk_rxbm_desc *desc = wed->rx_buf_ring.desc;
struct mt76_txwi_cache *t = NULL;
struct mt7915_dev *dev;
u32 length;
int i;
struct mt76_queue *q;
int i, len;
dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
length = SKB_DATA_ALIGN(NET_SKB_PAD + wed->wlan.rx_size +
sizeof(struct skb_shared_info));
q = &dev->mt76.q_rx[MT_RXQ_MAIN];
len = SKB_WITH_OVERHEAD(q->buf_size);
for (i = 0; i < size; i++) {
struct mt76_txwi_cache *t = mt76_get_rxwi(&dev->mt76);
dma_addr_t phy_addr;
struct page *page;
enum dma_data_direction dir;
dma_addr_t addr;
u32 offset;
int token;
void *ptr;
void *buf;
page = __dev_alloc_pages(GFP_KERNEL, get_order(length));
if (!page)
t = mt76_get_rxwi(&dev->mt76);
if (!t)
goto unmap;
ptr = page_address(page);
phy_addr = dma_map_single(dev->mt76.dma_dev, ptr,
wed->wlan.rx_size,
DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev->mt76.dev, phy_addr))) {
__free_pages(page, get_order(length));
buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
if (!buf)
goto unmap;
}
desc->buf0 = cpu_to_le32(phy_addr);
token = mt76_rx_token_consume(&dev->mt76, ptr, t, phy_addr);
addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset;
dir = page_pool_get_dma_dir(q->page_pool);
dma_sync_single_for_device(dev->mt76.dma_dev, addr, len, dir);
desc->buf0 = cpu_to_le32(addr);
token = mt76_rx_token_consume(&dev->mt76, buf, t, addr);
if (token < 0) {
dma_unmap_single(dev->mt76.dma_dev, phy_addr,
wed->wlan.rx_size, DMA_TO_DEVICE);
__free_pages(page, get_order(length));
mt76_put_page_pool_buf(buf, false);
goto unmap;
}
@@ -665,6 +661,8 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
return 0;
unmap:
if (t)
mt76_put_rxwi(&dev->mt76, t);
mt7915_mmio_wed_release_rx_buf(wed);
return -ENOMEM;
}
@@ -693,6 +691,42 @@ static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed,
rcu_read_unlock();
}
static int mt7915_mmio_wed_reset(struct mtk_wed_device *wed)
{
struct mt76_dev *mdev = container_of(wed, struct mt76_dev, mmio.wed);
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
struct mt76_phy *mphy = &dev->mphy;
int ret;
ASSERT_RTNL();
if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state))
return -EBUSY;
ret = mt7915_mcu_set_ser(dev, SER_RECOVER, SER_SET_RECOVER_L1,
mphy->band_idx);
if (ret)
goto out;
rtnl_unlock();
if (!wait_for_completion_timeout(&mdev->mmio.wed_reset, 20 * HZ)) {
dev_err(mdev->dev, "wed reset timeout\n");
ret = -ETIMEDOUT;
}
rtnl_lock();
out:
clear_bit(MT76_STATE_WED_RESET, &mphy->state);
return ret;
}
static void mt7915_mmio_wed_reset_complete(struct mtk_wed_device *wed)
{
struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);
complete(&dev->mmio.wed_reset_complete);
}
#endif
int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
@@ -748,7 +782,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
wed->wlan.wpdma_rx_glo = res->start + MT_WPDMA_GLO_CFG;
wed->wlan.wpdma_rx = res->start + MT_RXQ_WED_DATA_RING_BASE;
}
wed->wlan.nbuf = 4096;
wed->wlan.nbuf = MT7915_HW_TOKEN_SIZE;
wed->wlan.tx_tbit[0] = is_mt7915(&dev->mt76) ? 4 : 30;
wed->wlan.tx_tbit[1] = is_mt7915(&dev->mt76) ? 5 : 31;
wed->wlan.txfree_tbit = is_mt7986(&dev->mt76) ? 2 : 1;
@@ -775,6 +809,8 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
wed->wlan.init_rx_buf = mt7915_mmio_wed_init_rx_buf;
wed->wlan.release_rx_buf = mt7915_mmio_wed_release_rx_buf;
wed->wlan.update_wo_rx_stats = mt7915_mmio_wed_update_rx_stats;
wed->wlan.reset = mt7915_mmio_wed_reset;
wed->wlan.reset_complete = mt7915_mmio_wed_reset_complete;
dev->mt76.rx_token_size = wed->wlan.rx_npkt;

View File

@@ -53,6 +53,7 @@
#define MT7916_EEPROM_SIZE 4096
#define MT7915_EEPROM_BLOCK_SIZE 16
#define MT7915_HW_TOKEN_SIZE 4096
#define MT7915_TOKEN_SIZE 8192
#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
@@ -70,6 +71,11 @@
#define MT7915_WED_RX_TOKEN_SIZE 12288
#define MT7915_CRIT_TEMP_IDX 0
#define MT7915_MAX_TEMP_IDX 1
#define MT7915_CRIT_TEMP 110
#define MT7915_MAX_TEMP 120
struct mt7915_vif;
struct mt7915_sta;
struct mt7915_dfs_pulse;
@@ -543,6 +549,7 @@ int mt7915_mcu_apply_tx_dpd(struct mt7915_phy *phy);
int mt7915_mcu_get_chan_mib_info(struct mt7915_phy *phy, bool chan_switch);
int mt7915_mcu_get_temperature(struct mt7915_phy *phy);
int mt7915_mcu_set_thermal_throttling(struct mt7915_phy *phy, u8 state);
int mt7915_mcu_set_thermal_protect(struct mt7915_phy *phy);
int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct rate_info *rate);
int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,

View File

@@ -883,6 +883,8 @@ static int mt7986_wmac_wm_enable(struct mt7915_dev *dev, bool enable)
{
u32 cur;
mt76_wr(dev, MT_CONNINFRA_SKU_DEC_ADDR, 0);
mt76_rmw_field(dev, MT7986_TOP_WM_RESET,
MT7986_TOP_WM_RESET_MASK, enable);
if (!enable)

View File

@@ -33,14 +33,17 @@ mt7921_acpi_read(struct mt7921_dev *dev, u8 *method, u8 **tbl, u32 *len)
sar_root->package.elements[0].type != ACPI_TYPE_INTEGER) {
dev_err(mdev->dev, "sar cnt = %d\n",
sar_root->package.count);
ret = -EINVAL;
goto free;
}
if (!*tbl) {
*tbl = devm_kzalloc(mdev->dev, sar_root->package.count,
GFP_KERNEL);
if (!*tbl)
if (!*tbl) {
ret = -ENOMEM;
goto free;
}
}
if (len)
*len = sar_root->package.count;
@@ -52,9 +55,9 @@ mt7921_acpi_read(struct mt7921_dev *dev, u8 *method, u8 **tbl, u32 *len)
break;
*(*tbl + i) = (u8)sar_unit->integer.value;
}
free:
ret = (i == sar_root->package.count) ? 0 : -EINVAL;
free:
kfree(sar_root);
return ret;

View File

@@ -120,6 +120,7 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
@@ -142,6 +143,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
static void
mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
{
u32 mask, set;
mt76_rmw_field(dev, MT_TMAC_CTCR0(band),
MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
mt76_set(dev, MT_TMAC_CTCR0(band),
@@ -158,6 +161,12 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
mt76_rmw_field(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_MAX_RX_LEN, 1536);
/* disable rx rate report by default due to hw issues */
mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
/* filter out non-resp frames and get instantaneous signal reporting */
mask = MT_WTBLOFF_TOP_RSCR_RCPI_MODE | MT_WTBLOFF_TOP_RSCR_RCPI_PARAM;
set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) |
FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3);
mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
}
u8 mt7921_check_offload_capability(struct device *dev, const char *fw_wm)
@@ -229,8 +238,6 @@ int mt7921_mac_init(struct mt7921_dev *dev)
for (i = 0; i < 2; i++)
mt7921_mac_init_band(dev, i);
dev->mt76.rxfilter = mt76_rr(dev, MT_WF_RFCR(0));
return mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b, 0);
}
EXPORT_SYMBOL_GPL(mt7921_mac_init);

View File

@@ -59,6 +59,7 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
LIST_HEAD(sta_poll_list);
struct rate_info *rate;
s8 rssi[4];
int i;
spin_lock_bh(&dev->sta_poll_lock);
@@ -160,6 +161,20 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)
else
rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
}
/* get signal strength of resp frames (CTS/BA/ACK) */
addr = mt7921_mac_wtbl_lmac_addr(idx, 30);
val = mt76_rr(dev, addr);
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);
msta->ack_signal =
mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
}
}
EXPORT_SYMBOL_GPL(mt7921_mac_sta_poll);

View File

@@ -422,15 +422,15 @@ void mt7921_roc_timer(struct timer_list *timer)
static int mt7921_abort_roc(struct mt7921_phy *phy, struct mt7921_vif *vif)
{
int err;
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
return 0;
int err = 0;
del_timer_sync(&phy->roc_timer);
cancel_work_sync(&phy->roc_work);
err = mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
clear_bit(MT76_STATE_ROC, &phy->mt76->state);
mt7921_mutex_acquire(phy->dev);
if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
err = mt7921_mcu_abort_roc(phy, vif, phy->roc_token_id);
mt7921_mutex_release(phy->dev);
return err;
}
@@ -487,13 +487,8 @@ static int mt7921_cancel_remain_on_channel(struct ieee80211_hw *hw,
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
struct mt7921_phy *phy = mt7921_hw_phy(hw);
int err;
mt7921_mutex_acquire(phy->dev);
err = mt7921_abort_roc(phy, mvif);
mt7921_mutex_release(phy->dev);
return err;
return mt7921_abort_roc(phy, mvif);
}
static int mt7921_set_channel(struct mt7921_phy *phy)
@@ -681,7 +676,6 @@ static int mt7921_config(struct ieee80211_hw *hw, u32 changed)
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_sniffer_interface_iter, dev);
dev->mt76.rxfilter = mt76_rr(dev, MT_WF_RFCR(0));
}
out:
@@ -710,53 +704,12 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
u64 multicast)
{
struct mt7921_dev *dev = mt7921_hw_dev(hw);
u32 ctl_flags = MT_WF_RFCR1_DROP_ACK |
MT_WF_RFCR1_DROP_BF_POLL |
MT_WF_RFCR1_DROP_BA |
MT_WF_RFCR1_DROP_CFEND |
MT_WF_RFCR1_DROP_CFACK;
u32 flags = 0;
#define MT76_FILTER(_flag, _hw) do { \
flags |= *total_flags & FIF_##_flag; \
dev->mt76.rxfilter &= ~(_hw); \
dev->mt76.rxfilter |= !(flags & FIF_##_flag) * (_hw); \
} while (0)
mt7921_mutex_acquire(dev);
dev->mt76.rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS |
MT_WF_RFCR_DROP_OTHER_BEACON |
MT_WF_RFCR_DROP_FRAME_REPORT |
MT_WF_RFCR_DROP_PROBEREQ |
MT_WF_RFCR_DROP_MCAST_FILTERED |
MT_WF_RFCR_DROP_MCAST |
MT_WF_RFCR_DROP_BCAST |
MT_WF_RFCR_DROP_DUPLICATE |
MT_WF_RFCR_DROP_A2_BSSID |
MT_WF_RFCR_DROP_UNWANTED_CTL |
MT_WF_RFCR_DROP_STBC_MULTI);
MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM |
MT_WF_RFCR_DROP_A3_MAC |
MT_WF_RFCR_DROP_A3_BSSID);
MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL);
MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS |
MT_WF_RFCR_DROP_RTS |
MT_WF_RFCR_DROP_CTL_RSV |
MT_WF_RFCR_DROP_NDPA);
*total_flags = flags;
mt76_wr(dev, MT_WF_RFCR(0), dev->mt76.rxfilter);
if (*total_flags & FIF_CONTROL)
mt76_clear(dev, MT_WF_RFCR1(0), ctl_flags);
else
mt76_set(dev, MT_WF_RFCR1(0), ctl_flags);
mt7921_mcu_set_rxfilter(dev, *total_flags, 0, 0);
mt7921_mutex_release(dev);
*total_flags &= (FIF_OTHER_BSS | FIF_FCSFAIL | FIF_CONTROL);
}
static void mt7921_bss_info_changed(struct ieee80211_hw *hw,
@@ -860,6 +813,8 @@ void mt7921_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt76_connac_mcu_uni_add_bss(&dev->mphy, vif, &mvif->sta.wcid,
true, mvif->ctx);
ewma_avg_signal_init(&msta->avg_ack_signal);
mt7921_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
memset(msta->airtime_ac, 0, sizeof(msta->airtime_ac));
@@ -1135,17 +1090,34 @@ static void
mt7921_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 sset, u8 *data)
{
struct mt7921_dev *dev = mt7921_hw_dev(hw);
if (sset != ETH_SS_STATS)
return;
memcpy(data, *mt7921_gstrings_stats, sizeof(mt7921_gstrings_stats));
if (mt76_is_sdio(&dev->mt76))
return;
data += sizeof(mt7921_gstrings_stats);
page_pool_ethtool_stats_get_strings(data);
}
static int
mt7921_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int sset)
{
return sset == ETH_SS_STATS ? ARRAY_SIZE(mt7921_gstrings_stats) : 0;
struct mt7921_dev *dev = mt7921_hw_dev(hw);
if (sset != ETH_SS_STATS)
return 0;
if (mt76_is_sdio(&dev->mt76))
return ARRAY_SIZE(mt7921_gstrings_stats);
return ARRAY_SIZE(mt7921_gstrings_stats) +
page_pool_ethtool_stats_get_count();
}
static void
@@ -1157,7 +1129,7 @@ mt7921_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
if (msta->vif->mt76.idx != wi->idx)
return;
mt76_ethtool_worker(wi, &msta->wcid.stats);
mt76_ethtool_worker(wi, &msta->wcid.stats, false);
}
static
@@ -1165,6 +1137,7 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data)
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
int stats_size = ARRAY_SIZE(mt7921_gstrings_stats);
struct mt7921_phy *phy = mt7921_hw_phy(hw);
struct mt7921_dev *dev = phy->dev;
struct mib_stats *mib = &phy->mib;
@@ -1220,9 +1193,14 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return;
ei += wi.worker_stat_count;
if (ei != ARRAY_SIZE(mt7921_gstrings_stats))
dev_err(dev->mt76.dev, "ei: %d SSTATS_LEN: %zu",
ei, ARRAY_SIZE(mt7921_gstrings_stats));
if (!mt76_is_sdio(&dev->mt76)) {
mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei);
stats_size += page_pool_ethtool_stats_get_count();
}
if (ei != stats_size)
dev_err(dev->mt76.dev, "ei: %d SSTATS_LEN: %d", ei, stats_size);
}
static u64
@@ -1430,6 +1408,12 @@ static void mt7921_sta_statistics(struct ieee80211_hw *hw,
}
sinfo->txrate.flags = txrate->flags;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
sinfo->ack_signal = (s8)msta->ack_signal;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal);
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
}
#ifdef CONFIG_PM
@@ -1711,7 +1695,10 @@ static void mt7921_ctx_iter(void *priv, u8 *mac,
if (ctx != mvif->ctx)
return;
mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->mt76, ctx);
if (vif->type & NL80211_IFTYPE_MONITOR)
mt7921_mcu_config_sniffer(mvif, ctx);
else
mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->mt76, ctx);
}
static void
@@ -1778,11 +1765,8 @@ static void mt7921_mgd_complete_tx(struct ieee80211_hw *hw,
struct ieee80211_prep_tx_info *info)
{
struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
struct mt7921_dev *dev = mt7921_hw_dev(hw);
mt7921_mutex_acquire(dev);
mt7921_abort_roc(mvif->phy, mvif);
mt7921_mutex_release(dev);
}
const struct ieee80211_ops mt7921_ops = {

View File

@@ -174,7 +174,7 @@ mt7921_mcu_uni_roc_event(struct mt7921_dev *dev, struct sk_buff *skb)
wake_up(&dev->phy.roc_wait);
duration = le32_to_cpu(grant->max_interval);
mod_timer(&dev->phy.roc_timer,
round_jiffies_up(jiffies + msecs_to_jiffies(duration)));
jiffies + msecs_to_jiffies(duration));
}
static void
@@ -1019,6 +1019,8 @@ int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
struct ieee80211_vif *vif,
bool enable)
{
#define MT7921_FIF_BIT_CLR BIT(1)
#define MT7921_FIF_BIT_SET BIT(0)
int err;
if (enable) {
@@ -1026,7 +1028,11 @@ int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
if (err)
return err;
mt76_set(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
err = mt7921_mcu_set_rxfilter(dev, 0,
MT7921_FIF_BIT_SET,
MT_WF_RFCR_DROP_OTHER_BEACON);
if (err)
return err;
return 0;
}
@@ -1035,7 +1041,11 @@ int mt7921_mcu_set_beacon_filter(struct mt7921_dev *dev,
if (err)
return err;
mt76_clear(dev, MT_WF_RFCR(0), MT_WF_RFCR_DROP_OTHER_BEACON);
err = mt7921_mcu_set_rxfilter(dev, 0,
MT7921_FIF_BIT_CLR,
MT_WF_RFCR_DROP_OTHER_BEACON);
if (err)
return err;
return 0;
}
@@ -1093,6 +1103,74 @@ int mt7921_mcu_set_sniffer(struct mt7921_dev *dev, struct ieee80211_vif *vif,
true);
}
int mt7921_mcu_config_sniffer(struct mt7921_vif *vif,
struct ieee80211_chanctx_conf *ctx)
{
struct cfg80211_chan_def *chandef = &ctx->def;
int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
const u8 ch_band[] = {
[NL80211_BAND_2GHZ] = 1,
[NL80211_BAND_5GHZ] = 2,
[NL80211_BAND_6GHZ] = 3,
};
const u8 ch_width[] = {
[NL80211_CHAN_WIDTH_20_NOHT] = 0,
[NL80211_CHAN_WIDTH_20] = 0,
[NL80211_CHAN_WIDTH_40] = 0,
[NL80211_CHAN_WIDTH_80] = 1,
[NL80211_CHAN_WIDTH_160] = 2,
[NL80211_CHAN_WIDTH_80P80] = 3,
[NL80211_CHAN_WIDTH_5] = 4,
[NL80211_CHAN_WIDTH_10] = 5,
[NL80211_CHAN_WIDTH_320] = 6,
};
struct {
struct {
u8 band_idx;
u8 pad[3];
} __packed hdr;
struct config_tlv {
__le16 tag;
__le16 len;
u16 aid;
u8 ch_band;
u8 bw;
u8 control_ch;
u8 sco;
u8 center_ch;
u8 center_ch2;
u8 drop_err;
u8 pad[3];
} __packed tlv;
} __packed req = {
.hdr = {
.band_idx = vif->mt76.band_idx,
},
.tlv = {
.tag = cpu_to_le16(1),
.len = cpu_to_le16(sizeof(req.tlv)),
.control_ch = chandef->chan->hw_value,
.center_ch = ieee80211_frequency_to_channel(freq1),
.drop_err = 1,
},
};
if (chandef->chan->band < ARRAY_SIZE(ch_band))
req.tlv.ch_band = ch_band[chandef->chan->band];
if (chandef->width < ARRAY_SIZE(ch_width))
req.tlv.bw = ch_width[chandef->width];
if (freq2)
req.tlv.center_ch2 = ieee80211_frequency_to_channel(freq2);
if (req.tlv.control_ch < req.tlv.center_ch)
req.tlv.sco = 1; /* SCA */
else if (req.tlv.control_ch > req.tlv.center_ch)
req.tlv.sco = 3; /* SCB */
return mt76_mcu_send_msg(vif->phy->mt76->dev, MCU_UNI_CMD(SNIFFER),
&req, sizeof(req), true);
}
int
mt7921_mcu_uni_add_beacon_offload(struct mt7921_dev *dev,
struct ieee80211_hw *hw,
@@ -1255,3 +1333,25 @@ int mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2,
}
return 0;
}
int mt7921_mcu_set_rxfilter(struct mt7921_dev *dev, u32 fif,
u8 bit_op, u32 bit_map)
{
struct {
u8 rsv[4];
u8 mode;
u8 rsv2[3];
__le32 fif;
__le32 bit_map; /* bit_* for bitmap update */
u8 bit_op;
u8 pad[51];
} __packed data = {
.mode = fif ? 1 : 2,
.fif = cpu_to_le32(fif),
.bit_map = cpu_to_le32(bit_map),
.bit_op = bit_op,
};
return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_RX_FILTER),
&data, sizeof(data), false);
}

View File

@@ -144,6 +144,8 @@ enum mt7921_rxq_id {
MT7921_RXQ_MCU_WM = 0,
};
DECLARE_EWMA(avg_signal, 10, 8)
struct mt7921_sta {
struct mt76_wcid wcid; /* must be first */
@@ -152,6 +154,9 @@ struct mt7921_sta {
struct list_head poll_list;
u32 airtime_ac[8];
int ack_signal;
struct ewma_avg_signal avg_ack_signal;
unsigned long last_txs;
unsigned long ampdu_state;
@@ -383,6 +388,8 @@ int mt7921_mcu_get_rx_rate(struct mt7921_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct rate_info *rate);
int mt7921_mcu_fw_log_2_host(struct mt7921_dev *dev, u8 ctrl);
void mt7921_mcu_rx_event(struct mt7921_dev *dev, struct sk_buff *skb);
int mt7921_mcu_set_rxfilter(struct mt7921_dev *dev, u32 fif,
u8 bit_op, u32 bit_map);
static inline void mt7921_irq_enable(struct mt7921_dev *dev, u32 mask)
{
@@ -529,6 +536,8 @@ void mt7921_set_ipv6_ns_work(struct work_struct *work);
int mt7921_mcu_set_sniffer(struct mt7921_dev *dev, struct ieee80211_vif *vif,
bool enable);
int mt7921_mcu_config_sniffer(struct mt7921_vif *vif,
struct ieee80211_chanctx_conf *ctx);
int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,

View File

@@ -44,7 +44,6 @@ int mt7921e_mcu_init(struct mt7921_dev *dev)
.headroom = sizeof(struct mt76_connac2_mcu_txd),
.mcu_skb_send_msg = mt7921_mcu_send_message,
.mcu_parse_response = mt7921_mcu_parse_response,
.mcu_restart = mt76_connac_mcu_restart,
};
int err;
@@ -69,8 +68,8 @@ int __mt7921e_mcu_drv_pmctrl(struct mt7921_dev *dev)
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_CLR_OWN);
if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
PCIE_LPCR_HOST_OWN_SYNC, 0, 50))
if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL,
PCIE_LPCR_HOST_OWN_SYNC, 0, 50, 1))
break;
}
@@ -110,8 +109,8 @@ int mt7921e_mcu_fw_pmctrl(struct mt7921_dev *dev)
for (i = 0; i < MT7921_DRV_OWN_RETRY_COUNT; i++) {
mt76_wr(dev, MT_CONN_ON_LPCTL, PCIE_LPCR_HOST_SET_OWN);
if (mt76_poll_msec(dev, MT_CONN_ON_LPCTL,
PCIE_LPCR_HOST_OWN_SYNC, 4, 50))
if (mt76_poll_msec_tick(dev, MT_CONN_ON_LPCTL,
PCIE_LPCR_HOST_OWN_SYNC, 4, 50, 1))
break;
}

View File

@@ -80,6 +80,14 @@
#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3)
#define MT_DMA_DCR0_RXD_G5_EN BIT(23)
/* WTBLOFF TOP: band 0(0x820e9000),band 1(0x820f9000) */
#define MT_WTBLOFF_TOP_BASE(_band) ((_band) ? 0x820f9000 : 0x820e9000)
#define MT_WTBLOFF_TOP(_band, ofs) (MT_WTBLOFF_TOP_BASE(_band) + (ofs))
#define MT_WTBLOFF_TOP_RSCR(_band) MT_WTBLOFF_TOP(_band, 0x008)
#define MT_WTBLOFF_TOP_RSCR_RCPI_MODE GENMASK(31, 30)
#define MT_WTBLOFF_TOP_RSCR_RCPI_PARAM GENMASK(25, 24)
/* LPON: band 0(0x24200), band 1(0xa4200) */
#define MT_WF_LPON_BASE(_band) ((_band) ? 0x820fb000 : 0x820eb000)
#define MT_WF_LPON(_band, ofs) (MT_WF_LPON_BASE(_band) + (ofs))

View File

@@ -59,7 +59,6 @@ mt7921_tm_set(struct mt7921_dev *dev, struct mt7921_tm_cmd *req)
cancel_work_sync(&pm->wake_work);
__mt7921_mcu_drv_pmctrl(dev);
mt76_wr(dev, MT_WF_RFCR(0), dev->mt76.rxfilter);
phy->test.state = MT76_TM_STATE_ON;
}

View File

@@ -15,6 +15,9 @@
static const struct usb_device_id mt7921u_device_table[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
/* Comfast CF-952AX */
{ USB_DEVICE_AND_INTERFACE_INFO(0x3574, 0x6211, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
{ },
};
@@ -133,7 +136,6 @@ static int mt7921u_mcu_init(struct mt7921_dev *dev)
.tailroom = MT_USB_TAIL_SIZE,
.mcu_skb_send_msg = mt7921u_mcu_send_message,
.mcu_parse_response = mt7921_mcu_parse_response,
.mcu_restart = mt76_connac_mcu_restart,
};
int ret;

View File

@@ -791,10 +791,10 @@ static ssize_t mt7996_sta_fixed_rate_set(struct file *file,
else
buf[count] = '\0';
/* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9
* bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3
* nss - vht: 1~4, he: 1~4, others: ignore
* mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2
/* mode - cck: 0, ofdm: 1, ht: 2, gf: 3, vht: 4, he_su: 8, he_er: 9 EHT: 15
* bw - bw20: 0, bw40: 1, bw80: 2, bw160: 3, BW320: 4
* nss - vht: 1~4, he: 1~4, eht: 1~4, others: ignore
* mcs - cck: 0~4, ofdm: 0~7, ht: 0~32, vht: 0~9, he_su: 0~11, he_er: 0~2, eht: 0~13
* gi - (ht/vht) lgi: 0, sgi: 1; (he) 0.8us: 0, 1.6us: 1, 3.2us: 2
* preamble - short: 1, long: 0
* ldpc - off: 0, on: 1

View File

@@ -87,6 +87,28 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
return mt7996_check_eeprom(dev);
}
static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
{
#define MODE_HE_ONLY BIT(0)
#define WTBL_SIZE_GROUP GENMASK(31, 28)
u32 cap = 0;
int ret;
ret = mt7996_mcu_get_chip_config(dev, &cap);
if (ret)
return ret;
if (cap) {
dev->has_eht = !(cap & MODE_HE_ONLY);
dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP);
}
if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4)
dev->wtbl_size_group = 2; /* set default */
return 0;
}
static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy)
{
u8 *eeprom = phy->dev->mt76.eeprom.data;
@@ -133,6 +155,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
u8 path, nss, band_idx = phy->mt76->band_idx;
u8 *eeprom = dev->mt76.eeprom.data;
struct mt76_phy *mphy = phy->mt76;
int ret;
switch (band_idx) {
case MT_BAND1:
@@ -167,6 +190,10 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
dev->chainshift[band_idx + 1] = dev->chainshift[band_idx] +
hweight16(mphy->chainmask);
ret = mt7996_eeprom_parse_efuse_hw_cap(dev);
if (ret)
return ret;
return mt7996_eeprom_parse_band_config(phy);
}

View File

@@ -37,8 +37,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160) |
BIT(NL80211_CHAN_WIDTH_80P80),
BIT(NL80211_CHAN_WIDTH_160),
}
};
@@ -153,10 +152,12 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mt76_dev *mdev = &phy->dev->mt76;
struct wiphy *wiphy = hw->wiphy;
u16 max_subframes = phy->dev->has_eht ? IEEE80211_MAX_AMPDU_BUF_EHT :
IEEE80211_MAX_AMPDU_BUF_HE;
hw->queues = 4;
hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF_HE;
hw->max_rx_aggregation_subframes = max_subframes;
hw->max_tx_aggregation_subframes = max_subframes;
hw->netdev_features = NETIF_F_RXCSUM;
hw->radiotap_timestamp.units_pos =
@@ -214,7 +215,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
mt76_set_stream_caps(phy->mt76, true);
mt7996_set_stream_vht_txbf_caps(phy);
mt7996_set_stream_he_caps(phy);
mt7996_set_stream_he_eht_caps(phy);
wiphy->available_antennas_rx = phy->mt76->antenna_mask;
wiphy->available_antennas_tx = phy->mt76->antenna_mask;
@@ -256,7 +257,7 @@ static void mt7996_mac_init(struct mt7996_dev *dev)
mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT);
for (i = 0; i < MT7996_WTBL_SIZE; i++)
for (i = 0; i < mt7996_wtbl_size(dev); i++)
mt7996_mac_wtbl_update(dev, i,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -465,7 +466,7 @@ void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy)
*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
(3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, sts - 1);
*cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK |
IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
@@ -572,11 +573,15 @@ mt7996_gen_ppe_thresh(u8 *he_ppet, int nss)
(0xff >> (8 - (ppet_bits - 1) % 8));
}
static int
static void
mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
struct ieee80211_sband_iftype_data *data)
struct ieee80211_sband_iftype_data *data,
enum nl80211_iftype iftype)
{
int i, idx = 0, nss = hweight8(phy->mt76->antenna_mask);
struct ieee80211_sta_he_cap *he_cap = &data->he_cap;
struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem;
struct ieee80211_he_mcs_nss_supp *he_mcs = &he_cap->he_mcs_nss_supp;
int i, nss = hweight8(phy->mt76->antenna_mask);
u16 mcs_map = 0;
for (i = 0; i < 8; i++) {
@@ -586,13 +591,219 @@ mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
mcs_map |= (IEEE80211_HE_MCS_NOT_SUPPORTED << (i * 2));
}
for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
struct ieee80211_sta_he_cap *he_cap = &data[idx].he_cap;
struct ieee80211_he_cap_elem *he_cap_elem =
&he_cap->he_cap_elem;
struct ieee80211_he_mcs_nss_supp *he_mcs =
&he_cap->he_mcs_nss_supp;
he_cap->has_he = true;
he_cap_elem->mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE;
he_cap_elem->mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3;
he_cap_elem->mac_cap_info[4] = IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU;
if (band == NL80211_BAND_2GHZ)
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
else
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G;
he_cap_elem->phy_cap_info[1] = IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
he_cap_elem->phy_cap_info[2] = IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
switch (iftype) {
case NL80211_IFTYPE_AP:
he_cap_elem->mac_cap_info[0] |= IEEE80211_HE_MAC_CAP0_TWT_RES;
he_cap_elem->mac_cap_info[2] |= IEEE80211_HE_MAC_CAP2_BSR;
he_cap_elem->mac_cap_info[4] |= IEEE80211_HE_MAC_CAP4_BQR;
he_cap_elem->mac_cap_info[5] |=
IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX;
he_cap_elem->phy_cap_info[3] |=
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
he_cap_elem->phy_cap_info[6] |=
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
break;
case NL80211_IFTYPE_STATION:
he_cap_elem->mac_cap_info[1] |=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
if (band == NL80211_BAND_2GHZ)
he_cap_elem->phy_cap_info[0] |=
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
else
he_cap_elem->phy_cap_info[0] |=
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G;
he_cap_elem->phy_cap_info[1] |=
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
he_cap_elem->phy_cap_info[3] |=
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
he_cap_elem->phy_cap_info[6] |=
IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
he_cap_elem->phy_cap_info[7] |=
IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
he_cap_elem->phy_cap_info[8] |=
IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU |
IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484;
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB;
break;
default:
break;
}
he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map);
mt7996_set_stream_he_txbf_caps(phy, he_cap, iftype);
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
mt7996_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
u8_encode_bits(IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US,
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_MASK);
}
if (band == NL80211_BAND_6GHZ) {
u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2,
IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
u16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454,
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
data->he_6ghz_capa.capa = cpu_to_le16(cap);
}
}
static void
mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,
struct ieee80211_sband_iftype_data *data,
enum nl80211_iftype iftype)
{
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;
if (!phy->dev->has_eht)
return;
eht_cap->has_eht = true;
eht_cap_elem->mac_cap_info[0] =
IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS |
IEEE80211_EHT_MAC_CAP0_OM_CONTROL;
eht_cap_elem->phy_cap_info[0] =
IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ |
IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI |
IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER |
IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE;
eht_cap_elem->phy_cap_info[0] |=
u8_encode_bits(u8_get_bits(sts - 1, 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)),
IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) |
u8_encode_bits(sts - 1,
IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK) |
u8_encode_bits(sts - 1,
IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK);
eht_cap_elem->phy_cap_info[2] =
u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK) |
u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK) |
u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK);
eht_cap_elem->phy_cap_info[3] =
IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK |
IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK |
IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK |
IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK |
IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK |
IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK |
IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK;
eht_cap_elem->phy_cap_info[4] =
u8_encode_bits(min_t(int, sts - 1, 2),
IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK);
eht_cap_elem->phy_cap_info[5] =
IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK |
u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US,
IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK) |
u8_encode_bits(u8_get_bits(0x11, 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(u8_get_bits(0x11, GENMASK(4, 2)),
IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK) |
u8_encode_bits(val, IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK);
eht_cap_elem->phy_cap_info[7] =
IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ |
IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ |
IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ |
IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ |
IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ |
IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ;
val = u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_RX) |
u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_TX);
#define SET_EHT_MAX_NSS(_bw, _val) do { \
eht_nss->bw._##_bw.rx_tx_mcs9_max_nss = _val; \
eht_nss->bw._##_bw.rx_tx_mcs11_max_nss = _val; \
eht_nss->bw._##_bw.rx_tx_mcs13_max_nss = _val; \
} while (0)
SET_EHT_MAX_NSS(80, val);
SET_EHT_MAX_NSS(160, val);
SET_EHT_MAX_NSS(320, val);
#undef SET_EHT_MAX_NSS
}
static void
__mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy,
struct ieee80211_supported_band *sband,
enum nl80211_band band)
{
struct ieee80211_sband_iftype_data *data = phy->iftype[band];
int i, n = 0;
for (i = 0; i < NUM_NL80211_IFTYPES; i++) {
switch (i) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_AP:
@@ -604,161 +815,30 @@ mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
continue;
}
data[idx].types_mask = BIT(i);
he_cap->has_he = true;
data[n].types_mask = BIT(i);
mt7996_init_he_caps(phy, band, &data[n], i);
mt7996_init_eht_caps(phy, band, &data[n], i);
he_cap_elem->mac_cap_info[0] =
IEEE80211_HE_MAC_CAP0_HTC_HE;
he_cap_elem->mac_cap_info[3] =
IEEE80211_HE_MAC_CAP3_OMI_CONTROL |
IEEE80211_HE_MAC_CAP3_MAX_AMPDU_LEN_EXP_EXT_3;
he_cap_elem->mac_cap_info[4] =
IEEE80211_HE_MAC_CAP4_AMSDU_IN_AMPDU;
if (band == NL80211_BAND_2GHZ)
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G;
else
he_cap_elem->phy_cap_info[0] =
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G;
he_cap_elem->phy_cap_info[1] =
IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD;
he_cap_elem->phy_cap_info[2] =
IEEE80211_HE_PHY_CAP2_STBC_TX_UNDER_80MHZ |
IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ;
switch (i) {
case NL80211_IFTYPE_AP:
he_cap_elem->mac_cap_info[0] |=
IEEE80211_HE_MAC_CAP0_TWT_RES;
he_cap_elem->mac_cap_info[2] |=
IEEE80211_HE_MAC_CAP2_BSR;
he_cap_elem->mac_cap_info[4] |=
IEEE80211_HE_MAC_CAP4_BQR;
he_cap_elem->mac_cap_info[5] |=
IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX;
he_cap_elem->phy_cap_info[3] |=
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
he_cap_elem->phy_cap_info[6] |=
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU;
break;
case NL80211_IFTYPE_STATION:
he_cap_elem->mac_cap_info[1] |=
IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US;
if (band == NL80211_BAND_2GHZ)
he_cap_elem->phy_cap_info[0] |=
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_2G;
else
he_cap_elem->phy_cap_info[0] |=
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G;
he_cap_elem->phy_cap_info[1] |=
IEEE80211_HE_PHY_CAP1_DEVICE_CLASS_A |
IEEE80211_HE_PHY_CAP1_HE_LTF_AND_GI_FOR_HE_PPDUS_0_8US;
he_cap_elem->phy_cap_info[3] |=
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_QPSK |
IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_QPSK;
he_cap_elem->phy_cap_info[6] |=
IEEE80211_HE_PHY_CAP6_TRIG_CQI_FB |
IEEE80211_HE_PHY_CAP6_PARTIAL_BW_EXT_RANGE |
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT;
he_cap_elem->phy_cap_info[7] |=
IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP |
IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI;
he_cap_elem->phy_cap_info[8] |=
IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G |
IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU |
IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU |
IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_484;
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_LONGER_THAN_16_SIGB_OFDM_SYM |
IEEE80211_HE_PHY_CAP9_NON_TRIGGERED_CQI_FEEDBACK |
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_1024_QAM_LESS_THAN_242_TONE_RU |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_COMP_SIGB |
IEEE80211_HE_PHY_CAP9_RX_FULL_BW_SU_USING_MU_WITH_NON_COMP_SIGB;
break;
}
he_mcs->rx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_80 = cpu_to_le16(mcs_map);
he_mcs->rx_mcs_160 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_160 = cpu_to_le16(mcs_map);
he_mcs->rx_mcs_80p80 = cpu_to_le16(mcs_map);
he_mcs->tx_mcs_80p80 = cpu_to_le16(mcs_map);
mt7996_set_stream_he_txbf_caps(phy, he_cap, i);
memset(he_cap->ppe_thres, 0, sizeof(he_cap->ppe_thres));
if (he_cap_elem->phy_cap_info[6] &
IEEE80211_HE_PHY_CAP6_PPE_THRESHOLD_PRESENT) {
mt7996_gen_ppe_thresh(he_cap->ppe_thres, nss);
} else {
he_cap_elem->phy_cap_info[9] |=
IEEE80211_HE_PHY_CAP9_NOMINAL_PKT_PADDING_16US;
}
if (band == NL80211_BAND_6GHZ) {
u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2,
IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
u16_encode_bits(IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454,
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN);
data[idx].he_6ghz_capa.capa = cpu_to_le16(cap);
}
idx++;
n++;
}
return idx;
sband->iftype_data = data;
sband->n_iftype_data = n;
}
void mt7996_set_stream_he_caps(struct mt7996_phy *phy)
void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy)
{
struct ieee80211_sband_iftype_data *data;
struct ieee80211_supported_band *band;
int n;
if (phy->mt76->cap.has_2ghz)
__mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_2g.sband,
NL80211_BAND_2GHZ);
if (phy->mt76->cap.has_2ghz) {
data = phy->iftype[NL80211_BAND_2GHZ];
n = mt7996_init_he_caps(phy, NL80211_BAND_2GHZ, data);
if (phy->mt76->cap.has_5ghz)
__mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_5g.sband,
NL80211_BAND_5GHZ);
band = &phy->mt76->sband_2g.sband;
band->iftype_data = data;
band->n_iftype_data = n;
}
if (phy->mt76->cap.has_5ghz) {
data = phy->iftype[NL80211_BAND_5GHZ];
n = mt7996_init_he_caps(phy, NL80211_BAND_5GHZ, data);
band = &phy->mt76->sband_5g.sband;
band->iftype_data = data;
band->n_iftype_data = n;
}
if (phy->mt76->cap.has_6ghz) {
data = phy->iftype[NL80211_BAND_6GHZ];
n = mt7996_init_he_caps(phy, NL80211_BAND_6GHZ, data);
band = &phy->mt76->sband_6g.sband;
band->iftype_data = data;
band->n_iftype_data = n;
}
if (phy->mt76->cap.has_6ghz)
__mt7996_set_stream_he_eht_caps(phy, &phy->mt76->sband_6g.sband,
NL80211_BAND_6GHZ);
}
int mt7996_register_device(struct mt7996_dev *dev)

View File

@@ -189,6 +189,9 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
rate = &msta->wcid.rate;
switch (rate->bw) {
case RATE_INFO_BW_320:
bw = IEEE80211_STA_RX_BW_320;
break;
case RATE_INFO_BW_160:
bw = IEEE80211_STA_RX_BW_160;
break;
@@ -205,7 +208,11 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6);
val = mt76_rr(dev, addr);
if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {
addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5);
val = mt76_rr(dev, addr);
rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);
} else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
u8 offs = 24 + 2 * bw;
rate->he_gi = (val & (0x3 << offs)) >> offs;
@@ -469,7 +476,7 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
ether_addr_copy(hdr.addr4, eth_hdr->h_source);
break;
default:
break;
return -EINVAL;
}
skb_pull(skb, hdr_gap + sizeof(struct ethhdr) - 2);
@@ -560,6 +567,15 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
status->he_dcm = dcm;
break;
case MT_PHY_TYPE_EHT_SU:
case MT_PHY_TYPE_EHT_TRIG:
case MT_PHY_TYPE_EHT_MU:
/* TODO: currently report rx rate with HE rate */
status->nss = nss;
status->encoding = RX_ENC_HE;
bw = min_t(int, bw, IEEE80211_STA_RX_BW_160);
i = min_t(int, i & 0xf, 11);
break;
default:
return -EINVAL;
}
@@ -584,6 +600,9 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
case IEEE80211_STA_RX_BW_160:
status->bw = RATE_INFO_BW_160;
break;
case IEEE80211_STA_RX_BW_320:
status->bw = RATE_INFO_BW_320;
break;
default:
return -EINVAL;
}
@@ -959,51 +978,6 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
}
}
static u16
mt7996_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif,
bool beacon, bool mcast)
{
u8 mode = 0, band = mphy->chandef.chan->band;
int rateidx = 0, mcast_rate;
if (beacon) {
struct cfg80211_bitrate_mask *mask;
mask = &vif->bss_conf.beacon_tx_rate;
if (hweight16(mask->control[band].he_mcs[0]) == 1) {
rateidx = ffs(mask->control[band].he_mcs[0]) - 1;
mode = MT_PHY_TYPE_HE_SU;
goto out;
} else if (hweight16(mask->control[band].vht_mcs[0]) == 1) {
rateidx = ffs(mask->control[band].vht_mcs[0]) - 1;
mode = MT_PHY_TYPE_VHT;
goto out;
} else if (hweight8(mask->control[band].ht_mcs[0]) == 1) {
rateidx = ffs(mask->control[band].ht_mcs[0]) - 1;
mode = MT_PHY_TYPE_HT;
goto out;
} else if (hweight32(mask->control[band].legacy) == 1) {
rateidx = ffs(mask->control[band].legacy) - 1;
goto legacy;
}
}
mcast_rate = vif->bss_conf.mcast_rate[band];
if (mcast && mcast_rate > 0)
rateidx = mcast_rate - 1;
else
rateidx = ffs(vif->bss_conf.basic_rates) - 1;
legacy:
rateidx = mt76_calculate_default_rate(mphy, rateidx);
mode = rateidx >> 8;
rateidx &= GENMASK(7, 0);
out:
return FIELD_PREP(MT_TX_RATE_IDX, rateidx) |
FIELD_PREP(MT_TX_RATE_MODE, mode);
}
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
struct ieee80211_key_conf *key, u32 changed)
@@ -1091,7 +1065,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
/* Fixed rata is available just for 802.11 txd */
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
bool multicast = is_multicast_ether_addr(hdr->addr1);
u16 rate = mt7996_mac_tx_rate_val(mphy, vif, beacon, multicast);
u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon,
multicast);
/* fix to bw 20 */
val = MT_TXD6_FIXED_BW |
@@ -1113,8 +1088,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
struct ieee80211_key_conf *key = info->control.hw_key;
struct ieee80211_vif *vif = info->control.vif;
struct mt76_connac_txp_common *txp;
struct mt76_txwi_cache *t;
struct mt7996_txp *txp;
int id, i, pid, nbuf = tx_info->nbuf - 1;
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
u8 *txwi = (u8 *)txwi_ptr;
@@ -1148,35 +1123,35 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
key, 0);
txp = (struct mt7996_txp *)(txwi + MT_TXD_SIZE);
txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
for (i = 0; i < nbuf; i++) {
txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
}
txp->nbuf = nbuf;
txp->fw.nbuf = nbuf;
txp->flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
txp->flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
if (!key)
txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
if (vif) {
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
txp->bss_idx = mvif->mt76.idx;
txp->fw.bss_idx = mvif->mt76.idx;
}
txp->token = cpu_to_le16(id);
txp->fw.token = cpu_to_le16(id);
if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
txp->rept_wds_wcid = cpu_to_le16(wcid->idx);
txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
else
txp->rept_wds_wcid = cpu_to_le16(0xfff);
txp->fw.rept_wds_wcid = cpu_to_le16(0xfff);
tx_info->skb = DMA_DUMMY_DATA;
/* pass partial skb header to fw */
@@ -1212,18 +1187,6 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
ieee80211_start_tx_ba_session(sta, tid, 0);
}
static void
mt7996_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
{
struct mt7996_txp *txp;
int i;
txp = mt7996_txwi_to_txp(dev, t);
for (i = 0; i < txp->nbuf; i++)
dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]),
le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
}
static void
mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
struct ieee80211_sta *sta, struct list_head *free_list)
@@ -1233,7 +1196,7 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
__le32 *txwi;
u16 wcid_idx;
mt7996_txp_skb_unmap(mdev, t);
mt76_connac_txp_skb_unmap(mdev, t);
if (!t->skb)
goto out;
@@ -1434,6 +1397,15 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, int pid,
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;
}
@@ -1441,6 +1413,10 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, int pid,
stats->tx_mode[mode]++;
switch (FIELD_GET(MT_TXS0_BW, txs)) {
case IEEE80211_STA_RX_BW_320:
rate.bw = RATE_INFO_BW_320;
stats->tx_bw[4]++;
break;
case IEEE80211_STA_RX_BW_160:
rate.bw = RATE_INFO_BW_160;
stats->tx_bw[3]++;
@@ -1486,7 +1462,7 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
if (pid < MT_PACKET_ID_FIRST)
return;
if (wcidx >= MT7996_WTBL_SIZE)
if (wcidx >= mt7996_wtbl_size(dev))
return;
rcu_read_lock();
@@ -1589,27 +1565,6 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
}
}
void mt7996_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
{
if (!e->txwi) {
dev_kfree_skb_any(e->skb);
return;
}
/* error path */
if (e->skb == DMA_DUMMY_DATA) {
struct mt76_txwi_cache *t;
struct mt7996_txp *txp;
txp = mt7996_txwi_to_txp(mdev, e->txwi);
t = mt76_token_put(mdev, le16_to_cpu(txp->token));
e->skb = t ? t->skb : NULL;
}
if (e->skb)
mt76_tx_complete_skb(mdev, e->wcid, e->skb);
}
void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy)
{
struct mt7996_dev *dev = phy->dev;
@@ -1690,7 +1645,7 @@ void mt7996_mac_set_timing(struct mt7996_phy *phy)
else
val = MT7996_CFEND_RATE_11B;
mt76_rmw_field(dev, MT_AGG_ACR0(band_idx), MT_AGG_ACR_CFEND_RATE, val);
mt76_rmw_field(dev, MT_RATE_HRCR0(band_idx), MT_RATE_HRCR0_CFEND_RATE, val);
mt76_clear(dev, MT_ARB_SCR(band_idx),
MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
}

View File

@@ -268,17 +268,6 @@ enum tx_mgnt_type {
/* VHT/HE only use bits 0-3 */
#define MT_TX_RATE_IDX GENMASK(5, 0)
struct mt7996_txp {
__le16 flags;
__le16 token;
u8 bss_idx;
__le16 rept_wds_wcid;
u8 nbuf;
#define MT_TXP_MAX_BUF_NUM 6
__le32 buf[MT_TXP_MAX_BUF_NUM];
__le16 len[MT_TXP_MAX_BUF_NUM];
} __packed __aligned(4);
#define MT_TXFREE0_PKT_TYPE GENMASK(31, 27)
#define MT_TXFREE0_MSDU_CNT GENMASK(25, 16)
#define MT_TXFREE0_RX_BYTE GENMASK(15, 0)
@@ -382,17 +371,4 @@ struct mt7996_dfs_radar_spec {
struct mt7996_dfs_pattern radar_pattern[16];
};
static inline struct mt7996_txp *
mt7996_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
{
u8 *txwi;
if (!t)
return NULL;
txwi = mt76_get_txwi_ptr(dev, t);
return (struct mt7996_txp *)(txwi + MT_TXD_SIZE);
}
#endif

View File

@@ -170,7 +170,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
phy->monitor_vif = vif;
mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask);
if (mvif->mt76.idx >= (MT7996_MAX_INTERFACES << dev->dbdc_support)) {
if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) {
ret = -ENOSPC;
goto out;
}
@@ -880,14 +880,17 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
phy->mt76->antenna_mask = tx_ant;
/* restore to the origin chainmask which might have auxiliary path */
if (hweight8(tx_ant) == max_nss)
if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2)
phy->mt76->chainmask = ((dev->chainmask >> shift) &
(BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift;
else if (hweight8(tx_ant) == max_nss)
phy->mt76->chainmask = (dev->chainmask >> shift) << shift;
else
phy->mt76->chainmask = tx_ant << shift;
mt76_set_stream_caps(phy->mt76, true);
mt7996_set_stream_vht_txbf_caps(phy);
mt7996_set_stream_he_caps(phy);
mt7996_set_stream_he_eht_caps(phy);
mutex_unlock(&dev->mt76.mutex);
@@ -1081,10 +1084,14 @@ static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = {
"v_tx_mode_he_ext_su",
"v_tx_mode_he_tb",
"v_tx_mode_he_mu",
"v_tx_mode_eht_su",
"v_tx_mode_eht_trig",
"v_tx_mode_eht_mu",
"v_tx_bw_20",
"v_tx_bw_40",
"v_tx_bw_80",
"v_tx_bw_160",
"v_tx_bw_320",
"v_tx_mcs_0",
"v_tx_mcs_1",
"v_tx_mcs_2",
@@ -1097,6 +1104,8 @@ static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = {
"v_tx_mcs_9",
"v_tx_mcs_10",
"v_tx_mcs_11",
"v_tx_mcs_12",
"v_tx_mcs_13",
};
#define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats)
@@ -1130,7 +1139,7 @@ static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
if (msta->vif->mt76.idx != wi->idx)
return;
mt76_ethtool_worker(wi, &msta->stats);
mt76_ethtool_worker(wi, &msta->stats, true);
}
static

View File

@@ -70,6 +70,7 @@ struct mt7996_fw_region {
#define HE_PHY(p, c) u8_get_bits(c, IEEE80211_HE_PHY_##p)
#define HE_MAC(m, c) u8_get_bits(c, IEEE80211_HE_MAC_##m)
#define EHT_PHY(p, c) u8_get_bits(c, IEEE80211_EHT_PHY_##p)
static bool sr_scene_detect = true;
module_param(sr_scene_detect, bool, 0644);
@@ -771,9 +772,8 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
bss->dtim_period = vif->bss_conf.dtim_period;
bss->phymode = mt76_connac_get_phy_mode(phy, vif,
chandef->chan->band, NULL);
if (chandef->chan->band == NL80211_BAND_6GHZ)
bss->phymode_ext |= PHY_MODE_AX_6G;
bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, vif,
chandef->chan->band);
return 0;
}
@@ -951,6 +951,35 @@ mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
he_6g->capa = sta->deflink.he_6ghz_capa.capa;
}
static void
mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
{
struct ieee80211_eht_mcs_nss_supp *mcs_map;
struct ieee80211_eht_cap_elem_fixed *elem;
struct sta_rec_eht *eht;
struct tlv *tlv;
if (!sta->deflink.eht_cap.has_eht)
return;
mcs_map = &sta->deflink.eht_cap.eht_mcs_nss_supp;
elem = &sta->deflink.eht_cap.eht_cap_elem;
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht));
eht = (struct sta_rec_eht *)tlv;
eht->tid_bitmap = 0xff;
eht->mac_cap = cpu_to_le16(*(u16 *)elem->mac_cap_info);
eht->phy_cap = cpu_to_le64(*(u64 *)elem->phy_cap_info);
eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]);
if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20));
memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80));
memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160));
memcpy(eht->mcs_map_bw320, &mcs_map->bw._320, sizeof(eht->mcs_map_bw320));
}
static void
mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
{
@@ -1025,15 +1054,27 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool bfee)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
int tx_ant = hweight8(phy->mt76->antenna_mask) - 1;
int sts = hweight16(phy->mt76->chainmask);
if (vif->type != NL80211_IFTYPE_STATION &&
vif->type != NL80211_IFTYPE_AP)
return false;
if (!bfee && tx_ant < 2)
if (!bfee && sts < 2)
return false;
if (sta->deflink.eht_cap.has_eht) {
struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap;
struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
if (bfee)
return mvif->cap.eht_su_ebfee &&
EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
else
return mvif->cap.eht_su_ebfer &&
EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]);
}
if (sta->deflink.he_cap.has_he) {
struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
@@ -1190,13 +1231,69 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
bf->nrow_gt_bw80 = min_t(int, snd_dim, sts);
}
static void
mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
struct mt7996_phy *phy, struct sta_rec_bf *bf)
{
struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap;
struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp;
const struct ieee80211_sta_eht_cap *vc =
mt76_connac_get_eht_phy_cap(phy->mt76, vif);
const struct ieee80211_eht_cap_elem_fixed *ve = &vc->eht_cap_elem;
u8 nss_mcs = u8_get_bits(eht_nss->bw._80.rx_tx_mcs9_max_nss,
IEEE80211_EHT_MCS_NSS_RX) - 1;
u8 snd_dim, sts;
bf->tx_mode = MT_PHY_TYPE_EHT_MU;
mt7996_mcu_sta_sounding_rate(bf);
bf->trigger_su = EHT_PHY(CAP3_TRIG_SU_BF_FDBK, pe->phy_cap_info[3]);
bf->trigger_mu = EHT_PHY(CAP3_TRIG_MU_BF_PART_BW_FDBK, pe->phy_cap_info[3]);
snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_80MHZ_MASK, ve->phy_cap_info[2]);
sts = EHT_PHY(CAP0_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[0]) +
(EHT_PHY(CAP1_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[1]) << 1);
bf->nrow = min_t(u8, snd_dim, sts);
bf->ncol = min_t(u8, nss_mcs, bf->nrow);
bf->ibf_ncol = bf->ncol;
if (sta->deflink.bandwidth < IEEE80211_STA_RX_BW_160)
return;
switch (sta->deflink.bandwidth) {
case IEEE80211_STA_RX_BW_160:
snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_160MHZ_MASK, ve->phy_cap_info[2]);
sts = EHT_PHY(CAP1_BEAMFORMEE_SS_160MHZ_MASK, pe->phy_cap_info[1]);
nss_mcs = u8_get_bits(eht_nss->bw._160.rx_tx_mcs9_max_nss,
IEEE80211_EHT_MCS_NSS_RX) - 1;
bf->nrow_gt_bw80 = min_t(u8, snd_dim, sts);
bf->ncol_gt_bw80 = nss_mcs;
break;
case IEEE80211_STA_RX_BW_320:
snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_320MHZ_MASK, ve->phy_cap_info[2]) +
(EHT_PHY(CAP3_SOUNDING_DIM_320MHZ_MASK,
ve->phy_cap_info[3]) << 1);
sts = EHT_PHY(CAP1_BEAMFORMEE_SS_320MHZ_MASK, pe->phy_cap_info[1]);
nss_mcs = u8_get_bits(eht_nss->bw._320.rx_tx_mcs9_max_nss,
IEEE80211_EHT_MCS_NSS_RX) - 1;
bf->nrow_gt_bw80 = min_t(u8, snd_dim, sts) << 4;
bf->ncol_gt_bw80 = nss_mcs << 4;
break;
default:
break;
}
}
static void
mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
struct ieee80211_vif *vif, struct ieee80211_sta *sta)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_phy *phy = mvif->phy;
int tx_ant = hweight8(phy->mt76->antenna_mask) - 1;
int tx_ant = hweight8(phy->mt76->chainmask) - 1;
struct sta_rec_bf *bf;
struct tlv *tlv;
const u8 matrix[4][4] = {
@@ -1217,11 +1314,13 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BF, sizeof(*bf));
bf = (struct sta_rec_bf *)tlv;
/* he: eBF only, in accordance with spec
/* he/eht: eBF only, in accordance with spec
* vht: support eBF and iBF
* ht: iBF only, since mac80211 lacks of eBF support
*/
if (sta->deflink.he_cap.has_he && ebf)
if (sta->deflink.eht_cap.has_eht && ebf)
mt7996_mcu_sta_bfer_eht(sta, vif, phy, bf);
else if (sta->deflink.he_cap.has_he && ebf)
mt7996_mcu_sta_bfer_he(sta, vif, phy, bf);
else if (sta->deflink.vht_cap.vht_supported)
mt7996_mcu_sta_bfer_vht(sta, phy, bf, ebf);
@@ -1436,8 +1535,9 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
ra->auto_rate = true;
ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta);
ra->channel = chandef->chan->hw_value;
ra->bw = sta->deflink.bandwidth;
ra->phy.bw = sta->deflink.bandwidth;
ra->bw = (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) ?
CMD_CBW_320MHZ : sta->deflink.bandwidth;
ra->phy.bw = ra->bw;
ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode);
if (supp_rate) {
@@ -1619,6 +1719,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
mt7996_mcu_sta_he_tlv(skb, sta);
/* starec he 6g*/
mt7996_mcu_sta_he_6g_tlv(skb, sta);
/* starec eht */
mt7996_mcu_sta_eht_tlv(skb, sta);
/* TODO: starec muru */
/* starec bfee */
mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta);
@@ -1815,6 +1917,7 @@ mt7996_mcu_beacon_check_caps(struct mt7996_phy *phy, struct ieee80211_vif *vif,
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_vif_cap *vc = &mvif->cap;
const struct ieee80211_eht_cap_elem_fixed *eht;
const struct ieee80211_he_cap_elem *he;
const struct ieee80211_vht_cap *vht;
const struct ieee80211_ht_cap *ht;
@@ -1885,6 +1988,23 @@ mt7996_mcu_beacon_check_caps(struct mt7996_phy *phy, struct ieee80211_vif *vif,
HE_PHY(CAP4_MU_BEAMFORMER, he->phy_cap_info[4]) &&
HE_PHY(CAP4_MU_BEAMFORMER, pe->phy_cap_info[4]);
}
ie = cfg80211_find_ext_ie(WLAN_EID_EXT_EHT_CAPABILITY,
mgmt->u.beacon.variable, len);
if (ie && ie[1] >= sizeof(*eht) + 1) {
const struct ieee80211_sta_eht_cap *pc =
mt76_connac_get_eht_phy_cap(phy->mt76, vif);
const struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
eht = (void *)(ie + 3);
vc->eht_su_ebfer =
EHT_PHY(CAP0_SU_BEAMFORMER, eht->phy_cap_info[0]) &&
EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]);
vc->eht_su_ebfee =
EHT_PHY(CAP0_SU_BEAMFORMEE, eht->phy_cap_info[0]) &&
EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
}
}
int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
@@ -2247,6 +2367,26 @@ mt7996_firmware_state(struct mt7996_dev *dev, bool wa)
return 0;
}
static int
mt7996_mcu_restart(struct mt76_dev *dev)
{
struct {
u8 __rsv1[4];
__le16 tag;
__le16 len;
u8 power_mode;
u8 __rsv2[3];
} __packed req = {
.tag = cpu_to_le16(UNI_POWER_OFF),
.len = cpu_to_le16(sizeof(req) - 4),
.power_mode = 1,
};
return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(POWER_CTRL), &req,
sizeof(req), false);
}
static int mt7996_load_firmware(struct mt7996_dev *dev)
{
int ret;
@@ -2254,7 +2394,7 @@ static int mt7996_load_firmware(struct mt7996_dev *dev)
/* make sure fw is download state */
if (mt7996_firmware_state(dev, false)) {
/* restart firmware once */
__mt76_mcu_restart(&dev->mt76);
mt7996_mcu_restart(&dev->mt76);
ret = mt7996_firmware_state(dev, false);
if (ret) {
dev_err(dev->mt76.dev,
@@ -2383,33 +2523,12 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
MCU_WM_UNI_CMD(VOW), true);
}
static int
mt7996_mcu_restart(struct mt76_dev *dev)
{
struct {
u8 __rsv1[4];
__le16 tag;
__le16 len;
u8 power_mode;
u8 __rsv2[3];
} __packed req = {
.tag = cpu_to_le16(UNI_POWER_OFF),
.len = cpu_to_le16(sizeof(req) - 4),
.power_mode = 1,
};
return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(POWER_CREL), &req,
sizeof(req), false);
}
int mt7996_mcu_init(struct mt7996_dev *dev)
{
static const struct mt76_mcu_ops mt7996_mcu_ops = {
.headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */
.mcu_skb_send_msg = mt7996_mcu_send_message,
.mcu_parse_response = mt7996_mcu_parse_response,
.mcu_restart = mt7996_mcu_restart,
};
int ret;
@@ -2457,16 +2576,17 @@ int mt7996_mcu_init(struct mt7996_dev *dev)
void mt7996_mcu_exit(struct mt7996_dev *dev)
{
__mt76_mcu_restart(&dev->mt76);
mt7996_mcu_restart(&dev->mt76);
if (mt7996_firmware_state(dev, false)) {
dev_err(dev->mt76.dev, "Failed to exit mcu\n");
return;
goto out;
}
mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(0), MT_TOP_LPCR_HOST_FW_OWN);
if (dev->hif2)
mt76_wr(dev, MT_TOP_LPCR_HOST_BAND(1),
MT_TOP_LPCR_HOST_FW_OWN);
out:
skb_queue_purge(&dev->mt76.mcu.res_q);
}
@@ -2977,6 +3097,52 @@ int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num)
return 0;
}
int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap)
{
#define NIC_CAP 3
#define UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION 0x21
struct {
u8 _rsv[4];
__le16 tag;
__le16 len;
} __packed req = {
.tag = cpu_to_le16(NIC_CAP),
.len = cpu_to_le16(sizeof(req) - 4),
};
struct sk_buff *skb;
u8 *buf;
int ret;
ret = mt76_mcu_send_and_get_msg(&dev->mt76,
MCU_WM_UNI_CMD_QUERY(CHIP_CONFIG), &req,
sizeof(req), true, &skb);
if (ret)
return ret;
/* fixed field */
skb_pull(skb, 4);
buf = skb->data;
while (buf - skb->data < skb->len) {
struct tlv *tlv = (struct tlv *)buf;
switch (le16_to_cpu(tlv->tag)) {
case UNI_EVENT_CHIP_CONFIG_EFUSE_VERSION:
*cap = le32_to_cpu(*(__le32 *)(buf + sizeof(*tlv)));
break;
default:
break;
};
buf += le16_to_cpu(tlv->len);
}
dev_kfree_skb(skb);
return 0;
}
int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch)
{
struct {

View File

@@ -347,6 +347,21 @@ struct sta_rec_ba_uni {
u8 __rsv[3];
} __packed;
struct sta_rec_eht {
__le16 tag;
__le16 len;
u8 tid_bitmap;
u8 _rsv;
__le16 mac_cap;
__le64 phy_cap;
__le64 phy_cap_ext;
u8 mcs_map_bw20[4];
u8 mcs_map_bw80[3];
u8 mcs_map_bw160[3];
u8 mcs_map_bw320[3];
u8 _rsv2[3];
} __packed;
struct sec_key_uni {
__le16 wlan_idx;
u8 mgmt_prot;
@@ -554,6 +569,7 @@ enum {
sizeof(struct sta_rec_sec) + \
sizeof(struct sta_rec_ra_fixed) + \
sizeof(struct sta_rec_he_6g_capa) + \
sizeof(struct sta_rec_eht) + \
sizeof(struct sta_rec_hdrt) + \
sizeof(struct sta_rec_hdr_trans) + \
sizeof(struct tlv))

View File

@@ -21,6 +21,7 @@ static const struct __base mt7996_reg_base[] = {
[WF_ETBF_BASE] = { { 0x820ea000, 0x820fa000, 0x830ea000 } },
[WF_LPON_BASE] = { { 0x820eb000, 0x820fb000, 0x830eb000 } },
[WF_MIB_BASE] = { { 0x820ed000, 0x820fd000, 0x830ed000 } },
[WF_RATE_BASE] = { { 0x820ee000, 0x820fe000, 0x830ee000 } },
};
static const struct __map mt7996_reg_map[] = {
@@ -317,7 +318,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
{
static const struct mt76_driver_ops drv_ops = {
/* txwi_size = txd size + txp size */
.txwi_size = MT_TXD_SIZE + sizeof(struct mt7996_txp),
.txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp),
.drv_flags = MT_DRV_TXWI_NO_FREE |
MT_DRV_HW_MGMT_TXQ,
.survey_flags = SURVEY_INFO_TIME_TX |
@@ -325,7 +326,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
SURVEY_INFO_TIME_BSS_RX,
.token_size = MT7996_TOKEN_SIZE,
.tx_prepare_skb = mt7996_tx_prepare_skb,
.tx_complete_skb = mt7996_tx_complete_skb,
.tx_complete_skb = mt76_connac_tx_complete_skb,
.rx_skb = mt7996_queue_rx_skb,
.rx_check = mt7996_rx_check,
.rx_poll_complete = mt7996_rx_poll_complete,

View File

@@ -11,12 +11,11 @@
#include "../mt76_connac.h"
#include "regs.h"
#define MT7996_MAX_INTERFACES 19
#define MT7996_MAX_INTERFACES 19 /* per-band */
#define MT7996_MAX_WMM_SETS 4
#define MT7996_WTBL_SIZE 544
#define MT7996_WTBL_RESERVED (MT7996_WTBL_SIZE - 1)
#define MT7996_WTBL_RESERVED (mt7996_wtbl_size(dev) - 1)
#define MT7996_WTBL_STA (MT7996_WTBL_RESERVED - \
MT7996_MAX_INTERFACES)
mt7996_max_interface_num(dev))
#define MT7996_WATCHDOG_TIME (HZ / 10)
#define MT7996_RESET_TIMEOUT (30 * HZ)
@@ -124,6 +123,8 @@ struct mt7996_vif_cap {
bool he_su_ebfer:1;
bool he_su_ebfee:1;
bool he_mu_ebfer:1;
bool eht_su_ebfer:1;
bool eht_su_ebfee:1;
};
struct mt7996_vif {
@@ -264,6 +265,7 @@ struct mt7996_dev {
bool dbdc_support:1;
bool tbtc_support:1;
bool flash_mode:1;
bool has_eht:1;
bool ibf;
u8 fw_debug_wm;
@@ -281,6 +283,8 @@ struct mt7996_dev {
u32 reg_l1_backup;
u32 reg_l2_backup;
u8 wtbl_size_group;
};
enum {
@@ -419,6 +423,7 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset);
int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap);
int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band);
int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action);
int mt7996_mcu_set_fcc5_lpn(struct mt7996_dev *dev, int val);
@@ -443,6 +448,16 @@ int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
return MT7996_MAX_INTERFACES * (1 + dev->dbdc_support + dev->tbtc_support);
}
static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev)
{
return (dev->wtbl_size_group << 8) + 64;
}
void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg,
u32 clear, u32 set);
@@ -493,7 +508,6 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt7996_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
void mt7996_tx_token_put(struct mt7996_dev *dev);
void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb, u32 *info);
@@ -502,7 +516,7 @@ void mt7996_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
void mt7996_stats_work(struct work_struct *work);
int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force);
int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy);
void mt7996_set_stream_he_caps(struct mt7996_phy *phy);
void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy);
void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy);
void mt7996_update_channel(struct mt76_phy *mphy);
int mt7996_init_debugfs(struct mt7996_phy *phy);

View File

@@ -33,6 +33,7 @@ enum base_rev {
WF_ETBF_BASE,
WF_LPON_BASE,
WF_MIB_BASE,
WF_RATE_BASE,
__MT_REG_BASE_MAX,
};
@@ -235,13 +236,6 @@ enum base_rev {
FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \
FIELD_PREP(MT_WTBL_LMAC_DW, _dw))
/* AGG: band 0(0x820e2000), band 1(0x820f2000), band 2(0x830e2000) */
#define MT_WF_AGG_BASE(_band) __BASE(WF_AGG_BASE, (_band))
#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x054)
#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0)
/* ARB: band 0(0x820e3000), band 1(0x820f3000), band 2(0x830e3000) */
#define MT_WF_ARB_BASE(_band) __BASE(WF_ARB_BASE, (_band))
#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))
@@ -300,6 +294,13 @@ enum base_rev {
#define MT_WF_RMAC_RSVD0(_band) MT_WF_RMAC(_band, 0x03e0)
#define MT_WF_RMAC_RSVD0_EIFS_CLR BIT(21)
/* RATE: band 0(0x820ee000), band 1(0x820fe000), band 2(0x830ee000) */
#define MT_WF_RATE_BASE(_band) __BASE(WF_RATE_BASE, (_band))
#define MT_WF_RATE(_band, ofs) (MT_WF_RATE_BASE(_band) + (ofs))
#define MT_RATE_HRCR0(_band) MT_WF_RATE(_band, 0x050)
#define MT_RATE_HRCR0_CFEND_RATE GENMASK(14, 0)
/* WFDMA0 */
#define MT_WFDMA0_BASE 0xd4000
#define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs))

View File

@@ -562,6 +562,10 @@ mt76s_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
q->entry[q->head].buf_sz = len;
q->entry[q->head].skb = skb;
/* ensure the entry fully updated before bus access */
smp_wmb();
q->head = (q->head + 1) % q->ndesc;
q->queued++;

View File

@@ -319,29 +319,27 @@ mt76u_set_endpoints(struct usb_interface *intf,
static int
mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb,
int nsgs, gfp_t gfp)
int nsgs)
{
int i;
for (i = 0; i < nsgs; i++) {
struct page *page;
void *data;
int offset;
data = page_frag_alloc(&q->rx_page, q->buf_size, gfp);
data = mt76_get_page_pool_buf(q, &offset, q->buf_size);
if (!data)
break;
page = virt_to_head_page(data);
offset = data - page_address(page);
sg_set_page(&urb->sg[i], page, q->buf_size, offset);
sg_set_page(&urb->sg[i], virt_to_head_page(data), q->buf_size,
offset);
}
if (i < nsgs) {
int j;
for (j = nsgs; j < urb->num_sgs; j++)
skb_free_frag(sg_virt(&urb->sg[j]));
mt76_put_page_pool_buf(sg_virt(&urb->sg[j]), false);
urb->num_sgs = i;
}
@@ -354,15 +352,16 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb,
static int
mt76u_refill_rx(struct mt76_dev *dev, struct mt76_queue *q,
struct urb *urb, int nsgs, gfp_t gfp)
struct urb *urb, int nsgs)
{
enum mt76_rxq_id qid = q - &dev->q_rx[MT_RXQ_MAIN];
int offset;
if (qid == MT_RXQ_MAIN && dev->usb.sg_en)
return mt76u_fill_rx_sg(dev, q, urb, nsgs, gfp);
return mt76u_fill_rx_sg(dev, q, urb, nsgs);
urb->transfer_buffer_length = q->buf_size;
urb->transfer_buffer = page_frag_alloc(&q->rx_page, q->buf_size, gfp);
urb->transfer_buffer = mt76_get_page_pool_buf(q, &offset, q->buf_size);
return urb->transfer_buffer ? 0 : -ENOMEM;
}
@@ -400,7 +399,7 @@ mt76u_rx_urb_alloc(struct mt76_dev *dev, struct mt76_queue *q,
if (err)
return err;
return mt76u_refill_rx(dev, q, e->urb, sg_size, GFP_KERNEL);
return mt76u_refill_rx(dev, q, e->urb, sg_size);
}
static void mt76u_urb_free(struct urb *urb)
@@ -408,10 +407,10 @@ static void mt76u_urb_free(struct urb *urb)
int i;
for (i = 0; i < urb->num_sgs; i++)
skb_free_frag(sg_virt(&urb->sg[i]));
mt76_put_page_pool_buf(sg_virt(&urb->sg[i]), false);
if (urb->transfer_buffer)
skb_free_frag(urb->transfer_buffer);
mt76_put_page_pool_buf(urb->transfer_buffer, false);
usb_free_urb(urb);
}
@@ -547,6 +546,8 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb,
len -= data_len;
nsgs++;
}
skb_mark_for_recycle(skb);
dev->drv->rx_skb(dev, MT_RXQ_MAIN, skb, NULL);
return nsgs;
@@ -612,7 +613,7 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
count = mt76u_process_rx_entry(dev, urb, q->buf_size);
if (count > 0) {
err = mt76u_refill_rx(dev, q, urb, count, GFP_ATOMIC);
err = mt76u_refill_rx(dev, q, urb, count);
if (err < 0)
break;
}
@@ -663,6 +664,10 @@ mt76u_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid)
struct mt76_queue *q = &dev->q_rx[qid];
int i, err;
err = mt76_create_page_pool(dev, q);
if (err)
return err;
spin_lock_init(&q->lock);
q->entry = devm_kcalloc(dev->dev,
MT_NUM_RX_ENTRIES, sizeof(*q->entry),
@@ -691,7 +696,6 @@ EXPORT_SYMBOL_GPL(mt76u_alloc_mcu_queue);
static void
mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
struct page *page;
int i;
for (i = 0; i < q->ndesc; i++) {
@@ -701,13 +705,7 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
mt76u_urb_free(q->entry[i].urb);
q->entry[i].urb = NULL;
}
if (!q->rx_page.va)
return;
page = virt_to_page(q->rx_page.va);
__page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
memset(&q->rx_page, 0, sizeof(q->rx_page));
page_pool_destroy(q->page_pool);
}
static void mt76u_free_rx(struct mt76_dev *dev)

View File

@@ -24,23 +24,23 @@ bool __mt76_poll(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
}
EXPORT_SYMBOL_GPL(__mt76_poll);
bool __mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
int timeout)
bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val,
int timeout, int tick)
{
u32 cur;
timeout /= 10;
timeout /= tick;
do {
cur = __mt76_rr(dev, offset) & mask;
if (cur == val)
return true;
usleep_range(10000, 20000);
usleep_range(1000 * tick, 2000 * tick);
} while (timeout-- > 0);
return false;
}
EXPORT_SYMBOL_GPL(__mt76_poll_msec);
EXPORT_SYMBOL_GPL(____mt76_poll_msec);
int mt76_wcid_alloc(u32 *mask, int size)
{