Skip to content

Commit

Permalink
mt76: mt7915: add Wireless Ethernet Dispatch support
Browse files Browse the repository at this point in the history
This is used to support hardware flow offloading from Ethernet to WLAN

Signed-off-by: Felix Fietkau <nbd@nbd.name>
  • Loading branch information
nbd168 committed Apr 7, 2022
1 parent b8c842d commit 87a962e
Show file tree
Hide file tree
Showing 18 changed files with 502 additions and 94 deletions.
160 changes: 127 additions & 33 deletions dma.c
Expand Up @@ -7,9 +7,36 @@
#include "mt76.h"
#include "dma.h"

#define Q_READ(_dev, _q, _field) readl(&(_q)->regs->_field)
#define Q_WRITE(_dev, _q, _field, _val) writel(_val, &(_q)->regs->_field)
#if IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED)

#define Q_READ(_dev, _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, \
((_q)->wed_regs + \
_offset)); \
else \
_val = readl(&(_q)->regs->_field); \
_val; \
})

#define Q_WRITE(_dev, _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, \
((_q)->wed_regs + _offset), \
_val); \
else \
writel(_val, &(_q)->regs->_field); \
} while (0)

#else

#define Q_READ(_dev, _q, _field) readl(&(_q)->regs->_field)
#define Q_WRITE(_dev, _q, _field, _val) writel(_val, &(_q)->regs->_field)

#endif

static struct mt76_txwi_cache *
mt76_alloc_txwi(struct mt76_dev *dev)
Expand Down Expand Up @@ -111,36 +138,6 @@ mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q)
mt76_dma_sync_idx(dev, q);
}

static int
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize,
u32 ring_base)
{
int size;

spin_lock_init(&q->lock);
spin_lock_init(&q->cleanup_lock);

q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;
q->ndesc = n_desc;
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);
if (!q->desc)
return -ENOMEM;

size = q->ndesc * sizeof(*q->entry);
q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);
if (!q->entry)
return -ENOMEM;

mt76_dma_queue_reset(dev, q);

return 0;
}

static int
mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
struct mt76_queue_buf *buf, int nbufs, u32 info,
Expand Down Expand Up @@ -486,6 +483,85 @@ 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)
{
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
struct mtk_wed_device *wed = &dev->mmio.wed;
int ret, type, ring;
u8 flags = q->flags;

if (!mtk_wed_device_active(wed))
q->flags &= ~MT_QFLAG_WED;

if (!(q->flags & MT_QFLAG_WED))
return 0;

type = FIELD_GET(MT_QFLAG_WED_TYPE, q->flags);
ring = FIELD_GET(MT_QFLAG_WED_RING, q->flags);

switch (type) {
case MT76_WED_Q_TX:
ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs);
if (!ret)
q->wed_regs = 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);
q->flags = flags;

ret = mtk_wed_device_txfree_ring_setup(wed, q->regs);
if (!ret)
q->wed_regs = wed->txfree_ring.reg_base;
break;
default:
ret = -EINVAL;
}

return ret;
#else
return 0;
#endif
}

static int
mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
int idx, int n_desc, int bufsize,
u32 ring_base)
{
int ret, size;

spin_lock_init(&q->lock);
spin_lock_init(&q->cleanup_lock);

q->regs = dev->mmio.regs + ring_base + idx * MT_RING_SIZE;
q->ndesc = n_desc;
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);
if (!q->desc)
return -ENOMEM;

size = q->ndesc * sizeof(*q->entry);
q->entry = devm_kzalloc(dev->dev, size, GFP_KERNEL);
if (!q->entry)
return -ENOMEM;

ret = mt76_dma_wed_setup(dev, q);
if (ret)
return ret;

if (q->flags != MT_WED_Q_TXFREE)
mt76_dma_queue_reset(dev, q);

return 0;
}

