Commit 83eafc92 authored by Sujuan Chen's avatar Sujuan Chen Committed by Felix Fietkau
Browse files

wifi: mt76: mt7996: add wed tx support



Similar to MT7915, enable Wireless Ethernet Ditpatcher for MT7996
to offload traffic received from the LAN nic and transmitted on the
WLAN one

Co-developed-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarLorenzo Bianconi <lorenzo@kernel.org>
Signed-off-by: default avatarSujuan Chen <sujuan.chen@mediatek.com>
Signed-off-by: default avatarFelix Fietkau <nbd@nbd.name>
parent af8d2af5
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -988,10 +988,13 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
		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);
+11 −0
Original line number Diff line number Diff line
@@ -107,6 +107,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
};

@@ -604,6 +614,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;
};
+61 −15
Original line number Diff line number Diff line
@@ -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;
@@ -128,7 +148,7 @@ 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)
{
	u32 hif1_ofs = 0;
	u32 irq_mask;
@@ -153,11 +173,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 +184,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(&dev->mt76.mmio.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(&dev->mt76.mmio.wed, wed_irq_mask);
	}

	irq_mask = reset ? MT_INT_MCU_CMD : irq_mask;

	mt7996_irq_enable(dev, irq_mask);
	mt7996_irq_disable(dev, 0);
}
@@ -243,15 +268,16 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
		 */
		mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL,
			 MT_WFDMA0_RX_INT_SEL_RING3);

		/* TODO: redirect rx ring6 interrupt to pcie0 for wed function */
	}

	mt7996_dma_start(dev, reset);
	mt7996_dma_start(dev, reset, true);
}

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 +291,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,
	ret = mt7996_init_tx_queues(&dev->phy,
				    MT_TXQ_ID(dev->mphy.band_idx),
				    MT7996_TX_RING_SIZE,
					 MT_TXQ_RING_BASE(0), NULL, 0);
				    MT_TXQ_RING_BASE(0),
				    wed);
	if (ret)
		return ret;

@@ -315,6 +342,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 +356,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->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 +371,26 @@ 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;
		if (mtk_wed_device_active(wed))
			rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2);

		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->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,
+21 −9
Original line number Diff line number Diff line
@@ -156,7 +156,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;
@@ -168,6 +168,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;
@@ -356,6 +358,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;
@@ -367,8 +370,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)
@@ -401,12 +406,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,
	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,
					 NULL, 0);
				    wed);
	if (ret)
		goto error;

@@ -419,6 +424,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:
@@ -890,7 +902,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));
+30 −1
Original line number Diff line number Diff line
@@ -996,6 +996,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, struct sk_buff *skb)
{
@@ -1403,6 +1426,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;
@@ -1877,7 +1906,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);
Loading