Commit 37987228 authored by Kalle Valo's avatar Kalle Valo
Browse files

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

mt76 patches for 6.8

* fixes
* nvmem eeprom improvements
* mt7996 eht improvements
* mt7996 wed support
* mt7996 36-bit DMA support
parents 68d83f0a 10f29031
Loading
Loading
Loading
Loading
+187 −71
Original line number Diff line number Diff line
@@ -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,41 +188,67 @@ 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;

	if (!mt76_queue_is_wed_rro_ind(q)) {
		int i;

		/* clear descriptors */
		for (i = 0; i < q->ndesc; i++)
			q->desc[i].ctrl = cpu_to_le32(MT_DMA_CTL_DMA_DONE);
	}

	Q_WRITE(dev, q, cpu_idx, 0);
	Q_WRITE(dev, q, dma_idx, 0);
	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;
	u32 buf1 = 0, ctrl;
	struct mt76_desc *desc;
	int idx = q->head;
	u32 buf1 = 0, ctrl;
	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);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
	buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32);
#endif

	if (mt76_queue_is_wed_rx(q)) {
		txwi = mt76_get_rxwi(dev);
@@ -244,6 +270,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;
@@ -288,11 +315,18 @@ mt76_dma_add_buf(struct mt76_dev *dev, struct mt76_queue *q,
		entry->dma_len[0] = buf[0].len;

		ctrl = FIELD_PREP(MT_DMA_CTL_SD_LEN0, buf[0].len);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
		info |= FIELD_PREP(MT_DMA_CTL_SDP0_H, buf[0].addr >> 32);
#endif
		if (i < nbufs - 1) {
			entry->dma_addr[1] = buf[1].addr;
			entry->dma_len[1] = buf[1].len;
			buf1 = buf[1].addr;
			ctrl |= FIELD_PREP(MT_DMA_CTL_SD_LEN1, buf[1].len);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
			info |= FIELD_PREP(MT_DMA_CTL_SDP1_H,
					   buf[1].addr >> 32);
#endif
			if (buf[1].skip_unmap)
				entry->skip_buf1 = true;
		}
@@ -343,7 +377,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 +393,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 +405,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,19 +426,26 @@ 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;
	u32 ctrl, desc_info, buf1;
	void *buf = e->buf;

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

	desc_info = le32_to_cpu(desc->info);
	if (info)
		*info = le32_to_cpu(desc->info);
		*info = desc_info;

	buf1 = le32_to_cpu(desc->buf1);
	mt76_dma_should_drop_buf(drop, ctrl, buf1, desc_info);

	if (mt76_queue_is_wed_rx(q)) {
		u32 buf1 = le32_to_cpu(desc->buf1);
		u32 token = FIELD_GET(MT_DMA_CTL_TOKEN, buf1);
		struct mt76_txwi_cache *t = mt76_rx_token_release(dev, token);

@@ -420,23 +461,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,10 +484,15 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
	if (!q->queued)
		return NULL;

	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 +645,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 +663,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 +673,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 +684,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 +702,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 +771,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,7 +804,12 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
	if (ret)
		return ret;

	if (q->flags != MT_WED_Q_TXFREE)
	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;
@@ -747,6 +832,7 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
		if (!buf)
			break;

		if (!mt76_queue_is_wed_rro(q))
			mt76_put_page_pool_buf(buf, false);
	} while (1);

@@ -763,23 +849,32 @@ 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;

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

	if (mtk_wed_device_active(&dev->mmio.wed) &&
	    mt76_queue_is_wed_rro(q))
		return;

	mt76_dma_sync_idx(dev, q);
	mt76_dma_rx_fill(dev, q, false);
}
}

static void
mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
@@ -818,8 +913,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;
	}

@@ -829,7 +924,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;
@@ -957,6 +1052,20 @@ void mt76_dma_attach(struct mt76_dev *dev)
}
EXPORT_SYMBOL_GPL(mt76_dma_attach);

void mt76_dma_wed_reset(struct mt76_dev *dev)
{
	struct mt76_mmio *mmio = &dev->mmio;

	if (!test_bit(MT76_STATE_WED_RESET, &dev->phy.state))
		return;

	complete(&mmio->wed_reset);

	if (!wait_for_completion_timeout(&mmio->wed_reset_complete, 3 * HZ))
		dev_err(dev->dev, "wed reset complete timeout\n");
}
EXPORT_SYMBOL_GPL(mt76_dma_wed_reset);

