| From 4709ca02ba0332508ac6885acbc779bdfac3f0be Mon Sep 17 00:00:00 2001 |
| From: mtk27745 <rex.lu@mediatek.com> |
| Date: Fri, 6 Oct 2023 21:20:25 +0800 |
| Subject: [PATCH] wifi: mt76: wed: sync to wed upstream |
| |
| --- |
| dma.c | 219 +++++++++++++++++++++++++++------------ |
| dma.h | 12 +++ |
| mac80211.c | 19 +++- |
| mmio.c | 97 +++++++++++++++++ |
| mt76.h | 102 ++++++++++++++++-- |
| mt7603/dma.c | 9 +- |
| mt7615/dma.c | 6 +- |
| mt76_connac.h | 3 +- |
| mt76_connac_mac.c | 5 +- |
| mt76x02_mmio.c | 5 +- |
| mt7915/dma.c | 18 ++-- |
| mt7915/main.c | 16 +-- |
| mt7915/mmio.c | 107 +------------------ |
| mt7921/pci.c | 2 +- |
| mt7925/pci.c | 2 +- |
| mt7996/dma.c | 258 ++++++++++++++++++++++++++++++++++++++++++---- |
| mt7996/init.c | 156 ++++++++++++++++++++++++++-- |
| mt7996/mac.c | 72 +++++++++++-- |
| mt7996/main.c | 42 ++++++++ |
| mt7996/mcu.c | 13 ++- |
| mt7996/mmio.c | 208 +++++++++++++++++++++++++++++++++---- |
| mt7996/mt7996.h | 67 +++++++++++- |
| mt7996/pci.c | 72 ++++++++++--- |
| mt7996/regs.h | 65 +++++++++++- |
| 24 files changed, 1276 insertions(+), 299 deletions(-) |
| |
| diff --git a/dma.c b/dma.c |
| index 643e18e..dd20271 100644 |
| --- a/dma.c |
| +++ b/dma.c |
| @@ -9,11 +9,11 @@ |
| |
| #if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) |
| |
| -#define Q_READ(_dev, _q, _field) ({ \ |
| +#define Q_READ(_q, _field) ({ \ |
| u32 _offset = offsetof(struct mt76_queue_regs, _field); \ |
| u32 _val; \ |
| if ((_q)->flags & MT_QFLAG_WED) \ |
| - _val = mtk_wed_device_reg_read(&(_dev)->mmio.wed, \ |
| + _val = mtk_wed_device_reg_read((_q)->wed, \ |
| ((_q)->wed_regs + \ |
| _offset)); \ |
| else \ |
| @@ -21,10 +21,10 @@ |
| _val; \ |
| }) |
| |
| -#define Q_WRITE(_dev, _q, _field, _val) do { \ |
| +#define Q_WRITE(_q, _field, _val) do { \ |
| u32 _offset = offsetof(struct mt76_queue_regs, _field); \ |
| if ((_q)->flags & MT_QFLAG_WED) \ |
| - mtk_wed_device_reg_write(&(_dev)->mmio.wed, \ |
| + mtk_wed_device_reg_write((_q)->wed, \ |
| ((_q)->wed_regs + _offset), \ |
| _val); \ |
| else \ |
| @@ -33,8 +33,8 @@ |
| |
| #else |
| |
| -#define Q_READ(_dev, _q, _field) readl(&(_q)->regs->_field) |
| -#define Q_WRITE(_dev, _q, _field, _val) writel(_val, &(_q)->regs->_field) |
| +#define Q_READ(_q, _field) readl(&(_q)->regs->_field) |
| +#define Q_WRITE(_q, _field, _val) writel(_val, &(_q)->regs->_field) |
| |
| #endif |
| |
| @@ -188,40 +188,63 @@ EXPORT_SYMBOL_GPL(mt76_free_pending_rxwi); |
| static void |
| mt76_dma_sync_idx(struct mt76_dev *dev, struct mt76_queue *q) |
| { |
| - Q_WRITE(dev, q, desc_base, q->desc_dma); |
| - Q_WRITE(dev, q, ring_size, q->ndesc); |
| - q->head = Q_READ(dev, q, dma_idx); |
| + Q_WRITE(q, desc_base, q->desc_dma); |
| + if (q->flags & MT_QFLAG_WED_RRO_EN) |
| + Q_WRITE(q, ring_size, MT_DMA_RRO_EN | q->ndesc); |
| + else |
| + Q_WRITE(q, ring_size, q->ndesc); |
| + q->head = Q_READ(q, dma_idx); |
| q->tail = q->head; |
| } |
| |
| static void |
| -mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) |
| +__mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q, |
| + bool reset_idx) |
| { |
| - int i; |
| - |
| if (!q || !q->ndesc) |
| return; |
| |
| - /* clear descriptors */ |
| - for (i = 0; i < q->ndesc; i++) |
| - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); |
| + if (!mt76_queue_is_wed_rro_ind(q)) { |
| + int i; |
| |
| - Q_WRITE(dev, q, cpu_idx, 0); |
| - Q_WRITE(dev, q, dma_idx, 0); |
| + /* clear descriptors */ |
| + for (i = 0; i < q->ndesc; i++) |
| + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); |
| + } |
| + |
| + if (reset_idx) { |
| + Q_WRITE(q, cpu_idx, 0); |
| + Q_WRITE(q, dma_idx, 0); |
| + } |
| mt76_dma_sync_idx(dev, q); |
| } |
| |
| +static void |
| +mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q) |
| +{ |
| + __mt76_dma_queue_reset(dev, q, true); |
| +} |
| + |
| static int |
| mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, |
| struct mt76_queue_buf *buf, void *data) |
| { |
| - struct mt76_desc *desc = &q->desc[q->head]; |
| struct mt76_queue_entry *entry = &q->entry[q->head]; |
| struct mt76_txwi_cache *txwi = NULL; |
| + struct mt76_desc *desc; |
| u32 buf1 = 0, ctrl; |
| int idx = q->head; |
| int rx_token; |
| |
| + if (mt76_queue_is_wed_rro_ind(q)) { |
| + struct mt76_wed_rro_desc *rro_desc; |
| + |
| + rro_desc = (struct mt76_wed_rro_desc *)q->desc; |
| + data = &rro_desc[q->head]; |
| + goto done; |
| + } |
| + |
| + desc = &q->desc[q->head]; |
| ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len); |
| |
| if (mt76_queue_is_wed_rx(q)) { |
| @@ -244,6 +267,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q, |
| WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl)); |
| WRITE_ONCE(desc->info, 0); |
| |
| +done: |
| entry->dma_addr[0] = buf->addr; |
| entry->dma_len[0] = buf->len; |
| entry->txwi = txwi; |
| @@ -343,7 +367,7 @@ static void |
| mt76_dma_kick_queue(struct mt76_dev *dev, struct mt76_queue *q) |
| { |
| wmb(); |
| - Q_WRITE(dev, q, cpu_idx, q->head); |
| + Q_WRITE(q, cpu_idx, q->head); |
| } |
| |
| static void |
| @@ -359,7 +383,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) |
| if (flush) |
| last = -1; |
| else |
| - last = Q_READ(dev, q, dma_idx); |
| + last = Q_READ(q, dma_idx); |
| |
| while (q->queued > 0 && q->tail != last) { |
| mt76_dma_tx_cleanup_idx(dev, q, q->tail, &entry); |
| @@ -371,7 +395,7 @@ mt76_dma_tx_cleanup(struct mt76_dev *dev, struct mt76_queue *q, bool flush) |
| } |
| |
| if (!flush && q->tail == last) |
| - last = Q_READ(dev, q, dma_idx); |
| + last = Q_READ(q, dma_idx); |
| } |
| spin_unlock_bh(&q->cleanup_lock); |
| |
| @@ -392,10 +416,14 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, |
| { |
| struct mt76_queue_entry *e = &q->entry[idx]; |
| struct mt76_desc *desc = &q->desc[idx]; |
| - void *buf; |
| + void *buf = e->buf; |
| + u32 ctrl; |
| |
| + if (mt76_queue_is_wed_rro_ind(q)) |
| + goto done; |
| + |
| + ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); |
| if (len) { |
| - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); |
| *len = FIELD_GET(MT_DMA_CTL_SD_LEN0, ctrl); |
| *more = !(ctrl & MT_DMA_CTL_LAST_SEC0); |
| } |
| @@ -403,6 +431,12 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, |
| if (info) |
| *info = le32_to_cpu(desc->info); |
| |
| + if (drop) { |
| + *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | MT_DMA_CTL_DROP)); |
| + if (ctrl & MT_DMA_CTL_VER_MASK) |
| + *drop = !!(ctrl & MT_DMA_CTL_PN_CHK_FAIL); |
| + } |
| + |
| if (mt76_queue_is_wed_rx(q)) { |
| u32 buf1 = le32_to_cpu(desc->buf1); |
| u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1); |
| @@ -420,23 +454,16 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx, |
| t->ptr = NULL; |
| |
| mt76_put_rxwi(dev, t); |
| - |
| - if (drop) { |
| - u32 ctrl = le32_to_cpu(READ_ONCE(desc->ctrl)); |
| - |
| - *drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | |
| - MT_DMA_CTL_DROP)); |
| - |
| + if (drop) |
| *drop |= !!(buf1 & MT_DMA_CTL_WO_DROP); |
| - } |
| } else { |
| - buf = e->buf; |
| - e->buf = NULL; |
| 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)); |
| } |
| |
| +done: |
| + e->buf = NULL; |
| return buf; |
| } |
| |
| @@ -450,11 +477,16 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush, |
| if (!q->queued) |
| return NULL; |
| |
| - if (flush) |
| - q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); |
| - else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) |
| + if (mt76_queue_is_wed_rro_data(q)) |
| return NULL; |
| |
| + if (!mt76_queue_is_wed_rro_ind(q)) { |
| + if (flush) |
| + q->desc[idx].ctrl |= cpu_to_le32(MT_DMA_CTL_DMA_DONE); |
| + else if (!(q->desc[idx].ctrl & cpu_to_le32(MT_DMA_CTL_DMA_DONE))) |
| + return NULL; |
| + } |
| + |
| q->tail = (q->tail + 1) % q->ndesc; |
| q->queued--; |
| |
| @@ -606,11 +638,14 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, |
| spin_lock_bh(&q->lock); |
| |
| while (q->queued < q->ndesc - 1) { |
| + struct mt76_queue_buf qbuf = {}; |
| enum dma_data_direction dir; |
| - struct mt76_queue_buf qbuf; |
| dma_addr_t addr; |
| int offset; |
| - void *buf; |
| + void *buf = NULL; |
| + |
| + if (mt76_queue_is_wed_rro_ind(q)) |
| + goto done; |
| |
| buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); |
| if (!buf) |
| @@ -621,6 +656,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, |
| dma_sync_single_for_device(dev->dma_dev, addr, len, dir); |
| |
| qbuf.addr = addr + q->buf_offset; |
| +done: |
| qbuf.len = len - q->buf_offset; |
| qbuf.skip_unmap = false; |
| if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) { |
| @@ -630,7 +666,7 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q, |
| frames++; |
| } |
| |
| - if (frames) |
| + if (frames || mt76_queue_is_wed_rx(q)) |
| mt76_dma_kick_queue(dev, q); |
| |
| spin_unlock_bh(&q->lock); |
| @@ -641,15 +677,14 @@ mt76_dma_rx_fill(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; |
| + int ret = 0, type, ring; |
| + u16 flags; |
| |
| if (!q || !q->ndesc) |
| return -EINVAL; |
| |
| flags = q->flags; |
| - if (!mtk_wed_device_active(wed)) |
| + if (!q->wed || !mtk_wed_device_active(q->wed)) |
| q->flags &= ~MT_QFLAG_WED; |
| |
| if (!(q->flags & MT_QFLAG_WED)) |
| @@ -660,29 +695,52 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset) |
| |
| switch (type) { |
| case MT76_WED_Q_TX: |
| - ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, reset); |
| + ret = mtk_wed_device_tx_ring_setup(q->wed, ring, q->regs, |
| + reset); |
| if (!ret) |
| - q->wed_regs = wed->tx_ring[ring].reg_base; |
| + q->wed_regs = q->wed->tx_ring[ring].reg_base; |
| break; |
| case MT76_WED_Q_TXFREE: |
| /* 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, false); |
| - q->flags = flags; |
| |
| - ret = mtk_wed_device_txfree_ring_setup(wed, q->regs); |
| + ret = mtk_wed_device_txfree_ring_setup(q->wed, q->regs); |
| if (!ret) |
| - q->wed_regs = wed->txfree_ring.reg_base; |
| + q->wed_regs = q->wed->txfree_ring.reg_base; |
| break; |
| case MT76_WED_Q_RX: |
| - ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, reset); |
| + ret = mtk_wed_device_rx_ring_setup(q->wed, ring, q->regs, |
| + reset); |
| if (!ret) |
| - q->wed_regs = wed->rx_ring[ring].reg_base; |
| + q->wed_regs = q->wed->rx_ring[ring].reg_base; |
| + break; |
| + case MT76_WED_RRO_Q_DATA: |
| + q->flags &= ~MT_QFLAG_WED; |
| + __mt76_dma_queue_reset(dev, q, false); |
| + mtk_wed_device_rro_rx_ring_setup(q->wed, ring, q->regs); |
| + q->head = q->ndesc - 1; |
| + q->queued = q->head; |
| + break; |
| + case MT76_WED_RRO_Q_MSDU_PG: |
| + q->flags &= ~MT_QFLAG_WED; |
| + __mt76_dma_queue_reset(dev, q, false); |
| + mtk_wed_device_msdu_pg_rx_ring_setup(q->wed, ring, q->regs); |
| + q->head = q->ndesc - 1; |
| + q->queued = q->head; |
| + break; |
| + case MT76_WED_RRO_Q_IND: |
| + q->flags &= ~MT_QFLAG_WED; |
| + mt76_dma_queue_reset(dev, q); |
| + mt76_dma_rx_fill(dev, q, false); |
| + mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs); |
| break; |
| default: |
| ret = -EINVAL; |
| + break; |
| } |
| + q->flags = flags; |
| |
| return ret; |
| #else |
| @@ -706,11 +764,26 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, |
| q->buf_size = bufsize; |
| q->hw_idx = idx; |
| |
| - size = q->ndesc * sizeof(struct mt76_desc); |
| - q->desc = dmam_alloc_coherent(dev->dma_dev, size, &q->desc_dma, GFP_KERNEL); |
| + size = mt76_queue_is_wed_rro_ind(q) ? sizeof(struct mt76_wed_rro_desc) |
| + : sizeof(struct mt76_desc); |
| + q->desc = dmam_alloc_coherent(dev->dma_dev, q->ndesc * size, |
| + &q->desc_dma, GFP_KERNEL); |
| if (!q->desc) |
| return -ENOMEM; |
| |
| + if (mt76_queue_is_wed_rro_ind(q)) { |
| + struct mt76_wed_rro_desc *rro_desc; |
| + int i; |
| + |
| + rro_desc = (struct mt76_wed_rro_desc *)q->desc; |
| + for (i = 0; i < q->ndesc; i++) { |
| + struct mt76_wed_rro_ind *cmd; |
| + |
| + cmd = (struct mt76_wed_rro_ind *)&rro_desc[i]; |
| + cmd->magic_cnt = MT_DMA_WED_IND_CMD_CNT - 1; |
| + } |
| + } |
| + |
| size = q->ndesc * sizeof(*q->entry); |
| q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL); |
| if (!q->entry) |
| @@ -724,8 +797,13 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q, |
| if (ret) |
| return ret; |
| |
| - if (q->flags != MT_WED_Q_TXFREE) |
| - mt76_dma_queue_reset(dev, q); |
| + if (mtk_wed_device_active(&dev->mmio.wed)) { |
| + if ((mtk_wed_get_rx_capa(&dev->mmio.wed) && mt76_queue_is_wed_rro(q)) || |
| + mt76_queue_is_wed_tx_free(q)) |
| + return 0; |
| + } |
| + |
| + mt76_dma_queue_reset(dev, q); |
| |
| return 0; |
| } |
| @@ -746,7 +824,8 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q) |
| if (!buf) |
| break; |
| |
| - mt76_put_page_pool_buf(buf, false); |
| + if (!mt76_queue_is_wed_rro(q)) |
| + mt76_put_page_pool_buf(buf, false); |
| } while (1); |
| |
| if (q->rx_head) { |
| @@ -761,19 +840,22 @@ static void |
| mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid) |
| { |
| struct mt76_queue *q = &dev->q_rx[qid]; |
| - int i; |
| |
| if (!q->ndesc) |
| return; |
| |
| - for (i = 0; i < q->ndesc; i++) |
| - q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); |
| + if (!mt76_queue_is_wed_rro_ind(q)) { |
| + int i; |
| + |
| + for (i = 0; i < q->ndesc; i++) |
| + q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE); |
| + } |
| |
| mt76_dma_rx_cleanup(dev, q); |
| |
| /* reset WED rx queues */ |
| mt76_dma_wed_setup(dev, q, true); |
| - if (q->flags != MT_WED_Q_TXFREE) { |
| + if (!mt76_queue_is_wed_tx_free(q)) { |
| mt76_dma_sync_idx(dev, q); |
| mt76_dma_rx_fill(dev, q, false); |
| } |
| @@ -816,8 +898,8 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) |
| bool more; |
| |
| if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) && |
| - q->flags == MT_WED_Q_TXFREE) { |
| - dma_idx = Q_READ(dev, q, dma_idx); |
| + mt76_queue_is_wed_tx_free(q)) { |
| + dma_idx = Q_READ(q, dma_idx); |
| check_ddone = true; |
| } |
| |
| @@ -827,7 +909,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget) |
| |
| if (check_ddone) { |
| if (q->tail == dma_idx) |
| - dma_idx = Q_READ(dev, q, dma_idx); |
| + dma_idx = Q_READ(q, dma_idx); |
| |
| if (q->tail == dma_idx) |
| break; |
| @@ -979,16 +1061,23 @@ void mt76_dma_cleanup(struct mt76_dev *dev) |
| mt76_for_each_q_rx(dev, i) { |
| struct mt76_queue *q = &dev->q_rx[i]; |
| |
| + if (mtk_wed_device_active(&dev->mmio.wed) && |
| + mt76_queue_is_wed_rro(q)) |
| + continue; |
| + |
| netif_napi_del(&dev->napi[i]); |
| mt76_dma_rx_cleanup(dev, q); |
| |
| page_pool_destroy(q->page_pool); |
| } |
| |
| - mt76_free_pending_txwi(dev); |
| - mt76_free_pending_rxwi(dev); |
| - |
| if (mtk_wed_device_active(&dev->mmio.wed)) |
| mtk_wed_device_detach(&dev->mmio.wed); |
| + |
| + if (mtk_wed_device_active(&dev->mmio.wed_hif2)) |
| + mtk_wed_device_detach(&dev->mmio.wed_hif2); |
| + |
| + mt76_free_pending_txwi(dev); |
| + mt76_free_pending_rxwi(dev); |
| } |
| EXPORT_SYMBOL_GPL(mt76_dma_cleanup); |
| diff --git a/dma.h b/dma.h |
| index 1b090d7..22b79d5 100644 |
| --- a/dma.h |
| +++ b/dma.h |
| @@ -25,6 +25,13 @@ |
| #define MT_DMA_PPE_ENTRY GENMASK(30, 16) |
| #define MT_DMA_INFO_PPE_VLD BIT(31) |
| |
| +#define MT_DMA_CTL_PN_CHK_FAIL BIT(13) |
| +#define MT_DMA_CTL_VER_MASK BIT(7) |
| + |
| +#define MT_DMA_RRO_EN BIT(13) |
| + |
| +#define MT_DMA_WED_IND_CMD_CNT 8 |
| + |
| #define MT_DMA_HDR_LEN 4 |
| #define MT_RX_INFO_LEN 4 |
| #define MT_FCE_INFO_LEN 4 |
| @@ -37,6 +44,11 @@ struct mt76_desc { |
| __le32 info; |
| } __packed __aligned(4); |
| |
| +struct mt76_wed_rro_desc { |
| + __le32 buf0; |
| + __le32 buf1; |
| +} __packed __aligned(4); |
| + |
| enum mt76_qsel { |
| MT_QSEL_MGMT, |
| MT_QSEL_HCCA, |
| diff --git a/mac80211.c b/mac80211.c |
| index 12fcb2b..cd102dd 100644 |
| --- a/mac80211.c |
| +++ b/mac80211.c |
| @@ -1726,7 +1726,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna); |
| |
| struct mt76_queue * |
| mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, |
| - int ring_base, u32 flags) |
| + int ring_base, void *wed, u32 flags) |
| { |
| struct mt76_queue *hwq; |
| int err; |
| @@ -1736,6 +1736,7 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, |
| return ERR_PTR(-ENOMEM); |
| |
| hwq->flags = flags; |
| + hwq->wed = wed; |
| |
| err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base); |
| if (err < 0) |
| @@ -1843,3 +1844,19 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy) |
| return MT_DFS_STATE_ACTIVE; |
| } |
| EXPORT_SYMBOL_GPL(mt76_phy_dfs_state); |
| + |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| +int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| + struct net_device *netdev, enum tc_setup_type type, |
| + void *type_data) |
| +{ |
| + struct mt76_phy *phy = hw->priv; |
| + struct mtk_wed_device *wed = &phy->dev->mmio.wed; |
| + |
| + if (!mtk_wed_device_active(wed)) |
| + return -EOPNOTSUPP; |
| + |
| + return mtk_wed_device_setup_tc(wed, netdev, type, type_data); |
| +} |
| +EXPORT_SYMBOL_GPL(mt76_net_setup_tc); |
| +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ |
| diff --git a/mmio.c b/mmio.c |
| index 86e3d2a..c346249 100644 |
| --- a/mmio.c |
| +++ b/mmio.c |
| @@ -4,6 +4,7 @@ |
| */ |
| |
| #include "mt76.h" |
| +#include "dma.h" |
| #include "trace.h" |
| |
| static u32 mt76_mmio_rr(struct mt76_dev *dev, u32 offset) |
| @@ -84,6 +85,102 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr, |
| } |
| EXPORT_SYMBOL_GPL(mt76_set_irq_mask); |
| |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| +void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) |
| +{ |
| + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); |
| + int i; |
| + |
| + for (i = 0; i < dev->rx_token_size; i++) { |
| + struct mt76_txwi_cache *t; |
| + |
| + t = mt76_rx_token_release(dev, i); |
| + if (!t || !t->ptr) |
| + continue; |
| + |
| + mt76_put_page_pool_buf(t->ptr, false); |
| + t->ptr = NULL; |
| + |
| + mt76_put_rxwi(dev, t); |
| + } |
| + |
| + mt76_free_pending_rxwi(dev); |
| +} |
| +EXPORT_SYMBOL_GPL(mt76_mmio_wed_release_rx_buf); |
| + |
| +u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size) |
| +{ |
| + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); |
| + struct mtk_wed_bm_desc *desc = wed->rx_buf_ring.desc; |
| + struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN]; |
| + int i, len = SKB_WITH_OVERHEAD(q->buf_size); |
| + struct mt76_txwi_cache *t = NULL; |
| + |
| + for (i = 0; i < size; i++) { |
| + enum dma_data_direction dir; |
| + dma_addr_t addr; |
| + u32 offset; |
| + int token; |
| + void *buf; |
| + |
| + t = mt76_get_rxwi(dev); |
| + if (!t) |
| + goto unmap; |
| + |
| + buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); |
| + if (!buf) |
| + goto unmap; |
| + |
| + 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); |
| + |
| + desc->buf0 = cpu_to_le32(addr); |
| + token = mt76_rx_token_consume(dev, buf, t, addr); |
| + if (token < 0) { |
| + mt76_put_page_pool_buf(buf, false); |
| + goto unmap; |
| + } |
| + |
| + desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, |
| + token)); |
| + desc++; |
| + } |
| + |
| + return 0; |
| + |
| +unmap: |
| + if (t) |
| + mt76_put_rxwi(dev, t); |
| + mt76_mmio_wed_release_rx_buf(wed); |
| + |
| + return -ENOMEM; |
| +} |
| +EXPORT_SYMBOL_GPL(mt76_mmio_wed_init_rx_buf); |
| + |
| +int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed) |
| +{ |
| + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); |
| + |
| + spin_lock_bh(&dev->token_lock); |
| + dev->token_size = wed->wlan.token_start; |
| + spin_unlock_bh(&dev->token_lock); |
| + |
| + return !wait_event_timeout(dev->tx_wait, !dev->wed_token_count, HZ); |
| +} |
| +EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_enable); |
| + |
| +void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed) |
| +{ |
| + struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed); |
| + |
| + spin_lock_bh(&dev->token_lock); |
| + dev->token_size = dev->drv->token_size; |
| + spin_unlock_bh(&dev->token_lock); |
| +} |
| +EXPORT_SYMBOL_GPL(mt76_mmio_wed_offload_disable); |
| +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ |
| + |
| void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs) |
| { |
| static const struct mt76_bus_ops mt76_mmio_ops = { |
| diff --git a/mt76.h b/mt76.h |
| index a238216..7f93210 100644 |
| --- a/mt76.h |
| +++ b/mt76.h |
| @@ -28,15 +28,22 @@ |
| #define MT76_TOKEN_FREE_THR 64 |
| |
| #define MT_QFLAG_WED_RING GENMASK(1, 0) |
| -#define MT_QFLAG_WED_TYPE GENMASK(3, 2) |
| -#define MT_QFLAG_WED BIT(4) |
| +#define MT_QFLAG_WED_TYPE GENMASK(4, 2) |
| +#define MT_QFLAG_WED BIT(5) |
| +#define MT_QFLAG_WED_RRO BIT(6) |
| +#define MT_QFLAG_WED_RRO_EN BIT(7) |
| |
| #define __MT_WED_Q(_type, _n) (MT_QFLAG_WED | \ |
| FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \ |
| FIELD_PREP(MT_QFLAG_WED_RING, _n)) |
| +#define __MT_WED_RRO_Q(_type, _n) (MT_QFLAG_WED_RRO | __MT_WED_Q(_type, _n)) |
| + |
| #define MT_WED_Q_TX(_n) __MT_WED_Q(MT76_WED_Q_TX, _n) |
| #define MT_WED_Q_RX(_n) __MT_WED_Q(MT76_WED_Q_RX, _n) |
| #define MT_WED_Q_TXFREE __MT_WED_Q(MT76_WED_Q_TXFREE, 0) |
| +#define MT_WED_RRO_Q_DATA(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_DATA, _n) |
| +#define MT_WED_RRO_Q_MSDU_PG(_n) __MT_WED_RRO_Q(MT76_WED_RRO_Q_MSDU_PG, _n) |
| +#define MT_WED_RRO_Q_IND __MT_WED_RRO_Q(MT76_WED_RRO_Q_IND, 0) |
| |
| struct mt76_dev; |
| struct mt76_phy; |
| @@ -58,6 +65,9 @@ enum mt76_wed_type { |
| MT76_WED_Q_TX, |
| MT76_WED_Q_TXFREE, |
| MT76_WED_Q_RX, |
| + MT76_WED_RRO_Q_DATA, |
| + MT76_WED_RRO_Q_MSDU_PG, |
| + MT76_WED_RRO_Q_IND, |
| }; |
| |
| struct mt76_bus_ops { |
| @@ -106,6 +116,16 @@ enum mt76_rxq_id { |
| MT_RXQ_MAIN_WA, |
| MT_RXQ_BAND2, |
| MT_RXQ_BAND2_WA, |
| + MT_RXQ_RRO_BAND0, |
| + MT_RXQ_RRO_BAND1, |
| + MT_RXQ_RRO_BAND2, |
| + MT_RXQ_MSDU_PAGE_BAND0, |
| + MT_RXQ_MSDU_PAGE_BAND1, |
| + MT_RXQ_MSDU_PAGE_BAND2, |
| + MT_RXQ_TXFREE_BAND0, |
| + MT_RXQ_TXFREE_BAND1, |
| + MT_RXQ_TXFREE_BAND2, |
| + MT_RXQ_RRO_IND, |
| __MT_RXQ_MAX |
| }; |
| |
| @@ -183,6 +203,7 @@ struct mt76_queue { |
| spinlock_t lock; |
| spinlock_t cleanup_lock; |
| struct mt76_queue_entry *entry; |
| + struct mt76_rro_desc *rro_desc; |
| struct mt76_desc *desc; |
| |
| u16 first; |
| @@ -196,8 +217,9 @@ struct mt76_queue { |
| |
| u8 buf_offset; |
| u8 hw_idx; |
| - u8 flags; |
| + u16 flags; |
| |
| + struct mtk_wed_device *wed; |
| u32 wed_regs; |
| |
| dma_addr_t desc_dma; |
| @@ -352,6 +374,17 @@ struct mt76_txq { |
| bool aggr; |
| }; |
| |
| +struct mt76_wed_rro_ind { |
| + u32 se_id : 12; |
| + u32 rsv : 4; |
| + u32 start_sn : 12; |
| + u32 ind_reason : 4; |
| + u32 ind_cnt : 13; |
| + u32 win_sz : 3; |
| + u32 rsv2 : 13; |
| + u32 magic_cnt : 3; |
| +}; |
| + |
| struct mt76_txwi_cache { |
| struct list_head list; |
| dma_addr_t dma_addr; |
| @@ -602,6 +635,7 @@ struct mt76_mmio { |
| u32 irqmask; |
| |
| struct mtk_wed_device wed; |
| + struct mtk_wed_device wed_hif2; |
| struct completion wed_reset; |
| struct completion wed_reset_complete; |
| }; |
| @@ -1046,6 +1080,12 @@ bool ____mt76_poll_msec(struct mt76_dev *dev, u32 offset, u32 mask, u32 val, |
| void mt76_mmio_init(struct mt76_dev *dev, void __iomem *regs); |
| void mt76_pci_disable_aspm(struct pci_dev *pdev); |
| |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| +int mt76_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| + struct net_device *netdev, enum tc_setup_type type, |
| + void *type_data); |
| +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ |
| + |
| static inline u16 mt76_chip(struct mt76_dev *dev) |
| { |
| return dev->rev >> 16; |
| @@ -1056,6 +1096,13 @@ static inline u16 mt76_rev(struct mt76_dev *dev) |
| return dev->rev & 0xffff; |
| } |
| |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| +u32 mt76_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size); |
| +void mt76_mmio_wed_release_rx_buf(struct mtk_wed_device *wed); |
| +int mt76_mmio_wed_offload_enable(struct mtk_wed_device *wed); |
| +void mt76_mmio_wed_offload_disable(struct mtk_wed_device *wed); |
| +#endif /*CONFIG_NET_MEDIATEK_SOC_WED */ |
| + |
| #define mt76xx_chip(dev) mt76_chip(&((dev)->mt76)) |
| #define mt76xx_rev(dev) mt76_rev(&((dev)->mt76)) |
| |
| @@ -1105,15 +1152,16 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *data, int offset, int len); |
| |
| struct mt76_queue * |
| mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc, |
| - int ring_base, u32 flags); |
| + int ring_base, void *wed, u32 flags); |
| u16 mt76_calculate_default_rate(struct mt76_phy *phy, |
| struct ieee80211_vif *vif, int rateidx); |
| static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx, |
| - int n_desc, int ring_base, u32 flags) |
| + int n_desc, int ring_base, void *wed, |
| + u32 flags) |
| { |
| struct mt76_queue *q; |
| |
| - q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, flags); |
| + q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, wed, flags); |
| if (IS_ERR(q)) |
| return PTR_ERR(q); |
| |
| @@ -1127,7 +1175,7 @@ static inline int mt76_init_mcu_queue(struct mt76_dev *dev, int qid, int idx, |
| { |
| struct mt76_queue *q; |
| |
| - q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, 0); |
| + q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, NULL, 0); |
| if (IS_ERR(q)) |
| return PTR_ERR(q); |
| |
| @@ -1541,10 +1589,38 @@ 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) |
| +static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q) |
| { |
| return (q->flags & MT_QFLAG_WED) && |
| - FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX; |
| + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_TXFREE; |
| +} |
| + |
| +static inline bool mt76_queue_is_wed_rro(struct mt76_queue *q) |
| +{ |
| + return q->flags & MT_QFLAG_WED_RRO; |
| +} |
| + |
| +static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q) |
| +{ |
| + return mt76_queue_is_wed_rro(q) && |
| + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_IND; |
| +} |
| + |
| +static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q) |
| +{ |
| + return mt76_queue_is_wed_rro(q) && |
| + (FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_DATA || |
| + FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_RRO_Q_MSDU_PG); |
| +} |
| + |
| +static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q) |
| +{ |
| + if (!(q->flags & MT_QFLAG_WED)) |
| + return false; |
| + |
| + return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX || |
| + mt76_queue_is_wed_rro_ind(q) || mt76_queue_is_wed_rro_data(q); |
| + |
| } |
| |
| struct mt76_txwi_cache * |
| @@ -1584,10 +1660,14 @@ static inline void mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked) |
| static inline int |
| mt76_token_get(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi) |
| { |
| - int token; |
| + int token, start = 0; |
| + |
| + if (mtk_wed_device_active(&dev->mmio.wed)) |
| + start = dev->mmio.wed.wlan.nbuf; |
| |
| spin_lock_bh(&dev->token_lock); |
| - token = idr_alloc(&dev->token, *ptxwi, 0, dev->token_size, GFP_ATOMIC); |
| + token = idr_alloc(&dev->token, *ptxwi, start, start + dev->token_size, |
| + GFP_ATOMIC); |
| spin_unlock_bh(&dev->token_lock); |
| |
| return token; |
| diff --git a/mt7603/dma.c b/mt7603/dma.c |
| index 03ba11a..7a2f5d3 100644 |
| --- a/mt7603/dma.c |
| +++ b/mt7603/dma.c |
| @@ -173,13 +173,14 @@ int mt7603_dma_init(struct mt7603_dev *dev) |
| |
| for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { |
| ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], |
| - MT7603_TX_RING_SIZE, MT_TX_RING_BASE, 0); |
| + MT7603_TX_RING_SIZE, MT_TX_RING_BASE, |
| + NULL, 0); |
| if (ret) |
| return ret; |
| } |
| |
| ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, |
| - MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, 0); |
| + MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| |
| @@ -189,12 +190,12 @@ int mt7603_dma_init(struct mt7603_dev *dev) |
| return ret; |
| |
| ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_BEACON, MT_TX_HW_QUEUE_BCN, |
| - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); |
| + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| |
| ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_CAB, MT_TX_HW_QUEUE_BMC, |
| - MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0); |
| + MT_MCU_RING_SIZE, MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| |
| diff --git a/mt7615/dma.c b/mt7615/dma.c |
| index 0ce01cc..e7135b2 100644 |
| --- a/mt7615/dma.c |
| +++ b/mt7615/dma.c |
| @@ -26,14 +26,14 @@ mt7622_init_tx_queues_multi(struct mt7615_dev *dev) |
| for (i = 0; i < ARRAY_SIZE(wmm_queue_map); i++) { |
| ret = mt76_init_tx_queue(&dev->mphy, i, wmm_queue_map[i], |
| MT7615_TX_RING_SIZE / 2, |
| - MT_TX_RING_BASE, 0); |
| + MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| } |
| |
| ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT7622_TXQ_MGMT, |
| MT7615_TX_MGMT_RING_SIZE, |
| - MT_TX_RING_BASE, 0); |
| + MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| |
| @@ -55,7 +55,7 @@ mt7615_init_tx_queues(struct mt7615_dev *dev) |
| return mt7622_init_tx_queues_multi(dev); |
| |
| ret = mt76_connac_init_tx_queues(&dev->mphy, 0, MT7615_TX_RING_SIZE, |
| - MT_TX_RING_BASE, 0); |
| + MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| |
| diff --git a/mt76_connac.h b/mt76_connac.h |
| index 1f29d8c..e5ebde1 100644 |
| --- a/mt76_connac.h |
| +++ b/mt76_connac.h |
| @@ -391,7 +391,8 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm) |
| |
| void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss); |
| int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, |
| - int ring_base, u32 flags); |
| + int ring_base, void *wed, u32 flags); |
| + |
| void mt76_connac_write_hw_txp(struct mt76_dev *dev, |
| struct mt76_tx_info *tx_info, |
| void *txp_ptr, u32 id); |
| diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c |
| index 93402d2..c791464 100644 |
| --- a/mt76_connac_mac.c |
| +++ b/mt76_connac_mac.c |
| @@ -256,11 +256,12 @@ void mt76_connac_txp_skb_unmap(struct mt76_dev *dev, |
| EXPORT_SYMBOL_GPL(mt76_connac_txp_skb_unmap); |
| |
| int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc, |
| - int ring_base, u32 flags) |
| + int ring_base, void *wed, u32 flags) |
| { |
| int i, err; |
| |
| - err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, flags); |
| + err = mt76_init_tx_queue(phy, 0, idx, n_desc, ring_base, |
| + wed, flags); |
| if (err < 0) |
| return err; |
| |
| diff --git a/mt76x02_mmio.c b/mt76x02_mmio.c |
| index 9b5e3fb..e5ad635 100644 |
| --- a/mt76x02_mmio.c |
| +++ b/mt76x02_mmio.c |
| @@ -199,13 +199,14 @@ int mt76x02_dma_init(struct mt76x02_dev *dev) |
| for (i = 0; i < IEEE80211_NUM_ACS; i++) { |
| ret = mt76_init_tx_queue(&dev->mphy, i, mt76_ac_to_hwq(i), |
| MT76x02_TX_RING_SIZE, |
| - MT_TX_RING_BASE, 0); |
| + MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| } |
| |
| ret = mt76_init_tx_queue(&dev->mphy, MT_TXQ_PSD, MT_TX_HW_QUEUE_MGMT, |
| - MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, 0); |
| + MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, |
| + NULL, 0); |
| if (ret) |
| return ret; |
| |
| diff --git a/mt7915/dma.c b/mt7915/dma.c |
| index 59a44d7..1bceeb5 100644 |
| --- a/mt7915/dma.c |
| +++ b/mt7915/dma.c |
| @@ -9,18 +9,20 @@ static int |
| mt7915_init_tx_queues(struct mt7915_phy *phy, int idx, int n_desc, int ring_base) |
| { |
| struct mt7915_dev *dev = phy->dev; |
| + struct mtk_wed_device *wed = NULL; |
| |
| - if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) { |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { |
| if (is_mt798x(&dev->mt76)) |
| ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; |
| else |
| ring_base = MT_WED_TX_RING_BASE; |
| |
| idx -= MT_TXQ_ID(0); |
| + wed = &dev->mt76.mmio.wed; |
| } |
| |
| return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, ring_base, |
| - MT_WED_Q_TX(idx)); |
| + wed, MT_WED_Q_TX(idx)); |
| } |
| |
| static int mt7915_poll_tx(struct napi_struct *napi, int budget) |
| @@ -492,7 +494,8 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) |
| if (mtk_wed_device_active(&mdev->mmio.wed) && is_mt7915(mdev)) { |
| wa_rx_base = MT_WED_RX_RING_BASE; |
| wa_rx_idx = MT7915_RXQ_MCU_WA; |
| - dev->mt76.q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; |
| + mdev->q_rx[MT_RXQ_MCU_WA].flags = MT_WED_Q_TXFREE; |
| + mdev->q_rx[MT_RXQ_MCU_WA].wed = &mdev->mmio.wed; |
| } else { |
| wa_rx_base = MT_RXQ_RING_BASE(MT_RXQ_MCU_WA); |
| wa_rx_idx = MT_RXQ_ID(MT_RXQ_MCU_WA); |
| @@ -507,9 +510,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) |
| if (!dev->phy.mt76->band_idx) { |
| if (mtk_wed_device_active(&mdev->mmio.wed) && |
| mtk_wed_get_rx_capa(&mdev->mmio.wed)) { |
| - dev->mt76.q_rx[MT_RXQ_MAIN].flags = |
| + mdev->q_rx[MT_RXQ_MAIN].flags = |
| MT_WED_Q_RX(MT7915_RXQ_BAND0); |
| dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; |
| + mdev->q_rx[MT_RXQ_MAIN].wed = &mdev->mmio.wed; |
| } |
| |
| ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], |
| @@ -528,6 +532,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) |
| |
| if (mtk_wed_device_active(&mdev->mmio.wed)) { |
| mdev->q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; |
| + mdev->q_rx[MT_RXQ_MAIN_WA].wed = &mdev->mmio.wed; |
| if (is_mt7916(mdev)) { |
| wa_rx_base = MT_WED_RX_RING_BASE; |
| wa_rx_idx = MT7915_RXQ_MCU_WA; |
| @@ -544,9 +549,10 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2) |
| if (dev->dbdc_support || dev->phy.mt76->band_idx) { |
| if (mtk_wed_device_active(&mdev->mmio.wed) && |
| mtk_wed_get_rx_capa(&mdev->mmio.wed)) { |
| - dev->mt76.q_rx[MT_RXQ_BAND1].flags = |
| + mdev->q_rx[MT_RXQ_BAND1].flags = |
| MT_WED_Q_RX(MT7915_RXQ_BAND1); |
| dev->mt76.rx_token_size += MT7915_RX_RING_SIZE; |
| + mdev->q_rx[MT_RXQ_BAND1].wed = &mdev->mmio.wed; |
| } |
| |
| /* rx data queue for band1 */ |
| @@ -643,7 +649,7 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force) |
| mt76_queue_reset(dev, dev->mt76.q_mcu[i]); |
| |
| mt76_for_each_q_rx(&dev->mt76, i) { |
| - if (dev->mt76.q_rx[i].flags == MT_WED_Q_TXFREE) |
| + if (mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i])) |
| continue; |
| |
| mt76_queue_reset(dev, &dev->mt76.q_rx[i]); |
| diff --git a/mt7915/main.c b/mt7915/main.c |
| index a3fd54c..ba34c8e 100644 |
| --- a/mt7915/main.c |
| +++ b/mt7915/main.c |
| @@ -1653,20 +1653,6 @@ mt7915_net_fill_forward_path(struct ieee80211_hw *hw, |
| |
| return 0; |
| } |
| - |
| -static int |
| -mt7915_net_setup_tc(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| - struct net_device *netdev, enum tc_setup_type type, |
| - void *type_data) |
| -{ |
| - struct mt7915_dev *dev = mt7915_hw_dev(hw); |
| - struct mtk_wed_device *wed = &dev->mt76.mmio.wed; |
| - |
| - if (!mtk_wed_device_active(wed)) |
| - return -EOPNOTSUPP; |
| - |
| - return mtk_wed_device_setup_tc(wed, netdev, type, type_data); |
| -} |
| #endif |
| |
| const struct ieee80211_ops mt7915_ops = { |
| @@ -1721,6 +1707,6 @@ const struct ieee80211_ops mt7915_ops = { |
| .set_radar_background = mt7915_set_radar_background, |
| #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| .net_fill_forward_path = mt7915_net_fill_forward_path, |
| - .net_setup_tc = mt7915_net_setup_tc, |
| + .net_setup_tc = mt76_net_setup_tc, |
| #endif |
| }; |
| diff --git a/mt7915/mmio.c b/mt7915/mmio.c |
| index fc7ace6..85cb3fe 100644 |
| --- a/mt7915/mmio.c |
| +++ b/mt7915/mmio.c |
| @@ -542,105 +542,6 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) |
| } |
| |
| #ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| -static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed) |
| -{ |
| - struct mt7915_dev *dev; |
| - |
| - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); |
| - |
| - spin_lock_bh(&dev->mt76.token_lock); |
| - dev->mt76.token_size = wed->wlan.token_start; |
| - spin_unlock_bh(&dev->mt76.token_lock); |
| - |
| - return !wait_event_timeout(dev->mt76.tx_wait, |
| - !dev->mt76.wed_token_count, HZ); |
| -} |
| - |
| -static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed) |
| -{ |
| - struct mt7915_dev *dev; |
| - |
| - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); |
| - |
| - spin_lock_bh(&dev->mt76.token_lock); |
| - dev->mt76.token_size = MT7915_TOKEN_SIZE; |
| - spin_unlock_bh(&dev->mt76.token_lock); |
| -} |
| - |
| -static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed) |
| -{ |
| - struct mt7915_dev *dev; |
| - int i; |
| - |
| - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); |
| - for (i = 0; i < dev->mt76.rx_token_size; i++) { |
| - struct mt76_txwi_cache *t; |
| - |
| - t = mt76_rx_token_release(&dev->mt76, i); |
| - if (!t || !t->ptr) |
| - continue; |
| - |
| - 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; |
| - struct mt76_queue *q; |
| - int i, len; |
| - |
| - dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed); |
| - q = &dev->mt76.q_rx[MT_RXQ_MAIN]; |
| - len = SKB_WITH_OVERHEAD(q->buf_size); |
| - |
| - for (i = 0; i < size; i++) { |
| - enum dma_data_direction dir; |
| - dma_addr_t addr; |
| - u32 offset; |
| - int token; |
| - void *buf; |
| - |
| - t = mt76_get_rxwi(&dev->mt76); |
| - if (!t) |
| - goto unmap; |
| - |
| - buf = mt76_get_page_pool_buf(q, &offset, q->buf_size); |
| - if (!buf) |
| - goto unmap; |
| - |
| - 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) { |
| - mt76_put_page_pool_buf(buf, false); |
| - goto unmap; |
| - } |
| - |
| - desc->token |= cpu_to_le32(FIELD_PREP(MT_DMA_CTL_TOKEN, |
| - token)); |
| - desc++; |
| - } |
| - |
| - return 0; |
| - |
| -unmap: |
| - if (t) |
| - mt76_put_rxwi(&dev->mt76, t); |
| - mt7915_mmio_wed_release_rx_buf(wed); |
| - return -ENOMEM; |
| -} |
| - |
| static void mt7915_mmio_wed_update_rx_stats(struct mtk_wed_device *wed, |
| struct mtk_wed_wo_rx_stats *stats) |
| { |
| @@ -778,10 +679,10 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr, |
| } |
| |
| wed->wlan.init_buf = mt7915_wed_init_buf; |
| - wed->wlan.offload_enable = mt7915_mmio_wed_offload_enable; |
| - wed->wlan.offload_disable = mt7915_mmio_wed_offload_disable; |
| - wed->wlan.init_rx_buf = mt7915_mmio_wed_init_rx_buf; |
| - wed->wlan.release_rx_buf = mt7915_mmio_wed_release_rx_buf; |
| + wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; |
| + wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; |
| + wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; |
| + wed->wlan.release_rx_buf = mt76_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; |
| diff --git a/mt7921/pci.c b/mt7921/pci.c |
| index 9647e4b..9ea7e0c 100644 |
| --- a/mt7921/pci.c |
| +++ b/mt7921/pci.c |
| @@ -171,7 +171,7 @@ static int mt7921_dma_init(struct mt792x_dev *dev) |
| /* init tx queue */ |
| ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0, |
| MT7921_TX_RING_SIZE, |
| - MT_TX_RING_BASE, 0); |
| + MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| |
| diff --git a/mt7925/pci.c b/mt7925/pci.c |
| index 08ef75e..734f31e 100644 |
| --- a/mt7925/pci.c |
| +++ b/mt7925/pci.c |
| @@ -218,7 +218,7 @@ static int mt7925_dma_init(struct mt792x_dev *dev) |
| /* init tx queue */ |
| ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7925_TXQ_BAND0, |
| MT7925_TX_RING_SIZE, |
| - MT_TX_RING_BASE, 0); |
| + MT_TX_RING_BASE, NULL, 0); |
| if (ret) |
| return ret; |
| |
| diff --git a/mt7996/dma.c b/mt7996/dma.c |
| index 586e247..2221d22 100644 |
| --- a/mt7996/dma.c |
| +++ b/mt7996/dma.c |
| @@ -7,6 +7,26 @@ |
| #include "../dma.h" |
| #include "mac.h" |
| |
| +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc, |
| + int ring_base, struct mtk_wed_device *wed) |
| +{ |
| + struct mt7996_dev *dev = phy->dev; |
| + u32 flags = 0; |
| + |
| + if (mtk_wed_device_active(wed)) { |
| + ring_base += MT_TXQ_ID(0) * MT_RING_SIZE; |
| + idx -= MT_TXQ_ID(0); |
| + |
| + if (phy->mt76->band_idx == MT_BAND2) |
| + flags = MT_WED_Q_TX(0); |
| + else |
| + flags = MT_WED_Q_TX(idx); |
| + } |
| + |
| + return mt76_connac_init_tx_queues(phy->mt76, idx, n_desc, |
| + ring_base, wed, flags); |
| +} |
| + |
| static int mt7996_poll_tx(struct napi_struct *napi, int budget) |
| { |
| struct mt7996_dev *dev; |
| @@ -45,6 +65,29 @@ static void mt7996_dma_config(struct mt7996_dev *dev) |
| RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2); |
| RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI); |
| |
| + if (dev->has_rro) { |
| + /* band0 */ |
| + RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0, |
| + MT7996_RXQ_RRO_BAND0); |
| + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0, |
| + MT7996_RXQ_MSDU_PG_BAND0); |
| + RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN, |
| + MT7996_RXQ_TXFREE0); |
| + /* band1 */ |
| + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1, |
| + MT7996_RXQ_MSDU_PG_BAND1); |
| + /* band2 */ |
| + RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2, |
| + MT7996_RXQ_RRO_BAND2); |
| + RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2, |
| + MT7996_RXQ_MSDU_PG_BAND2); |
| + RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI, |
| + MT7996_RXQ_TXFREE2); |
| + |
| + RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND, |
| + MT7996_RXQ_RRO_IND); |
| + } |
| + |
| /* data tx queue */ |
| TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0); |
| TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1); |
| @@ -73,6 +116,24 @@ static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs) |
| mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10)); |
| mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10)); |
| |
| + if (dev->has_rro) { |
| + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs, |
| + PREFETCH(0x3a0, 0x10)); |
| + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs, |
| + PREFETCH(0x4a0, 0x10)); |
| + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs, |
| + PREFETCH(0x5a0, 0x4)); |
| + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs, |
| + PREFETCH(0x5e0, 0x4)); |
| + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs, |
| + PREFETCH(0x620, 0x4)); |
| + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs, |
| + PREFETCH(0x660, 0x4)); |
| + mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs, |
| + PREFETCH(0x6a0, 0x4)); |
| + } |
| +#undef PREFETCH |
| + |
| mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + ofs, WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE); |
| } |
| |
| @@ -128,8 +189,9 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset) |
| } |
| } |
| |
| -void mt7996_dma_start(struct mt7996_dev *dev, bool reset) |
| +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset) |
| { |
| + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; |
| u32 hif1_ofs = 0; |
| u32 irq_mask; |
| |
| @@ -138,11 +200,16 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset) |
| |
| /* enable WFDMA Tx/Rx */ |
| if (!reset) { |
| - mt76_set(dev, MT_WFDMA0_GLO_CFG, |
| - MT_WFDMA0_GLO_CFG_TX_DMA_EN | |
| - MT_WFDMA0_GLO_CFG_RX_DMA_EN | |
| - MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | |
| - MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); |
| + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) |
| + mt76_set(dev, MT_WFDMA0_GLO_CFG, |
| + MT_WFDMA0_GLO_CFG_TX_DMA_EN | |
| + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO); |
| + else |
| + mt76_set(dev, MT_WFDMA0_GLO_CFG, |
| + MT_WFDMA0_GLO_CFG_TX_DMA_EN | |
| + MT_WFDMA0_GLO_CFG_RX_DMA_EN | |
| + MT_WFDMA0_GLO_CFG_OMIT_TX_INFO | |
| + MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2); |
| |
| if (dev->hif2) |
| mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs, |
| @@ -153,11 +220,7 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset) |
| } |
| |
| /* enable interrupts for TX/RX rings */ |
| - irq_mask = MT_INT_MCU_CMD; |
| - if (reset) |
| - goto done; |
| - |
| - irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; |
| + irq_mask = MT_INT_MCU_CMD | MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU; |
| |
| if (!dev->mphy.band_idx) |
| irq_mask |= MT_INT_BAND0_RX_DONE; |
| @@ -168,7 +231,16 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset) |
| if (dev->tbtc_support) |
| irq_mask |= MT_INT_BAND2_RX_DONE; |
| |
| -done: |
| + if (mtk_wed_device_active(wed) && wed_reset) { |
| + u32 wed_irq_mask = irq_mask; |
| + |
| + wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1; |
| + mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask); |
| + mtk_wed_device_start(wed, wed_irq_mask); |
| + } |
| + |
| + irq_mask = reset ? MT_INT_MCU_CMD : irq_mask; |
| + |
| mt7996_irq_enable(dev, irq_mask); |
| mt7996_irq_disable(dev, 0); |
| } |
| @@ -241,17 +313,90 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset) |
| /* fix hardware limitation, pcie1's rx ring3 is not available |
| * so, redirect pcie0 rx ring3 interrupt to pcie1 |
| */ |
| - mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, |
| - MT_WFDMA0_RX_INT_SEL_RING3); |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed) && |
| + dev->has_rro) |
| + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs, |
| + MT_WFDMA0_RX_INT_SEL_RING6); |
| + else |
| + mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL, |
| + MT_WFDMA0_RX_INT_SEL_RING3); |
| + } |
| + |
| + mt7996_dma_start(dev, reset, true); |
| +} |
| + |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| +int mt7996_dma_rro_init(struct mt7996_dev *dev) |
| +{ |
| + struct mt76_dev *mdev = &dev->mt76; |
| + u32 irq_mask; |
| + int ret; |
| + |
| + /* ind cmd */ |
| + mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND; |
| + mdev->q_rx[MT_RXQ_RRO_IND].wed = &mdev->mmio.wed; |
| + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_RRO_IND], |
| + MT_RXQ_ID(MT_RXQ_RRO_IND), |
| + MT7996_RX_RING_SIZE, |
| + 0, MT_RXQ_RRO_IND_RING_BASE); |
| + if (ret) |
| + return ret; |
| |
| - /* TODO: redirect rx ring6 interrupt to pcie0 for wed function */ |
| + /* rx msdu page queue for band0 */ |
| + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].flags = |
| + MT_WED_RRO_Q_MSDU_PG(0) | MT_QFLAG_WED_RRO_EN; |
| + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0].wed = &mdev->mmio.wed; |
| + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND0], |
| + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND0), |
| + MT7996_RX_RING_SIZE, |
| + MT7996_RX_MSDU_PAGE_SIZE, |
| + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0)); |
| + if (ret) |
| + return ret; |
| + |
| + if (dev->dbdc_support) { |
| + /* rx msdu page queue for band1 */ |
| + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].flags = |
| + MT_WED_RRO_Q_MSDU_PG(1) | MT_QFLAG_WED_RRO_EN; |
| + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1].wed = &mdev->mmio.wed; |
| + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND1], |
| + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND1), |
| + MT7996_RX_RING_SIZE, |
| + MT7996_RX_MSDU_PAGE_SIZE, |
| + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1)); |
| + if (ret) |
| + return ret; |
| + } |
| + |
| + if (dev->tbtc_support) { |
| + /* rx msdu page queue for band2 */ |
| + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].flags = |
| + MT_WED_RRO_Q_MSDU_PG(2) | MT_QFLAG_WED_RRO_EN; |
| + mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2].wed = &mdev->mmio.wed; |
| + ret = mt76_queue_alloc(dev, &mdev->q_rx[MT_RXQ_MSDU_PAGE_BAND2], |
| + MT_RXQ_ID(MT_RXQ_MSDU_PAGE_BAND2), |
| + MT7996_RX_RING_SIZE, |
| + MT7996_RX_MSDU_PAGE_SIZE, |
| + MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2)); |
| + if (ret) |
| + return ret; |
| } |
| |
| - mt7996_dma_start(dev, reset); |
| + irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE | |
| + MT_INT_TX_DONE_BAND2; |
| + mt76_wr(dev, MT_INT_MASK_CSR, irq_mask); |
| + mtk_wed_device_start_hw_rro(&mdev->mmio.wed, irq_mask, false); |
| + mt7996_irq_enable(dev, irq_mask); |
| + |
| + return 0; |
| } |
| +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ |
| |
| int mt7996_dma_init(struct mt7996_dev *dev) |
| { |
| + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; |
| + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; |
| + u32 rx_base; |
| u32 hif1_ofs = 0; |
| int ret; |
| |
| @@ -265,10 +410,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) |
| mt7996_dma_disable(dev, true); |
| |
| /* init tx queue */ |
| - ret = mt76_connac_init_tx_queues(dev->phy.mt76, |
| - MT_TXQ_ID(dev->mphy.band_idx), |
| - MT7996_TX_RING_SIZE, |
| - MT_TXQ_RING_BASE(0), 0); |
| + ret = mt7996_init_tx_queues(&dev->phy, |
| + MT_TXQ_ID(dev->mphy.band_idx), |
| + MT7996_TX_RING_SIZE, |
| + MT_TXQ_RING_BASE(0), |
| + wed); |
| if (ret) |
| return ret; |
| |
| @@ -315,6 +461,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) |
| return ret; |
| |
| /* rx data queue for band0 and band1 */ |
| + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) { |
| + dev->mt76.q_rx[MT_RXQ_MAIN].flags = MT_WED_Q_RX(0); |
| + dev->mt76.q_rx[MT_RXQ_MAIN].wed = wed; |
| + } |
| + |
| ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], |
| MT_RXQ_ID(MT_RXQ_MAIN), |
| MT7996_RX_RING_SIZE, |
| @@ -324,6 +475,11 @@ int mt7996_dma_init(struct mt7996_dev *dev) |
| return ret; |
| |
| /* tx free notify event from WA for band0 */ |
| + if (mtk_wed_device_active(wed) && !dev->has_rro) { |
| + dev->mt76.q_rx[MT_RXQ_MAIN_WA].flags = MT_WED_Q_TXFREE; |
| + dev->mt76.q_rx[MT_RXQ_MAIN_WA].wed = wed; |
| + } |
| + |
| ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN_WA], |
| MT_RXQ_ID(MT_RXQ_MAIN_WA), |
| MT7996_RX_MCU_RING_SIZE, |
| @@ -334,17 +490,23 @@ int mt7996_dma_init(struct mt7996_dev *dev) |
| |
| if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { |
| /* rx data queue for band2 */ |
| + rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs; |
| ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2], |
| MT_RXQ_ID(MT_RXQ_BAND2), |
| MT7996_RX_RING_SIZE, |
| MT_RX_BUF_SIZE, |
| - MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs); |
| + rx_base); |
| if (ret) |
| return ret; |
| |
| /* tx free notify event from WA for band2 |
| * use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1 |
| */ |
| + if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) { |
| + dev->mt76.q_rx[MT_RXQ_BAND2_WA].flags = MT_WED_Q_TXFREE; |
| + dev->mt76.q_rx[MT_RXQ_BAND2_WA].wed = wed_hif2; |
| + } |
| + |
| ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND2_WA], |
| MT_RXQ_ID(MT_RXQ_BAND2_WA), |
| MT7996_RX_MCU_RING_SIZE, |
| @@ -354,6 +516,60 @@ int mt7996_dma_init(struct mt7996_dev *dev) |
| return ret; |
| } |
| |
| + if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) && |
| + dev->has_rro) { |
| + /* rx rro data queue for band0 */ |
| + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].flags = |
| + MT_WED_RRO_Q_DATA(0) | MT_QFLAG_WED_RRO_EN; |
| + dev->mt76.q_rx[MT_RXQ_RRO_BAND0].wed = wed; |
| + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0], |
| + MT_RXQ_ID(MT_RXQ_RRO_BAND0), |
| + MT7996_RX_RING_SIZE, |
| + MT7996_RX_BUF_SIZE, |
| + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0)); |
| + if (ret) |
| + return ret; |
| + |
| + /* tx free notify event from WA for band0 */ |
| + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].flags = MT_WED_Q_TXFREE; |
| + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed; |
| + |
| + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0], |
| + MT_RXQ_ID(MT_RXQ_TXFREE_BAND0), |
| + MT7996_RX_MCU_RING_SIZE, |
| + MT7996_RX_BUF_SIZE, |
| + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0)); |
| + if (ret) |
| + return ret; |
| + |
| + if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) { |
| + /* rx rro data queue for band2 */ |
| + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].flags = |
| + MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN; |
| + dev->mt76.q_rx[MT_RXQ_RRO_BAND2].wed = wed; |
| + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2], |
| + MT_RXQ_ID(MT_RXQ_RRO_BAND2), |
| + MT7996_RX_RING_SIZE, |
| + MT7996_RX_BUF_SIZE, |
| + MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs); |
| + if (ret) |
| + return ret; |
| + |
| + /* tx free notify event from MAC for band2 */ |
| + if (mtk_wed_device_active(wed_hif2)) { |
| + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].flags = MT_WED_Q_TXFREE; |
| + dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].wed = wed_hif2; |
| + } |
| + ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2], |
| + MT_RXQ_ID(MT_RXQ_TXFREE_BAND2), |
| + MT7996_RX_MCU_RING_SIZE, |
| + MT7996_RX_BUF_SIZE, |
| + MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND2) + hif1_ofs); |
| + if (ret) |
| + return ret; |
| + } |
| + } |
| + |
| ret = mt76_init_queues(dev, mt76_dma_rx_poll); |
| if (ret < 0) |
| return ret; |
| diff --git a/mt7996/init.c b/mt7996/init.c |
| index 12c2513..d335b58 100644 |
| --- a/mt7996/init.c |
| +++ b/mt7996/init.c |
| @@ -155,7 +155,7 @@ mt7996_regd_notifier(struct wiphy *wiphy, |
| } |
| |
| static void |
| -mt7996_init_wiphy(struct ieee80211_hw *hw) |
| +mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed) |
| { |
| struct mt7996_phy *phy = mt7996_hw_phy(hw); |
| struct mt76_dev *mdev = &phy->dev->mt76; |
| @@ -167,6 +167,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw) |
| hw->max_rx_aggregation_subframes = max_subframes; |
| hw->max_tx_aggregation_subframes = max_subframes; |
| hw->netdev_features = NETIF_F_RXCSUM; |
| + if (mtk_wed_device_active(wed)) |
| + hw->netdev_features |= NETIF_F_HW_TC; |
| |
| hw->radiotap_timestamp.units_pos = |
| IEEE80211_RADIOTAP_TIMESTAMP_UNIT_US; |
| @@ -312,8 +314,13 @@ void mt7996_mac_init(struct mt7996_dev *dev) |
| |
| /* rro module init */ |
| mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2); |
| - mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); |
| - mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); |
| + if (dev->has_rro) { |
| + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1); |
| + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0); |
| + } else { |
| + mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3); |
| + mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1); |
| + } |
| |
| mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET), |
| MCU_WA_PARAM_HW_PATH_HIF_VER, |
| @@ -350,6 +357,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, |
| struct mt76_phy *mphy; |
| u32 mac_ofs, hif1_ofs = 0; |
| int ret; |
| + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; |
| |
| if (band != MT_BAND1 && band != MT_BAND2) |
| return 0; |
| @@ -361,8 +369,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, |
| if (phy) |
| return 0; |
| |
| - if (band == MT_BAND2 && dev->hif2) |
| + if (band == MT_BAND2 && dev->hif2) { |
| hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); |
| + wed = &dev->mt76.mmio.wed_hif2; |
| + } |
| |
| mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band); |
| if (!mphy) |
| @@ -395,11 +405,12 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, |
| mt76_eeprom_override(mphy); |
| |
| /* init wiphy according to mphy and phy */ |
| - mt7996_init_wiphy(mphy->hw); |
| - ret = mt76_connac_init_tx_queues(phy->mt76, |
| - MT_TXQ_ID(band), |
| - MT7996_TX_RING_SIZE, |
| - MT_TXQ_RING_BASE(band) + hif1_ofs, 0); |
| + mt7996_init_wiphy(mphy->hw, wed); |
| + ret = mt7996_init_tx_queues(mphy->priv, |
| + MT_TXQ_ID(band), |
| + MT7996_TX_RING_SIZE, |
| + MT_TXQ_RING_BASE(band) + hif1_ofs, |
| + wed); |
| if (ret) |
| goto error; |
| |
| @@ -412,6 +423,13 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy, |
| if (ret) |
| goto error; |
| |
| + if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) { |
| + u32 irq_mask = dev->mt76.mmio.irqmask | MT_INT_TX_DONE_BAND2; |
| + |
| + mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask); |
| + mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, irq_mask); |
| + } |
| + |
| return 0; |
| |
| error: |
| @@ -456,6 +474,120 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev) |
| msleep(20); |
| } |
| |
| +static int mt7996_wed_rro_init(struct mt7996_dev *dev) |
| +{ |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; |
| + u32 reg = MT_RRO_ADDR_ELEM_SEG_ADDR0; |
| + struct mt7996_wed_rro_addr *addr; |
| + void *ptr; |
| + int i; |
| + |
| + if (!dev->has_rro) |
| + return 0; |
| + |
| + if (!mtk_wed_device_active(wed)) |
| + return 0; |
| + |
| + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) { |
| + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, |
| + MT7996_RRO_BA_BITMAP_CR_SIZE, |
| + &dev->wed_rro.ba_bitmap[i].phy_addr, |
| + GFP_KERNEL); |
| + if (!ptr) |
| + return -ENOMEM; |
| + |
| + dev->wed_rro.ba_bitmap[i].ptr = ptr; |
| + } |
| + |
| + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { |
| + int j; |
| + |
| + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, |
| + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr), |
| + &dev->wed_rro.addr_elem[i].phy_addr, |
| + GFP_KERNEL); |
| + if (!ptr) |
| + return -ENOMEM; |
| + |
| + dev->wed_rro.addr_elem[i].ptr = ptr; |
| + memset(dev->wed_rro.addr_elem[i].ptr, 0, |
| + MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr)); |
| + |
| + addr = dev->wed_rro.addr_elem[i].ptr; |
| + for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) { |
| + addr->signature = 0xff; |
| + addr++; |
| + } |
| + |
| + wed->wlan.ind_cmd.addr_elem_phys[i] = |
| + dev->wed_rro.addr_elem[i].phy_addr; |
| + } |
| + |
| + ptr = dmam_alloc_coherent(dev->mt76.dma_dev, |
| + MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr), |
| + &dev->wed_rro.session.phy_addr, |
| + GFP_KERNEL); |
| + if (!ptr) |
| + return -ENOMEM; |
| + |
| + dev->wed_rro.session.ptr = ptr; |
| + addr = dev->wed_rro.session.ptr; |
| + for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) { |
| + addr->signature = 0xff; |
| + addr++; |
| + } |
| + |
| + /* rro hw init */ |
| + /* TODO: remove line after WM has set */ |
| + mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK); |
| + |
| + /* setup BA bitmap cache address */ |
| + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0, |
| + dev->wed_rro.ba_bitmap[0].phy_addr); |
| + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0); |
| + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0, |
| + dev->wed_rro.ba_bitmap[1].phy_addr); |
| + mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0); |
| + |
| + /* setup Address element address */ |
| + for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) { |
| + mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4); |
| + reg += 4; |
| + } |
| + |
| + /* setup Address element address - separate address segment mode */ |
| + mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1, |
| + MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE); |
| + |
| + wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6; |
| + wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION; |
| + wed->wlan.ind_cmd.particular_se_phys = dev->wed_rro.session.phy_addr; |
| + wed->wlan.ind_cmd.se_group_nums = MT7996_RRO_ADDR_ELEM_LEN; |
| + wed->wlan.ind_cmd.ack_sn_addr = MT_RRO_ACK_SN_CTRL; |
| + |
| + mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0x15010e00); |
| + mt76_set(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, |
| + MT_RRO_IND_CMD_SIGNATURE_BASE1_EN); |
| + |
| + /* particular session configure */ |
| + /* use max session idx + 1 as particular session id */ |
| + mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr); |
| + mt76_wr(dev, MT_RRO_PARTICULAR_CFG1, |
| + MT_RRO_PARTICULAR_CONFG_EN | |
| + FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION)); |
| + |
| + /* interrupt enable */ |
| + mt76_wr(dev, MT_RRO_HOST_INT_ENA, |
| + MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA); |
| + |
| + /* rro ind cmd queue init */ |
| + return mt7996_dma_rro_init(dev); |
| +#else |
| + return 0; |
| +#endif |
| +} |
| + |
| static int mt7996_init_hardware(struct mt7996_dev *dev) |
| { |
| int ret, idx; |
| @@ -477,6 +609,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev) |
| if (ret) |
| return ret; |
| |
| + ret = mt7996_wed_rro_init(dev); |
| + if (ret) |
| + return ret; |
| + |
| ret = mt7996_eeprom_init(dev); |
| if (ret < 0) |
| return ret; |
| @@ -884,7 +1020,7 @@ int mt7996_register_device(struct mt7996_dev *dev) |
| if (ret) |
| return ret; |
| |
| - mt7996_init_wiphy(hw); |
| + mt7996_init_wiphy(hw, &dev->mt76.mmio.wed); |
| |
| ret = mt76_register_device(&dev->mt76, true, mt76_rates, |
| ARRAY_SIZE(mt76_rates)); |
| diff --git a/mt7996/mac.c b/mt7996/mac.c |
| index 1a1e218..4be5410 100644 |
| --- a/mt7996/mac.c |
| +++ b/mt7996/mac.c |
| @@ -449,8 +449,36 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev, |
| return 0; |
| } |
| |
| +static void |
| +mt7996_wed_check_ppe(struct mt7996_dev *dev, struct mt76_queue *q, |
| + struct mt7996_sta *msta, struct sk_buff *skb, |
| + u32 info) |
| +{ |
| + struct ieee80211_vif *vif; |
| + struct wireless_dev *wdev; |
| + |
| + if (!msta || !msta->vif) |
| + return; |
| + |
| + if (!mt76_queue_is_wed_rx(q)) |
| + return; |
| + |
| + if (!(info & MT_DMA_INFO_PPE_VLD)) |
| + return; |
| + |
| + vif = container_of((void *)msta->vif, struct ieee80211_vif, |
| + drv_priv); |
| + wdev = ieee80211_vif_to_wdev(vif); |
| + skb->dev = wdev->netdev; |
| + |
| + mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb, |
| + FIELD_GET(MT_DMA_PPE_CPU_REASON, info), |
| + FIELD_GET(MT_DMA_PPE_ENTRY, info)); |
| +} |
| + |
| static int |
| -mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) |
| +mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q, |
| + struct sk_buff *skb, u32 *info) |
| { |
| struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb; |
| struct mt76_phy *mphy = &dev->mt76.phy; |
| @@ -475,7 +503,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) |
| u16 seq_ctrl = 0; |
| __le16 fc = 0; |
| int idx; |
| + u8 hw_aggr = false; |
| + struct mt7996_sta *msta = NULL; |
| |
| + hw_aggr = status->aggr; |
| memset(status, 0, sizeof(*status)); |
| |
| band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1); |
| @@ -502,8 +533,6 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) |
| status->wcid = mt7996_rx_get_wcid(dev, idx, unicast); |
| |
| if (status->wcid) { |
| - struct mt7996_sta *msta; |
| - |
| msta = container_of(status->wcid, struct mt7996_sta, wcid); |
| spin_lock_bh(&dev->mt76.sta_poll_lock); |
| if (list_empty(&msta->wcid.poll_list)) |
| @@ -708,12 +737,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb) |
| } |
| } else { |
| status->flag |= RX_FLAG_8023; |
| + mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb, |
| + *info); |
| } |
| |
| if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023)) |
| mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode); |
| |
| - if (!status->wcid || !ieee80211_is_data_qos(fc)) |
| + if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr) |
| return 0; |
| |
| status->aggr = unicast && |
| @@ -1010,6 +1041,29 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr, |
| return 0; |
| } |
| |
| +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id) |
| +{ |
| + struct mt76_connac_fw_txp *txp = ptr + MT_TXD_SIZE; |
| + __le32 *txwi = ptr; |
| + u32 val; |
| + |
| + memset(ptr, 0, MT_TXD_SIZE + sizeof(*txp)); |
| + |
| + val = FIELD_PREP(MT_TXD0_TX_BYTES, MT_TXD_SIZE) | |
| + FIELD_PREP(MT_TXD0_PKT_FMT, MT_TX_TYPE_CT); |
| + txwi[0] = cpu_to_le32(val); |
| + |
| + val = BIT(31) | |
| + FIELD_PREP(MT_TXD1_HDR_FORMAT, MT_HDR_FORMAT_802_3); |
| + txwi[1] = cpu_to_le32(val); |
| + |
| + txp->token = cpu_to_le16(token_id); |
| + txp->nbuf = 1; |
| + txp->buf[0] = cpu_to_le32(phys + MT_TXD_SIZE + sizeof(*txp)); |
| + |
| + return MT_TXD_SIZE + sizeof(*txp); |
| +} |
| + |
| static void |
| mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi) |
| { |
| @@ -1388,6 +1442,12 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, |
| |
| switch (type) { |
| case PKT_TYPE_TXRX_NOTIFY: |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2) && |
| + q == MT_RXQ_TXFREE_BAND2) { |
| + dev_kfree_skb(skb); |
| + break; |
| + } |
| + |
| mt7996_mac_tx_free(dev, skb->data, skb->len); |
| napi_consume_skb(skb, 1); |
| break; |
| @@ -1404,7 +1464,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q, |
| dev_kfree_skb(skb); |
| break; |
| case PKT_TYPE_NORMAL: |
| - if (!mt7996_mac_fill_rx(dev, skb)) { |
| + if (!mt7996_mac_fill_rx(dev, q, skb, info)) { |
| mt76_rx(&dev->mt76, q, skb); |
| return; |
| } |
| @@ -1862,7 +1922,7 @@ void mt7996_mac_reset_work(struct work_struct *work) |
| mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE); |
| |
| /* enable DMA Tx/Tx and interrupt */ |
| - mt7996_dma_start(dev, false); |
| + mt7996_dma_start(dev, false, false); |
| |
| clear_bit(MT76_MCU_RESET, &dev->mphy.state); |
| clear_bit(MT76_RESET, &dev->mphy.state); |
| diff --git a/mt7996/main.c b/mt7996/main.c |
| index a2ab668..ae4f0ce 100644 |
| --- a/mt7996/main.c |
| +++ b/mt7996/main.c |
| @@ -1368,6 +1368,44 @@ out: |
| return ret; |
| } |
| |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| +static int |
| +mt7996_net_fill_forward_path(struct ieee80211_hw *hw, |
| + struct ieee80211_vif *vif, |
| + struct ieee80211_sta *sta, |
| + struct net_device_path_ctx *ctx, |
| + struct net_device_path *path) |
| +{ |
| + struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv; |
| + struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv; |
| + struct mt7996_dev *dev = mt7996_hw_dev(hw); |
| + struct mt7996_phy *phy = mt7996_hw_phy(hw); |
| + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; |
| + |
| + if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2) |
| + wed = &dev->mt76.mmio.wed_hif2; |
| + |
| + if (!mtk_wed_device_active(wed)) |
| + return -ENODEV; |
| + |
| + if (msta->wcid.idx > MT7996_WTBL_STA) |
| + return -EIO; |
| + |
| + path->type = DEV_PATH_MTK_WDMA; |
| + path->dev = ctx->dev; |
| + path->mtk_wdma.wdma_idx = wed->wdma_idx; |
| + path->mtk_wdma.bss = mvif->mt76.idx; |
| + path->mtk_wdma.queue = 0; |
| + path->mtk_wdma.wcid = msta->wcid.idx; |
| + |
| + path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed); |
| + ctx->dev = NULL; |
| + |
| + return 0; |
| +} |
| + |
| +#endif |
| + |
| const struct ieee80211_ops mt7996_ops = { |
| .tx = mt7996_tx, |
| .start = mt7996_start, |
| @@ -1412,4 +1450,8 @@ const struct ieee80211_ops mt7996_ops = { |
| .sta_add_debugfs = mt7996_sta_add_debugfs, |
| #endif |
| .set_radar_background = mt7996_set_radar_background, |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| + .net_fill_forward_path = mt7996_net_fill_forward_path, |
| + .net_setup_tc = mt76_net_setup_tc, |
| +#endif |
| }; |
| diff --git a/mt7996/mcu.c b/mt7996/mcu.c |
| index 12bf4e5..3ff70c6 100644 |
| --- a/mt7996/mcu.c |
| +++ b/mt7996/mcu.c |
| @@ -912,7 +912,7 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif) |
| } |
| |
| static int |
| -mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, |
| +mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif *mvif, |
| struct ieee80211_ampdu_params *params, |
| bool enable, bool tx) |
| { |
| @@ -921,7 +921,7 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, |
| struct sk_buff *skb; |
| struct tlv *tlv; |
| |
| - skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid, |
| + skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mvif, wcid, |
| MT7996_STA_UPDATE_MAX_SIZE); |
| if (IS_ERR(skb)) |
| return PTR_ERR(skb); |
| @@ -935,8 +935,9 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif, |
| ba->ba_en = enable << params->tid; |
| ba->amsdu = params->amsdu; |
| ba->tid = params->tid; |
| + ba->ba_rdd_rro = !tx && enable && dev->has_rro; |
| |
| - return mt76_mcu_skb_send_msg(dev, skb, |
| + return mt76_mcu_skb_send_msg(&dev->mt76, skb, |
| MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true); |
| } |
| |
| @@ -951,8 +952,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev, |
| if (enable && !params->amsdu) |
| msta->wcid.amsdu = false; |
| |
| - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, |
| - enable, true); |
| + return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, true); |
| } |
| |
| int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, |
| @@ -962,8 +962,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev, |
| struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv; |
| struct mt7996_vif *mvif = msta->vif; |
| |
| - return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params, |
| - enable, false); |
| + return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, false); |
| } |
| |
| static void |
| diff --git a/mt7996/mmio.c b/mt7996/mmio.c |
| index 3a591a7..c7b6d4b 100644 |
| --- a/mt7996/mmio.c |
| +++ b/mt7996/mmio.c |
| @@ -10,6 +10,10 @@ |
| #include "mt7996.h" |
| #include "mac.h" |
| #include "../trace.h" |
| +#include "../dma.h" |
| + |
| +static bool wed_enable; |
| +module_param(wed_enable, bool, 0644); |
| |
| static const struct __base mt7996_reg_base[] = { |
| [WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } }, |
| @@ -191,6 +195,143 @@ static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val) |
| return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val); |
| } |
| |
| +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, |
| + bool hif2, int *irq) |
| +{ |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; |
| + struct pci_dev *pci_dev = pdev_ptr; |
| + u32 hif1_ofs = 0; |
| + int ret; |
| + |
| + if (!wed_enable) |
| + return 0; |
| + |
| + dev->has_rro = true; |
| + |
| + hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0); |
| + |
| + if (hif2) |
| + wed = &dev->mt76.mmio.wed_hif2; |
| + |
| + wed->wlan.pci_dev = pci_dev; |
| + wed->wlan.bus_type = MTK_WED_BUS_PCIE; |
| + |
| + wed->wlan.base = devm_ioremap(dev->mt76.dev, |
| + pci_resource_start(pci_dev, 0), |
| + pci_resource_len(pci_dev, 0)); |
| + wed->wlan.phy_base = pci_resource_start(pci_dev, 0); |
| + |
| + if (hif2) { |
| + wed->wlan.wpdma_int = wed->wlan.phy_base + |
| + MT_INT_PCIE1_SOURCE_CSR_EXT; |
| + wed->wlan.wpdma_mask = wed->wlan.phy_base + |
| + MT_INT_PCIE1_MASK_CSR; |
| + wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs + |
| + MT_TXQ_RING_BASE(0) + |
| + MT7996_TXQ_BAND2 * MT_RING_SIZE; |
| + if (dev->has_rro) { |
| + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + |
| + MT_RXQ_RING_BASE(0) + |
| + MT7996_RXQ_TXFREE2 * MT_RING_SIZE; |
| + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1; |
| + } else { |
| + wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs + |
| + MT_RXQ_RING_BASE(0) + |
| + MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE; |
| + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1; |
| + } |
| + |
| + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG; |
| + wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs + |
| + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + |
| + MT7996_RXQ_BAND0 * MT_RING_SIZE; |
| + |
| + wed->wlan.id = 0x7991; |
| + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1; |
| + } else { |
| + wed->wlan.hw_rro = dev->has_rro; /* default on */ |
| + wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR; |
| + wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR; |
| + wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) + |
| + MT7996_TXQ_BAND0 * MT_RING_SIZE; |
| + |
| + wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG; |
| + |
| + wed->wlan.wpdma_rx = wed->wlan.phy_base + |
| + MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) + |
| + MT7996_RXQ_BAND0 * MT_RING_SIZE; |
| + |
| + wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base + |
| + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) + |
| + MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE; |
| + wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs + |
| + MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) + |
| + MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE; |
| + wed->wlan.wpdma_rx_pg = wed->wlan.phy_base + |
| + MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) + |
| + MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE; |
| + |
| + wed->wlan.rx_nbuf = 65536; |
| + wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576; |
| + wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE); |
| + |
| + wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1; |
| + wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1; |
| + |
| + wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1; |
| + wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1; |
| + |
| + wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1; |
| + wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1; |
| + wed->wlan.rx_pg_tbit[2] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND2) - 1; |
| + |
| + wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1; |
| + wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1; |
| + if (dev->has_rro) { |
| + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + |
| + MT7996_RXQ_TXFREE0 * MT_RING_SIZE; |
| + wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1; |
| + } else { |
| + wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1; |
| + wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) + |
| + MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE; |
| + } |
| + dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt; |
| + } |
| + |
| + wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE; |
| + wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf; |
| + |
| + wed->wlan.amsdu_max_subframes = 8; |
| + wed->wlan.amsdu_max_len = 1536; |
| + |
| + wed->wlan.init_buf = mt7996_wed_init_buf; |
| + wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf; |
| + wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf; |
| + wed->wlan.offload_enable = mt76_mmio_wed_offload_enable; |
| + wed->wlan.offload_disable = mt76_mmio_wed_offload_disable; |
| + |
| + if (mtk_wed_device_attach(wed)) |
| + return 0; |
| + |
| + *irq = wed->irq; |
| + dev->mt76.dma_dev = wed->dev; |
| + |
| + ret = dma_set_mask(wed->dev, DMA_BIT_MASK(32)); |
| + if (ret) |
| + return ret; |
| + |
| + ret = dma_set_coherent_mask(wed->dev, DMA_BIT_MASK(32)); |
| + if (ret) |
| + return ret; |
| + |
| + return 1; |
| +#else |
| + return 0; |
| +#endif |
| +} |
| + |
| static int mt7996_mmio_init(struct mt76_dev *mdev, |
| void __iomem *mem_base, |
| u32 device_id) |
| @@ -241,8 +382,17 @@ void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg, |
| mdev->mmio.irqmask |= set; |
| |
| if (write_reg) { |
| - mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); |
| - mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); |
| + if (mtk_wed_device_active(&mdev->mmio.wed)) { |
| + mtk_wed_device_irq_set_mask(&mdev->mmio.wed, |
| + mdev->mmio.irqmask); |
| + if (mtk_wed_device_active(&mdev->mmio.wed_hif2)) { |
| + mtk_wed_device_irq_set_mask(&mdev->mmio.wed_hif2, |
| + mdev->mmio.irqmask); |
| + } |
| + } else { |
| + mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask); |
| + mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask); |
| + } |
| } |
| |
| spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags); |
| @@ -260,22 +410,36 @@ static void mt7996_rx_poll_complete(struct mt76_dev *mdev, |
| static void mt7996_irq_tasklet(struct tasklet_struct *t) |
| { |
| struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet); |
| + struct mtk_wed_device *wed = &dev->mt76.mmio.wed; |
| + struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2; |
| u32 i, intr, mask, intr1; |
| |
| - mt76_wr(dev, MT_INT_MASK_CSR, 0); |
| - if (dev->hif2) |
| - mt76_wr(dev, MT_INT1_MASK_CSR, 0); |
| - |
| - intr = mt76_rr(dev, MT_INT_SOURCE_CSR); |
| - intr &= dev->mt76.mmio.irqmask; |
| - mt76_wr(dev, MT_INT_SOURCE_CSR, intr); |
| - |
| - if (dev->hif2) { |
| - intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); |
| - intr1 &= dev->mt76.mmio.irqmask; |
| - mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); |
| + if (dev->hif2 && mtk_wed_device_active(wed_hif2)) { |
| + mtk_wed_device_irq_set_mask(wed_hif2, 0); |
| + intr1 = mtk_wed_device_irq_get(wed_hif2, |
| + dev->mt76.mmio.irqmask); |
| + if (intr1 & MT_INT_RX_TXFREE_EXT) |
| + napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]); |
| + } |
| |
| - intr |= intr1; |
| + if (mtk_wed_device_active(wed)) { |
| + mtk_wed_device_irq_set_mask(wed, 0); |
| + intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask); |
| + intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT); |
| + } else { |
| + mt76_wr(dev, MT_INT_MASK_CSR, 0); |
| + if (dev->hif2) |
| + mt76_wr(dev, MT_INT1_MASK_CSR, 0); |
| + |
| + intr = mt76_rr(dev, MT_INT_SOURCE_CSR); |
| + intr &= dev->mt76.mmio.irqmask; |
| + mt76_wr(dev, MT_INT_SOURCE_CSR, intr); |
| + if (dev->hif2) { |
| + intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR); |
| + intr1 &= dev->mt76.mmio.irqmask; |
| + mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1); |
| + intr |= intr1; |
| + } |
| } |
| |
| trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask); |
| @@ -308,9 +472,17 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance) |
| { |
| struct mt7996_dev *dev = dev_instance; |
| |
| - mt76_wr(dev, MT_INT_MASK_CSR, 0); |
| - if (dev->hif2) |
| - mt76_wr(dev, MT_INT1_MASK_CSR, 0); |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) |
| + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed, 0); |
| + else |
| + mt76_wr(dev, MT_INT_MASK_CSR, 0); |
| + |
| + if (dev->hif2) { |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) |
| + mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed_hif2, 0); |
| + else |
| + mt76_wr(dev, MT_INT1_MASK_CSR, 0); |
| + } |
| |
| if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) |
| return IRQ_NONE; |
| diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h |
| index 7354e5c..c541eaa 100644 |
| --- a/mt7996/mt7996.h |
| +++ b/mt7996/mt7996.h |
| @@ -37,6 +37,7 @@ |
| #define MT7996_EEPROM_SIZE 7680 |
| #define MT7996_EEPROM_BLOCK_SIZE 16 |
| #define MT7996_TOKEN_SIZE 16384 |
| +#define MT7996_HW_TOKEN_SIZE 8192 |
| |
| #define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */ |
| #define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */ |
| @@ -49,6 +50,22 @@ |
| #define MT7996_BASIC_RATES_TBL 11 |
| #define MT7996_BEACON_RATES_TBL 25 |
| |
| +#define MT7996_RRO_MAX_SESSION 1024 |
| +#define MT7996_RRO_WINDOW_MAX_LEN 1024 |
| +#define MT7996_RRO_ADDR_ELEM_LEN 128 |
| +#define MT7996_RRO_BA_BITMAP_LEN 2 |
| +#define MT7996_RRO_BA_BITMAP_CR_SIZE ((MT7996_RRO_MAX_SESSION * 128) / \ |
| + MT7996_RRO_BA_BITMAP_LEN) |
| +#define MT7996_RRO_BA_BITMAP_SESSION_SIZE (MT7996_RRO_MAX_SESSION / \ |
| + MT7996_RRO_ADDR_ELEM_LEN) |
| +#define MT7996_RRO_WINDOW_MAX_SIZE (MT7996_RRO_WINDOW_MAX_LEN * \ |
| + MT7996_RRO_BA_BITMAP_SESSION_SIZE) |
| + |
| +#define MT7996_RX_BUF_SIZE (1800 + \ |
| + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) |
| +#define MT7996_RX_MSDU_PAGE_SIZE (128 + \ |
| + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) |
| + |
| struct mt7996_vif; |
| struct mt7996_sta; |
| struct mt7996_dfs_pulse; |
| @@ -78,6 +95,16 @@ enum mt7996_rxq_id { |
| MT7996_RXQ_BAND0 = 4, |
| MT7996_RXQ_BAND1 = 4,/* unused */ |
| MT7996_RXQ_BAND2 = 5, |
| + MT7996_RXQ_RRO_BAND0 = 8, |
| + MT7996_RXQ_RRO_BAND1 = 8,/* unused */ |
| + MT7996_RXQ_RRO_BAND2 = 6, |
| + MT7996_RXQ_MSDU_PG_BAND0 = 10, |
| + MT7996_RXQ_MSDU_PG_BAND1 = 11, |
| + MT7996_RXQ_MSDU_PG_BAND2 = 12, |
| + MT7996_RXQ_TXFREE0 = 9, |
| + MT7996_RXQ_TXFREE1 = 9, |
| + MT7996_RXQ_TXFREE2 = 7, |
| + MT7996_RXQ_RRO_IND = 0, |
| }; |
| |
| struct mt7996_twt_flow { |
| @@ -147,6 +174,15 @@ struct mt7996_hif { |
| int irq; |
| }; |
| |
| +struct mt7996_wed_rro_addr { |
| + u32 head_low; |
| + u32 head_high : 4; |
| + u32 count: 11; |
| + u32 oor: 1; |
| + u32 rsv : 8; |
| + u32 signature : 8; |
| +}; |
| + |
| struct mt7996_phy { |
| struct mt76_phy *mt76; |
| struct mt7996_dev *dev; |
| @@ -226,6 +262,22 @@ struct mt7996_dev { |
| bool tbtc_support:1; |
| bool flash_mode:1; |
| bool has_eht:1; |
| + bool has_rro:1; |
| + |
| + struct { |
| + struct { |
| + void *ptr; |
| + dma_addr_t phy_addr; |
| + } ba_bitmap[MT7996_RRO_BA_BITMAP_LEN]; |
| + struct { |
| + void *ptr; |
| + dma_addr_t phy_addr; |
| + } addr_elem[MT7996_RRO_ADDR_ELEM_LEN]; |
| + struct { |
| + void *ptr; |
| + dma_addr_t phy_addr; |
| + } session; |
| + } wed_rro; |
| |
| bool ibf; |
| u8 fw_debug_wm; |
| @@ -335,7 +387,9 @@ int mt7996_dma_init(struct mt7996_dev *dev); |
| void mt7996_dma_reset(struct mt7996_dev *dev, bool force); |
| void mt7996_dma_prefetch(struct mt7996_dev *dev); |
| void mt7996_dma_cleanup(struct mt7996_dev *dev); |
| -void mt7996_dma_start(struct mt7996_dev *dev, bool reset); |
| +void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset); |
| +int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, |
| + int n_desc, int ring_base, struct mtk_wed_device *wed); |
| void mt7996_init_txpower(struct mt7996_dev *dev, |
| struct ieee80211_supported_band *sband); |
| int mt7996_txbf_init(struct mt7996_dev *dev); |
| @@ -495,5 +549,16 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev, |
| void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif, |
| struct ieee80211_sta *sta, struct dentry *dir); |
| #endif |
| +int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr, |
| + bool hif2, int *irq); |
| +u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id); |
| + |
| +#ifdef CONFIG_MTK_DEBUG |
| +int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir); |
| +#endif |
| + |
| +#ifdef CONFIG_NET_MEDIATEK_SOC_WED |
| +int mt7996_dma_rro_init(struct mt7996_dev *dev); |
| +#endif /* CONFIG_NET_MEDIATEK_SOC_WED */ |
| |
| #endif |
| diff --git a/mt7996/pci.c b/mt7996/pci.c |
| index c530105..92869ca 100644 |
| --- a/mt7996/pci.c |
| +++ b/mt7996/pci.c |
| @@ -125,15 +125,26 @@ static int mt7996_pci_probe(struct pci_dev *pdev, |
| mt7996_wfsys_reset(dev); |
| hif2 = mt7996_pci_init_hif2(pdev); |
| |
| - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); |
| + ret = mt7996_mmio_wed_init(dev, pdev, false, &irq); |
| if (ret < 0) |
| - goto free_device; |
| + goto free_wed_or_irq_vector; |
| |
| - irq = pdev->irq; |
| - ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler, |
| + if (!ret) { |
| + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); |
| + if (ret < 0) |
| + goto free_device; |
| + } |
| + ret = devm_request_irq(mdev->dev, pdev->irq, mt7996_irq_handler, |
| IRQF_SHARED, KBUILD_MODNAME, dev); |
| if (ret) |
| - goto free_irq_vector; |
| + goto free_wed_or_irq_vector; |
| + |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) { |
| + ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler, |
| + IRQF_SHARED, KBUILD_MODNAME "-wed", dev); |
| + if (ret) |
| + goto free_irq; |
| + } |
| |
| mt76_wr(dev, MT_INT_MASK_CSR, 0); |
| /* master switch of PCIe tnterrupt enable */ |
| @@ -143,16 +154,30 @@ static int mt7996_pci_probe(struct pci_dev *pdev, |
| hif2_dev = container_of(hif2->dev, struct pci_dev, dev); |
| dev->hif2 = hif2; |
| |
| - ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES); |
| + ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &irq); |
| if (ret < 0) |
| - goto free_hif2; |
| + goto free_irq; |
| + |
| + if (!ret) { |
| + ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES); |
| + if (ret < 0) |
| + goto free_hif2; |
| |
| - dev->hif2->irq = hif2_dev->irq; |
| - ret = devm_request_irq(mdev->dev, dev->hif2->irq, |
| - mt7996_irq_handler, IRQF_SHARED, |
| - KBUILD_MODNAME "-hif", dev); |
| + dev->hif2->irq = hif2_dev->irq; |
| + } |
| + |
| + ret = devm_request_irq(mdev->dev, hif2_dev->irq, mt7996_irq_handler, |
| + IRQF_SHARED, KBUILD_MODNAME "-hif", dev); |
| if (ret) |
| - goto free_hif2_irq_vector; |
| + goto free_hif2; |
| + |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) { |
| + ret = devm_request_irq(mdev->dev, irq, |
| + mt7996_irq_handler, IRQF_SHARED, |
| + KBUILD_MODNAME "-wed-hif", dev); |
| + if (ret) |
| + goto free_hif2_irq_vector; |
| + } |
| |
| mt76_wr(dev, MT_INT1_MASK_CSR, 0); |
| /* master switch of PCIe tnterrupt enable */ |
| @@ -168,15 +193,28 @@ static int mt7996_pci_probe(struct pci_dev *pdev, |
| free_hif2_irq: |
| if (dev->hif2) |
| devm_free_irq(mdev->dev, dev->hif2->irq, dev); |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) |
| + devm_free_irq(mdev->dev, dev->mt76.mmio.wed_hif2.irq, dev); |
| free_hif2_irq_vector: |
| - if (dev->hif2) |
| - pci_free_irq_vectors(hif2_dev); |
| + if (dev->hif2) { |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) |
| + mtk_wed_device_detach(&dev->mt76.mmio.wed_hif2); |
| + else |
| + pci_free_irq_vectors(hif2_dev); |
| + } |
| free_hif2: |
| if (dev->hif2) |
| put_device(dev->hif2->dev); |
| - devm_free_irq(mdev->dev, irq, dev); |
| -free_irq_vector: |
| - pci_free_irq_vectors(pdev); |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) |
| + devm_free_irq(mdev->dev, dev->mt76.mmio.wed.irq, dev); |
| +free_irq: |
| + devm_free_irq(mdev->dev, pdev->irq, dev); |
| +free_wed_or_irq_vector: |
| + if (mtk_wed_device_active(&dev->mt76.mmio.wed)) |
| + mtk_wed_device_detach(&dev->mt76.mmio.wed); |
| + else |
| + pci_free_irq_vectors(pdev); |
| + |
| free_device: |
| mt76_free_device(&dev->mt76); |
| |
| diff --git a/mt7996/regs.h b/mt7996/regs.h |
| index 5702290..854390d 100644 |
| --- a/mt7996/regs.h |
| +++ b/mt7996/regs.h |
| @@ -39,6 +39,38 @@ enum base_rev { |
| |
| #define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)]) |
| |
| +/* RRO TOP */ |
| +#define MT_RRO_TOP_BASE 0xA000 |
| +#define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs)) |
| + |
| +#define MT_RRO_BA_BITMAP_BASE0 MT_RRO_TOP(0x8) |
| +#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC) |
| +#define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8) |
| +#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12) |
| +#define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34) |
| +#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31) |
| + |
| +#define MT_RRO_IND_CMD_SIGNATURE_BASE0 MT_RRO_TOP(0x38) |
| +#define MT_RRO_IND_CMD_SIGNATURE_BASE1 MT_RRO_TOP(0x3C) |
| +#define MT_RRO_IND_CMD_0_CTRL0 MT_RRO_TOP(0x40) |
| +#define MT_RRO_IND_CMD_SIGNATURE_BASE1_EN BIT(31) |
| + |
| +#define MT_RRO_PARTICULAR_CFG0 MT_RRO_TOP(0x5C) |
| +#define MT_RRO_PARTICULAR_CFG1 MT_RRO_TOP(0x60) |
| +#define MT_RRO_PARTICULAR_CONFG_EN BIT(31) |
| +#define MT_RRO_PARTICULAR_SID GENMASK(30, 16) |
| + |
| +#define MT_RRO_BA_BITMAP_BASE_EXT0 MT_RRO_TOP(0x70) |
| +#define MT_RRO_BA_BITMAP_BASE_EXT1 MT_RRO_TOP(0x74) |
| +#define MT_RRO_HOST_INT_ENA MT_RRO_TOP(0x204) |
| +#define MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA BIT(0) |
| + |
| +#define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400) |
| + |
| +#define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50) |
| +#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16) |
| +#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0) |
| + |
| #define MT_MCU_INT_EVENT 0x2108 |
| #define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0) |
| #define MT_MCU_INT_EVENT_DMA_INIT BIT(1) |
| @@ -323,6 +355,7 @@ enum base_rev { |
| |
| #define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154) |
| #define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3) |
| +#define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6) |
| |
| #define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4) |
| |
| @@ -367,6 +400,9 @@ enum base_rev { |
| #define MT_WFDMA0_PCIE1_BASE 0xd8000 |
| #define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs)) |
| |
| +#define MT_INT_PCIE1_SOURCE_CSR_EXT MT_WFDMA0_PCIE1(0x118) |
| +#define MT_INT_PCIE1_MASK_CSR MT_WFDMA0_PCIE1(0x11c) |
| + |
| #define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c) |
| #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0) |
| #define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1) |
| @@ -387,6 +423,7 @@ enum base_rev { |
| #define MT_MCUQ_RING_BASE(q) (MT_Q_BASE(q) + 0x300) |
| #define MT_TXQ_RING_BASE(q) (MT_Q_BASE(__TXQ(q)) + 0x300) |
| #define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500) |
| +#define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40) |
| |
| #define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \ |
| MT_MCUQ_ID(q) * 0x4) |
| @@ -412,6 +449,15 @@ enum base_rev { |
| #define MT_INT_RX_TXFREE_MAIN BIT(17) |
| #define MT_INT_RX_TXFREE_TRI BIT(15) |
| #define MT_INT_MCU_CMD BIT(29) |
| +#define MT_INT_RX_TXFREE_EXT BIT(26) |
| + |
| +#define MT_INT_RX_DONE_RRO_BAND0 BIT(16) |
| +#define MT_INT_RX_DONE_RRO_BAND1 BIT(16) |
| +#define MT_INT_RX_DONE_RRO_BAND2 BIT(14) |
| +#define MT_INT_RX_DONE_RRO_IND BIT(11) |
| +#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18) |
| +#define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19) |
| +#define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23) |
| |
| #define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)]) |
| #define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)]) |
| @@ -420,20 +466,31 @@ enum base_rev { |
| MT_INT_RX(MT_RXQ_MCU_WA)) |
| |
| #define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \ |
| - MT_INT_RX(MT_RXQ_MAIN_WA)) |
| + MT_INT_RX(MT_RXQ_MAIN_WA) | \ |
| + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) |
| |
| #define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \ |
| MT_INT_RX(MT_RXQ_BAND1_WA) | \ |
| - MT_INT_RX(MT_RXQ_MAIN_WA)) |
| + MT_INT_RX(MT_RXQ_MAIN_WA) | \ |
| + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) |
| |
| #define MT_INT_BAND2_RX_DONE (MT_INT_RX(MT_RXQ_BAND2) | \ |
| MT_INT_RX(MT_RXQ_BAND2_WA) | \ |
| - MT_INT_RX(MT_RXQ_MAIN_WA)) |
| + MT_INT_RX(MT_RXQ_MAIN_WA) | \ |
| + MT_INT_RX(MT_RXQ_TXFREE_BAND0)) |
| + |
| +#define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \ |
| + MT_INT_RX(MT_RXQ_RRO_BAND1) | \ |
| + MT_INT_RX(MT_RXQ_RRO_BAND2) | \ |
| + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \ |
| + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \ |
| + MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2)) |
| |
| #define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \ |
| MT_INT_BAND0_RX_DONE | \ |
| MT_INT_BAND1_RX_DONE | \ |
| - MT_INT_BAND2_RX_DONE) |
| + MT_INT_BAND2_RX_DONE | \ |
| + MT_INT_RRO_RX_DONE) |
| |
| #define MT_INT_TX_DONE_FWDL BIT(26) |
| #define MT_INT_TX_DONE_MCU_WM BIT(27) |
| -- |
| 2.18.0 |
| |