static void
mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
{
Expand Down Expand Up @@ -567,14 +643,29 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
static int
mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
{
int len, data_len, done = 0;
int len, data_len, done = 0, dma_idx;
struct sk_buff *skb;
unsigned char *data;
bool check_ddone = false;
bool more;

if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
q->flags == MT_WED_Q_TXFREE) {
dma_idx = Q_READ(dev, q, dma_idx);
check_ddone = true;
}

while (done < budget) {
u32 info;

if (check_ddone) {
if (q->tail == dma_idx)
dma_idx = Q_READ(dev, q, dma_idx);

if (q->tail == dma_idx)
break;
}

data = mt76_dma_dequeue(dev, q, false, &len, &info, &more);
if (!data)
break;
Expand Down Expand Up @@ -715,5 +806,8 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
}

mt76_free_pending_txwi(dev);

if (mtk_wed_device_active(&dev->mmio.wed))
mtk_wed_device_detach(&dev->mmio.wed);
}
EXPORT_SYMBOL_GPL(mt76_dma_cleanup);
4 changes: 3 additions & 1 deletion mac80211.c
Expand Up @@ -1580,7 +1580,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)
int ring_base, u32 flags)
{
struct mt76_queue *hwq;
int err;
Expand All @@ -1589,6 +1589,8 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
if (!hwq)
return ERR_PTR(-ENOMEM);

hwq->flags = flags;

err = dev->queue_ops->alloc(dev, hwq, idx, n_desc, 0, ring_base);
if (err < 0)
return ERR_PTR(err);
Expand Down
9 changes: 7 additions & 2 deletions mmio.c
Expand Up @@ -73,8 +73,13 @@ void mt76_set_irq_mask(struct mt76_dev *dev, u32 addr,
spin_lock_irqsave(&dev->mmio.irq_lock, flags);
dev->mmio.irqmask &= ~clear;
dev->mmio.irqmask |= set;
if (addr)
mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
if (addr) {
if (mtk_wed_device_active(&dev->mmio.wed))
mtk_wed_device_irq_set_mask(&dev->mmio.wed,
dev->mmio.irqmask);
else
mt76_mmio_wr(dev, addr, dev->mmio.irqmask);
}
spin_unlock_irqrestore(&dev->mmio.irq_lock, flags);
}
EXPORT_SYMBOL_GPL(mt76_set_irq_mask);
Expand Down
30 changes: 26 additions & 4 deletions mt76.h
Expand Up @@ -13,6 +13,7 @@
#include <linux/leds.h>
#include <linux/usb.h>
#include <linux/average.h>
#include <linux/soc/mediatek/mtk_wed.h>
#include <net/mac80211.h>
#include "util.h"
#include "testmode.h"
Expand All @@ -26,6 +27,16 @@

#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_WED_Q(_type, _n) (MT_QFLAG_WED | \
FIELD_PREP(MT_QFLAG_WED_TYPE, _type) | \
FIELD_PREP(MT_QFLAG_WED_RING, _n))
#define MT_WED_Q_TX(_n) __MT_WED_Q(MT76_WED_Q_TX, _n)
#define MT_WED_Q_TXFREE __MT_WED_Q(MT76_WED_Q_TXFREE, 0)

struct mt76_dev;
struct mt76_phy;
struct mt76_wcid;
Expand All @@ -42,6 +53,11 @@ enum mt76_bus_type {
MT76_BUS_SDIO,
};

enum mt76_wed_type {
MT76_WED_Q_TX,
MT76_WED_Q_TXFREE,
};

struct mt76_bus_ops {
u32 (*rr)(struct mt76_dev *dev, u32 offset);
void (*wr)(struct mt76_dev *dev, u32 offset, u32 val);
Expand Down Expand Up @@ -170,6 +186,9 @@ struct mt76_queue {
u8 buf_offset;
u8 hw_idx;
u8 qid;
u8 flags;

u32 wed_regs;

dma_addr_t desc_dma;
struct sk_buff *rx_head;
Expand Down Expand Up @@ -537,6 +556,8 @@ struct mt76_mmio {
void __iomem *regs;
spinlock_t irq_lock;
u32 irqmask;

struct mtk_wed_device wed;
};

struct mt76_rx_status {
Expand Down Expand Up @@ -719,6 +740,7 @@ struct mt76_dev {

spinlock_t token_lock;
struct idr token;
u16 wed_token_count;
u16 token_count;
u16 token_size;

Expand Down Expand Up @@ -944,14 +966,14 @@ 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);
int ring_base, u32 flags);
u16 mt76_calculate_default_rate(struct mt76_phy *phy, int rateidx);
static inline int mt76_init_tx_queue(struct mt76_phy *phy, int qid, int idx,
int n_desc, int ring_base)
int n_desc, int ring_base, u32 flags)
{
struct mt76_queue *q;

q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base);
q = mt76_init_queue(phy->dev, qid, idx, n_desc, ring_base, flags);
if (IS_ERR(q))
return PTR_ERR(q);

Expand All @@ -966,7 +988,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);
q = mt76_init_queue(dev, qid, idx, n_desc, ring_base, 0);
if (IS_ERR(q))
return PTR_ERR(q);

Expand Down
8 changes: 4 additions & 4 deletions mt7603/dma.c
Expand Up @@ -173,13 +173,13 @@ 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);
MT7603_TX_RING_SIZE, MT_TX_RING_BASE, 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);
MT7603_PSD_RING_SIZE, MT_TX_RING_BASE, 0);
if (ret)
return ret;

Expand All @@ -189,12 +189,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);
MT_MCU_RING_SIZE, MT_TX_RING_BASE, 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);
MT_MCU_RING_SIZE, MT_TX_RING_BASE, 0);
if (ret)
return ret;

Expand Down
6 changes: 3 additions & 3 deletions mt7615/dma.c
Expand Up @@ -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);
MT_TX_RING_BASE, 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);
MT_TX_RING_BASE, 0);
if (ret)
return ret;

Expand All @@ -55,7 +55,7 @@ mt7615_init_tx_queues(struct mt7615_dev *dev)
return mt7622_init_tx_queues_multi(dev);

ret = mt76_init_tx_queue(&dev->mphy, 0, 0, MT7615_TX_RING_SIZE,
MT_TX_RING_BASE);
MT_TX_RING_BASE, 0);
if (ret)
return ret;

Expand Down
4 changes: 2 additions & 2 deletions mt76x02_mmio.c
Expand Up @@ -191,13 +191,13 @@ 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);
MT_TX_RING_BASE, 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);
MT76x02_PSD_RING_SIZE, MT_TX_RING_BASE, 0);
if (ret)
return ret;

Expand Down

0 comments on commit 87a962e

Please sign in to comment.