summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mediatek/mt76/mt7996
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:12 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 18:50:12 +0000
commit8665bd53f2f2e27e5511d90428cb3f60e6d0ce15 (patch)
tree8d58900dc0ebd4a3011f92c128d2fe45bc7c4bf2 /drivers/net/wireless/mediatek/mt76/mt7996
parentAdding debian version 6.7.12-1. (diff)
downloadlinux-8665bd53f2f2e27e5511d90428cb3f60e6d0ce15.tar.xz
linux-8665bd53f2f2e27e5511d90428cb3f60e6d0ce15.zip
Merging upstream version 6.8.9.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7996')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/dma.c399
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c38
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/init.c520
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mac.c218
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/main.c77
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.c504
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.h230
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mmio.c360
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h160
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/pci.c71
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/regs.h182
13 files changed, 2398 insertions, 369 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
index 4d40ec7ff5..9bd953586b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
@@ -476,7 +476,7 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s)
{
struct mt76_mib_stats *mib = &phy->mib;
static const char * const bw[] = {
- "BW20", "BW40", "BW80", "BW160"
+ "BW20", "BW40", "BW80", "BW160", "BW320"
};
/* Tx Beamformer monitor */
@@ -489,8 +489,9 @@ mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s)
/* Tx Beamformer Rx feedback monitor */
seq_puts(s, "Tx Beamformer Rx feedback statistics: ");
- seq_printf(s, "All: %d, HE: %d, VHT: %d, HT: %d, ",
+ seq_printf(s, "All: %d, EHT: %d, HE: %d, VHT: %d, HT: %d, ",
mib->tx_bf_rx_fb_all_cnt,
+ mib->tx_bf_rx_fb_eht_cnt,
mib->tx_bf_rx_fb_he_cnt,
mib->tx_bf_rx_fb_vht_cnt,
mib->tx_bf_rx_fb_ht_cnt);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
index 586e247a1e..fe37110e66 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
@@ -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;
@@ -37,18 +57,51 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
RXQ_CONFIG(MT_RXQ_MCU, WFDMA0, MT_INT_RX_DONE_WM, MT7996_RXQ_MCU_WM);
RXQ_CONFIG(MT_RXQ_MCU_WA, WFDMA0, MT_INT_RX_DONE_WA, MT7996_RXQ_MCU_WA);
- /* band0/band1 */
+ /* mt7996: band0 and band1, mt7992: band0 */
RXQ_CONFIG(MT_RXQ_MAIN, WFDMA0, MT_INT_RX_DONE_BAND0, MT7996_RXQ_BAND0);
RXQ_CONFIG(MT_RXQ_MAIN_WA, WFDMA0, MT_INT_RX_DONE_WA_MAIN, MT7996_RXQ_MCU_WA_MAIN);
- /* band2 */
- RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2);
- RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI);
+ if (is_mt7996(&dev->mt76)) {
+ /* mt7996 band2 */
+ RXQ_CONFIG(MT_RXQ_BAND2, WFDMA0, MT_INT_RX_DONE_BAND2, MT7996_RXQ_BAND2);
+ RXQ_CONFIG(MT_RXQ_BAND2_WA, WFDMA0, MT_INT_RX_DONE_WA_TRI, MT7996_RXQ_MCU_WA_TRI);
+ } else {
+ /* mt7992 band1 */
+ RXQ_CONFIG(MT_RXQ_BAND1, WFDMA0, MT_INT_RX_DONE_BAND1, MT7996_RXQ_BAND1);
+ RXQ_CONFIG(MT_RXQ_BAND1_WA, WFDMA0, MT_INT_RX_DONE_WA_EXT, MT7996_RXQ_MCU_WA_EXT);
+ }
+
+ if (dev->has_rro) {
+ /* band0 */
+ RXQ_CONFIG(MT_RXQ_RRO_BAND0, WFDMA0, MT_INT_RX_DONE_RRO_BAND0,
+ MT7996_RXQ_RRO_BAND0);
+ RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND0, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND0,
+ MT7996_RXQ_MSDU_PG_BAND0);
+ RXQ_CONFIG(MT_RXQ_TXFREE_BAND0, WFDMA0, MT_INT_RX_TXFREE_MAIN,
+ MT7996_RXQ_TXFREE0);
+ /* band1 */
+ RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND1, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND1,
+ MT7996_RXQ_MSDU_PG_BAND1);
+ /* band2 */
+ RXQ_CONFIG(MT_RXQ_RRO_BAND2, WFDMA0, MT_INT_RX_DONE_RRO_BAND2,
+ MT7996_RXQ_RRO_BAND2);
+ RXQ_CONFIG(MT_RXQ_MSDU_PAGE_BAND2, WFDMA0, MT_INT_RX_DONE_MSDU_PG_BAND2,
+ MT7996_RXQ_MSDU_PG_BAND2);
+ RXQ_CONFIG(MT_RXQ_TXFREE_BAND2, WFDMA0, MT_INT_RX_TXFREE_TRI,
+ MT7996_RXQ_TXFREE2);
+
+ RXQ_CONFIG(MT_RXQ_RRO_IND, WFDMA0, MT_INT_RX_DONE_RRO_IND,
+ MT7996_RXQ_RRO_IND);
+ }
/* data tx queue */
TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
- TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
- TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2);
+ if (is_mt7996(&dev->mt76)) {
+ TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
+ TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2);
+ } else {
+ TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
+ }
/* mcu tx queue */
MCUQ_CONFIG(MT_MCUQ_WM, WFDMA0, MT_INT_TX_DONE_MCU_WM, MT7996_TXQ_MCU_WM);
@@ -56,22 +109,57 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
MCUQ_CONFIG(MT_MCUQ_FWDL, WFDMA0, MT_INT_TX_DONE_FWDL, MT7996_TXQ_FWDL);
}
+static u32 __mt7996_dma_prefetch_base(u16 *base, u8 depth)
+{
+ u32 ret = *base << 16 | depth;
+
+ *base = *base + (depth << 4);
+
+ return ret;
+}
+
static void __mt7996_dma_prefetch(struct mt7996_dev *dev, u32 ofs)
{
-#define PREFETCH(_base, _depth) ((_base) << 16 | (_depth))
+ u16 base = 0;
+ u8 queue;
+
+#define PREFETCH(_depth) (__mt7996_dma_prefetch_base(&base, (_depth)))
/* prefetch SRAM wrapping boundary for tx/rx ring. */
- mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x0, 0x2));
- mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x20, 0x2));
- mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x40, 0x4));
- mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x80, 0x4));
- mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0xc0, 0x2));
- mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0xe0, 0x4));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x120, 0x2));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x140, 0x2));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x160, 0x2));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2_WA) + ofs, PREFETCH(0x180, 0x2));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x1a0, 0x10));
- mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_BAND2) + ofs, PREFETCH(0x2a0, 0x10));
+ mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_FWDL) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WM) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_TXQ_EXT_CTRL(0) + ofs, PREFETCH(0x8));
+ mt76_wr(dev, MT_TXQ_EXT_CTRL(1) + ofs, PREFETCH(0x8));
+ mt76_wr(dev, MT_MCUQ_EXT_CTRL(MT_MCUQ_WA) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_TXQ_EXT_CTRL(2) + ofs, PREFETCH(0x8));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MCU_WA) + ofs, PREFETCH(0x2));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN_WA) + ofs, PREFETCH(0x2));
+
+ queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2_WA : MT_RXQ_BAND1_WA;
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x2));
+
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MAIN) + ofs, PREFETCH(0x10));
+
+ queue = is_mt7996(&dev->mt76) ? MT_RXQ_BAND2 : MT_RXQ_BAND1;
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(queue) + ofs, PREFETCH(0x10));
+
+ if (dev->has_rro) {
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND0) + ofs,
+ PREFETCH(0x10));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_RRO_BAND2) + ofs,
+ PREFETCH(0x10));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND0) + ofs,
+ PREFETCH(0x4));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND1) + ofs,
+ PREFETCH(0x4));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_MSDU_PAGE_BAND2) + ofs,
+ PREFETCH(0x4));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND0) + ofs,
+ PREFETCH(0x4));
+ mt76_wr(dev, MT_RXQ_BAND1_CTRL(MT_RXQ_TXFREE_BAND2) + ofs,
+ PREFETCH(0x4));
+ }
+#undef PREFETCH
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1 + ofs, WF_WFDMA0_GLO_CFG_EXT1_CALC_MODE);
}
@@ -128,8 +216,9 @@ 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)
{
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
u32 hif1_ofs = 0;
u32 irq_mask;
@@ -138,37 +227,50 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset)
/* enable WFDMA Tx/Rx */
if (!reset) {
- mt76_set(dev, MT_WFDMA0_GLO_CFG,
- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
- MT_WFDMA0_GLO_CFG_RX_DMA_EN |
- MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+ if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed))
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_EXT_EN);
+ else
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_RX_DMA_EN |
+ MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 |
+ MT_WFDMA0_GLO_CFG_EXT_EN);
if (dev->hif2)
mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN |
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
- MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
+ MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 |
+ MT_WFDMA0_GLO_CFG_EXT_EN);
}
/* 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)
+ if (mt7996_band_valid(dev, MT_BAND0))
irq_mask |= MT_INT_BAND0_RX_DONE;
- if (dev->dbdc_support)
+ if (mt7996_band_valid(dev, MT_BAND1))
irq_mask |= MT_INT_BAND1_RX_DONE;
- if (dev->tbtc_support)
+ if (mt7996_band_valid(dev, MT_BAND2))
irq_mask |= MT_INT_BAND2_RX_DONE;
-done:
+ if (mtk_wed_device_active(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(wed, wed_irq_mask);
+ }
+
+ irq_mask = reset ? MT_INT_MCU_CMD : irq_mask;
+
mt7996_irq_enable(dev, irq_mask);
mt7996_irq_disable(dev, 0);
}
@@ -223,6 +325,12 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT1,
WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
+ /* WFDMA rx threshold */
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH, 0xc000c);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH, 0x10008);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH, 0x10008);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH, 0x20);
+
if (dev->hif2) {
/* GLO_CFG_EXT0 */
mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
@@ -234,24 +342,108 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
mt76_set(dev, MT_WFDMA_HOST_CONFIG,
- MT_WFDMA_HOST_CONFIG_PDMA_BAND);
+ MT_WFDMA_HOST_CONFIG_PDMA_BAND |
+ MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
+
+ /* AXI read outstanding number */
+ mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL,
+ MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14);
+
+ /* WFDMA rx threshold */
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_89_TH + hif1_ofs, 0x10008);
+ mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_RRO_TH + hif1_ofs, 0x20);
}
if (dev->hif2) {
/* fix hardware limitation, pcie1's rx ring3 is not available
* so, redirect pcie0 rx ring3 interrupt to pcie1
*/
- mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL,
- MT_WFDMA0_RX_INT_SEL_RING3);
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ dev->has_rro)
+ mt76_set(dev, MT_WFDMA0_RX_INT_PCIE_SEL + hif1_ofs,
+ MT_WFDMA0_RX_INT_SEL_RING6);
+ else
+ 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, true);
+}
+
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+int mt7996_dma_rro_init(struct mt7996_dev *dev)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ u32 irq_mask;
+ int ret;
+
+ /* ind cmd */
+ mdev->q_rx[MT_RXQ_RRO_IND].flags = MT_WED_RRO_Q_IND;
+ 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),
+ MT7996_RX_RING_SIZE,
+ 0, MT_RXQ_RRO_IND_RING_BASE);
+ if (ret)
+ return ret;
+
+ /* 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;
+ 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),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_MSDU_PAGE_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND0));
+ if (ret)
+ return ret;
+
+ if (mt7996_band_valid(dev, MT_BAND1)) {
+ /* 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;
+ 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),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_MSDU_PAGE_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND1));
+ if (ret)
+ return ret;
}
- mt7996_dma_start(dev, reset);
+ if (mt7996_band_valid(dev, MT_BAND2)) {
+ /* 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;
+ 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),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_MSDU_PAGE_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_MSDU_PAGE_BAND2));
+ if (ret)
+ return ret;
+ }
+
+ irq_mask = mdev->mmio.irqmask | MT_INT_RRO_RX_DONE |
+ 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);
+
+ return 0;
}
+#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
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 +457,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,
- MT_TXQ_ID(dev->mphy.band_idx),
- MT7996_TX_RING_SIZE,
- MT_TXQ_RING_BASE(0), 0);
+ ret = mt7996_init_tx_queues(&dev->phy,
+ MT_TXQ_ID(dev->mphy.band_idx),
+ MT7996_TX_RING_SIZE,
+ MT_TXQ_RING_BASE(0),
+ wed);
if (ret)
return ret;
@@ -314,7 +507,12 @@ int mt7996_dma_init(struct mt7996_dev *dev)
if (ret)
return ret;
- /* rx data queue for band0 and band1 */
+ /* rx data queue for band0 and mt7996 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 +522,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->has_rro) {
+ 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,
@@ -332,19 +535,25 @@ int mt7996_dma_init(struct mt7996_dev *dev)
if (ret)
return ret;
- if (dev->tbtc_support || dev->mphy.band_idx == MT_BAND2) {
- /* rx data queue for band2 */
+ if (mt7996_band_valid(dev, MT_BAND2)) {
+ /* rx data queue for mt7996 band2 */
+ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND2) + hif1_ofs;
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
+ /* tx free notify event from WA for mt7996 band2
* use pcie0's rx ring3, but, redirect pcie0 rx ring3 interrupt to pcie1
*/
+ if (mtk_wed_device_active(wed_hif2) && !dev->has_rro) {
+ 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,
@@ -352,6 +561,80 @@ int mt7996_dma_init(struct mt7996_dev *dev)
MT_RXQ_RING_BASE(MT_RXQ_BAND2_WA));
if (ret)
return ret;
+ } else if (mt7996_band_valid(dev, MT_BAND1)) {
+ /* rx data queue for mt7992 band1 */
+ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1) + hif1_ofs;
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1],
+ MT_RXQ_ID(MT_RXQ_BAND1),
+ MT7996_RX_RING_SIZE,
+ MT_RX_BUF_SIZE,
+ rx_base);
+ if (ret)
+ return ret;
+
+ /* tx free notify event from WA for mt7992 band1 */
+ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs;
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA],
+ MT_RXQ_ID(MT_RXQ_BAND1_WA),
+ MT7996_RX_MCU_RING_SIZE,
+ MT_RX_BUF_SIZE,
+ rx_base);
+ if (ret)
+ return ret;
+ }
+
+ if (mtk_wed_device_active(wed) && mtk_wed_get_rx_capa(wed) &&
+ 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;
+ 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),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_BUF_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND0));
+ if (ret)
+ return ret;
+
+ /* 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],
+ MT_RXQ_ID(MT_RXQ_TXFREE_BAND0),
+ MT7996_RX_MCU_RING_SIZE,
+ MT7996_RX_BUF_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND0));
+ if (ret)
+ return ret;
+
+ if (mt7996_band_valid(dev, MT_BAND2)) {
+ /* 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;
+ 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),
+ MT7996_RX_RING_SIZE,
+ MT7996_RX_BUF_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_RRO_BAND2) + hif1_ofs);
+ if (ret)
+ return ret;
+
+ /* tx free notify event from MAC for band2 */
+ if (mtk_wed_device_active(wed_hif2)) {
+ dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].flags = MT_WED_Q_TXFREE;
+ dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2].wed = wed_hif2;
+ }
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_TXFREE_BAND2],
+ MT_RXQ_ID(MT_RXQ_TXFREE_BAND2),
+ MT7996_RX_MCU_RING_SIZE,
+ MT7996_RX_BUF_SIZE,
+ MT_RXQ_RING_BASE(MT_RXQ_TXFREE_BAND2) + hif1_ofs);
+ if (ret)
+ return ret;
+ }
}
ret = mt76_init_queues(dev, mt76_dma_rx_poll);
@@ -405,21 +688,33 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
if (force)
mt7996_wfsys_reset(dev);
+ if (dev->hif2 && mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ mtk_wed_device_dma_reset(&dev->mt76.mmio.wed_hif2);
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_dma_reset(&dev->mt76.mmio.wed);
+
mt7996_dma_disable(dev, force);
+ mt76_dma_wed_reset(&dev->mt76);
/* reset hw queues */
for (i = 0; i < __MT_TXQ_MAX; i++) {
- mt76_queue_reset(dev, dev->mphy.q_tx[i]);
+ mt76_dma_reset_tx_queue(&dev->mt76, dev->mphy.q_tx[i]);
if (phy2)
- mt76_queue_reset(dev, phy2->q_tx[i]);
+ mt76_dma_reset_tx_queue(&dev->mt76, phy2->q_tx[i]);
if (phy3)
- mt76_queue_reset(dev, phy3->q_tx[i]);
+ mt76_dma_reset_tx_queue(&dev->mt76, phy3->q_tx[i]);
}
for (i = 0; i < __MT_MCUQ_MAX; i++)
mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
mt76_for_each_q_rx(&dev->mt76, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ if (mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]) ||
+ mt76_queue_is_wed_tx_free(&dev->mt76.q_rx[i]))
+ continue;
+
mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
index 544b6c6f1e..4a82371182 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.c
@@ -14,7 +14,9 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
switch (val) {
case 0x7990:
- return 0;
+ return is_mt7996(&dev->mt76) ? 0 : -EINVAL;
+ case 0x7992:
+ return is_mt7992(&dev->mt76) ? 0 : -EINVAL;
default:
return -EINVAL;
}
@@ -22,8 +24,14 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
static char *mt7996_eeprom_name(struct mt7996_dev *dev)
{
- /* reserve for future variants */
- return MT7996_EEPROM_DEFAULT;
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7990:
+ return MT7996_EEPROM_DEFAULT;
+ case 0x7992:
+ return MT7992_EEPROM_DEFAULT;
+ default:
+ return MT7996_EEPROM_DEFAULT;
+ }
}
static int
@@ -103,7 +111,8 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP);
}
- if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4)
+ if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4 ||
+ is_mt7992(&dev->mt76))
dev->wtbl_size_group = 2; /* set default */
return 0;
@@ -148,36 +157,49 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy)
int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
{
- u8 path, nss, band_idx = phy->mt76->band_idx;
+ u8 path, rx_path, nss, band_idx = phy->mt76->band_idx;
u8 *eeprom = dev->mt76.eeprom.data;
struct mt76_phy *mphy = phy->mt76;
+ int max_path = 5, max_nss = 4;
int ret;
switch (band_idx) {
case MT_BAND1:
path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1,
eeprom[MT_EE_WIFI_CONF + 2]);
+ rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1,
+ eeprom[MT_EE_WIFI_CONF + 3]);
nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1,
eeprom[MT_EE_WIFI_CONF + 5]);
break;
case MT_BAND2:
path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2,
eeprom[MT_EE_WIFI_CONF + 2]);
+ rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2,
+ eeprom[MT_EE_WIFI_CONF + 4]);
nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2,
eeprom[MT_EE_WIFI_CONF + 5]);
break;
default:
path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0,
eeprom[MT_EE_WIFI_CONF + 1]);
+ rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0,
+ eeprom[MT_EE_WIFI_CONF + 3]);
nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0,
eeprom[MT_EE_WIFI_CONF + 4]);
break;
}
- if (!path || path > 4)
- path = 4;
+ if (!path || path > max_path)
+ path = max_path;
+
+ if (!nss || nss > max_nss)
+ nss = max_nss;
+
+ nss = min_t(u8, nss, path);
- nss = min_t(u8, min_t(u8, 4, nss), path);
+ if (path != rx_path)
+ phy->has_aux_rx = true;
mphy->antenna_mask = BIT(nss) - 1;
mphy->chainmask = (BIT(path) - 1) << dev->chainshift[band_idx];
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h
index 0c749774f6..412d6e2f80 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/eeprom.h
@@ -33,6 +33,9 @@ enum mt7996_eeprom_field {
#define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3)
+#define MT_EE_WIFI_CONF3_RX_PATH_BAND0 GENMASK(2, 0)
+#define MT_EE_WIFI_CONF3_RX_PATH_BAND1 GENMASK(5, 3)
+#define MT_EE_WIFI_CONF4_RX_PATH_BAND2 GENMASK(2, 0)
#define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0)
#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/init.c b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
index f8b61df15f..a929c657be 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/init.c
@@ -5,6 +5,8 @@
#include <linux/etherdevice.h>
#include <linux/of.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
#include <linux/thermal.h>
#include "mt7996.h"
#include "mac.h"
@@ -43,6 +45,183 @@ static const struct ieee80211_iface_combination if_comb[] = {
}
};
+static ssize_t mt7996_thermal_temp_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mt7996_phy *phy = dev_get_drvdata(dev);
+ int i = to_sensor_dev_attr(attr)->index;
+ int temperature;
+
+ switch (i) {
+ case 0:
+ temperature = mt7996_mcu_get_temperature(phy);
+ if (temperature < 0)
+ return temperature;
+ /* display in millidegree celcius */
+ return sprintf(buf, "%u\n", temperature * 1000);
+ case 1:
+ case 2:
+ return sprintf(buf, "%u\n",
+ phy->throttle_temp[i - 1] * 1000);
+ case 3:
+ return sprintf(buf, "%hhu\n", phy->throttle_state);
+ default:
+ return -EINVAL;
+ }
+}
+
+static ssize_t mt7996_thermal_temp_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct mt7996_phy *phy = dev_get_drvdata(dev);
+ int ret, i = to_sensor_dev_attr(attr)->index;
+ long val;
+
+ ret = kstrtol(buf, 10, &val);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130);
+
+ /* add a safety margin ~10 */
+ if ((i - 1 == MT7996_CRIT_TEMP_IDX &&
+ val > phy->throttle_temp[MT7996_MAX_TEMP_IDX] - 10) ||
+ (i - 1 == MT7996_MAX_TEMP_IDX &&
+ val - 10 < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) {
+ dev_err(phy->dev->mt76.dev,
+ "temp1_max shall be 10 degrees higher than temp1_crit.");
+ mutex_unlock(&phy->dev->mt76.mutex);
+ return -EINVAL;
+ }
+
+ phy->throttle_temp[i - 1] = val;
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+ ret = mt7996_mcu_set_thermal_protect(phy, true);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0);
+static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1);
+static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2);
+static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3);
+
+static struct attribute *mt7996_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_throttle1.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(mt7996_hwmon);
+
+static int
+mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = MT7996_CDEV_THROTTLE_MAX;
+
+ return 0;
+}
+
+static int
+mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct mt7996_phy *phy = cdev->devdata;
+
+ *state = phy->cdev_state;
+
+ return 0;
+}
+
+static int
+mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long state)
+{
+ struct mt7996_phy *phy = cdev->devdata;
+ u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state;
+ int ret;
+
+ if (state > MT7996_CDEV_THROTTLE_MAX) {
+ dev_err(phy->dev->mt76.dev,
+ "please specify a valid throttling state\n");
+ return -EINVAL;
+ }
+
+ if (state == phy->cdev_state)
+ return 0;
+
+ /* cooling_device convention: 0 = no cooling, more = more cooling
+ * mcu convention: 1 = max cooling, more = less cooling
+ */
+ ret = mt7996_mcu_set_thermal_throttling(phy, throttling);
+ if (ret)
+ return ret;
+
+ phy->cdev_state = state;
+
+ return 0;
+}
+
+static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
+ .get_max_state = mt7996_thermal_get_max_throttle_state,
+ .get_cur_state = mt7996_thermal_get_cur_throttle_state,
+ .set_cur_state = mt7996_thermal_set_cur_throttle_state,
+};
+
+static void mt7996_unregister_thermal(struct mt7996_phy *phy)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+
+ if (!phy->cdev)
+ return;
+
+ sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
+ thermal_cooling_device_unregister(phy->cdev);
+}
+
+static int mt7996_thermal_init(struct mt7996_phy *phy)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct thermal_cooling_device *cdev;
+ struct device *hwmon;
+ const char *name;
+
+ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
+ wiphy_name(wiphy));
+
+ cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops);
+ if (!IS_ERR(cdev)) {
+ if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
+ "cooling_device") < 0)
+ thermal_cooling_device_unregister(cdev);
+ else
+ phy->cdev = cdev;
+ }
+
+ /* initialize critical/maximum high temperature */
+ phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
+ phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
+
+ if (!IS_REACHABLE(CONFIG_HWMON))
+ return 0;
+
+ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
+ mt7996_hwmon_groups);
+
+ if (IS_ERR(hwmon))
+ return PTR_ERR(hwmon);
+
+ return 0;
+}
+
static void mt7996_led_set_config(struct led_classdev *led_cdev,
u8 delay_on, u8 delay_off)
{
@@ -109,10 +288,11 @@ static void mt7996_led_set_brightness(struct led_classdev *led_cdev,
mt7996_led_set_config(led_cdev, 0xff, 0);
}
-void mt7996_init_txpower(struct mt7996_dev *dev,
- struct ieee80211_supported_band *sband)
+static void __mt7996_init_txpower(struct mt7996_phy *phy,
+ struct ieee80211_supported_band *sband)
{
- int i, nss = hweight8(dev->mphy.antenna_mask);
+ struct mt7996_dev *dev = phy->dev;
+ int i, nss = hweight16(phy->mt76->chainmask);
int nss_delta = mt76_tx_power_nss_delta(nss);
int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band);
struct mt76_power_limits limits;
@@ -122,7 +302,7 @@ void mt7996_init_txpower(struct mt7996_dev *dev,
int target_power = mt7996_eeprom_get_target_power(dev, chan);
target_power += pwr_delta;
- target_power = mt76_get_rate_power_limits(&dev->mphy, chan,
+ target_power = mt76_get_rate_power_limits(phy->mt76, chan,
&limits,
target_power);
target_power += nss_delta;
@@ -133,6 +313,19 @@ void mt7996_init_txpower(struct mt7996_dev *dev,
}
}
+void mt7996_init_txpower(struct mt7996_phy *phy)
+{
+ if (!phy)
+ return;
+
+ if (phy->mt76->cap.has_2ghz)
+ __mt7996_init_txpower(phy, &phy->mt76->sband_2g.sband);
+ if (phy->mt76->cap.has_5ghz)
+ __mt7996_init_txpower(phy, &phy->mt76->sband_5g.sband);
+ if (phy->mt76->cap.has_6ghz)
+ __mt7996_init_txpower(phy, &phy->mt76->sband_6g.sband);
+}
+
static void
mt7996_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
@@ -147,16 +340,14 @@ mt7996_regd_notifier(struct wiphy *wiphy,
if (dev->mt76.region == NL80211_DFS_UNSET)
mt7996_mcu_rdd_background_enable(phy, NULL);
- mt7996_init_txpower(dev, &phy->mt76->sband_2g.sband);
- mt7996_init_txpower(dev, &phy->mt76->sband_5g.sband);
- mt7996_init_txpower(dev, &phy->mt76->sband_6g.sband);
+ mt7996_init_txpower(phy);
phy->mt76->dfs_state = MT_DFS_STATE_UNKNOWN;
mt7996_dfs_init_radar_detector(phy);
}
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,11 +359,14 @@ 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;
phy->slottime = 9;
+ phy->beacon_rate = -1;
hw->sta_data_size = sizeof(struct mt7996_sta);
hw->vif_data_size = sizeof(struct mt7996_vif);
@@ -242,6 +436,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
mt76_set_stream_caps(phy->mt76, true);
mt7996_set_stream_vht_txbf_caps(phy);
mt7996_set_stream_he_eht_caps(phy);
+ mt7996_init_txpower(phy);
wiphy->available_antennas_rx = phy->mt76->antenna_mask;
wiphy->available_antennas_tx = phy->mt76->antenna_mask;
@@ -287,11 +482,12 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
for (i = 0; i < ARRAY_SIZE(mt76_rates); i++) {
u16 rate = mt76_rates[i].hw_value;
- u16 idx = MT7996_BASIC_RATES_TBL + i;
+ /* odd index for driver, even index for firmware */
+ u16 idx = MT7996_BASIC_RATES_TBL + 2 * i;
rate = FIELD_PREP(MT_TX_RATE_MODE, rate >> 8) |
FIELD_PREP(MT_TX_RATE_IDX, rate & GENMASK(7, 0));
- mt7996_mac_set_fixed_rate_table(dev, idx, rate);
+ mt7996_mcu_set_fixed_rate_table(&dev->phy, idx, rate, false);
}
}
@@ -317,9 +513,23 @@ void mt7996_mac_init(struct mt7996_dev *dev)
mt76_rmw_field(dev, MT_DMA_TCRF1(2), MT_DMA_TCRF1_QIDX, 0);
/* rro module init */
- mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2);
- mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3);
- mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1);
+ if (is_mt7996(&dev->mt76))
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, 2);
+ else
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE,
+ dev->hif2 ? 7 : 0);
+
+ if (dev->has_rro) {
+ u16 timeout;
+
+ timeout = mt76_rr(dev, MT_HW_REV) == MT_HW_REV1 ? 512 : 128;
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_FLUSH_TIMEOUT, timeout);
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 1);
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 0);
+ } else {
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, 3);
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, 1);
+ }
mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
MCU_WA_PARAM_HW_PATH_HIF_VER,
@@ -335,7 +545,8 @@ int mt7996_txbf_init(struct mt7996_dev *dev)
{
int ret;
- if (dev->dbdc_support) {
+ if (mt7996_band_valid(dev, MT_BAND1) ||
+ mt7996_band_valid(dev, MT_BAND2)) {
ret = mt7996_mcu_set_txbf(dev, BF_MOD_EN_CTRL);
if (ret)
return ret;
@@ -356,19 +567,18 @@ 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;
-
- if ((band == MT_BAND1 && !dev->dbdc_support) ||
- (band == MT_BAND2 && !dev->tbtc_support))
+ if (!mt7996_band_valid(dev, band) || band == MT_BAND0)
return 0;
if (phy)
return 0;
- if (band == MT_BAND2 && dev->hif2)
+ if (is_mt7996(&dev->mt76) && 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,11 +611,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,
- MT_TXQ_ID(band),
- MT7996_TX_RING_SIZE,
- MT_TXQ_RING_BASE(band) + hif1_ofs, 0);
+ 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,
+ wed);
if (ret)
goto error;
@@ -414,10 +625,21 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
if (ret)
goto error;
+ ret = mt7996_thermal_init(phy);
+ if (ret)
+ goto error;
+
ret = mt7996_init_debugfs(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:
@@ -434,6 +656,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
if (!phy)
return;
+ mt7996_unregister_thermal(phy);
+
mphy = phy->dev->mt76.phys[band];
mt76_unregister_phy(mphy);
ieee80211_free_hw(mphy->hw);
@@ -447,9 +671,6 @@ static void mt7996_init_work(struct work_struct *work)
mt7996_mcu_set_eeprom(dev);
mt7996_mac_init(dev);
- mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
- mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
- mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
mt7996_txbf_init(dev);
}
@@ -462,16 +683,225 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev)
msleep(20);
}
+static int mt7996_wed_rro_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;
+ struct mt7996_wed_rro_addr *addr;
+ void *ptr;
+ int i;
+
+ 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,
+ &dev->wed_rro.ba_bitmap[i].phy_addr,
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ dev->wed_rro.ba_bitmap[i].ptr = ptr;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
+ int j;
+
+ ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr),
+ &dev->wed_rro.addr_elem[i].phy_addr,
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ dev->wed_rro.addr_elem[i].ptr = ptr;
+ memset(dev->wed_rro.addr_elem[i].ptr, 0,
+ MT7996_RRO_WINDOW_MAX_SIZE * sizeof(*addr));
+
+ addr = dev->wed_rro.addr_elem[i].ptr;
+ for (j = 0; j < MT7996_RRO_WINDOW_MAX_SIZE; j++) {
+ addr->signature = 0xff;
+ addr++;
+ }
+
+ wed->wlan.ind_cmd.addr_elem_phys[i] =
+ dev->wed_rro.addr_elem[i].phy_addr;
+ }
+
+ ptr = dmam_alloc_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr),
+ &dev->wed_rro.session.phy_addr,
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ dev->wed_rro.session.ptr = ptr;
+ addr = dev->wed_rro.session.ptr;
+ for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) {
+ addr->signature = 0xff;
+ addr++;
+ }
+
+ /* rro hw init */
+ /* TODO: remove line after WM has set */
+ mt76_clear(dev, WF_RRO_AXI_MST_CFG, WF_RRO_AXI_MST_CFG_DIDX_OK);
+
+ /* setup BA bitmap cache address */
+ mt76_wr(dev, MT_RRO_BA_BITMAP_BASE0,
+ dev->wed_rro.ba_bitmap[0].phy_addr);
+ mt76_wr(dev, MT_RRO_BA_BITMAP_BASE1, 0);
+ mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT0,
+ dev->wed_rro.ba_bitmap[1].phy_addr);
+ mt76_wr(dev, MT_RRO_BA_BITMAP_BASE_EXT1, 0);
+
+ /* setup Address element address */
+ for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
+ mt76_wr(dev, reg, dev->wed_rro.addr_elem[i].phy_addr >> 4);
+ reg += 4;
+ }
+
+ /* setup Address element address - separate address segment mode */
+ mt76_wr(dev, MT_RRO_ADDR_ARRAY_BASE1,
+ MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE);
+
+ wed->wlan.ind_cmd.win_size = ffs(MT7996_RRO_WINDOW_MAX_LEN) - 6;
+ wed->wlan.ind_cmd.particular_sid = MT7996_RRO_MAX_SESSION;
+ 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;
+
+ 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);
+
+ /* particular session configure */
+ /* use max session idx + 1 as particular session id */
+ mt76_wr(dev, MT_RRO_PARTICULAR_CFG0, dev->wed_rro.session.phy_addr);
+ mt76_wr(dev, MT_RRO_PARTICULAR_CFG1,
+ MT_RRO_PARTICULAR_CONFG_EN |
+ FIELD_PREP(MT_RRO_PARTICULAR_SID, MT7996_RRO_MAX_SESSION));
+
+ /* interrupt enable */
+ mt76_wr(dev, MT_RRO_HOST_INT_ENA,
+ MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA);
+
+ /* rro ind cmd queue init */
+ 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;
+
+ dmam_free_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_BA_BITMAP_CR_SIZE,
+ dev->wed_rro.ba_bitmap[i].ptr,
+ dev->wed_rro.ba_bitmap[i].phy_addr);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(dev->wed_rro.addr_elem); i++) {
+ if (!dev->wed_rro.addr_elem[i].ptr)
+ continue;
+
+ dmam_free_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_WINDOW_MAX_SIZE *
+ sizeof(struct mt7996_wed_rro_addr),
+ dev->wed_rro.addr_elem[i].ptr,
+ dev->wed_rro.addr_elem[i].phy_addr);
+ }
+
+ if (!dev->wed_rro.session.ptr)
+ return;
+
+ dmam_free_coherent(dev->mt76.dma_dev,
+ MT7996_RRO_WINDOW_MAX_LEN *
+ 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
+ struct mt7996_dev *dev;
+ LIST_HEAD(list);
+
+ dev = (struct mt7996_dev *)container_of(work, struct mt7996_dev,
+ wed_rro.work);
+
+ spin_lock_bh(&dev->wed_rro.lock);
+ list_splice_init(&dev->wed_rro.poll_list, &list);
+ spin_unlock_bh(&dev->wed_rro.lock);
+
+ while (!list_empty(&list)) {
+ struct mt7996_wed_rro_session_id *e;
+ int i;
+
+ e = list_first_entry(&list, struct mt7996_wed_rro_session_id,
+ list);
+ list_del_init(&e->list);
+
+ for (i = 0; i < MT7996_RRO_WINDOW_MAX_LEN; i++) {
+ void *ptr = dev->wed_rro.session.ptr;
+ struct mt7996_wed_rro_addr *elem;
+ u32 idx, elem_id = i;
+
+ if (e->id == MT7996_RRO_MAX_SESSION)
+ goto reset;
+
+ idx = e->id / MT7996_RRO_BA_BITMAP_SESSION_SIZE;
+ if (idx >= ARRAY_SIZE(dev->wed_rro.addr_elem))
+ goto out;
+
+ ptr = dev->wed_rro.addr_elem[idx].ptr;
+ elem_id +=
+ (e->id % MT7996_RRO_BA_BITMAP_SESSION_SIZE) *
+ MT7996_RRO_WINDOW_MAX_LEN;
+reset:
+ elem = ptr + elem_id * sizeof(*elem);
+ elem->signature = 0xff;
+ }
+ mt7996_mcu_wed_rro_reset_sessions(dev, e->id);
+out:
+ kfree(e);
+ }
+#endif
+}
+
static int mt7996_init_hardware(struct mt7996_dev *dev)
{
int ret, idx;
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
+ if (is_mt7992(&dev->mt76)) {
+ mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND0), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0);
+ mt76_rmw(dev, MT_AFE_CTL_BAND_PLL_03(MT_BAND1), MT_AFE_CTL_BAND_PLL_03_MSB_EN, 0);
+ }
INIT_WORK(&dev->init_work, mt7996_init_work);
-
- dev->dbdc_support = true;
- dev->tbtc_support = true;
+ INIT_WORK(&dev->wed_rro.work, mt7996_wed_rro_work);
+ INIT_LIST_HEAD(&dev->wed_rro.poll_list);
+ spin_lock_init(&dev->wed_rro.lock);
ret = mt7996_dma_init(dev);
if (ret)
@@ -483,6 +913,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
if (ret)
return ret;
+ ret = mt7996_wed_rro_init(dev);
+ if (ret)
+ return ret;
+
ret = mt7996_eeprom_init(dev);
if (ret < 0)
return ret;
@@ -890,14 +1324,16 @@ 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));
if (ret)
return ret;
- ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+ ret = mt7996_thermal_init(&dev->phy);
+ if (ret)
+ return ret;
ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
if (ret)
@@ -907,21 +1343,35 @@ int mt7996_register_device(struct mt7996_dev *dev)
if (ret)
return ret;
+ ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+
dev->recovery.hw_init_done = true;
ret = mt7996_init_debugfs(&dev->phy);
if (ret)
- return ret;
+ goto error;
+
+ ret = mt7996_coredump_register(dev);
+ if (ret)
+ goto error;
- return mt7996_coredump_register(dev);
+ return 0;
+
+error:
+ cancel_work_sync(&dev->init_work);
+
+ return ret;
}
void mt7996_unregister_device(struct mt7996_dev *dev)
{
+ cancel_work_sync(&dev->wed_rro.work);
mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
+ mt7996_unregister_thermal(&dev->phy);
mt7996_coredump_unregister(dev);
mt76_unregister_device(&dev->mt76);
+ mt7996_wed_rro_free(dev);
mt7996_mcu_exit(dev);
mt7996_tx_token_put(dev);
mt7996_dma_cleanup(dev);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index 7d33b0c895..0384fb059d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -102,7 +102,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
};
struct ieee80211_sta *sta;
struct mt7996_sta *msta;
- struct rate_info *rate;
u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
LIST_HEAD(sta_poll_list);
int i;
@@ -118,7 +117,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
u32 addr, val;
u16 idx;
s8 rssi[4];
- u8 bw;
spin_lock_bh(&dev->mt76.sta_poll_lock);
if (list_empty(&sta_poll_list)) {
@@ -174,49 +172,6 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
}
- /* We don't support reading GI info from txs packets.
- * For accurate tx status reporting and AQL improvement,
- * we need to make sure that flags match so polling GI
- * from per-sta counters directly.
- */
- rate = &msta->wcid.rate;
-
- switch (rate->bw) {
- case RATE_INFO_BW_320:
- bw = IEEE80211_STA_RX_BW_320;
- break;
- case RATE_INFO_BW_160:
- bw = IEEE80211_STA_RX_BW_160;
- break;
- case RATE_INFO_BW_80:
- bw = IEEE80211_STA_RX_BW_80;
- break;
- case RATE_INFO_BW_40:
- bw = IEEE80211_STA_RX_BW_40;
- break;
- default:
- bw = IEEE80211_STA_RX_BW_20;
- break;
- }
-
- addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 6);
- val = mt76_rr(dev, addr);
- if (rate->flags & RATE_INFO_FLAGS_EHT_MCS) {
- addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 5);
- val = mt76_rr(dev, addr);
- rate->eht_gi = FIELD_GET(GENMASK(25, 24), val);
- } else if (rate->flags & RATE_INFO_FLAGS_HE_MCS) {
- u8 offs = 24 + 2 * bw;
-
- rate->he_gi = (val & (0x3 << offs)) >> offs;
- } else if (rate->flags &
- (RATE_INFO_FLAGS_VHT_MCS | RATE_INFO_FLAGS_MCS)) {
- if (val & BIT(12 + bw))
- rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
- else
- rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
- }
-
/* get signal strength of resp frames (CTS/BA/ACK) */
addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34);
val = mt76_rr(dev, addr);
@@ -248,17 +203,6 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
mt76_clear(dev, addr, BIT(5));
}
-void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
- u8 tbl_idx, u16 rate_idx)
-{
- u32 ctrl = MT_WTBL_ITCR_WR | MT_WTBL_ITCR_EXEC | tbl_idx;
-
- mt76_wr(dev, MT_WTBL_ITDR0, rate_idx);
- /* use wtbl spe idx */
- mt76_wr(dev, MT_WTBL_ITDR1, MT_WTBL_SPE_IDX_SEL);
- mt76_wr(dev, MT_WTBL_ITCR, ctrl);
-}
-
/* The HW does not translate the mac header to 802.3 for mesh point */
static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
{
@@ -449,8 +393,36 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
return 0;
}
+static void
+mt7996_wed_check_ppe(struct mt7996_dev *dev, struct mt76_queue *q,
+ struct mt7996_sta *msta, struct sk_buff *skb,
+ u32 info)
+{
+ struct ieee80211_vif *vif;
+ struct wireless_dev *wdev;
+
+ if (!msta || !msta->vif)
+ return;
+
+ if (!mt76_queue_is_wed_rx(q))
+ return;
+
+ if (!(info & MT_DMA_INFO_PPE_VLD))
+ return;
+
+ vif = container_of((void *)msta->vif, struct ieee80211_vif,
+ drv_priv);
+ wdev = ieee80211_vif_to_wdev(vif);
+ skb->dev = wdev->netdev;
+
+ mtk_wed_device_ppe_check(&dev->mt76.mmio.wed, skb,
+ FIELD_GET(MT_DMA_PPE_CPU_REASON, info),
+ FIELD_GET(MT_DMA_PPE_ENTRY, info));
+}
+
static int
-mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
+mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ struct sk_buff *skb, u32 *info)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct mt76_phy *mphy = &dev->mt76.phy;
@@ -475,7 +447,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
u16 seq_ctrl = 0;
__le16 fc = 0;
int idx;
+ u8 hw_aggr = false;
+ struct mt7996_sta *msta = NULL;
+ hw_aggr = status->aggr;
memset(status, 0, sizeof(*status));
band_idx = FIELD_GET(MT_RXD1_NORMAL_BAND_IDX, rxd1);
@@ -502,8 +477,6 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
if (status->wcid) {
- struct mt7996_sta *msta;
-
msta = container_of(status->wcid, struct mt7996_sta, wcid);
spin_lock_bh(&dev->mt76.sta_poll_lock);
if (list_empty(&msta->wcid.poll_list))
@@ -708,12 +681,14 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
}
} else {
status->flag |= RX_FLAG_8023;
+ mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb,
+ *info);
}
if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);
- if (!status->wcid || !ieee80211_is_data_qos(fc))
+ if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr)
return 0;
status->aggr = unicast &&
@@ -757,6 +732,9 @@ mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype);
txwi[2] |= cpu_to_le32(val);
+
+ if (wcid->amsdu)
+ txwi[3] |= cpu_to_le32(MT_TXD3_HW_AMSDU);
}
static void
@@ -887,8 +865,6 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
val |= MT_TXD3_PROTECT_FRAME;
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
val |= MT_TXD3_NO_ACK;
- if (wcid->amsdu)
- val |= MT_TXD3_HW_AMSDU;
txwi[3] = cpu_to_le32(val);
txwi[4] = 0;
@@ -898,8 +874,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
val |= MT_TXD5_TX_STATUS_HOST;
txwi[5] = cpu_to_le32(val);
- val = MT_TXD6_DIS_MAT | MT_TXD6_DAS |
- FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+ val = MT_TXD6_DIS_MAT | MT_TXD6_DAS;
+ if (is_mt7996(&dev->mt76))
+ val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+ else
+ val |= FIELD_PREP(MT_TXD6_MSDU_CNT_V2, 1);
txwi[6] = cpu_to_le32(val);
txwi[7] = 0;
@@ -923,7 +902,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
idx = mvif->basic_rates_idx;
}
- txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));
+ val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW;
+ txwi[6] |= cpu_to_le32(val);
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
}
}
@@ -963,8 +943,16 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
for (i = 0; i < nbuf; i++) {
+ u16 len;
+
+ len = FIELD_PREP(MT_TXP_BUF_LEN, tx_info->buf[i + 1].len);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ len |= FIELD_PREP(MT_TXP_DMA_ADDR_H,
+ tx_info->buf[i + 1].addr >> 32);
+#endif
+
txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
- txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
+ txp->fw.len[i] = cpu_to_le16(len);
}
txp->fw.nbuf = nbuf;
@@ -996,6 +984,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)
{
@@ -1257,6 +1268,8 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
goto out;
rate.flags = RATE_INFO_FLAGS_VHT_MCS;
+ if (wcid->rate.flags & RATE_INFO_FLAGS_SHORT_GI)
+ rate.flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
case MT_PHY_TYPE_HE_SU:
case MT_PHY_TYPE_HE_EXT_SU:
@@ -1406,6 +1419,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;
@@ -1422,7 +1441,7 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
dev_kfree_skb(skb);
break;
case PKT_TYPE_NORMAL:
- if (!mt7996_mac_fill_rx(dev, skb)) {
+ if (!mt7996_mac_fill_rx(dev, q, skb, info)) {
mt76_rx(&dev->mt76, q, skb);
return;
}
@@ -1528,7 +1547,7 @@ mt7996_phy_get_nf(struct mt7996_phy *phy, u8 band_idx)
void mt7996_update_channel(struct mt76_phy *mphy)
{
- struct mt7996_phy *phy = (struct mt7996_phy *)mphy->priv;
+ struct mt7996_phy *phy = mphy->priv;
struct mt76_channel_state *state = mphy->chan_state;
int nf;
@@ -1655,6 +1674,10 @@ mt7996_mac_restart(struct mt7996_dev *dev)
/* disable all tx/rx napi */
mt76_worker_disable(&dev->mt76.tx_worker);
mt76_for_each_q_rx(mdev, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ mt76_queue_is_wed_rro(&mdev->q_rx[i]))
+ continue;
+
if (mdev->q_rx[i].ndesc)
napi_disable(&dev->mt76.napi[i]);
}
@@ -1668,6 +1691,10 @@ mt7996_mac_restart(struct mt7996_dev *dev)
local_bh_disable();
mt76_for_each_q_rx(mdev, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ mt76_queue_is_wed_rro(&mdev->q_rx[i]))
+ continue;
+
if (mdev->q_rx[i].ndesc) {
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
@@ -1700,9 +1727,9 @@ mt7996_mac_restart(struct mt7996_dev *dev)
goto out;
mt7996_mac_init(dev);
- mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
- mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
- mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
+ mt7996_init_txpower(&dev->phy);
+ mt7996_init_txpower(phy2);
+ mt7996_init_txpower(phy3);
ret = mt7996_txbf_init(dev);
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
@@ -1757,6 +1784,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
if (phy3)
ieee80211_stop_queues(phy3->mt76->hw);
+ cancel_work_sync(&dev->wed_rro.work);
cancel_delayed_work_sync(&dev->mphy.mac_work);
if (phy2)
cancel_delayed_work_sync(&phy2->mt76->mac_work);
@@ -1839,6 +1867,13 @@ void mt7996_mac_reset_work(struct work_struct *work)
dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
wiphy_name(dev->mt76.hw->wiphy));
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ mtk_wed_device_stop(&dev->mt76.mmio.wed_hif2);
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_stop(&dev->mt76.mmio.wed);
+
ieee80211_stop_queues(mt76_hw(dev));
if (phy2)
ieee80211_stop_queues(phy2->mt76->hw);
@@ -1848,6 +1883,8 @@ void mt7996_mac_reset_work(struct work_struct *work)
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
+
+ cancel_work_sync(&dev->wed_rro.work);
cancel_delayed_work_sync(&dev->mphy.mac_work);
if (phy2) {
set_bit(MT76_RESET, &phy2->mt76->state);
@@ -1858,8 +1895,13 @@ void mt7996_mac_reset_work(struct work_struct *work)
cancel_delayed_work_sync(&phy3->mt76->mac_work);
}
mt76_worker_disable(&dev->mt76.tx_worker);
- mt76_for_each_q_rx(&dev->mt76, i)
+ mt76_for_each_q_rx(&dev->mt76, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
+ continue;
+
napi_disable(&dev->mt76.napi[i]);
+ }
napi_disable(&dev->mt76.tx_napi);
mutex_lock(&dev->mt76.mutex);
@@ -1880,7 +1922,28 @@ 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);
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
+ u32 wed_irq_mask = MT_INT_RRO_RX_DONE | MT_INT_TX_DONE_BAND2 |
+ dev->mt76.mmio.irqmask;
+
+ if (mtk_wed_get_rx_capa(&dev->mt76.mmio.wed))
+ wed_irq_mask &= ~MT_INT_RX_DONE_RRO_IND;
+
+ mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
+
+ mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask,
+ true);
+ mt7996_irq_enable(dev, wed_irq_mask);
+ mt7996_irq_disable(dev, 0);
+ }
+
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2)) {
+ mt76_wr(dev, MT_INT_PCIE1_MASK_CSR, MT_INT_TX_RX_DONE_EXT);
+ mtk_wed_device_start(&dev->mt76.mmio.wed_hif2,
+ MT_INT_TX_RX_DONE_EXT);
+ }
clear_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_RESET, &dev->mphy.state);
@@ -1891,6 +1954,10 @@ void mt7996_mac_reset_work(struct work_struct *work)
local_bh_disable();
mt76_for_each_q_rx(&dev->mt76, i) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+ mt76_queue_is_wed_rro(&dev->mt76.q_rx[i]))
+ continue;
+
napi_enable(&dev->mt76.napi[i]);
napi_schedule(&dev->mt76.napi[i]);
}
@@ -2190,7 +2257,9 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
IEEE80211_RC_BW_CHANGED))
mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
- /* TODO: smps change */
+ if (changed & IEEE80211_RC_SMPS_CHANGED)
+ mt7996_mcu_set_fixed_field(dev, vif, sta, NULL,
+ RATE_PARAM_MMPS_UPDATE);
spin_lock_bh(&dev->mt76.sta_poll_lock);
}
@@ -2215,6 +2284,7 @@ void mt7996_mac_work(struct work_struct *work)
mt7996_mac_update_stats(phy);
+ mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE);
if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT);
mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 482a8f7d75..51deea84b6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -51,6 +51,14 @@ int mt7996_run(struct ieee80211_hw *hw)
if (ret)
goto out;
+ ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
+ if (ret)
+ goto out;
+
+ ret = mt7996_mcu_set_thermal_protect(phy, true);
+ if (ret)
+ goto out;
+
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
@@ -394,6 +402,13 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
ieee80211_wake_queues(hw);
}
+ if (changed & (IEEE80211_CONF_CHANGE_POWER |
+ IEEE80211_CONF_CHANGE_CHANNEL)) {
+ ret = mt7996_mcu_set_txpower_sku(phy);
+ if (ret)
+ return ret;
+ }
+
mutex_lock(&dev->mt76.mutex);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
@@ -520,24 +535,25 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
struct mt76_phy *mphy = hw->priv;
u16 rate;
- u8 i, idx, ht;
+ u8 i, idx;
rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast);
- ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM;
- if (beacon && ht) {
- struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ if (beacon) {
+ struct mt7996_phy *phy = mphy->priv;
+
+ /* odd index for driver, even index for firmware */
+ idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx;
+ if (phy->beacon_rate != rate)
+ mt7996_mcu_set_fixed_rate_table(phy, idx, rate, beacon);
- /* must odd index */
- idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20);
- mt7996_mac_set_fixed_rate_table(dev, idx, rate);
return idx;
}
idx = FIELD_GET(MT_TX_RATE_IDX, rate);
for (i = 0; i < ARRAY_SIZE(mt76_rates); i++)
if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx)
- return MT7996_BASIC_RATES_TBL + i;
+ return MT7996_BASIC_RATES_TBL + 2 * i;
return mvif->basic_rates_idx;
}
@@ -962,8 +978,8 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
mt76_set_stream_caps(phy->mt76, true);
mt7996_set_stream_vht_txbf_caps(phy);
mt7996_set_stream_he_eht_caps(phy);
+ mt7996_mcu_set_txpower_sku(phy);
- /* TODO: update bmc_wtbl spe_idx when antenna changes */
mutex_unlock(&dev->mt76.mutex);
return 0;
@@ -988,6 +1004,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
sinfo->txrate.he_gi = txrate->he_gi;
sinfo->txrate.he_dcm = txrate->he_dcm;
sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
+ sinfo->txrate.eht_gi = txrate->eht_gi;
}
sinfo->txrate.flags = txrate->flags;
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
@@ -1394,6 +1411,44 @@ out:
return ret;
}
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+static int
+mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct net_device_path_ctx *ctx,
+ struct net_device_path *path)
+{
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+
+ if (phy != &dev->phy && phy->mt76->band_idx == MT_BAND2)
+ wed = &dev->mt76.mmio.wed_hif2;
+
+ if (!mtk_wed_device_active(wed))
+ return -ENODEV;
+
+ if (msta->wcid.idx > MT7996_WTBL_STA)
+ return -EIO;
+
+ path->type = DEV_PATH_MTK_WDMA;
+ path->dev = ctx->dev;
+ path->mtk_wdma.wdma_idx = wed->wdma_idx;
+ path->mtk_wdma.bss = mvif->mt76.idx;
+ path->mtk_wdma.queue = 0;
+ path->mtk_wdma.wcid = msta->wcid.idx;
+
+ path->mtk_wdma.amsdu = mtk_wed_is_amsdu_supported(wed);
+ ctx->dev = NULL;
+
+ return 0;
+}
+
+#endif
+
const struct ieee80211_ops mt7996_ops = {
.tx = mt7996_tx,
.start = mt7996_start,
@@ -1438,4 +1493,8 @@ const struct ieee80211_ops mt7996_ops = {
.sta_add_debugfs = mt7996_sta_add_debugfs,
#endif
.set_radar_background = mt7996_set_radar_background,
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ .net_fill_forward_path = mt7996_net_fill_forward_path,
+ .net_setup_tc = mt76_net_setup_tc,
+#endif
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 0586f5bd41..9e70b96008 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -10,6 +10,20 @@
#include "mac.h"
#include "eeprom.h"
+#define fw_name(_dev, name, ...) ({ \
+ char *_fw; \
+ switch (mt76_chip(&(_dev)->mt76)) { \
+ case 0x7992: \
+ _fw = MT7992_##name; \
+ break; \
+ case 0x7990: \
+ default: \
+ _fw = MT7996_##name; \
+ break; \
+ } \
+ _fw; \
+})
+
struct mt7996_patch_hdr {
char build_date[16];
char platform[4];
@@ -449,6 +463,43 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
}
}
+static int
+mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rate)
+{
+ switch (mcu_rate->tx_mode) {
+ case MT_PHY_TYPE_CCK:
+ case MT_PHY_TYPE_OFDM:
+ break;
+ case MT_PHY_TYPE_HT:
+ case MT_PHY_TYPE_HT_GF:
+ case MT_PHY_TYPE_VHT:
+ if (mcu_rate->tx_gi)
+ rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
+ else
+ rate->flags &= ~RATE_INFO_FLAGS_SHORT_GI;
+ break;
+ case MT_PHY_TYPE_HE_SU:
+ case MT_PHY_TYPE_HE_EXT_SU:
+ case MT_PHY_TYPE_HE_TB:
+ case MT_PHY_TYPE_HE_MU:
+ if (mcu_rate->tx_gi > NL80211_RATE_INFO_HE_GI_3_2)
+ return -EINVAL;
+ rate->he_gi = mcu_rate->tx_gi;
+ break;
+ case MT_PHY_TYPE_EHT_SU:
+ case MT_PHY_TYPE_EHT_TRIG:
+ case MT_PHY_TYPE_EHT_MU:
+ if (mcu_rate->tx_gi > NL80211_RATE_INFO_EHT_GI_3_2)
+ return -EINVAL;
+ rate->eht_gi = mcu_rate->tx_gi;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static void
mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
@@ -465,6 +516,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
struct mt76_wcid *wcid;
switch (le16_to_cpu(res->tag)) {
+ case UNI_ALL_STA_TXRX_RATE:
+ wlan_idx = le16_to_cpu(res->rate[i].wlan_idx);
+ wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+
+ if (!wcid)
+ break;
+
+ if (mt7996_mcu_update_tx_gi(&wcid->rate, &res->rate[i]))
+ dev_err(dev->mt76.dev, "Failed to update TX GI\n");
+ break;
case UNI_ALL_STA_TXRX_ADM_STAT:
wlan_idx = le16_to_cpu(res->adm_stat[i].wlan_idx);
wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
@@ -498,6 +559,34 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
}
static void
+mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+#define THERMAL_NOTIFY_TAG 0x4
+#define THERMAL_NOTIFY 0x2
+ struct mt76_phy *mphy = &dev->mt76.phy;
+ struct mt7996_mcu_thermal_notify *n;
+ struct mt7996_phy *phy;
+
+ n = (struct mt7996_mcu_thermal_notify *)skb->data;
+
+ if (le16_to_cpu(n->tag) != THERMAL_NOTIFY_TAG)
+ return;
+
+ if (n->event_id != THERMAL_NOTIFY)
+ return;
+
+ if (n->band_idx > MT_BAND2)
+ return;
+
+ mphy = dev->mt76.phys[n->band_idx];
+ if (!mphy)
+ return;
+
+ phy = (struct mt7996_phy *)mphy->priv;
+ phy->throttle_state = n->duty_percent;
+}
+
+static void
mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
@@ -520,6 +609,9 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_EVENT_EXT:
mt7996_mcu_rx_ext_event(dev, skb);
break;
+ case MCU_UNI_EVENT_THERMAL:
+ mt7996_mcu_rx_thermal_notify(dev, skb);
+ break;
default:
break;
}
@@ -527,6 +619,73 @@ mt7996_mcu_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
}
static void
+mt7996_mcu_wed_rro_event(struct mt7996_dev *dev, struct sk_buff *skb)
+{
+ struct mt7996_mcu_wed_rro_event *event = (void *)skb->data;
+
+ if (!dev->has_rro)
+ return;
+
+ skb_pull(skb, sizeof(struct mt7996_mcu_rxd) + 4);
+
+ switch (le16_to_cpu(event->tag)) {
+ case UNI_WED_RRO_BA_SESSION_STATUS: {
+ struct mt7996_mcu_wed_rro_ba_event *e;
+
+ while (skb->len >= sizeof(*e)) {
+ struct mt76_rx_tid *tid;
+ struct mt76_wcid *wcid;
+ u16 idx;
+
+ e = (void *)skb->data;
+ idx = le16_to_cpu(e->wlan_id);
+ if (idx >= ARRAY_SIZE(dev->mt76.wcid))
+ break;
+
+ wcid = rcu_dereference(dev->mt76.wcid[idx]);
+ if (!wcid || !wcid->sta)
+ break;
+
+ if (e->tid >= ARRAY_SIZE(wcid->aggr))
+ break;
+
+ tid = rcu_dereference(wcid->aggr[e->tid]);
+ if (!tid)
+ break;
+
+ tid->id = le16_to_cpu(e->id);
+ skb_pull(skb, sizeof(*e));
+ }
+ break;
+ }
+ case UNI_WED_RRO_BA_SESSION_DELETE: {
+ struct mt7996_mcu_wed_rro_ba_delete_event *e;
+
+ while (skb->len >= sizeof(*e)) {
+ struct mt7996_wed_rro_session_id *session;
+
+ e = (void *)skb->data;
+ session = kzalloc(sizeof(*session), GFP_ATOMIC);
+ if (!session)
+ break;
+
+ session->id = le16_to_cpu(e->session_id);
+
+ spin_lock_bh(&dev->wed_rro.lock);
+ list_add_tail(&session->list, &dev->wed_rro.poll_list);
+ spin_unlock_bh(&dev->wed_rro.lock);
+
+ ieee80211_queue_work(mt76_hw(dev), &dev->wed_rro.work);
+ skb_pull(skb, sizeof(*e));
+ }
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
@@ -544,6 +703,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_UNI_EVENT_ALL_STA_INFO:
mt7996_mcu_rx_all_sta_info_event(dev, skb);
break;
+ case MCU_UNI_EVENT_WED_RRO:
+ mt7996_mcu_wed_rro_event(dev, skb);
+ break;
default:
break;
}
@@ -963,7 +1125,7 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif)
}
static int
-mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
+mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif *mvif,
struct ieee80211_ampdu_params *params,
bool enable, bool tx)
{
@@ -972,7 +1134,7 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
struct sk_buff *skb;
struct tlv *tlv;
- skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid,
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mvif, wcid,
MT7996_STA_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
return PTR_ERR(skb);
@@ -986,8 +1148,9 @@ mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
ba->ba_en = enable << params->tid;
ba->amsdu = params->amsdu;
ba->tid = params->tid;
+ ba->ba_rdd_rro = !tx && enable && dev->has_rro;
- return mt76_mcu_skb_send_msg(dev, skb,
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
@@ -1002,8 +1165,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
if (enable && !params->amsdu)
msta->wcid.amsdu = false;
- return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
- enable, true);
+ return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, true);
}
int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
@@ -1013,8 +1175,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
struct mt7996_vif *mvif = msta->vif;
- return mt7996_mcu_sta_ba(&dev->mt76, &mvif->mt76, params,
- enable, false);
+ return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, false);
}
static void
@@ -1120,7 +1281,7 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
static void
mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
{
- struct sta_rec_ht *ht;
+ struct sta_rec_ht_uni *ht;
struct tlv *tlv;
if (!sta->deflink.ht_cap.ht_supported)
@@ -1128,8 +1289,12 @@ mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
- ht = (struct sta_rec_ht *)tlv;
+ ht = (struct sta_rec_ht_uni *)tlv;
ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);
+ ht->ampdu_param = u8_encode_bits(sta->deflink.ht_cap.ampdu_factor,
+ IEEE80211_HT_AMPDU_PARM_FACTOR) |
+ u8_encode_bits(sta->deflink.ht_cap.ampdu_density,
+ IEEE80211_HT_AMPDU_PARM_DENSITY);
}
static void
@@ -1587,44 +1752,6 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
}
static void
-mt7996_mcu_sta_phy_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
-{
- struct sta_rec_phy *phy;
- struct tlv *tlv;
- u8 af = 0, mm = 0;
-
- if (!sta->deflink.ht_cap.ht_supported && !sta->deflink.he_6ghz_capa.capa)
- return;
-
- tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_PHY, sizeof(*phy));
-
- phy = (struct sta_rec_phy *)tlv;
- if (sta->deflink.ht_cap.ht_supported) {
- af = sta->deflink.ht_cap.ampdu_factor;
- mm = sta->deflink.ht_cap.ampdu_density;
- }
-
- if (sta->deflink.vht_cap.vht_supported) {
- u8 vht_af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
- sta->deflink.vht_cap.cap);
-
- af = max_t(u8, af, vht_af);
- }
-
- if (sta->deflink.he_6ghz_capa.capa) {
- af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
- IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
- mm = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
- IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START);
- }
-
- phy->ampdu = FIELD_PREP(IEEE80211_HT_AMPDU_PARM_FACTOR, af) |
- FIELD_PREP(IEEE80211_HT_AMPDU_PARM_DENSITY, mm);
- phy->max_ampdu_len = af;
-}
-
-static void
mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb)
{
struct sta_rec_hdrt *hdrt;
@@ -1712,14 +1839,13 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
MCU_WM_UNI_CMD(RA), true);
}
-static int
-mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, void *data, u32 field)
+int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, void *data, u32 field)
{
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
- struct sta_phy *phy = data;
- struct sta_rec_ra_fixed *ra;
+ struct sta_phy_uni *phy = data;
+ struct sta_rec_ra_fixed_uni *ra;
struct sk_buff *skb;
struct tlv *tlv;
@@ -1730,7 +1856,7 @@ mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
return PTR_ERR(skb);
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA_UPDATE, sizeof(*ra));
- ra = (struct sta_rec_ra_fixed *)tlv;
+ ra = (struct sta_rec_ra_fixed_uni *)tlv;
switch (field) {
case RATE_PARAM_AUTO:
@@ -1742,6 +1868,9 @@ mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
if (phy)
ra->phy = *phy;
break;
+ case RATE_PARAM_MMPS_UPDATE:
+ ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode);
+ break;
default:
break;
}
@@ -1759,7 +1888,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif
struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
enum nl80211_band band = chandef->chan->band;
- struct sta_phy phy = {};
+ struct sta_phy_uni phy = {};
int ret, nrates = 0;
#define __sta_phy_bitrate_mask_check(_mcs, _gi, _ht, _he) \
@@ -1847,13 +1976,13 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
struct cfg80211_chan_def *chandef = &mphy->chandef;
struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
enum nl80211_band band = chandef->chan->band;
- struct sta_rec_ra *ra;
+ struct sta_rec_ra_uni *ra;
struct tlv *tlv;
u32 supp_rate = sta->deflink.supp_rates[band];
u32 cap = sta->wme ? STA_CAP_WMM : 0;
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
- ra = (struct sta_rec_ra *)tlv;
+ ra = (struct sta_rec_ra_uni *)tlv;
ra->valid = true;
ra->auto_rate = true;
@@ -2030,8 +2159,6 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
/* tag order is in accordance with firmware dependency. */
if (sta) {
- /* starec phy */
- mt7996_mcu_sta_phy_tlv(dev, skb, vif, sta);
/* starec hdrt mode */
mt7996_mcu_sta_hdrt_tlv(dev, skb);
/* starec bfer */
@@ -2538,7 +2665,7 @@ static int mt7996_load_patch(struct mt7996_dev *dev)
return -EAGAIN;
}
- ret = request_firmware(&fw, MT7996_ROM_PATCH, dev->mt76.dev);
+ ret = request_firmware(&fw, fw_name(dev, ROM_PATCH), dev->mt76.dev);
if (ret)
goto out;
@@ -2701,17 +2828,17 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
{
int ret;
- ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM,
+ ret = __mt7996_load_ram(dev, "WM", fw_name(dev, FIRMWARE_WM),
MT7996_RAM_TYPE_WM);
if (ret)
return ret;
- ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP,
+ ret = __mt7996_load_ram(dev, "DSP", fw_name(dev, FIRMWARE_DSP),
MT7996_RAM_TYPE_DSP);
if (ret)
return ret;
- return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA,
+ return __mt7996_load_ram(dev, "WA", fw_name(dev, FIRMWARE_WA),
MT7996_RAM_TYPE_WA);
}
@@ -2863,9 +2990,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
{
struct uni_header hdr = {};
struct sk_buff *skb;
- int len, num;
+ int len, num, i;
- num = 2 + 2 * (dev->dbdc_support + dev->tbtc_support);
+ num = 2 + 2 * (mt7996_band_valid(dev, MT_BAND1) +
+ mt7996_band_valid(dev, MT_BAND2));
len = sizeof(hdr) + num * sizeof(struct vow_rx_airtime);
skb = mt76_mcu_msg_alloc(&dev->mt76, NULL, len);
if (!skb)
@@ -2873,13 +3001,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
skb_put_data(skb, &hdr, sizeof(hdr));
- mt7996_add_rx_airtime_tlv(skb, dev->mt76.phy.band_idx);
-
- if (dev->dbdc_support)
- mt7996_add_rx_airtime_tlv(skb, MT_BAND1);
-
- if (dev->tbtc_support)
- mt7996_add_rx_airtime_tlv(skb, MT_BAND2);
+ for (i = 0; i < __MT_MAX_BAND; i++) {
+ if (mt7996_band_valid(dev, i))
+ mt7996_add_rx_airtime_tlv(skb, i);
+ }
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WM_UNI_CMD(VOW), true);
@@ -3305,7 +3430,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
.center_ch = ieee80211_frequency_to_channel(freq1),
.bw = mt76_connac_chan_bw(chandef),
.tx_path_num = hweight16(phy->mt76->chainmask),
- .rx_path = phy->mt76->chainmask >> dev->chainshift[band_idx],
+ .rx_path = mt7996_rx_chainmask(phy) >> dev->chainshift[band_idx],
.band_idx = band_idx,
.channel_band = ch_band[chandef->chan->band],
};
@@ -3577,6 +3702,121 @@ out:
return 0;
}
+int mt7996_mcu_get_temperature(struct mt7996_phy *phy)
+{
+#define TEMPERATURE_QUERY 0
+#define GET_TEMPERATURE 0
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 rsv1;
+ u8 action;
+ u8 band_idx;
+ u8 rsv2;
+ } req = {
+ .tag = cpu_to_le16(TEMPERATURE_QUERY),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .action = GET_TEMPERATURE,
+ .band_idx = phy->mt76->band_idx,
+ };
+ struct mt7996_mcu_thermal {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ __le32 rsv;
+ __le32 temperature;
+ } __packed * res;
+ struct sk_buff *skb;
+ int ret;
+
+ ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
+ &req, sizeof(req), true, &skb);
+ if (ret)
+ return ret;
+
+ res = (void *)skb->data;
+
+ return le32_to_cpu(res->temperature);
+}
+
+int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
+{
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ struct mt7996_mcu_thermal_ctrl ctrl;
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .ctrl = {
+ .band_idx = phy->mt76->band_idx,
+ },
+ };
+ int level, ret;
+
+ /* set duty cycle and level */
+ for (level = 0; level < 4; level++) {
+ req.ctrl.duty.duty_level = level;
+ req.ctrl.duty.duty_cycle = state;
+ state /= 2;
+
+ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
+ &req, sizeof(req), false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable)
+{
+#define SUSTAIN_PERIOD 10
+ struct {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ struct mt7996_mcu_thermal_ctrl ctrl;
+ struct mt7996_mcu_thermal_enable enable;
+ } __packed req = {
+ .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)),
+ .ctrl = {
+ .band_idx = phy->mt76->band_idx,
+ .type.protect_type = 1,
+ .type.trigger_type = 1,
+ },
+ };
+ int ret;
+
+ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE);
+
+ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
+ &req, sizeof(req) - sizeof(req.enable), false);
+ if (ret || !enable)
+ return ret;
+
+ /* set high-temperature trigger threshold */
+ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE);
+ req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0]);
+ req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
+ req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
+
+ req.len = cpu_to_le16(sizeof(req) - 4);
+
+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
+ &req, sizeof(req), false);
+}
+
int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
{
struct {
@@ -4039,6 +4279,35 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
+int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx,
+ u16 rate_idx, bool beacon)
+{
+#define UNI_FIXED_RATE_TABLE_SET 0
+#define SPE_IXD_SELECT_TXD 0
+#define SPE_IXD_SELECT_BMC_WTBL 1
+ struct mt7996_dev *dev = phy->dev;
+ struct fixed_rate_table_ctrl req = {
+ .tag = cpu_to_le16(UNI_FIXED_RATE_TABLE_SET),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .table_idx = table_idx,
+ .rate_idx = cpu_to_le16(rate_idx),
+ .gi = 1,
+ .he_ltf = 1,
+ };
+ u8 band_idx = phy->mt76->band_idx;
+
+ if (beacon) {
+ req.spe_idx_sel = SPE_IXD_SELECT_TXD;
+ req.spe_idx = 24 + band_idx;
+ phy->beacon_rate = rate_idx;
+ } else {
+ req.spe_idx_sel = SPE_IXD_SELECT_BMC_WTBL;
+ }
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(FIXED_RATE_TABLE),
+ &req, sizeof(req), false);
+}
+
int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set)
{
struct {
@@ -4094,14 +4363,12 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev)
&req, sizeof(req), false);
}
-int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
+int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val)
{
struct {
u8 __rsv1[4];
-
__le16 tag;
__le16 len;
-
union {
struct {
u8 type;
@@ -4116,6 +4383,11 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
u8 path;
u8 __rsv2[3];
} __packed txfree_path;
+ struct {
+ __le16 flush_one;
+ __le16 flush_all;
+ u8 __rsv2[4];
+ } __packed timeout;
};
} __packed req = {
.tag = cpu_to_le16(tag),
@@ -4132,6 +4404,10 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val)
case UNI_RRO_SET_TXFREE_PATH:
req.txfree_path.path = val;
break;
+ case UNI_RRO_SET_FLUSH_TIMEOUT:
+ req.timeout.flush_one = cpu_to_le16(val);
+ req.timeout.flush_all = cpu_to_le16(2 * val);
+ break;
default:
return -EINVAL;
}
@@ -4156,3 +4432,81 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag)
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(ALL_STA_INFO),
&req, sizeof(req), false);
}
+
+int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
+{
+ struct {
+ u8 __rsv[4];
+
+ __le16 tag;
+ __le16 len;
+ __le16 session_id;
+ u8 pad[4];
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_RRO_DEL_BA_SESSION),
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .session_id = cpu_to_le16(id),
+ };
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(RRO), &req,
+ sizeof(req), true);
+}
+
+int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
+{
+#define TX_POWER_LIMIT_TABLE_RATE 0
+ struct mt7996_dev *dev = phy->dev;
+ struct mt76_phy *mphy = phy->mt76;
+ struct ieee80211_hw *hw = mphy->hw;
+ struct tx_power_limit_table_ctrl {
+ u8 __rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+ u8 power_ctrl_id;
+ u8 power_limit_type;
+ u8 band_idx;
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL),
+ .len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4),
+ .power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL,
+ .power_limit_type = TX_POWER_LIMIT_TABLE_RATE,
+ .band_idx = phy->mt76->band_idx,
+ };
+ struct mt76_power_limits la = {};
+ struct sk_buff *skb;
+ int i, tx_power;
+
+ tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
+ tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
+ &la, tx_power);
+ mphy->txpower_cur = tx_power;
+
+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
+ sizeof(req) + MT7996_SKU_RATE_NUM);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, &req, sizeof(req));
+ /* cck and ofdm */
+ skb_put_data(skb, &la.cck, sizeof(la.cck));
+ skb_put_data(skb, &la.ofdm, sizeof(la.ofdm));
+ /* ht20 */
+ skb_put_data(skb, &la.mcs[0], 8);
+ /* ht40 */
+ skb_put_data(skb, &la.mcs[1], 9);
+
+ /* vht */
+ for (i = 0; i < 4; i++) {
+ skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i]));
+ skb_put_zero(skb, 2); /* padding */
+ }
+
+ /* he */
+ skb_put_data(skb, &la.ru[0], sizeof(la.ru));
+ /* eht */
+ skb_put_data(skb, &la.eht[0], sizeof(la.eht));
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WM_UNI_CMD(TXPOWER), true);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index 32ce57c8c4..36cacc495c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event {
__le32 status; /* 0: success, others: fail */
} __packed;
+struct mt7996_mcu_thermal_ctrl {
+ u8 ctrl_id;
+ u8 band_idx;
+ union {
+ struct {
+ u8 protect_type; /* 1: duty admit, 2: radio off */
+ u8 trigger_type; /* 0: low, 1: high */
+ } __packed type;
+ struct {
+ u8 duty_level; /* level 0~3 */
+ u8 duty_cycle;
+ } __packed duty;
+ };
+} __packed;
+
+struct mt7996_mcu_thermal_enable {
+ __le32 trigger_temp;
+ __le32 restore_temp;
+ __le16 sustain_time;
+ u8 rsv[2];
+} __packed;
+
struct mt7996_mcu_csa_notify {
struct mt7996_mcu_rxd rxd;
@@ -153,6 +175,27 @@ struct mt7996_mcu_mib {
__le64 data;
} __packed;
+struct all_sta_trx_rate {
+ __le16 wlan_idx;
+ u8 __rsv1[2];
+ u8 tx_mode;
+ u8 flags;
+ u8 tx_stbc;
+ u8 tx_gi;
+ u8 tx_bw;
+ u8 tx_ldpc;
+ u8 tx_mcs;
+ u8 tx_nss;
+ u8 rx_rate;
+ u8 rx_mode;
+ u8 rx_nsts;
+ u8 rx_gi;
+ u8 rx_coding;
+ u8 rx_stbc;
+ u8 rx_bw;
+ u8 __rsv2;
+} __packed;
+
struct mt7996_mcu_all_sta_info_event {
u8 rsv[4];
__le16 tag;
@@ -163,22 +206,74 @@ struct mt7996_mcu_all_sta_info_event {
u8 rsv3[4];
union {
- struct {
+ DECLARE_FLEX_ARRAY(struct all_sta_trx_rate, rate);
+ DECLARE_FLEX_ARRAY(struct {
__le16 wlan_idx;
u8 rsv[2];
__le32 tx_bytes[IEEE80211_NUM_ACS];
__le32 rx_bytes[IEEE80211_NUM_ACS];
- } adm_stat[0] __packed;
+ } __packed, adm_stat);
- struct {
+ DECLARE_FLEX_ARRAY(struct {
__le16 wlan_idx;
u8 rsv[2];
__le32 tx_msdu_cnt;
__le32 rx_msdu_cnt;
- } msdu_cnt[0] __packed;
+ } __packed, msdu_cnt);
} __packed;
} __packed;
+struct mt7996_mcu_wed_rro_event {
+ struct mt7996_mcu_rxd rxd;
+
+ u8 __rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+} __packed;
+
+struct mt7996_mcu_wed_rro_ba_event {
+ __le16 tag;
+ __le16 len;
+
+ __le16 wlan_id;
+ u8 tid;
+ u8 __rsv1;
+ __le32 status;
+ __le16 id;
+ u8 __rsv2[2];
+} __packed;
+
+struct mt7996_mcu_wed_rro_ba_delete_event {
+ __le16 tag;
+ __le16 len;
+
+ __le16 session_id;
+ u8 __rsv2[2];
+} __packed;
+
+enum {
+ UNI_WED_RRO_BA_SESSION_STATUS,
+ UNI_WED_RRO_BA_SESSION_TBL,
+ UNI_WED_RRO_BA_SESSION_DELETE,
+};
+
+struct mt7996_mcu_thermal_notify {
+ struct mt7996_mcu_rxd rxd;
+
+ u8 __rsv1[4];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 event_id;
+ u8 band_idx;
+ u8 level_idx;
+ u8 duty_percent;
+ __le32 restore_temp;
+ u8 __rsv2[4];
+} __packed;
+
enum mt7996_chan_mib_offs {
UNI_MIB_OBSS_AIRTIME = 26,
UNI_MIB_NON_WIFI_TIME = 27,
@@ -389,6 +484,15 @@ struct bss_mld_tlv {
u8 __rsv[3];
} __packed;
+struct sta_rec_ht_uni {
+ __le16 tag;
+ __le16 len;
+ __le16 ht_cap;
+ __le16 ht_cap_ext;
+ u8 ampdu_param;
+ u8 _rsv[3];
+} __packed;
+
struct sta_rec_ba_uni {
__le16 tag;
__le16 len;
@@ -438,6 +542,73 @@ struct sta_rec_sec_uni {
struct sec_key_uni key[2];
} __packed;
+struct sta_phy_uni {
+ u8 type;
+ u8 flag;
+ u8 stbc;
+ u8 sgi;
+ u8 bw;
+ u8 ldpc;
+ u8 mcs;
+ u8 nss;
+ u8 he_ltf;
+ u8 rsv[3];
+};
+
+struct sta_rec_ra_uni {
+ __le16 tag;
+ __le16 len;
+
+ u8 valid;
+ u8 auto_rate;
+ u8 phy_mode;
+ u8 channel;
+ u8 bw;
+ u8 disable_cck;
+ u8 ht_mcs32;
+ u8 ht_gf;
+ u8 ht_mcs[4];
+ u8 mmps_mode;
+ u8 gband_256;
+ u8 af;
+ u8 auth_wapi_mode;
+ u8 rate_len;
+
+ u8 supp_mode;
+ u8 supp_cck_rate;
+ u8 supp_ofdm_rate;
+ __le32 supp_ht_mcs;
+ __le16 supp_vht_mcs[4];
+
+ u8 op_mode;
+ u8 op_vht_chan_width;
+ u8 op_vht_rx_nss;
+ u8 op_vht_rx_nss_type;
+
+ __le32 sta_cap;
+
+ struct sta_phy_uni phy;
+ u8 rx_rcpi[4];
+} __packed;
+
+struct sta_rec_ra_fixed_uni {
+ __le16 tag;
+ __le16 len;
+
+ __le32 field;
+ u8 op_mode;
+ u8 op_vht_chan_width;
+ u8 op_vht_rx_nss;
+ u8 op_vht_rx_nss_type;
+
+ struct sta_phy_uni phy;
+
+ u8 spe_idx;
+ u8 short_preamble;
+ u8 is_5g;
+ u8 mmps_mode;
+} __packed;
+
struct sta_rec_hdrt {
__le16 tag;
__le16 len;
@@ -613,17 +784,16 @@ enum {
#define MT7996_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \
sizeof(struct sta_rec_basic) + \
sizeof(struct sta_rec_bf) + \
- sizeof(struct sta_rec_ht) + \
+ sizeof(struct sta_rec_ht_uni) + \
sizeof(struct sta_rec_he_v2) + \
sizeof(struct sta_rec_ba_uni) + \
sizeof(struct sta_rec_vht) + \
sizeof(struct sta_rec_uapsd) + \
sizeof(struct sta_rec_amsdu) + \
sizeof(struct sta_rec_bfee) + \
- sizeof(struct sta_rec_phy) + \
- sizeof(struct sta_rec_ra) + \
+ sizeof(struct sta_rec_ra_uni) + \
sizeof(struct sta_rec_sec) + \
- sizeof(struct sta_rec_ra_fixed) + \
+ sizeof(struct sta_rec_ra_fixed_uni) + \
sizeof(struct sta_rec_he_6g_capa) + \
sizeof(struct sta_rec_eht) + \
sizeof(struct sta_rec_hdrt) + \
@@ -639,6 +809,18 @@ enum {
#define MT7996_MAX_BSS_OFFLOAD_SIZE (MT7996_MAX_BEACON_SIZE + \
MT7996_BEACON_UPDATE_SIZE)
+static inline s8
+mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower)
+{
+ struct mt76_phy *mphy = phy->mt76;
+ int n_chains = hweight16(mphy->chainmask);
+
+ txpower = mt76_get_sar_power(mphy, mphy->chandef.chan, txpower * 2);
+ txpower -= mt76_tx_power_nss_delta(n_chains);
+
+ return txpower;
+}
+
enum {
UNI_BAND_CONFIG_RADIO_ENABLE,
UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
@@ -686,6 +868,8 @@ enum {
UNI_RRO_GET_BA_SESSION_TABLE,
UNI_RRO_SET_BYPASS_MODE,
UNI_RRO_SET_TXFREE_PATH,
+ UNI_RRO_DEL_BA_SESSION,
+ UNI_RRO_SET_FLUSH_TIMEOUT
};
enum{
@@ -700,6 +884,16 @@ enum{
};
enum {
+ UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6,
+ UNI_CMD_THERMAL_PROTECT_DISABLE,
+ UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
+};
+
+enum {
+ UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
+};
+
+enum {
UNI_CMD_ACCESS_REG_BASIC = 0x0,
UNI_CMD_ACCESS_RF_REG_BASIC,
};
@@ -737,4 +931,24 @@ enum {
#define MT7996_SEC_KEY_IDX GENMASK(2, 1)
#define MT7996_SEC_IV BIT(3)
+struct fixed_rate_table_ctrl {
+ u8 _rsv[4];
+
+ __le16 tag;
+ __le16 len;
+
+ u8 table_idx;
+ u8 antenna_idx;
+ __le16 rate_idx;
+ u8 spe_idx_sel;
+ u8 spe_idx;
+ u8 gi;
+ u8 he_ltf;
+ bool ldpc;
+ bool txbf;
+ bool dynamic_bw;
+
+ u8 _rsv2;
+} __packed;
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
index 3a591a7b47..efd4a767eb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mmio.c
@@ -6,10 +6,16 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/rtnetlink.h>
#include "mt7996.h"
#include "mac.h"
+#include "mcu.h"
#include "../trace.h"
+#include "../dma.h"
+
+static bool wed_enable;
+module_param(wed_enable, bool, 0644);
static const struct __base mt7996_reg_base[] = {
[WF_AGG_BASE] = { { 0x820e2000, 0x820f2000, 0x830e2000 } },
@@ -24,6 +30,58 @@ static const struct __base mt7996_reg_base[] = {
[WF_RATE_BASE] = { { 0x820ee000, 0x820fe000, 0x830ee000 } },
};
+static const u32 mt7996_offs[] = {
+ [MIB_RVSR0] = 0x720,
+ [MIB_RVSR1] = 0x724,
+ [MIB_BTSCR5] = 0x788,
+ [MIB_BTSCR6] = 0x798,
+ [MIB_RSCR1] = 0x7ac,
+ [MIB_RSCR27] = 0x954,
+ [MIB_RSCR28] = 0x958,
+ [MIB_RSCR29] = 0x95c,
+ [MIB_RSCR30] = 0x960,
+ [MIB_RSCR31] = 0x964,
+ [MIB_RSCR33] = 0x96c,
+ [MIB_RSCR35] = 0x974,
+ [MIB_RSCR36] = 0x978,
+ [MIB_BSCR0] = 0x9cc,
+ [MIB_BSCR1] = 0x9d0,
+ [MIB_BSCR2] = 0x9d4,
+ [MIB_BSCR3] = 0x9d8,
+ [MIB_BSCR4] = 0x9dc,
+ [MIB_BSCR5] = 0x9e0,
+ [MIB_BSCR6] = 0x9e4,
+ [MIB_BSCR7] = 0x9e8,
+ [MIB_BSCR17] = 0xa10,
+ [MIB_TRDR1] = 0xa28,
+};
+
+static const u32 mt7992_offs[] = {
+ [MIB_RVSR0] = 0x760,
+ [MIB_RVSR1] = 0x764,
+ [MIB_BTSCR5] = 0x7c8,
+ [MIB_BTSCR6] = 0x7d8,
+ [MIB_RSCR1] = 0x7f0,
+ [MIB_RSCR27] = 0x998,
+ [MIB_RSCR28] = 0x99c,
+ [MIB_RSCR29] = 0x9a0,
+ [MIB_RSCR30] = 0x9a4,
+ [MIB_RSCR31] = 0x9a8,
+ [MIB_RSCR33] = 0x9b0,
+ [MIB_RSCR35] = 0x9b8,
+ [MIB_RSCR36] = 0x9bc,
+ [MIB_BSCR0] = 0xac8,
+ [MIB_BSCR1] = 0xacc,
+ [MIB_BSCR2] = 0xad0,
+ [MIB_BSCR3] = 0xad4,
+ [MIB_BSCR4] = 0xad8,
+ [MIB_BSCR5] = 0xadc,
+ [MIB_BSCR6] = 0xae0,
+ [MIB_BSCR7] = 0xae4,
+ [MIB_BSCR17] = 0xb0c,
+ [MIB_TRDR1] = 0xb24,
+};
+
static const struct __map mt7996_reg_map[] = {
{ 0x54000000, 0x02000, 0x1000 }, /* WFDMA_0 (PCIE0 MCU DMA0) */
{ 0x55000000, 0x03000, 0x1000 }, /* WFDMA_1 (PCIE0 MCU DMA1) */
@@ -82,7 +140,6 @@ static u32 mt7996_reg_map_l1(struct mt7996_dev *dev, u32 addr)
u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr);
u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr);
- dev->reg_l1_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L1);
dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L1,
MT_HIF_REMAP_L1_MASK,
FIELD_PREP(MT_HIF_REMAP_L1_MASK, base));
@@ -97,7 +154,6 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr)
u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr);
u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr);
- dev->reg_l2_backup = dev->bus_ops->rr(&dev->mt76, MT_HIF_REMAP_L2);
dev->bus_ops->rmw(&dev->mt76, MT_HIF_REMAP_L2,
MT_HIF_REMAP_L2_MASK,
FIELD_PREP(MT_HIF_REMAP_L2_MASK, base));
@@ -107,26 +163,10 @@ static u32 mt7996_reg_map_l2(struct mt7996_dev *dev, u32 addr)
return MT_HIF_REMAP_BASE_L2 + offset;
}
-static void mt7996_reg_remap_restore(struct mt7996_dev *dev)
-{
- /* remap to ori status */
- if (unlikely(dev->reg_l1_backup)) {
- dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L1, dev->reg_l1_backup);
- dev->reg_l1_backup = 0;
- }
-
- if (dev->reg_l2_backup) {
- dev->bus_ops->wr(&dev->mt76, MT_HIF_REMAP_L2, dev->reg_l2_backup);
- dev->reg_l2_backup = 0;
- }
-}
-
static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)
{
int i;
- mt7996_reg_remap_restore(dev);
-
if (addr < 0x100000)
return addr;
@@ -143,6 +183,11 @@ static u32 __mt7996_reg_addr(struct mt7996_dev *dev, u32 addr)
return dev->reg.map[i].mapped + ofs;
}
+ return 0;
+}
+
+static u32 __mt7996_reg_remap_addr(struct mt7996_dev *dev, u32 addr)
+{
if ((addr >= MT_INFRA_BASE && addr < MT_WFSYS0_PHY_START) ||
(addr >= MT_WFSYS0_PHY_START && addr < MT_WFSYS1_PHY_START) ||
(addr >= MT_WFSYS1_PHY_START && addr <= MT_WFSYS1_PHY_END))
@@ -167,28 +212,223 @@ void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset,
{
u32 addr = __mt7996_reg_addr(dev, offset);
- memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len);
+ if (addr) {
+ memcpy_fromio(buf, dev->mt76.mmio.regs + addr, len);
+ return;
+ }
+
+ spin_lock_bh(&dev->reg_lock);
+ memcpy_fromio(buf, dev->mt76.mmio.regs +
+ __mt7996_reg_remap_addr(dev, offset), len);
+ spin_unlock_bh(&dev->reg_lock);
}
static u32 mt7996_rr(struct mt76_dev *mdev, u32 offset)
{
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+ u32 addr = __mt7996_reg_addr(dev, offset), val;
- return dev->bus_ops->rr(mdev, __mt7996_reg_addr(dev, offset));
+ if (addr)
+ return dev->bus_ops->rr(mdev, addr);
+
+ spin_lock_bh(&dev->reg_lock);
+ val = dev->bus_ops->rr(mdev, __mt7996_reg_remap_addr(dev, offset));
+ spin_unlock_bh(&dev->reg_lock);
+
+ return val;
}
static void mt7996_wr(struct mt76_dev *mdev, u32 offset, u32 val)
{
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+ u32 addr = __mt7996_reg_addr(dev, offset);
+
+ if (addr) {
+ dev->bus_ops->wr(mdev, addr, val);
+ return;
+ }
- dev->bus_ops->wr(mdev, __mt7996_reg_addr(dev, offset), val);
+ spin_lock_bh(&dev->reg_lock);
+ dev->bus_ops->wr(mdev, __mt7996_reg_remap_addr(dev, offset), val);
+ spin_unlock_bh(&dev->reg_lock);
}
static u32 mt7996_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
{
struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+ u32 addr = __mt7996_reg_addr(dev, offset);
+
+ if (addr)
+ return dev->bus_ops->rmw(mdev, addr, mask, val);
- return dev->bus_ops->rmw(mdev, __mt7996_reg_addr(dev, offset), mask, val);
+ spin_lock_bh(&dev->reg_lock);
+ val = dev->bus_ops->rmw(mdev, __mt7996_reg_remap_addr(dev, offset), mask, val);
+ spin_unlock_bh(&dev->reg_lock);
+
+ return val;
+}
+
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+static int mt7996_mmio_wed_reset(struct mtk_wed_device *wed)
+{
+ struct mt76_dev *mdev = container_of(wed, struct mt76_dev, mmio.wed);
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+ struct mt76_phy *mphy = &dev->mphy;
+ int ret;
+
+ ASSERT_RTNL();
+
+ if (test_and_set_bit(MT76_STATE_WED_RESET, &mphy->state))
+ return -EBUSY;
+
+ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, UNI_CMD_SER_SET_RECOVER_L1,
+ mphy->band_idx);
+ if (ret)
+ goto out;
+
+ rtnl_unlock();
+ if (!wait_for_completion_timeout(&mdev->mmio.wed_reset, 20 * HZ)) {
+ dev_err(mdev->dev, "wed reset timeout\n");
+ ret = -ETIMEDOUT;
+ }
+ rtnl_lock();
+out:
+ clear_bit(MT76_STATE_WED_RESET, &mphy->state);
+
+ return ret;
+}
+#endif
+
+int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
+ bool hif2, int *irq)
+{
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+ struct pci_dev *pci_dev = pdev_ptr;
+ u32 hif1_ofs = 0;
+
+ if (!wed_enable)
+ return 0;
+
+ dev->has_rro = true;
+
+ hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+
+ if (hif2)
+ wed = &dev->mt76.mmio.wed_hif2;
+
+ wed->wlan.pci_dev = pci_dev;
+ wed->wlan.bus_type = MTK_WED_BUS_PCIE;
+
+ wed->wlan.base = devm_ioremap(dev->mt76.dev,
+ pci_resource_start(pci_dev, 0),
+ pci_resource_len(pci_dev, 0));
+ wed->wlan.phy_base = pci_resource_start(pci_dev, 0);
+
+ if (hif2) {
+ wed->wlan.wpdma_int = wed->wlan.phy_base +
+ MT_INT_PCIE1_SOURCE_CSR_EXT;
+ wed->wlan.wpdma_mask = wed->wlan.phy_base +
+ MT_INT_PCIE1_MASK_CSR;
+ wed->wlan.wpdma_tx = wed->wlan.phy_base + hif1_ofs +
+ MT_TXQ_RING_BASE(0) +
+ MT7996_TXQ_BAND2 * MT_RING_SIZE;
+ if (dev->has_rro) {
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(0) +
+ MT7996_RXQ_TXFREE2 * MT_RING_SIZE;
+ wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1;
+ } else {
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(0) +
+ MT7996_RXQ_MCU_WA_TRI * MT_RING_SIZE;
+ wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_TRI) - 1;
+ }
+
+ wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + hif1_ofs + MT_WFDMA0_GLO_CFG;
+ wed->wlan.wpdma_rx = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) +
+ MT7996_RXQ_BAND0 * MT_RING_SIZE;
+
+ wed->wlan.id = 0x7991;
+ wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND2) - 1;
+ } else {
+ wed->wlan.hw_rro = dev->has_rro; /* default on */
+ wed->wlan.wpdma_int = wed->wlan.phy_base + MT_INT_SOURCE_CSR;
+ wed->wlan.wpdma_mask = wed->wlan.phy_base + MT_INT_MASK_CSR;
+ wed->wlan.wpdma_tx = wed->wlan.phy_base + MT_TXQ_RING_BASE(0) +
+ MT7996_TXQ_BAND0 * MT_RING_SIZE;
+
+ wed->wlan.wpdma_rx_glo = wed->wlan.phy_base + MT_WFDMA0_GLO_CFG;
+
+ wed->wlan.wpdma_rx = wed->wlan.phy_base +
+ MT_RXQ_RING_BASE(MT7996_RXQ_BAND0) +
+ MT7996_RXQ_BAND0 * MT_RING_SIZE;
+
+ wed->wlan.wpdma_rx_rro[0] = wed->wlan.phy_base +
+ MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND0) +
+ MT7996_RXQ_RRO_BAND0 * MT_RING_SIZE;
+ wed->wlan.wpdma_rx_rro[1] = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(MT7996_RXQ_RRO_BAND2) +
+ MT7996_RXQ_RRO_BAND2 * MT_RING_SIZE;
+ wed->wlan.wpdma_rx_pg = wed->wlan.phy_base +
+ MT_RXQ_RING_BASE(MT7996_RXQ_MSDU_PG_BAND0) +
+ MT7996_RXQ_MSDU_PG_BAND0 * MT_RING_SIZE;
+
+ wed->wlan.rx_nbuf = 65536;
+ wed->wlan.rx_npkt = dev->hif2 ? 32768 : 24576;
+ wed->wlan.rx_size = SKB_WITH_OVERHEAD(MT_RX_BUF_SIZE);
+
+ wed->wlan.rx_tbit[0] = ffs(MT_INT_RX_DONE_BAND0) - 1;
+ wed->wlan.rx_tbit[1] = ffs(MT_INT_RX_DONE_BAND2) - 1;
+
+ wed->wlan.rro_rx_tbit[0] = ffs(MT_INT_RX_DONE_RRO_BAND0) - 1;
+ wed->wlan.rro_rx_tbit[1] = ffs(MT_INT_RX_DONE_RRO_BAND2) - 1;
+
+ wed->wlan.rx_pg_tbit[0] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND0) - 1;
+ wed->wlan.rx_pg_tbit[1] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND1) - 1;
+ wed->wlan.rx_pg_tbit[2] = ffs(MT_INT_RX_DONE_MSDU_PG_BAND2) - 1;
+
+ wed->wlan.tx_tbit[0] = ffs(MT_INT_TX_DONE_BAND0) - 1;
+ wed->wlan.tx_tbit[1] = ffs(MT_INT_TX_DONE_BAND1) - 1;
+ if (dev->has_rro) {
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) +
+ MT7996_RXQ_TXFREE0 * MT_RING_SIZE;
+ wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_MAIN) - 1;
+ } else {
+ wed->wlan.txfree_tbit = ffs(MT_INT_RX_DONE_WA_MAIN) - 1;
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + MT_RXQ_RING_BASE(0) +
+ MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE;
+ }
+ dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt;
+ }
+
+ wed->wlan.nbuf = MT7996_HW_TOKEN_SIZE;
+ wed->wlan.token_start = MT7996_TOKEN_SIZE - wed->wlan.nbuf;
+
+ wed->wlan.amsdu_max_subframes = 8;
+ wed->wlan.amsdu_max_len = 1536;
+
+ wed->wlan.init_buf = mt7996_wed_init_buf;
+ wed->wlan.init_rx_buf = mt76_mmio_wed_init_rx_buf;
+ wed->wlan.release_rx_buf = mt76_mmio_wed_release_rx_buf;
+ wed->wlan.offload_enable = mt76_mmio_wed_offload_enable;
+ wed->wlan.offload_disable = mt76_mmio_wed_offload_disable;
+ if (!hif2) {
+ wed->wlan.reset = mt7996_mmio_wed_reset;
+ wed->wlan.reset_complete = mt76_mmio_wed_reset_complete;
+ }
+
+ if (mtk_wed_device_attach(wed))
+ return 0;
+
+ *irq = wed->irq;
+ dev->mt76.dma_dev = wed->dev;
+
+ return 1;
+#else
+ return 0;
+#endif
}
static int mt7996_mmio_init(struct mt76_dev *mdev,
@@ -200,10 +440,18 @@ static int mt7996_mmio_init(struct mt76_dev *mdev,
dev = container_of(mdev, struct mt7996_dev, mt76);
mt76_mmio_init(&dev->mt76, mem_base);
+ spin_lock_init(&dev->reg_lock);
switch (device_id) {
case 0x7990:
dev->reg.base = mt7996_reg_base;
+ dev->reg.offs_rev = mt7996_offs;
+ dev->reg.map = mt7996_reg_map;
+ dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map);
+ break;
+ case 0x7992:
+ dev->reg.base = mt7996_reg_base;
+ dev->reg.offs_rev = mt7992_offs;
dev->reg.map = mt7996_reg_map;
dev->reg.map_size = ARRAY_SIZE(mt7996_reg_map);
break;
@@ -241,8 +489,17 @@ void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg,
mdev->mmio.irqmask |= set;
if (write_reg) {
- mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask);
- mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask);
+ if (mtk_wed_device_active(&mdev->mmio.wed)) {
+ mtk_wed_device_irq_set_mask(&mdev->mmio.wed,
+ mdev->mmio.irqmask);
+ if (mtk_wed_device_active(&mdev->mmio.wed_hif2)) {
+ mtk_wed_device_irq_set_mask(&mdev->mmio.wed_hif2,
+ mdev->mmio.irqmask);
+ }
+ } else {
+ mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask);
+ mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask);
+ }
}
spin_unlock_irqrestore(&mdev->mmio.irq_lock, flags);
@@ -260,22 +517,36 @@ static void mt7996_rx_poll_complete(struct mt76_dev *mdev,
static void mt7996_irq_tasklet(struct tasklet_struct *t)
{
struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet);
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+ struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2;
u32 i, intr, mask, intr1;
- mt76_wr(dev, MT_INT_MASK_CSR, 0);
- if (dev->hif2)
- mt76_wr(dev, MT_INT1_MASK_CSR, 0);
-
- intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
- intr &= dev->mt76.mmio.irqmask;
- mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
-
- if (dev->hif2) {
- intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR);
- intr1 &= dev->mt76.mmio.irqmask;
- mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1);
+ if (dev->hif2 && mtk_wed_device_active(wed_hif2)) {
+ mtk_wed_device_irq_set_mask(wed_hif2, 0);
+ intr1 = mtk_wed_device_irq_get(wed_hif2,
+ dev->mt76.mmio.irqmask);
+ if (intr1 & MT_INT_RX_TXFREE_EXT)
+ napi_schedule(&dev->mt76.napi[MT_RXQ_TXFREE_BAND2]);
+ }
- intr |= intr1;
+ if (mtk_wed_device_active(wed)) {
+ mtk_wed_device_irq_set_mask(wed, 0);
+ intr = mtk_wed_device_irq_get(wed, dev->mt76.mmio.irqmask);
+ intr |= (intr1 & ~MT_INT_RX_TXFREE_EXT);
+ } else {
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+ if (dev->hif2)
+ mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+
+ intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
+ intr &= dev->mt76.mmio.irqmask;
+ mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
+ if (dev->hif2) {
+ intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR);
+ intr1 &= dev->mt76.mmio.irqmask;
+ mt76_wr(dev, MT_INT1_SOURCE_CSR, intr1);
+ intr |= intr1;
+ }
}
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
@@ -308,9 +579,17 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance)
{
struct mt7996_dev *dev = dev_instance;
- mt76_wr(dev, MT_INT_MASK_CSR, 0);
- if (dev->hif2)
- mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed, 0);
+ else
+ mt76_wr(dev, MT_INT_MASK_CSR, 0);
+
+ if (dev->hif2) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ mtk_wed_device_irq_set_mask(&dev->mt76.mmio.wed_hif2, 0);
+ else
+ mt76_wr(dev, MT_INT1_MASK_CSR, 0);
+ }
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
return IRQ_NONE;
@@ -391,4 +670,5 @@ static void __exit mt7996_exit(void)
module_init(mt7996_init);
module_exit(mt7996_exit);
+MODULE_DESCRIPTION("MediaTek MT7996 MMIO helpers");
MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 6733ee9744..36d1f247d5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -13,6 +13,7 @@
#define MT7996_MAX_INTERFACES 19 /* per-band */
#define MT7996_MAX_WMM_SETS 4
+#define MT7996_WTBL_BMC_SIZE (is_mt7992(&dev->mt76) ? 32 : 64)
#define MT7996_WTBL_RESERVED (mt7996_wtbl_size(dev) - 1)
#define MT7996_WTBL_STA (MT7996_WTBL_RESERVED - \
mt7996_max_interface_num(dev))
@@ -33,23 +34,55 @@
#define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin"
#define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin"
+#define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin"
+#define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin"
+#define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin"
+#define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin"
+
#define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
+#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin"
#define MT7996_EEPROM_SIZE 7680
#define MT7996_EEPROM_BLOCK_SIZE 16
#define MT7996_TOKEN_SIZE 16384
+#define MT7996_HW_TOKEN_SIZE 8192
#define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
+#define MT7996_SKU_RATE_NUM 417
+
#define MT7996_MAX_TWT_AGRT 16
#define MT7996_MAX_STA_TWT_AGRT 8
#define MT7996_MIN_TWT_DUR 64
#define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3)
/* NOTE: used to map mt76_rates. idx may change if firmware expands table */
-#define MT7996_BASIC_RATES_TBL 11
+#define MT7996_BASIC_RATES_TBL 31
#define MT7996_BEACON_RATES_TBL 25
+#define MT7996_THERMAL_THROTTLE_MAX 100
+#define MT7996_CDEV_THROTTLE_MAX 99
+#define MT7996_CRIT_TEMP_IDX 0
+#define MT7996_MAX_TEMP_IDX 1
+#define MT7996_CRIT_TEMP 110
+#define MT7996_MAX_TEMP 120
+
+#define MT7996_RRO_MAX_SESSION 1024
+#define MT7996_RRO_WINDOW_MAX_LEN 1024
+#define MT7996_RRO_ADDR_ELEM_LEN 128
+#define MT7996_RRO_BA_BITMAP_LEN 2
+#define MT7996_RRO_BA_BITMAP_CR_SIZE ((MT7996_RRO_MAX_SESSION * 128) / \
+ MT7996_RRO_BA_BITMAP_LEN)
+#define MT7996_RRO_BA_BITMAP_SESSION_SIZE (MT7996_RRO_MAX_SESSION / \
+ MT7996_RRO_ADDR_ELEM_LEN)
+#define MT7996_RRO_WINDOW_MAX_SIZE (MT7996_RRO_WINDOW_MAX_LEN * \
+ MT7996_RRO_BA_BITMAP_SESSION_SIZE)
+
+#define MT7996_RX_BUF_SIZE (1800 + \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+#define MT7996_RX_MSDU_PAGE_SIZE (128 + \
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
+
struct mt7996_vif;
struct mt7996_sta;
struct mt7996_dfs_pulse;
@@ -74,11 +107,21 @@ enum mt7996_rxq_id {
MT7996_RXQ_MCU_WM = 0,
MT7996_RXQ_MCU_WA,
MT7996_RXQ_MCU_WA_MAIN = 2,
- MT7996_RXQ_MCU_WA_EXT = 2,/* unused */
+ MT7996_RXQ_MCU_WA_EXT = 3, /* for mt7992 */
MT7996_RXQ_MCU_WA_TRI = 3,
MT7996_RXQ_BAND0 = 4,
- MT7996_RXQ_BAND1 = 4,/* unused */
+ MT7996_RXQ_BAND1 = 5, /* for mt7992 */
MT7996_RXQ_BAND2 = 5,
+ MT7996_RXQ_RRO_BAND0 = 8,
+ MT7996_RXQ_RRO_BAND1 = 8,/* unused */
+ MT7996_RXQ_RRO_BAND2 = 6,
+ MT7996_RXQ_MSDU_PG_BAND0 = 10,
+ MT7996_RXQ_MSDU_PG_BAND1 = 11,
+ MT7996_RXQ_MSDU_PG_BAND2 = 12,
+ MT7996_RXQ_TXFREE0 = 9,
+ MT7996_RXQ_TXFREE1 = 9,
+ MT7996_RXQ_TXFREE2 = 7,
+ MT7996_RXQ_RRO_IND = 0,
};
struct mt7996_twt_flow {
@@ -147,6 +190,20 @@ struct mt7996_hif {
int irq;
};
+struct mt7996_wed_rro_addr {
+ u32 head_low;
+ u32 head_high : 4;
+ u32 count: 11;
+ u32 oor: 1;
+ u32 rsv : 8;
+ u32 signature : 8;
+};
+
+struct mt7996_wed_rro_session_id {
+ struct list_head list;
+ u16 id;
+};
+
struct mt7996_phy {
struct mt76_phy *mt76;
struct mt7996_dev *dev;
@@ -155,6 +212,11 @@ struct mt7996_phy {
struct ieee80211_vif *monitor_vif;
+ struct thermal_cooling_device *cdev;
+ u8 cdev_state;
+ u8 throttle_state;
+ u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
+
u32 rxfilter;
u64 omac_mask;
@@ -165,11 +227,15 @@ struct mt7996_phy {
u8 rdd_state;
+ u16 beacon_rate;
+
u32 rx_ampdu_ts;
u32 ampdu_ref;
struct mt76_mib_stats mib;
struct mt76_channel_state state_ts;
+
+ bool has_aux_rx;
};
struct mt7996_dev {
@@ -222,10 +288,28 @@ struct mt7996_dev {
u32 hw_pattern;
- bool dbdc_support:1;
- bool tbtc_support:1;
bool flash_mode:1;
bool has_eht:1;
+ bool has_rro:1;
+
+ struct {
+ struct {
+ void *ptr;
+ dma_addr_t phy_addr;
+ } ba_bitmap[MT7996_RRO_BA_BITMAP_LEN];
+ struct {
+ void *ptr;
+ dma_addr_t phy_addr;
+ } addr_elem[MT7996_RRO_ADDR_ELEM_LEN];
+ struct {
+ void *ptr;
+ dma_addr_t phy_addr;
+ } session;
+
+ struct work_struct work;
+ struct list_head poll_list;
+ spinlock_t lock;
+ } wed_rro;
bool ibf;
u8 fw_debug_wm;
@@ -241,8 +325,7 @@ struct mt7996_dev {
u8 n_agrt;
} twt;
- u32 reg_l1_backup;
- u32 reg_l2_backup;
+ spinlock_t reg_lock;
u8 wtbl_size_group;
};
@@ -315,6 +398,20 @@ mt7996_phy3(struct mt7996_dev *dev)
return __mt7996_phy(dev, MT_BAND2);
}
+static inline bool
+mt7996_band_valid(struct mt7996_dev *dev, u8 band)
+{
+ if (is_mt7992(&dev->mt76))
+ return band <= MT_BAND1;
+
+ /* tri-band support */
+ if (band <= MT_BAND2 &&
+ mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1)
+ return true;
+
+ return band == MT_BAND0 || band == MT_BAND2;
+}
+
extern const struct ieee80211_ops mt7996_ops;
extern struct pci_driver mt7996_pci_driver;
extern struct pci_driver mt7996_hif_driver;
@@ -335,9 +432,10 @@ int mt7996_dma_init(struct mt7996_dev *dev);
void mt7996_dma_reset(struct mt7996_dev *dev, bool force);
void mt7996_dma_prefetch(struct mt7996_dev *dev);
void mt7996_dma_cleanup(struct mt7996_dev *dev);
-void mt7996_dma_start(struct mt7996_dev *dev, bool reset);
-void mt7996_init_txpower(struct mt7996_dev *dev,
- struct ieee80211_supported_band *sband);
+void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset);
+int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx,
+ int n_desc, int ring_base, struct mtk_wed_device *wed);
+void mt7996_init_txpower(struct mt7996_phy *phy);
int mt7996_txbf_init(struct mt7996_dev *dev);
void mt7996_reset(struct mt7996_dev *dev);
int mt7996_run(struct ieee80211_hw *hw);
@@ -374,6 +472,8 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif);
int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
void *data, u16 version);
+int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, void *data, u32 field);
int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset);
int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
@@ -389,13 +489,19 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif);
int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
+int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
+int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
+int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable);
+int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy);
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
u8 rx_sel, u8 val);
int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
struct cfg80211_chan_def *chandef);
+int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx,
+ u16 rate_idx, bool beacon);
int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set);
int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans);
-int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u8 val);
+int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val);
int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl);
int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
@@ -403,15 +509,18 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev);
void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
+int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
- return MT7996_MAX_INTERFACES * (1 + dev->dbdc_support + dev->tbtc_support);
+ return min(MT7996_MAX_INTERFACES * (1 + mt7996_band_valid(dev, MT_BAND1) +
+ mt7996_band_valid(dev, MT_BAND2)),
+ MT7996_WTBL_BMC_SIZE);
}
static inline u16 mt7996_wtbl_size(struct mt7996_dev *dev)
{
- return (dev->wtbl_size_group << 8) + 64;
+ return (dev->wtbl_size_group << 8) + MT7996_WTBL_BMC_SIZE;
}
void mt7996_dual_hif_set_irq_mask(struct mt7996_dev *dev, bool write_reg,
@@ -438,6 +547,18 @@ static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask)
void mt7996_memcpy_fromio(struct mt7996_dev *dev, void *buf, u32 offset,
size_t len);
+static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy)
+{
+ int max_nss = hweight8(phy->mt76->hw->wiphy->available_antennas_tx);
+ int cur_nss = hweight8(phy->mt76->antenna_mask);
+ u16 tx_chainmask = phy->mt76->chainmask;
+
+ if (cur_nss != max_nss)
+ return tx_chainmask;
+
+ return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx);
+}
+
void mt7996_mac_init(struct mt7996_dev *dev);
u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw);
bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask);
@@ -446,8 +567,6 @@ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy);
void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
struct ieee80211_vif *vif, bool enable);
-void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
- u8 tbl_idx, u16 rate_idx);
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
@@ -497,5 +616,16 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir);
#endif
+int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
+ bool hif2, int *irq);
+u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
+
+#ifdef CONFIG_MTK_DEBUG
+int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
+#endif
+
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+int mt7996_dma_rro_init(struct mt7996_dev *dev);
+#endif /* CONFIG_NET_MEDIATEK_SOC_WED */
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
index 67c0158962..0405618136 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
@@ -96,10 +96,10 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct pci_dev *hif2_dev;
+ struct mt7996_hif *hif2;
struct mt7996_dev *dev;
+ int irq, hif2_irq, ret;
struct mt76_dev *mdev;
- struct mt7996_hif *hif2;
- int irq, ret;
ret = pcim_enable_device(pdev);
if (ret)
@@ -111,7 +111,11 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
pci_set_master(pdev);
- ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
+ ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(36));
+ if (ret)
+ return ret;
+
+ ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
if (ret)
return ret;
@@ -129,15 +133,22 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
mt7996_wfsys_reset(dev);
hif2 = mt7996_pci_init_hif2(pdev);
- ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ ret = mt7996_mmio_wed_init(dev, pdev, false, &irq);
if (ret < 0)
- goto free_device;
+ goto free_wed_or_irq_vector;
+
+ if (!ret) {
+ ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ goto free_device;
+
+ irq = pdev->irq;
+ }
- irq = pdev->irq;
ret = devm_request_irq(mdev->dev, irq, mt7996_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
- goto free_irq_vector;
+ goto free_wed_or_irq_vector;
mt76_wr(dev, MT_INT_MASK_CSR, 0);
/* master switch of PCIe tnterrupt enable */
@@ -147,16 +158,25 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
hif2_dev = container_of(hif2->dev, struct pci_dev, dev);
dev->hif2 = hif2;
- ret = pci_alloc_irq_vectors(hif2_dev, 1, 1, PCI_IRQ_ALL_TYPES);
+ ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &hif2_irq);
if (ret < 0)
- goto free_hif2;
+ goto free_hif2_wed_irq_vector;
+
+ if (!ret) {
+ ret = pci_alloc_irq_vectors(hif2_dev, 1, 1,
+ PCI_IRQ_ALL_TYPES);
+ if (ret < 0)
+ goto free_hif2;
- dev->hif2->irq = hif2_dev->irq;
- ret = devm_request_irq(mdev->dev, dev->hif2->irq,
- mt7996_irq_handler, IRQF_SHARED,
- KBUILD_MODNAME "-hif", dev);
+ dev->hif2->irq = hif2_dev->irq;
+ hif2_irq = dev->hif2->irq;
+ }
+
+ ret = devm_request_irq(mdev->dev, hif2_irq, mt7996_irq_handler,
+ IRQF_SHARED, KBUILD_MODNAME "-hif",
+ dev);
if (ret)
- goto free_hif2_irq_vector;
+ goto free_hif2_wed_irq_vector;
mt76_wr(dev, MT_INT1_MASK_CSR, 0);
/* master switch of PCIe tnterrupt enable */
@@ -171,16 +191,23 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
free_hif2_irq:
if (dev->hif2)
- devm_free_irq(mdev->dev, dev->hif2->irq, dev);
-free_hif2_irq_vector:
- if (dev->hif2)
- pci_free_irq_vectors(hif2_dev);
+ devm_free_irq(mdev->dev, hif2_irq, dev);
+free_hif2_wed_irq_vector:
+ if (dev->hif2) {
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
+ mtk_wed_device_detach(&dev->mt76.mmio.wed_hif2);
+ else
+ pci_free_irq_vectors(hif2_dev);
+ }
free_hif2:
if (dev->hif2)
put_device(dev->hif2->dev);
devm_free_irq(mdev->dev, irq, dev);
-free_irq_vector:
- pci_free_irq_vectors(pdev);
+free_wed_or_irq_vector:
+ if (mtk_wed_device_active(&dev->mt76.mmio.wed))
+ mtk_wed_device_detach(&dev->mt76.mmio.wed);
+ else
+ pci_free_irq_vectors(pdev);
free_device:
mt76_free_device(&dev->mt76);
@@ -225,3 +252,7 @@ MODULE_FIRMWARE(MT7996_FIRMWARE_WA);
MODULE_FIRMWARE(MT7996_FIRMWARE_WM);
MODULE_FIRMWARE(MT7996_FIRMWARE_DSP);
MODULE_FIRMWARE(MT7996_ROM_PATCH);
+MODULE_FIRMWARE(MT7992_FIRMWARE_WA);
+MODULE_FIRMWARE(MT7992_FIRMWARE_WM);
+MODULE_FIRMWARE(MT7992_FIRMWARE_DSP);
+MODULE_FIRMWARE(MT7992_ROM_PATCH);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
index 0086a78666..47b429d8bf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/regs.h
@@ -19,6 +19,7 @@ struct __base {
/* used to differentiate between generations */
struct mt7996_reg_desc {
const struct __base *base;
+ const u32 *offs_rev;
const struct __map *map;
u32 map_size;
};
@@ -39,6 +40,73 @@ enum base_rev {
#define __BASE(_id, _band) (dev->reg.base[(_id)].band_base[(_band)])
+enum offs_rev {
+ MIB_RVSR0,
+ MIB_RVSR1,
+ MIB_BTSCR5,
+ MIB_BTSCR6,
+ MIB_RSCR1,
+ MIB_RSCR27,
+ MIB_RSCR28,
+ MIB_RSCR29,
+ MIB_RSCR30,
+ MIB_RSCR31,
+ MIB_RSCR33,
+ MIB_RSCR35,
+ MIB_RSCR36,
+ MIB_BSCR0,
+ MIB_BSCR1,
+ MIB_BSCR2,
+ MIB_BSCR3,
+ MIB_BSCR4,
+ MIB_BSCR5,
+ MIB_BSCR6,
+ MIB_BSCR7,
+ MIB_BSCR17,
+ MIB_TRDR1,
+ __MT_OFFS_MAX,
+};
+
+#define __OFFS(id) (dev->reg.offs_rev[(id)])
+
+/* RRO TOP */
+#define MT_RRO_TOP_BASE 0xA000
+#define MT_RRO_TOP(ofs) (MT_RRO_TOP_BASE + (ofs))
+
+#define MT_RRO_BA_BITMAP_BASE0 MT_RRO_TOP(0x8)
+#define MT_RRO_BA_BITMAP_BASE1 MT_RRO_TOP(0xC)
+#define WF_RRO_AXI_MST_CFG MT_RRO_TOP(0xB8)
+#define WF_RRO_AXI_MST_CFG_DIDX_OK BIT(12)
+#define MT_RRO_ADDR_ARRAY_BASE1 MT_RRO_TOP(0x34)
+#define MT_RRO_ADDR_ARRAY_ELEM_ADDR_SEG_MODE BIT(31)
+
+#define MT_RRO_IND_CMD_SIGNATURE_BASE0 MT_RRO_TOP(0x38)
+#define MT_RRO_IND_CMD_SIGNATURE_BASE1 MT_RRO_TOP(0x3C)
+#define MT_RRO_IND_CMD_0_CTRL0 MT_RRO_TOP(0x40)
+#define MT_RRO_IND_CMD_SIGNATURE_BASE1_EN BIT(31)
+
+#define MT_RRO_PARTICULAR_CFG0 MT_RRO_TOP(0x5C)
+#define MT_RRO_PARTICULAR_CFG1 MT_RRO_TOP(0x60)
+#define MT_RRO_PARTICULAR_CONFG_EN BIT(31)
+#define MT_RRO_PARTICULAR_SID GENMASK(30, 16)
+
+#define MT_RRO_BA_BITMAP_BASE_EXT0 MT_RRO_TOP(0x70)
+#define MT_RRO_BA_BITMAP_BASE_EXT1 MT_RRO_TOP(0x74)
+#define MT_RRO_HOST_INT_ENA MT_RRO_TOP(0x204)
+#define MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA BIT(0)
+
+#define MT_RRO_ADDR_ELEM_SEG_ADDR0 MT_RRO_TOP(0x400)
+
+#define MT_RRO_ACK_SN_CTRL MT_RRO_TOP(0x50)
+#define MT_RRO_ACK_SN_CTRL_SN_MASK GENMASK(27, 16)
+#define MT_RRO_ACK_SN_CTRL_SESSION_MASK GENMASK(11, 0)
+
+#define MT_RRO_DBG_RD_CTRL MT_RRO_TOP(0xe0)
+#define MT_RRO_DBG_RD_ADDR GENMASK(15, 0)
+#define MT_RRO_DBG_RD_EXEC BIT(31)
+
+#define MT_RRO_DBG_RDAT_DW(_n) MT_RRO_TOP(0xf0 + (_n) * 0x4)
+
#define MT_MCU_INT_EVENT 0x2108
#define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0)
#define MT_MCU_INT_EVENT_DMA_INIT BIT(1)
@@ -140,32 +208,32 @@ enum base_rev {
#define MT_WF_MIB_BASE(_band) __BASE(WF_MIB_BASE, (_band))
#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
-#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, 0x9cc)
-#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, 0x9d0)
-#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, 0x9d4)
-#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, 0x9d8)
-#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, 0x9dc)
-#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, 0x9e0)
-#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, 0x9e4)
-#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, 0x9e8)
-#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, 0xa10)
+#define MT_MIB_BSCR0(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR0))
+#define MT_MIB_BSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR1))
+#define MT_MIB_BSCR2(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR2))
+#define MT_MIB_BSCR3(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR3))
+#define MT_MIB_BSCR4(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR4))
+#define MT_MIB_BSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR5))
+#define MT_MIB_BSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR6))
+#define MT_MIB_BSCR7(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR7))
+#define MT_MIB_BSCR17(_band) MT_WF_MIB(_band, __OFFS(MIB_BSCR17))
#define MT_MIB_TSCR5(_band) MT_WF_MIB(_band, 0x6c4)
#define MT_MIB_TSCR6(_band) MT_WF_MIB(_band, 0x6c8)
#define MT_MIB_TSCR7(_band) MT_WF_MIB(_band, 0x6d0)
-#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, 0x7ac)
+#define MT_MIB_RSCR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR1))
/* rx mpdu counter, full 32 bits */
-#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, 0x964)
-#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, 0x96c)
+#define MT_MIB_RSCR31(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR31))
+#define MT_MIB_RSCR33(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR33))
#define MT_MIB_SDR6(_band) MT_WF_MIB(_band, 0x020)
#define MT_MIB_SDR6_CHANNEL_IDL_CNT_MASK GENMASK(15, 0)
-#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, 0x720)
+#define MT_MIB_RVSR0(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR0))
-#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, 0x974)
-#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, 0x978)
+#define MT_MIB_RSCR35(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR35))
+#define MT_MIB_RSCR36(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR36))
/* tx ampdu cnt, full 32 bits */
#define MT_MIB_TSCR0(_band) MT_WF_MIB(_band, 0x6b0)
@@ -178,16 +246,16 @@ enum base_rev {
#define MT_MIB_TSCR4(_band) MT_WF_MIB(_band, 0x6c0)
/* rx ampdu count, 32-bit */
-#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, 0x954)
+#define MT_MIB_RSCR27(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR27))
/* rx ampdu bytes count, 32-bit */
-#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, 0x958)
+#define MT_MIB_RSCR28(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR28))
/* rx ampdu valid subframe count */
-#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, 0x95c)
+#define MT_MIB_RSCR29(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR29))
/* rx ampdu valid subframe bytes count, 32bits */
-#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, 0x960)
+#define MT_MIB_RSCR30(_band) MT_WF_MIB(_band, __OFFS(MIB_RSCR30))
/* remaining windows protected stats */
#define MT_MIB_SDR27(_band) MT_WF_MIB(_band, 0x080)
@@ -196,18 +264,18 @@ enum base_rev {
#define MT_MIB_SDR28(_band) MT_WF_MIB(_band, 0x084)
#define MT_MIB_SDR28_TX_RWP_NEED_CNT GENMASK(15, 0)
-#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, 0x724)
+#define MT_MIB_RVSR1(_band) MT_WF_MIB(_band, __OFFS(MIB_RVSR1))
/* rx blockack count, 32 bits */
#define MT_MIB_TSCR1(_band) MT_WF_MIB(_band, 0x6b4)
#define MT_MIB_BTSCR0(_band) MT_WF_MIB(_band, 0x5e0)
-#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, 0x788)
-#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, 0x798)
+#define MT_MIB_BTSCR5(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR5))
+#define MT_MIB_BTSCR6(_band) MT_WF_MIB(_band, __OFFS(MIB_BTSCR6))
#define MT_MIB_BFTFCR(_band) MT_WF_MIB(_band, 0x5d0)
-#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0xa28 + ((n) << 2))
+#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, __OFFS(MIB_TRDR1) + ((n) << 2))
#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x0b0 + ((n) << 2))
#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 4)) & GENMASK(9, 0))
@@ -330,15 +398,22 @@ enum base_rev {
#define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154)
#define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3)
+#define MT_WFDMA0_RX_INT_SEL_RING6 BIT(6)
#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4)
#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
#define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0)
#define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2)
-#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28)
-#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27)
#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21)
+#define MT_WFDMA0_GLO_CFG_EXT_EN BIT(26)
+#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27)
+#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28)
+
+#define MT_WFDMA0_PAUSE_RX_Q_45_TH MT_WFDMA0(0x268)
+#define MT_WFDMA0_PAUSE_RX_Q_67_TH MT_WFDMA0(0x26c)
+#define MT_WFDMA0_PAUSE_RX_Q_89_TH MT_WFDMA0(0x270)
+#define MT_WFDMA0_PAUSE_RX_Q_RRO_TH MT_WFDMA0(0x27c)
#define WF_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0)
#define WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD BIT(18)
@@ -362,10 +437,14 @@ enum base_rev {
#define MT_WFDMA_HOST_CONFIG MT_WFDMA_EXT_CSR(0x30)
#define MT_WFDMA_HOST_CONFIG_PDMA_BAND BIT(0)
+#define MT_WFDMA_HOST_CONFIG_BAND2_PCIE1 BIT(22)
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
+#define MT_WFDMA_AXI_R2A_CTRL MT_WFDMA_EXT_CSR(0x500)
+#define MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK GENMASK(4, 0)
+
#define MT_PCIE_RECOG_ID 0xd7090
#define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0)
#define MT_PCIE_RECOG_ID_SEM BIT(31)
@@ -374,6 +453,9 @@ enum base_rev {
#define MT_WFDMA0_PCIE1_BASE 0xd8000
#define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs))
+#define MT_INT_PCIE1_SOURCE_CSR_EXT MT_WFDMA0_PCIE1(0x118)
+#define MT_INT_PCIE1_MASK_CSR MT_WFDMA0_PCIE1(0x11c)
+
#define MT_WFDMA0_PCIE1_BUSY_ENA MT_WFDMA0_PCIE1(0x13c)
#define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0)
#define MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1)
@@ -394,6 +476,7 @@ enum base_rev {
#define MT_MCUQ_RING_BASE(q) (MT_Q_BASE(q) + 0x300)
#define MT_TXQ_RING_BASE(q) (MT_Q_BASE(__TXQ(q)) + 0x300)
#define MT_RXQ_RING_BASE(q) (MT_Q_BASE(__RXQ(q)) + 0x500)
+#define MT_RXQ_RRO_IND_RING_BASE MT_RRO_TOP(0x40)
#define MT_MCUQ_EXT_CTRL(q) (MT_Q_BASE(q) + 0x600 + \
MT_MCUQ_ID(q) * 0x4)
@@ -409,17 +492,27 @@ enum base_rev {
#define MT_INT1_MASK_CSR MT_WFDMA0_PCIE1(0x204)
#define MT_INT_RX_DONE_BAND0 BIT(12)
-#define MT_INT_RX_DONE_BAND1 BIT(12)
+#define MT_INT_RX_DONE_BAND1 BIT(13) /* for mt7992 */
#define MT_INT_RX_DONE_BAND2 BIT(13)
#define MT_INT_RX_DONE_WM BIT(0)
#define MT_INT_RX_DONE_WA BIT(1)
#define MT_INT_RX_DONE_WA_MAIN BIT(2)
-#define MT_INT_RX_DONE_WA_EXT BIT(2)
+#define MT_INT_RX_DONE_WA_EXT BIT(3) /* for mt7992 */
#define MT_INT_RX_DONE_WA_TRI BIT(3)
#define MT_INT_RX_TXFREE_MAIN BIT(17)
#define MT_INT_RX_TXFREE_TRI BIT(15)
+#define MT_INT_RX_DONE_BAND2_EXT BIT(23)
+#define MT_INT_RX_TXFREE_EXT BIT(26)
#define MT_INT_MCU_CMD BIT(29)
+#define MT_INT_RX_DONE_RRO_BAND0 BIT(16)
+#define MT_INT_RX_DONE_RRO_BAND1 BIT(16)
+#define MT_INT_RX_DONE_RRO_BAND2 BIT(14)
+#define MT_INT_RX_DONE_RRO_IND BIT(11)
+#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18)
+#define MT_INT_RX_DONE_MSDU_PG_BAND1 BIT(19)
+#define MT_INT_RX_DONE_MSDU_PG_BAND2 BIT(23)
+
#define MT_INT_RX(q) (dev->q_int_mask[__RXQ(q)])
#define MT_INT_TX_MCU(q) (dev->q_int_mask[(q)])
@@ -427,20 +520,31 @@ enum base_rev {
MT_INT_RX(MT_RXQ_MCU_WA))
#define MT_INT_BAND0_RX_DONE (MT_INT_RX(MT_RXQ_MAIN) | \
- MT_INT_RX(MT_RXQ_MAIN_WA))
+ MT_INT_RX(MT_RXQ_MAIN_WA) | \
+ MT_INT_RX(MT_RXQ_TXFREE_BAND0))
#define MT_INT_BAND1_RX_DONE (MT_INT_RX(MT_RXQ_BAND1) | \
MT_INT_RX(MT_RXQ_BAND1_WA) | \
- MT_INT_RX(MT_RXQ_MAIN_WA))
+ MT_INT_RX(MT_RXQ_MAIN_WA) | \
+ MT_INT_RX(MT_RXQ_TXFREE_BAND0))
#define MT_INT_BAND2_RX_DONE (MT_INT_RX(MT_RXQ_BAND2) | \
MT_INT_RX(MT_RXQ_BAND2_WA) | \
- MT_INT_RX(MT_RXQ_MAIN_WA))
+ MT_INT_RX(MT_RXQ_MAIN_WA) | \
+ MT_INT_RX(MT_RXQ_TXFREE_BAND0))
+
+#define MT_INT_RRO_RX_DONE (MT_INT_RX(MT_RXQ_RRO_BAND0) | \
+ MT_INT_RX(MT_RXQ_RRO_BAND1) | \
+ MT_INT_RX(MT_RXQ_RRO_BAND2) | \
+ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND0) | \
+ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND1) | \
+ MT_INT_RX(MT_RXQ_MSDU_PAGE_BAND2))
#define MT_INT_RX_DONE_ALL (MT_INT_RX_DONE_MCU | \
MT_INT_BAND0_RX_DONE | \
MT_INT_BAND1_RX_DONE | \
- MT_INT_BAND2_RX_DONE)
+ MT_INT_BAND2_RX_DONE | \
+ MT_INT_RRO_RX_DONE)
#define MT_INT_TX_DONE_FWDL BIT(26)
#define MT_INT_TX_DONE_MCU_WM BIT(27)
@@ -449,6 +553,10 @@ enum base_rev {
#define MT_INT_TX_DONE_BAND1 BIT(31)
#define MT_INT_TX_DONE_BAND2 BIT(15)
+#define MT_INT_TX_RX_DONE_EXT (MT_INT_TX_DONE_BAND2 | \
+ MT_INT_RX_DONE_BAND2_EXT | \
+ MT_INT_RX_TXFREE_EXT)
+
#define MT_INT_TX_DONE_MCU (MT_INT_TX_MCU(MT_MCUQ_WA) | \
MT_INT_TX_MCU(MT_MCUQ_WM) | \
MT_INT_TX_MCU(MT_MCUQ_FWDL))
@@ -552,7 +660,12 @@ enum base_rev {
#define MT_TOP_MISC MT_TOP(0xf0)
#define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
+#define MT_PAD_GPIO 0x700056f0
+#define MT_PAD_GPIO_ADIE_COMB GENMASK(16, 15)
+
#define MT_HW_REV 0x70010204
+#define MT_HW_REV1 0x8a00
+
#define MT_WF_SUBSYS_RST 0x70028600
/* PCIE MAC */
@@ -601,4 +714,11 @@ enum base_rev {
#define MT_MCU_WM_EXCP_LR_CTRL MT_MCU_WM_EXCP(0x200)
#define MT_MCU_WM_EXCP_LR_LOG MT_MCU_WM_EXCP(0x204)
+/* CONN AFE CTL CON */
+#define MT_AFE_CTL_BASE 0x18043000
+#define MT_AFE_CTL_BAND(_band, ofs) (MT_AFE_CTL_BASE + \
+ ((_band) * 0x1000) + (ofs))
+#define MT_AFE_CTL_BAND_PLL_03(_band) MT_AFE_CTL_BAND(_band, 0x2c)
+#define MT_AFE_CTL_BAND_PLL_03_MSB_EN BIT(1)
+
#endif