void mt76_dma_cleanup(struct mt76_dev *dev)
{
	int i;
@@ -981,16 +1090,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);
+54 −0
Original line number Diff line number Diff line
@@ -19,12 +19,23 @@
#define MT_DMA_CTL_TO_HOST_A		BIT(12)
#define MT_DMA_CTL_DROP			BIT(14)
#define MT_DMA_CTL_TOKEN		GENMASK(31, 16)
#define MT_DMA_CTL_SDP1_H		GENMASK(19, 16)
#define MT_DMA_CTL_SDP0_H		GENMASK(3, 0)
#define MT_DMA_CTL_WO_DROP		BIT(8)

#define MT_DMA_PPE_CPU_REASON		GENMASK(15, 11)
#define MT_DMA_PPE_ENTRY		GENMASK(30, 16)
#define MT_DMA_INFO_DMA_FRAG		BIT(9)
#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_WED_IND_REASON		GENMASK(15, 12)

#define MT_DMA_HDR_LEN			4
#define MT_RX_INFO_LEN			4
#define MT_FCE_INFO_LEN			4
@@ -37,6 +48,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,
@@ -54,9 +70,47 @@ enum mt76_mcu_evt_type {
	EVT_EVENT_DFS_DETECT_RSP,
};

enum mt76_dma_wed_ind_reason {
	MT_DMA_WED_IND_REASON_NORMAL,
	MT_DMA_WED_IND_REASON_REPEAT,
	MT_DMA_WED_IND_REASON_OLDPKT,
};

int mt76_dma_rx_poll(struct napi_struct *napi, int budget);
void mt76_dma_attach(struct mt76_dev *dev);
void mt76_dma_cleanup(struct mt76_dev *dev);
int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset);
void mt76_dma_wed_reset(struct mt76_dev *dev);

static inline void
mt76_dma_reset_tx_queue(struct mt76_dev *dev, struct mt76_queue *q)
{
	dev->queue_ops->reset_q(dev, q);
	if (mtk_wed_device_active(&dev->mmio.wed))
		mt76_dma_wed_setup(dev, q, true);
}

static inline void
mt76_dma_should_drop_buf(bool *drop, u32 ctrl, u32 buf1, u32 info)
{
	if (!drop)
		return;

	*drop = !!(ctrl & (MT_DMA_CTL_TO_HOST_A | MT_DMA_CTL_DROP));
	if (!(ctrl & MT_DMA_CTL_VER_MASK))
		return;

	switch (FIELD_GET(MT_DMA_WED_IND_REASON, buf1)) {
	case MT_DMA_WED_IND_REASON_REPEAT:
		*drop = true;
		break;
	case MT_DMA_WED_IND_REASON_OLDPKT:
		*drop = !(info & MT_DMA_INFO_DMA_FRAG);
		break;
	default:
		*drop = !!(ctrl & MT_DMA_CTL_PN_CHK_FAIL);
		break;
	}
}

#endif
+12 −10
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
	return 0;
}

static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
{
#ifdef CONFIG_MTD
	struct device_node *np = dev->dev->of_node;
@@ -67,7 +67,7 @@ static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offs
		goto out_put_node;
	}

	offset = be32_to_cpup(list);
	offset += be32_to_cpup(list);
	ret = mtd_read(mtd, offset, len, &retlen, eep);
	put_mtd_device(mtd);
	if (mtd_is_bitflip(ret))
@@ -105,8 +105,10 @@ static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offs
	return -ENOENT;
#endif
}
EXPORT_SYMBOL_GPL(mt76_get_of_data_from_mtd);

