Commit 7b3c83dd authored by Rex Lu's avatar Rex Lu Committed by Felix Fietkau
Browse files

wifi: mt76: mt7996: Decouple RRO logic from WED support



Decouple RRO logic from WED support in MT7996 driver in order to reuse
it when WED module is not available.

Signed-off-by: default avatarRex Lu <rex.lu@mediatek.com>
Co-developed-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Link: https://patch.msgid.link/20250909-mt7996-rro-rework-v5-14-7d66f6eb7795@kernel.org


Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent 1a7c1bff
Loading
Loading
Loading
Loading
+43 −11
Original line number Diff line number Diff line
@@ -224,9 +224,9 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
{
	struct mt76_queue_entry *entry = &q->entry[q->head];
	struct mt76_txwi_cache *txwi = NULL;
	u32 buf1 = 0, ctrl, info = 0;
	struct mt76_desc *desc;
	int idx = q->head;
	u32 buf1 = 0, ctrl;
	int rx_token;

	if (mt76_queue_is_wed_rro_ind(q)) {
@@ -243,7 +243,7 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
	buf1 = FIELD_PREP(MT_DMA_CTL_SDP0_H, buf->addr >> 32);
#endif

	if (mt76_queue_is_wed_rx(q)) {
	if (mt76_queue_is_wed_rx(q) || mt76_queue_is_wed_rro_data(q)) {
		txwi = mt76_get_rxwi(dev);
		if (!txwi)
			return -ENOMEM;
@@ -260,10 +260,22 @@ mt76_dma_add_rx_buf(struct mt76_dev *dev, struct mt76_queue *q,
		txwi->qid = q - dev->q_rx;
	}

	if (mt76_queue_is_wed_rro_msdu_pg(q) &&
	    dev->drv->rx_rro_add_msdu_page) {
		if (dev->drv->rx_rro_add_msdu_page(dev, q, buf->addr, data))
			return -ENOMEM;
	}

	if (q->flags & MT_QFLAG_WED_RRO_EN) {
		info |= FIELD_PREP(MT_DMA_MAGIC_MASK, q->magic_cnt);
		if ((q->head + 1) == q->ndesc)
			q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_MAGIC_CNT;
	}

	WRITE_ONCE(desc->buf0, cpu_to_le32(buf->addr));
	WRITE_ONCE(desc->buf1, cpu_to_le32(buf1));
	WRITE_ONCE(desc->ctrl, cpu_to_le32(ctrl));
	WRITE_ONCE(desc->info, 0);
	WRITE_ONCE(desc->info, cpu_to_le32(info));

done:
	entry->dma_addr[0] = buf->addr;
@@ -424,7 +436,7 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
	u32 ctrl, desc_info, buf1;
	void *buf = e->buf;

	if (mt76_queue_is_wed_rro_ind(q))
	if (mt76_queue_is_wed_rro(q))
		goto done;

	ctrl = le32_to_cpu(READ_ONCE(desc->ctrl));
@@ -480,15 +492,27 @@ mt76_dma_dequeue(struct mt76_dev *dev, struct mt76_queue *q, bool flush,
		return NULL;

	if (mt76_queue_is_wed_rro_data(q) || mt76_queue_is_wed_rro_msdu_pg(q))
		goto done;

	if (mt76_queue_is_wed_rro_ind(q)) {
		struct mt76_wed_rro_ind *cmd;

		if (flush)
			goto done;

		cmd = q->entry[idx].buf;
		if (cmd->magic_cnt != q->magic_cnt)
			return NULL;

	if (!mt76_queue_is_wed_rro_ind(q)) {
		if (q->tail == q->ndesc - 1)
			q->magic_cnt = (q->magic_cnt + 1) % MT_DMA_WED_IND_CMD_CNT;
	} else {
		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;
	}

done:
	q->tail = (q->tail + 1) % q->ndesc;
	q->queued--;

@@ -837,8 +861,9 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
	bool allow_direct = !mt76_queue_is_wed_rx(q);
	bool more;

	if (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
	    mt76_queue_is_wed_tx_free(q)) {
	if ((q->flags & MT_QFLAG_WED_RRO_EN) ||
	    (IS_ENABLED(CONFIG_NET_MEDIATEK_SOC_WED) &&
	     mt76_queue_is_wed_tx_free(q))) {
		dma_idx = Q_READ(q, dma_idx);
		check_ddone = true;
	}
@@ -860,6 +885,14 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
		if (!data)
			break;

		if (mt76_queue_is_wed_rro_ind(q) && dev->drv->rx_rro_ind_process)
			dev->drv->rx_rro_ind_process(dev, data);

		if (mt76_queue_is_wed_rro(q)) {
			done++;
			continue;
		}

		if (drop)
			goto free_frag;

@@ -978,8 +1011,7 @@ mt76_dma_init(struct mt76_dev *dev,
	init_completion(&dev->mmio.wed_reset_complete);

	mt76_for_each_q_rx(dev, i) {
		if (mtk_wed_device_active(&dev->mmio.wed) &&
		    mt76_queue_is_wed_rro(&dev->q_rx[i]))
		if (mt76_queue_is_wed_rro(&dev->q_rx[i]))
			continue;

		mt76_dma_rx_queue_init(dev, i, poll);
+6 −1
Original line number Diff line number Diff line
@@ -31,8 +31,13 @@
#define MT_DMA_CTL_PN_CHK_FAIL		BIT(13)
#define MT_DMA_CTL_VER_MASK		BIT(7)

#define MT_DMA_SDP0			GENMASK(15, 0)
#define MT_DMA_TOKEN_ID			GENMASK(31, 16)
#define MT_DMA_MAGIC_MASK		GENMASK(31, 28)
#define MT_DMA_RRO_EN			BIT(13)

#define MT_DMA_MAGIC_CNT		16

#define MT_DMA_WED_IND_CMD_CNT		8
#define MT_DMA_WED_IND_REASON		GENMASK(15, 12)

+3 −7
Original line number Diff line number Diff line
@@ -232,6 +232,7 @@ struct mt76_queue {

	u8 buf_offset;
	u16 flags;
	u8 magic_cnt;

	struct mtk_wed_device *wed;
	u32 wed_regs;
@@ -1808,13 +1809,8 @@ static inline bool mt76_queue_is_wed_rro_msdu_pg(struct mt76_queue *q)

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) ||
	       mt76_queue_is_wed_rro_msdu_pg(q);

	return (q->flags & MT_QFLAG_WED) &&
	       FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX;
}

struct mt76_txwi_cache *
+53 −20
Original line number Diff line number Diff line
@@ -325,7 +325,7 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset)
	}

	if (mt7996_band_valid(dev, MT_BAND2))
		irq_mask |= MT_INT_BAND2_RX_DONE;
		irq_mask |= MT_INT_BAND2_RX_DONE | MT_INT_TX_RX_DONE_EXT;

	if (mtk_wed_device_active(wed) && wed_reset) {
		u32 wed_irq_mask = irq_mask;
@@ -482,7 +482,6 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
	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;
@@ -491,6 +490,8 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)

	/* ind cmd */
	mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND;
	if (mtk_wed_device_active(&mdev->mmio.wed) &&
	    mtk_wed_get_rx_capa(&mdev->mmio.wed))
		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),
@@ -502,6 +503,8 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
	/* 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;
	if (mtk_wed_device_active(&mdev->mmio.wed) &&
	    mtk_wed_get_rx_capa(&mdev->mmio.wed))
		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),
@@ -515,6 +518,8 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
		/* 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;
		if (mtk_wed_device_active(&mdev->mmio.wed) &&
		    mtk_wed_get_rx_capa(&mdev->mmio.wed))
			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),
@@ -529,6 +534,8 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
		/* 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;
		if (mtk_wed_device_active(&mdev->mmio.wed) &&
		    mtk_wed_get_rx_capa(&mdev->mmio.wed))
			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),
@@ -539,15 +546,35 @@ int mt7996_dma_rro_init(struct mt7996_dev *dev)
			return ret;
	}

	irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE |
	if (mtk_wed_device_active(&mdev->mmio.wed)) {
		irq_mask = mdev->mmio.irqmask |
			   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);
	} else {
		if (is_mt7996(&dev->mt76)) {
			mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND1,
					   mt76_dma_rx_poll);
			mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND2,
					   mt76_dma_rx_poll);
			mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND2,
					   mt76_dma_rx_poll);
		} else {
			mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND1,
					   mt76_dma_rx_poll);
		}

		mt76_queue_rx_init(dev, MT_RXQ_RRO_BAND0, mt76_dma_rx_poll);
		mt76_queue_rx_init(dev, MT_RXQ_RRO_IND, mt76_dma_rx_poll);
		mt76_queue_rx_init(dev, MT_RXQ_MSDU_PAGE_BAND0,
				   mt76_dma_rx_poll);
		mt7996_irq_enable(dev, MT_INT_RRO_RX_DONE);
	}

	return 0;
}
#endif /* CONFIG_NET_MEDIATEK_SOC_WED */

int mt7996_dma_init(struct mt7996_dev *dev)
{
@@ -738,11 +765,11 @@ int mt7996_dma_init(struct mt7996_dev *dev)
		}
	}

	if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) &&
	    dev->has_rro) {
	if (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;
		if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed))
			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),
@@ -755,6 +782,8 @@ int mt7996_dma_init(struct mt7996_dev *dev)
		if (is_mt7992(&dev->mt76)) {
			dev->mt76.q_rx[MT_RXQ_RRO_BAND1].flags =
				MT_WED_RRO_Q_DATA(1) | MT_QFLAG_WED_RRO_EN;
			if (mtk_wed_device_active(wed) &&
			    mtk_wed_get_rx_capa(wed))
				dev->mt76.q_rx[MT_RXQ_RRO_BAND1].wed = wed;
			ret = mt76_queue_alloc(dev,
					       &dev->mt76.q_rx[MT_RXQ_RRO_BAND1],
@@ -765,9 +794,11 @@ int mt7996_dma_init(struct mt7996_dev *dev)
			if (ret)
				return ret;
		} else {
			if (mtk_wed_device_active(wed)) {
				/* 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],
@@ -783,6 +814,8 @@ int mt7996_dma_init(struct mt7996_dev *dev)
			/* 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;
			if (mtk_wed_device_active(wed) &&
			    mtk_wed_get_rx_capa(wed))
				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),
+30 −30
Original line number Diff line number Diff line
@@ -766,7 +766,6 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev)

void mt7996_rro_hw_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;
	int i;
@@ -809,6 +808,9 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev)
		mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1,
			MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE);
	}

#ifdef CONFIG_NET_MEDIATEK_SOC_WED
	if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) {
		wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6;
		if (is_mt7996(&dev->mt76))
			wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION;
@@ -817,10 +819,17 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev)
		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;
	}
#endif /* CONFIG_NET_MEDIATEK_SOC_WED */

	if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed)) {
		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);
	} else {
		mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE0, 0);
		mt76_wr(dev, MT_RRO_IND_CMD_SIGNATURE_BASE1, 0);
	}

	/* particular session configure */
	/* use max session idx + 1 as particular session id */
