Commit f68d6762 authored by Felix Fietkau's avatar Felix Fietkau
Browse files

mt76: mt7915: add Wireless Ethernet Dispatch support



This is used to support hardware flow offloading from Ethernet to WLAN

Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 61b5156b
Loading
Loading
Loading
Loading
+127 −33
Original line number Diff line number Diff line
@@ -7,9 +7,36 @@
#include "mt76.h"
#include "dma.h"

#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)
@@ -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,
@@ -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)
{
@@ -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;
@@ -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);
+3 −1
Original line number Diff line number Diff line
@@ -1582,7 +1582,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;
@@ -1591,6 +1591,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);
+7 −2
Original line number Diff line number Diff line
@@ -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)
	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);
+26 −4
Original line number Diff line number Diff line
@@ -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"
@@ -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;
@@ -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);
@@ -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;
@@ -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 {
@@ -719,6 +740,7 @@ struct mt76_dev {

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

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

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

+4 −4
Original line number Diff line number Diff line
@@ -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;

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

Loading