static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int len)
int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
				const char *cell_name, int len)
{
	struct device_node *np = dev->dev->of_node;
	struct nvmem_cell *cell;
@@ -114,7 +116,7 @@ static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int le
	size_t retlen;
	int ret = 0;

	cell = of_nvmem_cell_get(np, "eeprom");
	cell = of_nvmem_cell_get(np, cell_name);
	if (IS_ERR(cell))
		return PTR_ERR(cell);

@@ -136,8 +138,9 @@ static int mt76_get_of_epprom_from_nvmem(struct mt76_dev *dev, void *eep, int le

	return ret;
}
EXPORT_SYMBOL_GPL(mt76_get_of_data_from_nvmem);

int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
{
	struct device_node *np = dev->dev->of_node;
	int ret;
@@ -149,13 +152,12 @@ int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
	if (!ret)
		return 0;

	ret = mt76_get_of_epprom_from_mtd(dev, eep, offset, len);
	ret = mt76_get_of_data_from_mtd(dev, eep, 0, len);
	if (!ret)
		return 0;

	return mt76_get_of_epprom_from_nvmem(dev, eep, len);
	return mt76_get_of_data_from_nvmem(dev, eep, "eeprom", len);
}
EXPORT_SYMBOL_GPL(mt76_get_of_eeprom);

void
mt76_eeprom_override(struct mt76_phy *phy)
@@ -379,7 +381,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
	if (!np)
		return target_power;

	txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask));
	txs_delta = mt76_get_txs_delta(np, hweight16(phy->chainmask));

	val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck));
	mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val,
@@ -412,6 +414,6 @@ mt76_eeprom_init(struct mt76_dev *dev, int len)
	if (!dev->eeprom.data)
		return -ENOMEM;

	return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len);
	return !mt76_get_of_eeprom(dev, dev->eeprom.data, len);
}
EXPORT_SYMBOL_GPL(mt76_eeprom_init);
+44 −16
Original line number Diff line number Diff line
@@ -197,10 +197,33 @@ static int mt76_led_init(struct mt76_phy *phy)
{
	struct mt76_dev *dev = phy->dev;
	struct ieee80211_hw *hw = phy->hw;
	struct device_node *np = dev->dev->of_node;

	if (!phy->leds.cdev.brightness_set && !phy->leds.cdev.blink_set)
		return 0;

	np = of_get_child_by_name(np, "led");
	if (np) {
		if (!of_device_is_available(np)) {
			of_node_put(np);
			dev_info(dev->dev,
				"led registration was explicitly disabled by dts\n");
			return 0;
		}

		if (phy == &dev->phy) {
			int led_pin;

			if (!of_property_read_u32(np, "led-sources", &led_pin))
				phy->leds.pin = led_pin;

			phy->leds.al =
				of_property_read_bool(np, "led-active-low");
		}

		of_node_put(np);
	}

	snprintf(phy->leds.name, sizeof(phy->leds.name), "mt76-%s",
		 wiphy_name(hw->wiphy));

@@ -211,20 +234,8 @@ static int mt76_led_init(struct mt76_phy *phy)
					mt76_tpt_blink,
					ARRAY_SIZE(mt76_tpt_blink));

	if (phy == &dev->phy) {
		struct device_node *np = dev->dev->of_node;

		np = of_get_child_by_name(np, "led");
		if (np) {
			int led_pin;

			if (!of_property_read_u32(np, "led-sources", &led_pin))
				phy->leds.pin = led_pin;
			phy->leds.al = of_property_read_bool(np,
							     "led-active-low");
			of_node_put(np);
		}
	}
	dev_info(dev->dev,
		"registering led '%s'\n", phy->leds.name);

	return led_classdev_register(dev->dev, &phy->leds.cdev);
}
@@ -1537,7 +1548,7 @@ int mt76_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
		     int *dbm)
{
	struct mt76_phy *phy = hw->priv;
	int n_chains = hweight8(phy->antenna_mask);
	int n_chains = hweight16(phy->chainmask);
	int delta = mt76_tx_power_nss_delta(n_chains);

	*dbm = DIV_ROUND_UP(phy->txpower_cur + delta, 2);
@@ -1725,7 +1736,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;
@@ -1735,6 +1746,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)
@@ -1842,3 +1854,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 */
+108 −0
Original line number Diff line number Diff line
@@ -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,113 @@ 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;
		}

		token = FIELD_PREP(MT_DMA_CTL_TOKEN, token);
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
		token |= FIELD_PREP(MT_DMA_CTL_SDP0_H, addr >> 32);
#endif
		desc->token |= cpu_to_le32(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);

void mt76_mmio_wed_reset_complete(struct mtk_wed_device *wed)
{
	struct mt76_dev *dev = container_of(wed, struct mt76_dev, mmio.wed);

	complete(&dev->mmio.wed_reset_complete);
}
EXPORT_SYMBOL_GPL(mt76_mmio_wed_reset_complete);
#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 = {
Loading