@@ -850,14 +859,11 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev)
	/* interrupt enable */
	mt76_wr(dev, MT_RRO_HOST_INT_ENA,
		MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA);
#endif
}

static int mt7996_wed_rro_init(struct mt7996_dev *dev)
{
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
	u32 val = FIELD_PREP(WED_RRO_ADDR_SIGNATURE_MASK, 0xff);
	struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
	struct mt7996_wed_rro_addr *addr;
	void *ptr;
	int i;
@@ -865,9 +871,6 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
	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,
@@ -899,9 +902,16 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
			addr++;
		}

#ifdef CONFIG_NET_MEDIATEK_SOC_WED
		if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
		    mtk_wed_get_rx_capa(&dev->mt76.mmio.wed)) {
			struct mtk_wed_device *wed = &dev->mt76.mmio.wed;

			wed->wlan.ind_cmd.addr_elem_phys[i] =
				dev->wed_rro.addr_elem[i].phy_addr;
		}
#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
	}

	for (i = 0; i < ARRAY_SIZE(dev->wed_rro.msdu_pg); i++) {
		ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
@@ -934,22 +944,15 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
	mt7996_rro_hw_init(dev);

	return mt7996_dma_rro_init(dev);
#else
	return 0;
#endif
}

static void mt7996_wed_rro_free(struct mt7996_dev *dev)
{
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
	int i;

	if (!dev->has_rro)
		return;

	if (!mtk_wed_device_active(&dev->mt76.mmio.wed))
		return;

	for (i = 0; i < ARRAY_SIZE(dev->wed_rro.ba_bitmap); i++) {
		if (!dev->wed_rro.ba_bitmap[i].ptr)
			continue;
@@ -989,12 +992,10 @@ static void mt7996_wed_rro_free(struct mt7996_dev *dev)
			   sizeof(struct mt7996_wed_rro_addr),
			   dev->wed_rro.session.ptr,
			   dev->wed_rro.session.phy_addr);
#endif
}

static void mt7996_wed_rro_work(struct work_struct *work)
{
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
	u32 val = FIELD_PREP(WED_RRO_ADDR_SIGNATURE_MASK, 0xff);
	struct mt7996_dev *dev;
	LIST_HEAD(list);
@@ -1038,7 +1039,6 @@ static void mt7996_wed_rro_work(struct work_struct *work)
out:
		kfree(e);
	}
#endif
}

static int mt7996_variant_type_init(struct mt7996_dev *dev)
Loading