mt76: add mac80211 driver for MT7915 PCIe-based chipsets

Add support for the MediaTek latest generation IEEE 802.11ax 4x4
device MT7915E, which supports concurrent dual-band operation at
both 5GHz and 2.4GHz.

Note that this patch just add basic part and will add more HE
capabilities support in the further patches.

The driver supports AP, Station, Mesh and monitor mode.

Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
Signed-off-by: Chih-Min Chen <chih-min.chen@mediatek.com>
Suggested-by: Shihwei Lin <shihwei.lin@mediatek.com>
Tested-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
Acked-by: Yiwei Chung <yiwei.chung@mediatek.com>
Acked-by: YF Luo <yf.luo@mediatek.com>
Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Ryder Lee 2020-04-25 03:32:27 +08:00 committed by Felix Fietkau
parent d3377b78ce
commit e57b790146
17 changed files with 7616 additions and 0 deletions

View file

@ -24,3 +24,4 @@ source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7603/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7615/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt7915/Kconfig"

View file

@ -27,3 +27,4 @@ obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
obj-$(CONFIG_MT7603E) += mt7603/
obj-$(CONFIG_MT7615_COMMON) += mt7615/
obj-$(CONFIG_MT7915E) += mt7915/

View file

@ -0,0 +1,13 @@
# SPDX-License-Identifier: ISC
config MT7915E
tristate "MediaTek MT7915E (PCIe) support"
select MT76_CORE
depends on MAC80211
depends on PCI
help
This adds support for MT7915-based wireless PCIe devices,
which support concurrent dual-band operation at both 5GHz
and 2.4GHz IEEE 802.11ax 4x4:4SS 1024-QAM, 160MHz channels,
OFDMA, spatial reuse and dual carrier modulation.
To compile this driver as a module, choose M here.

View file

@ -0,0 +1,6 @@
#SPDX-License-Identifier: ISC
obj-$(CONFIG_MT7915E) += mt7915e.o
mt7915e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
debugfs.o

View file

@ -0,0 +1,245 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#include "mt7915.h"
#include "eeprom.h"
/** global debugfs **/
/* test knob of system layer 1/2 error recovery */
static int mt7915_ser_trigger_set(void *data, u64 val)
{
enum {
SER_SET_RECOVER_L1 = 1,
SER_SET_RECOVER_L2,
SER_ENABLE = 2,
SER_RECOVER
};
struct mt7915_dev *dev = data;
int ret = 0;
switch (val) {
case SER_SET_RECOVER_L1:
case SER_SET_RECOVER_L2:
/* fall through */
ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0);
if (ret)
return ret;
return mt7915_mcu_set_ser(dev, SER_RECOVER, val, 0);
default:
break;
}
return ret;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL,
mt7915_ser_trigger_set, "%lld\n");
static int
mt7915_radar_trigger(void *data, u64 val)
{
struct mt7915_dev *dev = data;
return mt7915_mcu_rdd_cmd(dev, RDD_RADAR_EMULATE, 1, 0, 0);
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_trigger, NULL,
mt7915_radar_trigger, "%lld\n");
static int
mt7915_dbdc_set(void *data, u64 val)
{
struct mt7915_dev *dev = data;
if (val)
mt7915_register_ext_phy(dev);
else
mt7915_unregister_ext_phy(dev);
return 0;
}
static int
mt7915_dbdc_get(void *data, u64 *val)
{
struct mt7915_dev *dev = data;
*val = !!mt7915_ext_phy(dev);
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_dbdc, mt7915_dbdc_get,
mt7915_dbdc_set, "%lld\n");
static void
mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
struct seq_file *file)
{
struct mt7915_dev *dev = file->private;
bool ext_phy = phy != &dev->phy;
int bound[15], range[4], i, n;
if (!phy)
return;
/* Tx ampdu stat */
for (i = 0; i < ARRAY_SIZE(range); i++)
range[i] = mt76_rr(dev, MT_MIB_ARNG(ext_phy, i));
for (i = 0; i < ARRAY_SIZE(bound); i++)
bound[i] = MT_MIB_ARNCR_RANGE(range[i / 4], i) + 1;
seq_printf(file, "\nPhy %d\n", ext_phy);
seq_printf(file, "Length: %8d | ", bound[0]);
for (i = 0; i < ARRAY_SIZE(bound) - 1; i++)
seq_printf(file, "%3d -%3d | ",
bound[i] + 1, bound[i + 1]);
seq_puts(file, "\nCount: ");
n = ext_phy ? ARRAY_SIZE(dev->mt76.aggr_stats) / 2 : 0;
for (i = 0; i < ARRAY_SIZE(bound); i++)
seq_printf(file, "%8d | ", dev->mt76.aggr_stats[i + n]);
seq_puts(file, "\n");
seq_printf(file, "BA miss count: %d\n", phy->mib.ba_miss_cnt);
}
static int
mt7915_tx_stats_read(struct seq_file *file, void *data)
{
struct mt7915_dev *dev = file->private;
int stat[8], i, n;
mt7915_ampdu_stat_read_phy(&dev->phy, file);
mt7915_ampdu_stat_read_phy(mt7915_ext_phy(dev), file);
/* Tx amsdu info */
seq_puts(file, "Tx MSDU stat:\n");
for (i = 0, n = 0; i < ARRAY_SIZE(stat); i++) {
stat[i] = mt76_rr(dev, MT_PLE_AMSDU_PACK_MSDU_CNT(i));
n += stat[i];
}
for (i = 0; i < ARRAY_SIZE(stat); i++) {
seq_printf(file, "AMSDU pack count of %d MSDU in TXD: 0x%x ",
i + 1, stat[i]);
if (n != 0)
seq_printf(file, "(%d%%)\n", stat[i] * 100 / n);
else
seq_puts(file, "\n");
}
return 0;
}
static int
mt7915_tx_stats_open(struct inode *inode, struct file *f)
{
return single_open(f, mt7915_tx_stats_read, inode->i_private);
}
static const struct file_operations fops_tx_stats = {
.open = mt7915_tx_stats_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int mt7915_read_temperature(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
int temp;
/* cpu */
temp = mt7915_mcu_get_temperature(dev, 0);
seq_printf(s, "Temperature: %d\n", temp);
return 0;
}
static int
mt7915_queues_acq(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
int i;
for (i = 0; i < 16; i++) {
int j, acs = i / 4, index = i % 4;
u32 ctrl, val, qlen = 0;
val = mt76_rr(dev, MT_PLE_AC_QEMPTY(acs, index));
ctrl = BIT(31) | BIT(15) | (acs << 8);
for (j = 0; j < 32; j++) {
if (val & BIT(j))
continue;
mt76_wr(dev, MT_PLE_FL_Q0_CTRL,
ctrl | (j + (index << 5)));
qlen += mt76_get_field(dev, MT_PLE_FL_Q3_CTRL,
GENMASK(11, 0));
}
seq_printf(s, "AC%d%d: queued=%d\n", acs, index, qlen);
}
return 0;
}
static int
mt7915_queues_read(struct seq_file *s, void *data)
{
struct mt7915_dev *dev = dev_get_drvdata(s->private);
static const struct {
char *queue;
int id;
} queue_map[] = {
{ "WFDMA0", MT_TXQ_BE },
{ "MCUWM", MT_TXQ_MCU },
{ "MCUWA", MT_TXQ_MCU_WA },
{ "MCUFWQ", MT_TXQ_FWDL },
};
int i;
for (i = 0; i < ARRAY_SIZE(queue_map); i++) {
struct mt76_sw_queue *q = &dev->mt76.q_tx[queue_map[i].id];
if (!q->q)
continue;
seq_printf(s,
"%s: queued=%d head=%d tail=%d\n",
queue_map[i].queue, q->q->queued, q->q->head,
q->q->tail);
}
return 0;
}
int mt7915_init_debugfs(struct mt7915_dev *dev)
{
struct dentry *dir;
dir = mt76_register_debugfs(&dev->mt76);
if (!dir)
return -ENOMEM;
debugfs_create_devm_seqfile(dev->mt76.dev, "queues", dir,
mt7915_queues_read);
debugfs_create_devm_seqfile(dev->mt76.dev, "acq", dir,
mt7915_queues_acq);
debugfs_create_file("tx_stats", 0400, dir, dev, &fops_tx_stats);
debugfs_create_file("dbdc", 0600, dir, dev, &fops_dbdc);
debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern);
/* test knobs */
debugfs_create_file("radar_trigger", 0200, dir, dev,
&fops_radar_trigger);
debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger);
debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
mt7915_read_temperature);
return 0;
}

View file

@ -0,0 +1,285 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#include "mt7915.h"
#include "../dma.h"
#include "mac.h"
static int
mt7915_init_tx_queues(struct mt7915_dev *dev, int n_desc)
{
struct mt76_sw_queue *q;
struct mt76_queue *hwq;
int err, i;
hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
if (!hwq)
return -ENOMEM;
err = mt76_queue_alloc(dev, hwq, MT7915_TXQ_BAND0, n_desc, 0,
MT_TX_RING_BASE);
if (err < 0)
return err;
for (i = 0; i < MT_TXQ_MCU; i++) {
q = &dev->mt76.q_tx[i];
INIT_LIST_HEAD(&q->swq);
q->q = hwq;
}
return 0;
}
static int
mt7915_init_mcu_queue(struct mt7915_dev *dev, struct mt76_sw_queue *q,
int idx, int n_desc)
{
struct mt76_queue *hwq;
int err;
hwq = devm_kzalloc(dev->mt76.dev, sizeof(*hwq), GFP_KERNEL);
if (!hwq)
return -ENOMEM;
err = mt76_queue_alloc(dev, hwq, idx, n_desc, 0, MT_TX_RING_BASE);
if (err < 0)
return err;
INIT_LIST_HEAD(&q->swq);
q->q = hwq;
return 0;
}
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb)
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
__le32 *rxd = (__le32 *)skb->data;
enum rx_pkt_type type;
type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
switch (type) {
case PKT_TYPE_TXRX_NOTIFY:
mt7915_mac_tx_free(dev, skb);
break;
case PKT_TYPE_RX_EVENT:
mt7915_mcu_rx_event(dev, skb);
break;
case PKT_TYPE_NORMAL:
if (!mt7915_mac_fill_rx(dev, skb)) {
mt76_rx(&dev->mt76, q, skb);
return;
}
/* fall through */
default:
dev_kfree_skb(skb);
break;
}
}
static int mt7915_poll_tx(struct napi_struct *napi, int budget)
{
static const u8 queue_map[] = {
MT_TXQ_MCU,
MT_TXQ_MCU_WA,
MT_TXQ_BE
};
struct mt7915_dev *dev;
int i;
dev = container_of(napi, struct mt7915_dev, mt76.tx_napi);
for (i = 0; i < ARRAY_SIZE(queue_map); i++)
mt76_queue_tx_cleanup(dev, queue_map[i], false);
if (napi_complete_done(napi, 0))
mt7915_irq_enable(dev, MT_INT_TX_DONE_ALL);
for (i = 0; i < ARRAY_SIZE(queue_map); i++)
mt76_queue_tx_cleanup(dev, queue_map[i], false);
mt7915_mac_sta_poll(dev);
tasklet_schedule(&dev->mt76.tx_tasklet);
return 0;
}
void mt7915_dma_prefetch(struct mt7915_dev *dev)
{
#define PREFETCH(base, depth) ((base) << 16 | (depth))
mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0, 0x4));
mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x40, 0x4));
mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x80, 0x0));
mt76_wr(dev, MT_WFDMA1_TX_RING0_EXT_CTRL, PREFETCH(0x80, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING1_EXT_CTRL, PREFETCH(0xc0, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING2_EXT_CTRL, PREFETCH(0x100, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING3_EXT_CTRL, PREFETCH(0x140, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING4_EXT_CTRL, PREFETCH(0x180, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING5_EXT_CTRL, PREFETCH(0x1c0, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING6_EXT_CTRL, PREFETCH(0x200, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING7_EXT_CTRL, PREFETCH(0x240, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING16_EXT_CTRL, PREFETCH(0x280, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING17_EXT_CTRL, PREFETCH(0x2c0, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING18_EXT_CTRL, PREFETCH(0x300, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING19_EXT_CTRL, PREFETCH(0x340, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING20_EXT_CTRL, PREFETCH(0x380, 0x4));
mt76_wr(dev, MT_WFDMA1_TX_RING21_EXT_CTRL, PREFETCH(0x3c0, 0x0));
mt76_wr(dev, MT_WFDMA1_RX_RING0_EXT_CTRL, PREFETCH(0x3c0, 0x4));
mt76_wr(dev, MT_WFDMA1_RX_RING1_EXT_CTRL, PREFETCH(0x400, 0x4));
mt76_wr(dev, MT_WFDMA1_RX_RING2_EXT_CTRL, PREFETCH(0x440, 0x4));
mt76_wr(dev, MT_WFDMA1_RX_RING3_EXT_CTRL, PREFETCH(0x480, 0x0));
}
int mt7915_dma_init(struct mt7915_dev *dev)
{
/* Increase buffer size to receive large VHT/HE MPDUs */
int rx_buf_size = MT_RX_BUF_SIZE * 2;
int ret;
mt76_dma_attach(&dev->mt76);
/* configure global setting */
mt76_set(dev, MT_WFDMA1_GLO_CFG,
MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
/* configure perfetch settings */
mt7915_dma_prefetch(dev);
/* reset dma idx */
mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
mt76_wr(dev, MT_WFDMA1_RST_DTX_PTR, ~0);
/* configure delay interrupt */
mt76_wr(dev, MT_WFDMA0_PRI_DLY_INT_CFG0, 0);
mt76_wr(dev, MT_WFDMA1_PRI_DLY_INT_CFG0, 0);
/* init tx queue */
ret = mt7915_init_tx_queues(dev, MT7915_TX_RING_SIZE);
if (ret)
return ret;
/* command to WM */
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU],
MT7915_TXQ_MCU_WM,
MT7915_TX_MCU_RING_SIZE);
if (ret)
return ret;
/* command to WA */
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_MCU_WA],
MT7915_TXQ_MCU_WA,
MT7915_TX_MCU_RING_SIZE);
if (ret)
return ret;
/* firmware download */
ret = mt7915_init_mcu_queue(dev, &dev->mt76.q_tx[MT_TXQ_FWDL],
MT7915_TXQ_FWDL,
MT7915_TX_FWDL_RING_SIZE);
if (ret)
return ret;
/* event from WM */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
MT7915_RXQ_MCU_WM, MT7915_RX_MCU_RING_SIZE,
rx_buf_size, MT_RX_EVENT_RING_BASE);
if (ret)
return ret;
/* event from WA */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
MT7915_RXQ_MCU_WA, MT7915_RX_MCU_RING_SIZE,
rx_buf_size, MT_RX_EVENT_RING_BASE);
if (ret)
return ret;
/* rx data */
ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN], 0,
MT7915_RX_RING_SIZE, rx_buf_size,
MT_RX_DATA_RING_BASE);
if (ret)
return ret;
ret = mt76_init_queues(dev);
if (ret < 0)
return ret;
netif_tx_napi_add(&dev->mt76.napi_dev, &dev->mt76.tx_napi,
mt7915_poll_tx, NAPI_POLL_WEIGHT);
napi_enable(&dev->mt76.tx_napi);
/* hif wait WFDMA idle */
mt76_set(dev, MT_WFDMA0_BUSY_ENA,
MT_WFDMA0_BUSY_ENA_TX_FIFO0 |
MT_WFDMA0_BUSY_ENA_TX_FIFO1 |
MT_WFDMA0_BUSY_ENA_RX_FIFO);
mt76_set(dev, MT_WFDMA1_BUSY_ENA,
MT_WFDMA1_BUSY_ENA_TX_FIFO0 |
MT_WFDMA1_BUSY_ENA_TX_FIFO1 |
MT_WFDMA1_BUSY_ENA_RX_FIFO);
mt76_set(dev, MT_WFDMA0_PCIE1_BUSY_ENA,
MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO0 |
MT_WFDMA0_PCIE1_BUSY_ENA_TX_FIFO1 |
MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO);
mt76_set(dev, MT_WFDMA1_PCIE1_BUSY_ENA,
MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO0 |
MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 |
MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO);
mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC,
MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000);
/* set WFDMA Tx/Rx */
mt76_set(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
mt76_set(dev, MT_WFDMA1_GLO_CFG,
MT_WFDMA1_GLO_CFG_TX_DMA_EN | MT_WFDMA1_GLO_CFG_RX_DMA_EN);
/* enable interrupts for TX/RX rings */
mt7915_irq_enable(dev, MT_INT_RX_DONE_ALL | MT_INT_TX_DONE_ALL |
MT_INT_MCU_CMD);
return 0;
}
void mt7915_dma_cleanup(struct mt7915_dev *dev)
{
/* disable */
mt76_clear(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN |
MT_WFDMA0_GLO_CFG_RX_DMA_EN);
mt76_clear(dev, MT_WFDMA1_GLO_CFG,
MT_WFDMA1_GLO_CFG_TX_DMA_EN |
MT_WFDMA1_GLO_CFG_RX_DMA_EN);
/* reset */
mt76_clear(dev, MT_WFDMA1_RST,
MT_WFDMA1_RST_DMASHDL_ALL_RST |
MT_WFDMA1_RST_LOGIC_RST);
mt76_set(dev, MT_WFDMA1_RST,
MT_WFDMA1_RST_DMASHDL_ALL_RST |
MT_WFDMA1_RST_LOGIC_RST);
mt76_clear(dev, MT_WFDMA0_RST,
MT_WFDMA0_RST_DMASHDL_ALL_RST |
MT_WFDMA0_RST_LOGIC_RST);
mt76_set(dev, MT_WFDMA0_RST,
MT_WFDMA0_RST_DMASHDL_ALL_RST |
MT_WFDMA0_RST_LOGIC_RST);
tasklet_kill(&dev->mt76.tx_tasklet);
mt76_dma_cleanup(&dev->mt76);
}

View file

@ -0,0 +1,125 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#include "mt7915.h"
#include "eeprom.h"
static inline bool mt7915_efuse_valid(u8 val)
{
return !(val == 0xff);
}
u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset)
{
u8 *data = dev->mt76.eeprom.data;
if (!mt7915_efuse_valid(data[offset]))
mt7915_mcu_get_eeprom(dev, offset);
return data[offset];
}
static int mt7915_eeprom_load(struct mt7915_dev *dev)
{
int ret;
ret = mt76_eeprom_init(&dev->mt76, MT7915_EEPROM_SIZE);
if (ret < 0)
return ret;
memset(dev->mt76.eeprom.data, -1, MT7915_EEPROM_SIZE);
return 0;
}
static int mt7915_check_eeprom(struct mt7915_dev *dev)
{
u16 val;
u8 *eeprom = dev->mt76.eeprom.data;
mt7915_eeprom_read(dev, 0);
val = get_unaligned_le16(eeprom);
switch (val) {
case 0x7915:
return 0;
default:
return -EINVAL;
}
}
static void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev)
{
u8 *eeprom = dev->mt76.eeprom.data;
u8 tx_mask, max_nss = 4;
u32 val = mt7915_eeprom_read(dev, MT_EE_WIFI_CONF);
val = FIELD_GET(MT_EE_WIFI_CONF_BAND_SEL, val);
switch (val) {
case MT_EE_5GHZ:
dev->mt76.cap.has_5ghz = true;
break;
case MT_EE_2GHZ:
dev->mt76.cap.has_2ghz = true;
break;
default:
dev->mt76.cap.has_2ghz = true;
dev->mt76.cap.has_5ghz = true;
break;
}
/* read tx mask from eeprom */
tx_mask = FIELD_GET(MT_EE_WIFI_CONF_TX_MASK,
eeprom[MT_EE_WIFI_CONF]);
if (!tx_mask || tx_mask > max_nss)
tx_mask = max_nss;
dev->chainmask = BIT(tx_mask) - 1;
dev->mphy.antenna_mask = dev->chainmask;
dev->phy.chainmask = dev->chainmask;
}
int mt7915_eeprom_init(struct mt7915_dev *dev)
{
int ret;
ret = mt7915_eeprom_load(dev);
if (ret < 0)
return ret;
ret = mt7915_check_eeprom(dev);
if (ret)
return ret;
mt7915_eeprom_parse_hw_cap(dev);
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
ETH_ALEN);
mt76_eeprom_override(&dev->mt76);
return 0;
}
int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
struct ieee80211_channel *chan,
u8 chain_idx)
{
int index;
bool tssi_on;
if (chain_idx > 3)
return -EINVAL;
tssi_on = mt7915_tssi_enabled(dev, chan->band);
if (chan->band == NL80211_BAND_2GHZ) {
index = MT_EE_TX0_POWER_2G + chain_idx * 3 + !tssi_on;
} else {
int group = tssi_on ?
mt7915_get_channel_group(chan->hw_value) : 8;
index = MT_EE_TX0_POWER_5G + chain_idx * 12 + group;
}
return mt7915_eeprom_read(dev, index);
}

View file

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7915_EEPROM_H
#define __MT7915_EEPROM_H
#include "mt7915.h"
struct cal_data {
u8 count;
u16 offset[60];
};
enum mt7915_eeprom_field {
MT_EE_CHIP_ID = 0x000,
MT_EE_VERSION = 0x002,
MT_EE_MAC_ADDR = 0x004,
MT_EE_DDIE_FT_VERSION = 0x050,
MT_EE_WIFI_CONF = 0x190,
MT_EE_TX0_POWER_2G = 0x2fc,
MT_EE_TX0_POWER_5G = 0x34b,
MT_EE_ADIE_FT_VERSION = 0x9a0,
__MT_EE_MAX = 0xe00
};
#define MT_EE_WIFI_CONF_TX_MASK GENMASK(2, 0)
#define MT_EE_WIFI_CONF_BAND_SEL GENMASK(7, 6)
#define MT_EE_WIFI_CONF_TSSI0_2G BIT(0)
#define MT_EE_WIFI_CONF_TSSI0_5G BIT(2)
#define MT_EE_WIFI_CONF_TSSI1_5G BIT(4)
enum mt7915_eeprom_band {
MT_EE_DUAL_BAND,
MT_EE_5GHZ,
MT_EE_2GHZ,
MT_EE_DBDC,
};
struct sku_group {
u8 len;
u16 offset[2];
const u8 *delta_map;
};
static inline int
mt7915_get_channel_group(int channel)
{
if (channel >= 184 && channel <= 196)
return 0;
if (channel <= 48)
return 1;
if (channel <= 64)
return 2;
if (channel <= 96)
return 3;
if (channel <= 112)
return 4;
if (channel <= 128)
return 5;
if (channel <= 144)
return 6;
return 7;
}
static inline bool
mt7915_tssi_enabled(struct mt7915_dev *dev, enum nl80211_band band)
{
u8 *eep = dev->mt76.eeprom.data;
/* TODO: DBDC */
if (band == NL80211_BAND_5GHZ)
return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_5G;
else
return eep[MT_EE_WIFI_CONF + 7] & MT_EE_WIFI_CONF_TSSI0_2G;
}
#endif

View file

@ -0,0 +1,395 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#include <linux/etherdevice.h>
#include "mt7915.h"
#include "mac.h"
#include "eeprom.h"
static void
mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
{
u32 mask, set;
mt76_rmw_field(dev, MT_TMAC_CTCR0(band),
MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
mt76_set(dev, MT_TMAC_CTCR0(band),
MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN |
MT_TMAC_CTCR0_INS_DDLMT_EN);
mask = MT_MDP_RCFR0_MCU_RX_MGMT |
MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR |
MT_MDP_RCFR0_MCU_RX_CTL_BAR;
set = FIELD_PREP(MT_MDP_RCFR0_MCU_RX_MGMT, MT_MDP_TO_HIF) |
FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR, MT_MDP_TO_HIF) |
FIELD_PREP(MT_MDP_RCFR0_MCU_RX_CTL_BAR, MT_MDP_TO_HIF);
mt76_rmw(dev, MT_MDP_BNRCFR0(band), mask, set);
mask = MT_MDP_RCFR1_MCU_RX_BYPASS |
MT_MDP_RCFR1_RX_DROPPED_UCAST |
MT_MDP_RCFR1_RX_DROPPED_MCAST;
set = FIELD_PREP(MT_MDP_RCFR1_MCU_RX_BYPASS, MT_MDP_TO_HIF) |
FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_UCAST, MT_MDP_TO_HIF) |
FIELD_PREP(MT_MDP_RCFR1_RX_DROPPED_MCAST, MT_MDP_TO_HIF);
mt76_rmw(dev, MT_MDP_BNRCFR1(band), mask, set);
mt76_set(dev, MT_WF_RMAC_MIB_TIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0(band), MT_WF_RMAC_MIB_RXTIME_EN);
}
static void mt7915_mac_init(struct mt7915_dev *dev)
{
int i;
mt76_rmw_field(dev, MT_DMA_DCR0, MT_DMA_DCR0_MAX_RX_LEN, 1536);
mt76_rmw_field(dev, MT_MDP_DCR1, MT_MDP_DCR1_MAX_RX_LEN, 1536);
/* disable hardware de-agg */
mt76_clear(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
for (i = 0; i < MT7915_WTBL_SIZE; i++)
mt7915_mac_wtbl_update(dev, i,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
mt7915_mac_init_band(dev, 0);
mt7915_mac_init_band(dev, 1);
mt7915_mcu_set_rts_thresh(&dev->phy, 0x92b);
}
static void
mt7915_init_txpower_band(struct mt7915_dev *dev,
struct ieee80211_supported_band *sband)
{
int i, n_chains = hweight8(dev->mphy.antenna_mask);
for (i = 0; i < sband->n_channels; i++) {
struct ieee80211_channel *chan = &sband->channels[i];
u32 target_power = 0;
int j;
for (j = 0; j < n_chains; j++) {
u32 val;
val = mt7915_eeprom_get_target_power(dev, chan, j);
target_power = max(target_power, val);
}
chan->max_power = min_t(int, chan->max_reg_power,
target_power / 2);
chan->orig_mpwr = target_power / 2;
}
}
static void mt7915_init_txpower(struct mt7915_dev *dev)
{
mt7915_init_txpower_band(dev, &dev->mphy.sband_2g.sband);
mt7915_init_txpower_band(dev, &dev->mphy.sband_5g.sband);
}
static void mt7915_init_work(struct work_struct *work)
{
struct mt7915_dev *dev = container_of(work, struct mt7915_dev,
init_work);
mt7915_mcu_set_eeprom(dev);
mt7915_mac_init(dev);
mt7915_init_txpower(dev);
}
static int mt7915_init_hardware(struct mt7915_dev *dev)
{
int ret, idx;
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
INIT_WORK(&dev->init_work, mt7915_init_work);
spin_lock_init(&dev->token_lock);
idr_init(&dev->token);
ret = mt7915_dma_init(dev);
if (ret)
return ret;
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
ret = mt7915_mcu_init(dev);
if (ret)
return ret;
ret = mt7915_eeprom_init(dev);
if (ret < 0)
return ret;
/* Beacon and mgmt frames should occupy wcid 0 */
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1);
if (idx)
return -ENOSPC;
dev->mt76.global_wcid.idx = idx;
dev->mt76.global_wcid.hw_key_idx = -1;
dev->mt76.global_wcid.tx_info |= MT_WCID_TX_INFO_SET;
rcu_assign_pointer(dev->mt76.wcid[idx], &dev->mt76.global_wcid);
return 0;
}
#define CCK_RATE(_idx, _rate) { \
.bitrate = _rate, \
.flags = IEEE80211_RATE_SHORT_PREAMBLE, \
.hw_value = (MT_PHY_TYPE_CCK << 8) | (_idx), \
.hw_value_short = (MT_PHY_TYPE_CCK << 8) | (4 + (_idx)), \
}
#define OFDM_RATE(_idx, _rate) { \
.bitrate = _rate, \
.hw_value = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
.hw_value_short = (MT_PHY_TYPE_OFDM << 8) | (_idx), \
}
static struct ieee80211_rate mt7915_rates[] = {
CCK_RATE(0, 10),
CCK_RATE(1, 20),
CCK_RATE(2, 55),
CCK_RATE(3, 110),
OFDM_RATE(11, 60),
OFDM_RATE(15, 90),
OFDM_RATE(10, 120),
OFDM_RATE(14, 180),
OFDM_RATE(9, 240),
OFDM_RATE(13, 360),
OFDM_RATE(8, 480),
OFDM_RATE(12, 540),
};
static const struct ieee80211_iface_limit if_limits[] = {
{
.max = 1,
.types = BIT(NL80211_IFTYPE_ADHOC)
}, {
.max = MT7915_MAX_INTERFACES,
.types = BIT(NL80211_IFTYPE_AP) |
#ifdef CONFIG_MAC80211_MESH
BIT(NL80211_IFTYPE_MESH_POINT) |
#endif
BIT(NL80211_IFTYPE_STATION)
}
};
static const struct ieee80211_iface_combination if_comb[] = {
{
.limits = if_limits,
.n_limits = ARRAY_SIZE(if_limits),
.max_interfaces = 4,
.num_different_channels = 1,
.beacon_int_infra_match = true,
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
BIT(NL80211_CHAN_WIDTH_20) |
BIT(NL80211_CHAN_WIDTH_40) |
BIT(NL80211_CHAN_WIDTH_80) |
BIT(NL80211_CHAN_WIDTH_160) |
BIT(NL80211_CHAN_WIDTH_80P80),
}
};
static void
mt7915_regd_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt76_phy *mphy = hw->priv;
struct mt7915_phy *phy = mphy->priv;
struct cfg80211_chan_def *chandef = &mphy->chandef;
dev->mt76.region = request->dfs_region;
if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
return;
mt7915_dfs_init_radar_detector(phy);
}
static void
mt7915_init_wiphy(struct ieee80211_hw *hw)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct wiphy *wiphy = hw->wiphy;
hw->queues = 4;
hw->max_rx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
hw->max_tx_aggregation_subframes = IEEE80211_MAX_AMPDU_BUF;
phy->slottime = 9;
hw->sta_data_size = sizeof(struct mt7915_sta);
hw->vif_data_size = sizeof(struct mt7915_vif);
wiphy->iface_combinations = if_comb;
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
wiphy->reg_notifier = mt7915_regd_notifier;
wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
ieee80211_hw_set(hw, HAS_RATE_CONTROL);
hw->max_tx_fragments = 4;
}
static void
mt7915_cap_dbdc_enable(struct mt7915_dev *dev)
{
dev->mphy.sband_5g.sband.vht_cap.cap &=
~(IEEE80211_VHT_CAP_SHORT_GI_160 |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ);
if (dev->chainmask == 0xf)
dev->mphy.antenna_mask = dev->chainmask >> 2;
else
dev->mphy.antenna_mask = dev->chainmask >> 1;
dev->phy.chainmask = dev->mphy.antenna_mask;
dev->mphy.hw->wiphy->available_antennas_rx = dev->phy.chainmask;
dev->mphy.hw->wiphy->available_antennas_tx = dev->phy.chainmask;
mt76_set_stream_caps(&dev->mt76, true);
}
static void
mt7915_cap_dbdc_disable(struct mt7915_dev *dev)
{
dev->mphy.sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_SHORT_GI_160 |
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
dev->mphy.antenna_mask = dev->chainmask;
dev->phy.chainmask = dev->chainmask;
dev->mphy.hw->wiphy->available_antennas_rx = dev->chainmask;
dev->mphy.hw->wiphy->available_antennas_tx = dev->chainmask;
mt76_set_stream_caps(&dev->mt76, true);
}
int mt7915_register_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
struct mt76_phy *mphy;
int ret;
bool bound;
/* TODO: enble DBDC */
bound = mt7915_l1_rr(dev, MT_HW_BOUND) & BIT(5);
if (!bound)
return -EINVAL;
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
return -EINVAL;
if (phy)
return 0;
mt7915_cap_dbdc_enable(dev);
mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7915_ops);
if (!mphy)
return -ENOMEM;
phy = mphy->priv;
phy->dev = dev;
phy->mt76 = mphy;
phy->chainmask = dev->chainmask & ~dev->phy.chainmask;
mphy->antenna_mask = BIT(hweight8(phy->chainmask)) - 1;
mt7915_init_wiphy(mphy->hw);
/*
* Make the secondary PHY MAC address local without overlapping with
* the usual MAC address allocation scheme on multiple virtual interfaces
*/
mphy->hw->wiphy->perm_addr[0] |= 2;
mphy->hw->wiphy->perm_addr[0] ^= BIT(7);
/* The second interface does not get any packets unless it has a vif */
ieee80211_hw_set(mphy->hw, WANT_MONITOR_VIF);
ret = mt76_register_phy(mphy);
if (ret)
ieee80211_free_hw(mphy->hw);
return ret;
}
void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
{
struct mt7915_phy *phy = mt7915_ext_phy(dev);
struct mt76_phy *mphy = dev->mt76.phy2;
if (!phy)
return;
mt7915_cap_dbdc_disable(dev);
mt76_unregister_phy(mphy);
ieee80211_free_hw(mphy->hw);
}
int mt7915_register_device(struct mt7915_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
int ret;
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
dev->mt76.phy.priv = &dev->phy;
INIT_DELAYED_WORK(&dev->mt76.mac_work, mt7915_mac_work);
INIT_LIST_HEAD(&dev->sta_poll_list);
spin_lock_init(&dev->sta_poll_lock);
init_waitqueue_head(&dev->reset_wait);
INIT_WORK(&dev->reset_work, mt7915_mac_reset_work);
ret = mt7915_init_hardware(dev);
if (ret)
return ret;
mt7915_init_wiphy(hw);
dev->mphy.sband_2g.sband.ht_cap.cap |=
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_MAX_AMSDU;
dev->mphy.sband_5g.sband.ht_cap.cap |=
IEEE80211_HT_CAP_LDPC_CODING |
IEEE80211_HT_CAP_MAX_AMSDU;
dev->mphy.sband_5g.sband.vht_cap.cap |=
IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 |
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
mt7915_cap_dbdc_disable(dev);
dev->phy.dfs_state = -1;
ret = mt76_register_device(&dev->mt76, true, mt7915_rates,
ARRAY_SIZE(mt7915_rates));
if (ret)
return ret;
ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
return mt7915_init_debugfs(dev);
}
void mt7915_unregister_device(struct mt7915_dev *dev)
{
struct mt76_txwi_cache *txwi;
int id;
mt7915_unregister_ext_phy(dev);
mt76_unregister_device(&dev->mt76);
mt7915_mcu_exit(dev);
mt7915_dma_cleanup(dev);
spin_lock_bh(&dev->token_lock);
idr_for_each_entry(&dev->token, txwi, id) {
mt7915_txp_skb_unmap(&dev->mt76, txwi);
if (txwi->skb)
dev_kfree_skb_any(txwi->skb);
mt76_put_txwi(&dev->mt76, txwi);
}
spin_unlock_bh(&dev->token_lock);
idr_destroy(&dev->token);
mt76_free_device(&dev->mt76);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,328 @@
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7915_MAC_H
#define __MT7915_MAC_H
#define MT_CT_PARSE_LEN 72
#define MT_CT_DMA_BUF_NUM 2
#define MT_RXD0_LENGTH GENMASK(15, 0)
#define MT_RXD0_PKT_TYPE GENMASK(31, 27)
#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
#define MT_RXD0_NORMAL_IP_SUM BIT(23)
#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
enum rx_pkt_type {
PKT_TYPE_TXS,
PKT_TYPE_TXRXV,
PKT_TYPE_NORMAL,
PKT_TYPE_RX_DUP_RFB,
PKT_TYPE_RX_TMR,
PKT_TYPE_RETRIEVE,
PKT_TYPE_TXRX_NOTIFY,
PKT_TYPE_RX_EVENT,
};
/* RXD DW1 */
#define MT_RXD1_NORMAL_WLAN_IDX GENMASK(9, 0)
#define MT_RXD1_NORMAL_GROUP_1 BIT(11)
#define MT_RXD1_NORMAL_GROUP_2 BIT(12)
#define MT_RXD1_NORMAL_GROUP_3 BIT(13)
#define MT_RXD1_NORMAL_GROUP_4 BIT(14)
#define MT_RXD1_NORMAL_GROUP_5 BIT(15)
#define MT_RXD1_NORMAL_SEC_MODE GENMASK(20, 16)
#define MT_RXD1_NORMAL_KEY_ID GENMASK(22, 21)
#define MT_RXD1_NORMAL_CM BIT(23)
#define MT_RXD1_NORMAL_CLM BIT(24)
#define MT_RXD1_NORMAL_ICV_ERR BIT(25)
#define MT_RXD1_NORMAL_TKIP_MIC_ERR BIT(26)
#define MT_RXD1_NORMAL_FCS_ERR BIT(27)
#define MT_RXD1_NORMAL_BAND_IDX BIT(28)
#define MT_RXD1_NORMAL_SPP_EN BIT(29)
#define MT_RXD1_NORMAL_ADD_OM BIT(30)
#define MT_RXD1_NORMAL_SEC_DONE BIT(31)
/* RXD DW2 */
#define MT_RXD2_NORMAL_BSSID GENMASK(5, 0)
#define MT_RXD2_NORMAL_CO_ANT BIT(6)
#define MT_RXD2_NORMAL_BF_CQI BIT(7)
#define MT_RXD2_NORMAL_MAC_HDR_LEN GENMASK(12, 8)
#define MT_RXD2_NORMAL_HDR_TRANS BIT(13)
#define MT_RXD2_NORMAL_HDR_OFFSET GENMASK(15, 14)
#define MT_RXD2_NORMAL_TID GENMASK(19, 16)
#define MT_RXD2_NORMAL_MU_BAR BIT(21)
#define MT_RXD2_NORMAL_SW_BIT BIT(22)
#define MT_RXD2_NORMAL_AMSDU_ERR BIT(23)
#define MT_RXD2_NORMAL_MAX_LEN_ERROR BIT(24)
#define MT_RXD2_NORMAL_HDR_TRANS_ERROR BIT(25)
#define MT_RXD2_NORMAL_INT_FRAME BIT(26)
#define MT_RXD2_NORMAL_FRAG BIT(27)
#define MT_RXD2_NORMAL_NULL_FRAME BIT(28)
#define MT_RXD2_NORMAL_NDATA BIT(29)
#define MT_RXD2_NORMAL_NON_AMPDU BIT(30)
#define MT_RXD2_NORMAL_BF_REPORT BIT(31)
/* RXD DW3 */
#define MT_RXD3_NORMAL_RXV_SEQ GENMASK(7, 0)
#define MT_RXD3_NORMAL_CH_FREQ GENMASK(15, 8)
#define MT_RXD3_NORMAL_ADDR_TYPE GENMASK(17, 16)
#define MT_RXD3_NORMAL_U2M BIT(0)
#define MT_RXD3_NORMAL_HTC_VLD BIT(0)
#define MT_RXD3_NORMAL_TSF_COMPARE_LOSS BIT(19)
#define MT_RXD3_NORMAL_BEACON_MC BIT(20)
#define MT_RXD3_NORMAL_BEACON_UC BIT(21)
#define MT_RXD3_NORMAL_AMSDU BIT(22)
#define MT_RXD3_NORMAL_MESH BIT(23)
#define MT_RXD3_NORMAL_MHCP BIT(24)
#define MT_RXD3_NORMAL_NO_INFO_WB BIT(25)
#define MT_RXD3_NORMAL_DISABLE_RX_HDR_TRANS BIT(26)
#define MT_RXD3_NORMAL_POWER_SAVE_STAT BIT(27)
#define MT_RXD3_NORMAL_MORE BIT(28)
#define MT_RXD3_NORMAL_UNWANT BIT(29)
#define MT_RXD3_NORMAL_RX_DROP BIT(30)
#define MT_RXD3_NORMAL_VLAN2ETH BIT(31)
/* RXD DW4 */
#define MT_RXD4_NORMAL_PAYLOAD_FORMAT GENMASK(1, 0)
#define MT_RXD4_NORMAL_PATTERN_DROP BIT(9)
#define MT_RXD4_NORMAL_CLS BIT(10)
#define MT_RXD4_NORMAL_OFLD GENMASK(12, 11)
#define MT_RXD4_NORMAL_MAGIC_PKT BIT(13)
#define MT_RXD4_NORMAL_WOL GENMASK(18, 14)
#define MT_RXD4_NORMAL_CLS_BITMAP GENMASK(28, 19)
#define MT_RXD3_NORMAL_PF_MODE BIT(29)
#define MT_RXD3_NORMAL_PF_STS GENMASK(31, 30)
/* P-RXV */
#define MT_PRXV_TX_RATE GENMASK(6, 0)
#define MT_PRXV_NSTS GENMASK(9, 7)
#define MT_PRXV_HT_AD_CODE BIT(11)
#define MT_PRXV_RCPI3 GENMASK(31, 24)
#define MT_PRXV_RCPI2 GENMASK(23, 16)
#define MT_PRXV_RCPI1 GENMASK(15, 8)
#define MT_PRXV_RCPI0 GENMASK(7, 0)
/* C-RXV */
#define MT_CRXV_HT_STBC GENMASK(1, 0)
#define MT_CRXV_TX_MODE GENMASK(7, 4)
#define MT_CRXV_FRAME_MODE GENMASK(10, 8)
#define MT_CRXV_HT_SHORT_GI GENMASK(14, 13)
struct mt7915_rxv {
u32 phy;
/* P-RXV: bit 0~1, C-RXV: bit 2~19 */
__le32 v[20];
};
enum tx_header_format {
MT_HDR_FORMAT_802_3,
MT_HDR_FORMAT_CMD,
MT_HDR_FORMAT_802_11,
MT_HDR_FORMAT_802_11_EXT,
};
enum tx_pkt_type {
MT_TX_TYPE_CT,
MT_TX_TYPE_SF,
MT_TX_TYPE_CMD,
MT_TX_TYPE_FW,
};
enum tx_pkt_queue_idx {
MT_LMAC_AC00,
MT_LMAC_AC01,
MT_LMAC_AC02,
MT_LMAC_AC03,
MT_LMAC_ALTX0 = 0x10,
MT_LMAC_BMC0 = 0x10,
MT_LMAC_BCN0 = 0x12,
};
enum tx_port_idx {
MT_TX_PORT_IDX_LMAC,
MT_TX_PORT_IDX_MCU
};
enum tx_mcu_port_q_idx {
MT_TX_MCU_PORT_RX_Q0 = 0x20,
MT_TX_MCU_PORT_RX_Q1,
MT_TX_MCU_PORT_RX_Q2,
MT_TX_MCU_PORT_RX_Q3,
MT_TX_MCU_PORT_RX_FWDL = 0x3e
};
#define MT_CT_INFO_APPLY_TXD BIT(0)
#define MT_CT_INFO_COPY_HOST_TXD_ALL BIT(1)
#define MT_CT_INFO_MGMT_FRAME BIT(2)
#define MT_CT_INFO_NONE_CIPHER_FRAME BIT(3)
#define MT_CT_INFO_HSR2_TX BIT(4)
#define MT_TXD_SIZE (8 * 4)
#define MT_TXD0_Q_IDX GENMASK(31, 25)
#define MT_TXD0_PKT_FMT GENMASK(24, 23)
#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
#define MT_TXD0_TX_BYTES GENMASK(15, 0)
#define MT_TXD1_LONG_FORMAT BIT(31)
#define MT_TXD1_TGID BIT(30)
#define MT_TXD1_OWN_MAC GENMASK(29, 24)
#define MT_TXD1_AMSDU BIT(23)
#define MT_TXD1_TID GENMASK(22, 20)
#define MT_TXD1_HDR_PAD GENMASK(19, 18)
#define MT_TXD1_HDR_FORMAT GENMASK(17, 16)
#define MT_TXD1_HDR_INFO GENMASK(15, 11)
#define MT_TXD1_VTA BIT(10)
#define MT_TXD1_WLAN_IDX GENMASK(9, 0)
#define MT_TXD2_FIX_RATE BIT(31)
#define MT_TXD2_FIXED_RATE BIT(30)
#define MT_TXD2_POWER_OFFSET GENMASK(29, 24)
#define MT_TXD2_MAX_TX_TIME GENMASK(23, 16)
#define MT_TXD2_FRAG GENMASK(15, 14)
#define MT_TXD2_HTC_VLD BIT(13)
#define MT_TXD2_DURATION BIT(12)
#define MT_TXD2_BIP BIT(11)
#define MT_TXD2_MULTICAST BIT(10)
#define MT_TXD2_RTS BIT(9)
#define MT_TXD2_SOUNDING BIT(8)
#define MT_TXD2_NDPA BIT(7)
#define MT_TXD2_NDP BIT(6)
#define MT_TXD2_FRAME_TYPE GENMASK(5, 4)
#define MT_TXD2_SUB_TYPE GENMASK(3, 0)
#define MT_TXD3_SN_VALID BIT(31)
#define MT_TXD3_PN_VALID BIT(30)
#define MT_TXD3_SW_POWER_MGMT BIT(29)
#define MT_TXD3_BA_DISABLE BIT(28)
#define MT_TXD3_SEQ GENMASK(27, 16)
#define MT_TXD3_REM_TX_COUNT GENMASK(15, 11)
#define MT_TXD3_TX_COUNT GENMASK(10, 6)
#define MT_TXD3_TIMING_MEASURE BIT(5)
#define MT_TXD3_DAS BIT(4)
#define MT_TXD3_EEOSP BIT(3)
#define MT_TXD3_EMRD BIT(2)
#define MT_TXD3_PROTECT_FRAME BIT(1)
#define MT_TXD3_NO_ACK BIT(0)
#define MT_TXD4_PN_LOW GENMASK(31, 0)
#define MT_TXD5_PN_HIGH GENMASK(31, 16)
#define MT_TXD5_MD BIT(15)
#define MT_TXD5_ADD_BA BIT(14)
#define MT_TXD5_TX_STATUS_HOST BIT(10)
#define MT_TXD5_TX_STATUS_MCU BIT(9)
#define MT_TXD5_TX_STATUS_FMT BIT(8)
#define MT_TXD5_PID GENMASK(7, 0)
#define MT_TXD6_TX_IBF BIT(31)
#define MT_TXD6_TX_EBF BIT(30)
#define MT_TXD6_TX_RATE GENMASK(29, 16)
#define MT_TXD6_SGI GENMASK(15, 14)
#define MT_TXD6_HELTF GENMASK(13, 12)
#define MT_TXD6_LDPC BIT(11)
#define MT_TXD6_SPE_ID_IDX BIT(10)
#define MT_TXD6_ANT_ID GENMASK(7, 4)
#define MT_TXD6_DYN_BW BIT(3)
#define MT_TXD6_FIXED_BW BIT(2)
#define MT_TXD6_BW GENMASK(2, 0)
#define MT_TXD7_TXD_LEN GENMASK(31, 30)
#define MT_TXD7_UDP_TCP_SUM BIT(29)
#define MT_TXD7_IP_SUM BIT(28)
#define MT_TXD7_TYPE GENMASK(21, 20)
#define MT_TXD7_SUB_TYPE GENMASK(19, 16)
#define MT_TXD7_PSE_FID GENMASK(27, 16)
#define MT_TXD7_SPE_IDX GENMASK(15, 11)
#define MT_TXD7_HW_AMSDU BIT(10)
#define MT_TXD7_TX_TIME GENMASK(9, 0)
#define MT_TX_RATE_STBC BIT(13)
#define MT_TX_RATE_NSS GENMASK(12, 10)
#define MT_TX_RATE_MODE GENMASK(9, 6)
#define MT_TX_RATE_IDX GENMASK(5, 0)
#define MT_TXP_MAX_BUF_NUM 6
struct mt7915_txp {
__le16 flags;
__le16 token;
u8 bss_idx;
u8 rept_wds_wcid;
u8 rsv;
u8 nbuf;
__le32 buf[MT_TXP_MAX_BUF_NUM];
__le16 len[MT_TXP_MAX_BUF_NUM];
} __packed __aligned(4);
struct mt7915_tx_free {
__le16 rx_byte_cnt;
__le16 ctrl;
u8 txd_cnt;
u8 rsv[3];
__le32 info[];
} __packed __aligned(4);
#define MT_TX_FREE_MSDU_CNT GENMASK(9, 0)
#define MT_TX_FREE_WLAN_ID GENMASK(23, 14)
#define MT_TX_FREE_LATENCY GENMASK(12, 0)
/* 0: success, others: dropped */
#define MT_TX_FREE_STATUS GENMASK(14, 13)
#define MT_TX_FREE_MSDU_ID GENMASK(30, 16)
#define MT_TX_FREE_PAIR BIT(31)
/* will support this field in further revision */
#define MT_TX_FREE_RATE GENMASK(13, 0)
struct mt7915_dfs_pulse {
u32 max_width; /* us */
int max_pwr; /* dbm */
int min_pwr; /* dbm */
u32 min_stgr_pri; /* us */
u32 max_stgr_pri; /* us */
u32 min_cr_pri; /* us */
u32 max_cr_pri; /* us */
};
struct mt7915_dfs_pattern {
u8 enb;
u8 stgr;
u8 min_crpn;
u8 max_crpn;
u8 min_crpr;
u8 min_pw;
u32 min_pri;
u32 max_pri;
u8 max_pw;
u8 min_crbn;
u8 max_crbn;
u8 min_stgpn;
u8 max_stgpn;
u8 min_stgpr;
u8 rsv[2];
u32 min_stgpr_diff;
} __packed;
struct mt7915_dfs_radar_spec {
struct mt7915_dfs_pulse pulse_th;
struct mt7915_dfs_pattern radar_pattern[16];
};
static inline struct mt7915_txp *
mt7915_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
{
u8 *txwi;
if (!t)
return NULL;
txwi = mt76_get_txwi_ptr(dev, t);
return (struct mt7915_txp *)(txwi + MT_TXD_SIZE);
}
#endif

View file

@ -0,0 +1,741 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc. */
#include <linux/etherdevice.h>
#include <linux/platform_device.h>
#include <linux/pci.h>
#include <linux/module.h>
#include "mt7915.h"
#include "mcu.h"
static bool mt7915_dev_running(struct mt7915_dev *dev)
{
struct mt7915_phy *phy;
if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
return true;
phy = mt7915_ext_phy(dev);
return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
}
static int mt7915_start(struct ieee80211_hw *hw)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
bool running;
mutex_lock(&dev->mt76.mutex);
running = mt7915_dev_running(dev);
if (!running) {
mt7915_mcu_set_pm(dev, 0, 0);
mt7915_mcu_set_mac(dev, 0, true, false);
mt7915_mcu_set_scs(dev, 0, true);
}
if (phy != &dev->phy) {
mt7915_mcu_set_pm(dev, 1, 0);
mt7915_mcu_set_mac(dev, 1, true, false);
mt7915_mcu_set_scs(dev, 1, true);
}
mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_SET_RX_PATH);
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
if (running)
goto out;
mt7915_mac_reset_counters(phy);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
MT7915_WATCHDOG_TIME);
out:
mutex_unlock(&dev->mt76.mutex);
return 0;
}
static void mt7915_stop(struct ieee80211_hw *hw)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
mutex_lock(&dev->mt76.mutex);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
if (phy != &dev->phy) {
mt7915_mcu_set_pm(dev, 1, 1);
mt7915_mcu_set_mac(dev, 1, false, false);
}
if (!mt7915_dev_running(dev)) {
cancel_delayed_work_sync(&dev->mt76.mac_work);
mt7915_mcu_set_pm(dev, 0, 1);
mt7915_mcu_set_mac(dev, 0, false, false);
}
mutex_unlock(&dev->mt76.mutex);
}
static int get_omac_idx(enum nl80211_iftype type, u32 mask)
{
int i;
switch (type) {
case NL80211_IFTYPE_MONITOR:
case NL80211_IFTYPE_AP:
/* ap uses hw bssid 0 and ext bssid */
if (~mask & BIT(HW_BSSID_0))
return HW_BSSID_0;
for (i = EXT_BSSID_1; i < EXT_BSSID_END; i++)
if (~mask & BIT(i))
return i;
break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_STATION:
/* station uses hw bssid other than 0 */
for (i = HW_BSSID_1; i < HW_BSSID_MAX; i++)
if (~mask & BIT(i))
return i;
break;
default:
WARN_ON(1);
break;
}
return -1;
}
static int mt7915_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt76_txq *mtxq;
bool ext_phy = phy != &dev->phy;
int idx, ret = 0;
mutex_lock(&dev->mt76.mutex);
mvif->idx = ffs(~phy->vif_mask) - 1;
if (mvif->idx >= MT7915_MAX_INTERFACES) {
ret = -ENOSPC;
goto out;
}
idx = get_omac_idx(vif->type, phy->omac_mask);
if (idx < 0) {
ret = -ENOSPC;
goto out;
}
mvif->omac_idx = idx;
mvif->dev = dev;
mvif->band_idx = ext_phy;
if (ext_phy)
mvif->wmm_idx = ext_phy * (MT7915_MAX_WMM_SETS / 2) +
mvif->idx % (MT7915_MAX_WMM_SETS / 2);
else
mvif->wmm_idx = mvif->idx % MT7915_MAX_WMM_SETS;
ret = mt7915_mcu_add_dev_info(dev, vif, true);
if (ret)
goto out;
phy->vif_mask |= BIT(mvif->idx);
phy->omac_mask |= BIT(mvif->omac_idx);
idx = MT7915_WTBL_RESERVED - mvif->idx;
INIT_LIST_HEAD(&mvif->sta.poll_list);
mvif->sta.wcid.idx = idx;
mvif->sta.wcid.ext_phy = mvif->band_idx;
mvif->sta.wcid.hw_key_idx = -1;
mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET;
mt7915_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
if (vif->txq) {
mtxq = (struct mt76_txq *)vif->txq->drv_priv;
mtxq->wcid = &mvif->sta.wcid;
mt76_txq_init(&dev->mt76, vif->txq);
}
out:
mutex_unlock(&dev->mt76.mutex);
return ret;
}
static void mt7915_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct mt7915_sta *msta = &mvif->sta;
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
int idx = msta->wcid.idx;
/* TODO: disable beacon for the bss */
mt7915_mcu_add_dev_info(dev, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
if (vif->txq)
mt76_txq_remove(&dev->mt76, vif->txq);
mutex_lock(&dev->mt76.mutex);
phy->vif_mask &= ~BIT(mvif->idx);
phy->omac_mask &= ~BIT(mvif->omac_idx);
mutex_unlock(&dev->mt76.mutex);
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
}
static void mt7915_init_dfs_state(struct mt7915_phy *phy)
{
struct mt76_phy *mphy = phy->mt76;
struct ieee80211_hw *hw = mphy->hw;
struct cfg80211_chan_def *chandef = &hw->conf.chandef;
if (hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
return;
if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
return;
if (mphy->chandef.chan->center_freq == chandef->chan->center_freq &&
mphy->chandef.width == chandef->width)
return;
phy->dfs_state = -1;
}
static int mt7915_set_channel(struct mt7915_phy *phy)
{
struct mt7915_dev *dev = phy->dev;
int ret;
cancel_delayed_work_sync(&dev->mt76.mac_work);
mutex_lock(&dev->mt76.mutex);
set_bit(MT76_RESET, &phy->mt76->state);
mt7915_init_dfs_state(phy);
mt76_set_channel(phy->mt76);
ret = mt7915_mcu_set_chan_info(phy, MCU_EXT_CMD_CHANNEL_SWITCH);
if (ret)
goto out;
mt7915_mac_set_timing(phy);
ret = mt7915_dfs_init_radar_detector(phy);
mt7915_mac_cca_stats_reset(phy);
mt7915_mac_reset_counters(phy);
phy->noise = 0;
out:
clear_bit(MT76_RESET, &phy->mt76->state);
mutex_unlock(&dev->mt76.mutex);
mt76_txq_schedule_all(phy->mt76);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
MT7915_WATCHDOG_TIME);
return ret;
}
static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct mt7915_sta *msta = sta ? (struct mt7915_sta *)sta->drv_priv :
&mvif->sta;
struct mt76_wcid *wcid = &msta->wcid;
int idx = key->keyidx;
/* The hardware does not support per-STA RX GTK, fallback
* to software mode for these.
*/
if ((vif->type == NL80211_IFTYPE_ADHOC ||
vif->type == NL80211_IFTYPE_MESH_POINT) &&
(key->cipher == WLAN_CIPHER_SUITE_TKIP ||
key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;
/* fall back to sw encryption for unsupported ciphers */
switch (key->cipher) {
case WLAN_CIPHER_SUITE_AES_CMAC:
key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
break;
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
case WLAN_CIPHER_SUITE_TKIP:
case WLAN_CIPHER_SUITE_CCMP:
case WLAN_CIPHER_SUITE_CCMP_256:
case WLAN_CIPHER_SUITE_GCMP:
case WLAN_CIPHER_SUITE_GCMP_256:
case WLAN_CIPHER_SUITE_SMS4:
break;
default:
return -EOPNOTSUPP;
}
if (cmd == SET_KEY) {
key->hw_key_idx = wcid->idx;
wcid->hw_key_idx = idx;
} else if (idx == wcid->hw_key_idx) {
wcid->hw_key_idx = -1;
}
mt76_wcid_key_setup(&dev->mt76, wcid,
cmd == SET_KEY ? key : NULL);
return mt7915_mcu_add_key(dev, vif, msta, key, cmd);
}
static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
bool band = phy != &dev->phy;
int ret;
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
ieee80211_stop_queues(hw);
ret = mt7915_set_channel(phy);
if (ret)
return ret;
ieee80211_wake_queues(hw);
}
mutex_lock(&dev->mt76.mutex);
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
if (!(hw->conf.flags & IEEE80211_CONF_MONITOR))
phy->rxfilter |= MT_WF_RFCR_DROP_OTHER_UC;
else
phy->rxfilter &= ~MT_WF_RFCR_DROP_OTHER_UC;
mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter);
}
mutex_unlock(&dev->mt76.mutex);
return 0;
}
static int
mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
/* no need to update right away, we'll get BSS_CHANGED_QOS */
mvif->wmm[queue].cw_min = params->cw_min;
mvif->wmm[queue].cw_max = params->cw_max;
mvif->wmm[queue].aifs = params->aifs;
mvif->wmm[queue].txop = params->txop;
return 0;
}
static void mt7915_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
bool band = phy != &dev->phy;
u32 ctl_flags = MT_WF_RFCR1_DROP_ACK |
MT_WF_RFCR1_DROP_BF_POLL |
MT_WF_RFCR1_DROP_BA |
MT_WF_RFCR1_DROP_CFEND |
MT_WF_RFCR1_DROP_CFACK;
u32 flags = 0;
#define MT76_FILTER(_flag, _hw) do { \
flags |= *total_flags & FIF_##_flag; \
phy->rxfilter &= ~(_hw); \
phy->rxfilter |= !(flags & FIF_##_flag) * (_hw); \
} while (0)
phy->rxfilter &= ~(MT_WF_RFCR_DROP_OTHER_BSS |
MT_WF_RFCR_DROP_OTHER_BEACON |
MT_WF_RFCR_DROP_FRAME_REPORT |
MT_WF_RFCR_DROP_PROBEREQ |
MT_WF_RFCR_DROP_MCAST_FILTERED |
MT_WF_RFCR_DROP_MCAST |
MT_WF_RFCR_DROP_BCAST |
MT_WF_RFCR_DROP_DUPLICATE |
MT_WF_RFCR_DROP_A2_BSSID |
MT_WF_RFCR_DROP_UNWANTED_CTL |
MT_WF_RFCR_DROP_STBC_MULTI);
MT76_FILTER(OTHER_BSS, MT_WF_RFCR_DROP_OTHER_TIM |
MT_WF_RFCR_DROP_A3_MAC |
MT_WF_RFCR_DROP_A3_BSSID);
MT76_FILTER(FCSFAIL, MT_WF_RFCR_DROP_FCSFAIL);
MT76_FILTER(CONTROL, MT_WF_RFCR_DROP_CTS |
MT_WF_RFCR_DROP_RTS |
MT_WF_RFCR_DROP_CTL_RSV |
MT_WF_RFCR_DROP_NDPA);
*total_flags = flags;
mt76_wr(dev, MT_WF_RFCR(band), phy->rxfilter);
if (*total_flags & FIF_CONTROL)
mt76_clear(dev, MT_WF_RFCR1(band), ctl_flags);
else
mt76_set(dev, MT_WF_RFCR1(band), ctl_flags);
}
static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u32 changed)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mt7915_dev *dev = mt7915_hw_dev(hw);
mutex_lock(&dev->mt76.mutex);
/*
* station mode uses BSSID to map the wlan entry to a peer,
* and then peer references bss_info_rfch to set bandwidth cap.
*/
if (changed & BSS_CHANGED_BSSID &&
vif->type == NL80211_IFTYPE_STATION) {
bool join = !is_zero_ether_addr(info->bssid);
mt7915_mcu_add_bss_info(phy, vif, join);
mt7915_mcu_add_sta(dev, vif, NULL, join);
}
if (changed & BSS_CHANGED_ASSOC)
mt7915_mcu_add_bss_info(phy, vif, info->assoc);
if (changed & BSS_CHANGED_ERP_SLOT) {
int slottime = info->use_short_slot ? 9 : 20;
if (slottime != phy->slottime) {
phy->slottime = slottime;
mt7915_mac_set_timing(phy);
}
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
mt7915_mcu_add_bss_info(phy, vif, info->enable_beacon);
mt7915_mcu_add_sta(dev, vif, NULL, info->enable_beacon);
}
/* ensure that enable txcmd_mode after bss_info */
if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED))
mt7915_mcu_set_tx(dev, vif);
if (changed & (BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED))
mt7915_mcu_add_beacon(hw, vif, info->enable_beacon);
mutex_unlock(&dev->mt76.mutex);
}
static void
mt7915_channel_switch_beacon(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_chan_def *chandef)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
mutex_lock(&dev->mt76.mutex);
mt7915_mcu_add_beacon(hw, vif, true);
mutex_unlock(&dev->mt76.mutex);
}
int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
int idx;
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA - 1);
if (idx < 0)
return -ENOSPC;
INIT_LIST_HEAD(&msta->poll_list);
INIT_WORK(&msta->stats_work, mt7915_mac_sta_stats_work);
spin_lock_init(&msta->ampdu_lock);
msta->vif = mvif;
msta->wcid.sta = 1;
msta->wcid.idx = idx;
msta->wcid.ext_phy = mvif->band_idx;
msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
msta->stats.jiffies = jiffies;
mt7915_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
mt7915_mcu_add_sta(dev, vif, sta, true);
return 0;
}
void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
mt7915_mcu_add_sta(dev, vif, sta, false);
mt7915_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
spin_lock_bh(&dev->sta_poll_lock);
if (!list_empty(&msta->poll_list))
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
}
static void mt7915_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt76_phy *mphy = hw->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
struct mt76_wcid *wcid = &dev->mt76.global_wcid;
if (control->sta) {
struct mt7915_sta *sta;
sta = (struct mt7915_sta *)control->sta->drv_priv;
wcid = &sta->wcid;
}
if (vif && !control->sta) {
struct mt7915_vif *mvif;
mvif = (struct mt7915_vif *)vif->drv_priv;
wcid = &mvif->sta.wcid;
}
mt76_tx(mphy, control->sta, wcid, skb);
}
static int mt7915_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
mutex_lock(&dev->mt76.mutex);
mt7915_mcu_set_rts_thresh(phy, val);
mutex_unlock(&dev->mt76.mutex);
return 0;
}
static int
mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params)
{
enum ieee80211_ampdu_mlme_action action = params->action;
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct ieee80211_sta *sta = params->sta;
struct ieee80211_txq *txq = sta->txq[params->tid];
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
u16 tid = params->tid;
u16 ssn = params->ssn;
struct mt76_txq *mtxq;
int ret = 0;
if (!txq)
return -EINVAL;
mtxq = (struct mt76_txq *)txq->drv_priv;
mutex_lock(&dev->mt76.mutex);
switch (action) {
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
params->buf_size);
mt7915_mcu_add_rx_ba(dev, params, true);
break;
case IEEE80211_AMPDU_RX_STOP:
mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
mt7915_mcu_add_rx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
mtxq->aggr = true;
mtxq->send_bar = false;
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_OPERATIONAL);
mt7915_mcu_add_tx_ba(dev, params, true);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP);
mt7915_mcu_add_tx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_START:
mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_START);
ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
mt7915_set_aggr_state(msta, tid, MT7915_AGGR_STOP);
mt7915_mcu_add_tx_ba(dev, params, false);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
mutex_unlock(&dev->mt76.mutex);
return ret;
}
static int
mt7915_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST,
IEEE80211_STA_NONE);
}
static int
mt7915_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE,
IEEE80211_STA_NOTEXIST);
}
static int
mt7915_get_stats(struct ieee80211_hw *hw,
struct ieee80211_low_level_stats *stats)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
struct mib_stats *mib = &phy->mib;
stats->dot11RTSSuccessCount = mib->rts_cnt;
stats->dot11RTSFailureCount = mib->rts_retries_cnt;
stats->dot11FCSErrorCount = mib->fcs_err_cnt;
stats->dot11ACKFailureCount = mib->ack_fail_cnt;
return 0;
}
static void
mt7915_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
{
struct mt7915_phy *phy = mt7915_hw_phy(hw);
phy->coverage_class = max_t(s16, coverage_class, 0);
mt7915_mac_set_timing(phy);
}
static int
mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
int max_nss = hweight8(hw->wiphy->available_antennas_tx);
bool ext_phy = phy != &dev->phy;
if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss)
return -EINVAL;
if ((BIT(hweight8(tx_ant)) - 1) != tx_ant)
tx_ant = BIT(ffs(tx_ant) - 1) - 1;
mutex_lock(&dev->mt76.mutex);
phy->mt76->antenna_mask = tx_ant;
if (ext_phy) {
if (dev->chainmask == 0xf)
tx_ant <<= 2;
else
tx_ant <<= 1;
}
phy->chainmask = tx_ant;
mt76_set_stream_caps(&dev->mt76, true);
mutex_unlock(&dev->mt76.mutex);
return 0;
}
static void
mt7915_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
u32 changed)
{
struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
rcu_read_lock();
sta = ieee80211_find_sta(vif, sta->addr);
if (!sta) {
rcu_read_unlock();
return;
}
rcu_read_lock();
set_bit(changed, &msta->stats.changed);
ieee80211_queue_work(hw, &msta->stats_work);
}
const struct ieee80211_ops mt7915_ops = {
.tx = mt7915_tx,
.start = mt7915_start,
.stop = mt7915_stop,
.add_interface = mt7915_add_interface,
.remove_interface = mt7915_remove_interface,
.config = mt7915_config,
.conf_tx = mt7915_conf_tx,
.configure_filter = mt7915_configure_filter,
.bss_info_changed = mt7915_bss_info_changed,
.sta_add = mt7915_sta_add,
.sta_remove = mt7915_sta_remove,
.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
.sta_rc_update = mt7915_sta_rc_update,
.set_key = mt7915_set_key,
.ampdu_action = mt7915_ampdu_action,
.set_rts_threshold = mt7915_set_rts_threshold,
.wake_tx_queue = mt76_wake_tx_queue,
.sw_scan_start = mt76_sw_scan,
.sw_scan_complete = mt76_sw_scan_complete,
.release_buffered_frames = mt76_release_buffered_frames,
.get_txpower = mt76_get_txpower,
.channel_switch_beacon = mt7915_channel_switch_beacon,
.get_stats = mt7915_get_stats,
.get_survey = mt76_get_survey,
.get_antenna = mt76_get_antenna,
.set_antenna = mt7915_set_antenna,
.set_coverage_class = mt7915_set_coverage_class,
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,837 @@
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7915_MCU_H
#define __MT7915_MCU_H
struct mt7915_mcu_txd {
__le32 txd[8];
__le16 len;
__le16 pq_id;
u8 cid;
u8 pkt_type;
u8 set_query; /* FW don't care */
u8 seq;
u8 uc_d2b0_rev;
u8 ext_cid;
u8 s2d_index;
u8 ext_cid_ack;
u32 reserved[5];
} __packed __aligned(4);
/* event table */
enum {
MCU_EVENT_TARGET_ADDRESS_LEN = 0x01,
MCU_EVENT_FW_START = 0x01,
MCU_EVENT_GENERIC = 0x01,
MCU_EVENT_ACCESS_REG = 0x02,
MCU_EVENT_MT_PATCH_SEM = 0x04,
MCU_EVENT_CH_PRIVILEGE = 0x18,
MCU_EVENT_EXT = 0xed,
MCU_EVENT_RESTART_DL = 0xef,
};
/* ext event table */
enum {
MCU_EXT_EVENT_PS_SYNC = 0x5,
MCU_EXT_EVENT_THERMAL_PROTECT = 0x22,
MCU_EXT_EVENT_ASSERT_DUMP = 0x23,
MCU_EXT_EVENT_RDD_REPORT = 0x3a,
MCU_EXT_EVENT_CSA_NOTIFY = 0x4f,
MCU_EXT_EVENT_RATE_REPORT = 0x87,
};
struct mt7915_mcu_rxd {
__le32 rxd[6];
__le16 len;
__le16 pkt_type_id;
u8 eid;
u8 seq;
__le16 __rsv;
u8 ext_eid;
u8 __rsv1[2];
u8 s2d_index;
};
struct mt7915_mcu_rdd_report {
struct mt7915_mcu_rxd rxd;
u8 idx;
u8 long_detected;
u8 constant_prf_detected;
u8 staggered_prf_detected;
u8 radar_type_idx;
u8 periodic_pulse_num;
u8 long_pulse_num;
u8 hw_pulse_num;
u8 out_lpn;
u8 out_spn;
u8 out_crpn;
u8 out_crpw;
u8 out_crbn;
u8 out_stgpn;
u8 out_stgpw;
u8 rsv;
__le32 out_pri_const;
__le32 out_pri_stg[3];
struct {
__le32 start;
__le16 pulse_width;
__le16 pulse_power;
u8 mdrdy_flag;
u8 rsv[3];
} long_pulse[32];
struct {
__le32 start;
__le16 pulse_width;
__le16 pulse_power;
u8 mdrdy_flag;
u8 rsv[3];
} periodic_pulse[32];
struct {
__le32 start;
__le16 pulse_width;
__le16 pulse_power;
u8 sc_pass;
u8 sw_reset;
u8 mdrdy_flag;
u8 tx_active;
} hw_pulse[32];
} __packed;
struct mt7915_mcu_eeprom_info {
__le32 addr;
__le32 valid;
u8 data[16];
} __packed;
struct mt7915_mcu_ra_info {
struct mt7915_mcu_rxd rxd;
__le32 event_id;
__le16 wlan_idx;
__le16 ru_idx;
__le16 direction;
__le16 dump_group;
__le32 suggest_rate;
__le32 min_rate; /* for dynamic sounding */
__le32 max_rate; /* for dynamic sounding */
__le32 init_rate_down_rate;
__le16 curr_rate;
__le16 init_rate_down_total;
__le16 init_rate_down_succ;
__le16 success;
__le16 attempts;
__le16 prev_rate;
__le16 prob_up_rate;
u8 no_rate_up_cnt;
u8 ppdu_cnt;
u8 gi;
u8 try_up_fail;
u8 try_up_total;
u8 suggest_wf;
u8 try_up_check;
u8 prob_up_period;
u8 prob_down_pending;
} __packed;
#define MT_RA_RATE_NSS GENMASK(8, 6)
#define MT_RA_RATE_MCS GENMASK(3, 0)
#define MT_RA_RATE_TX_MODE GENMASK(12, 9)
#define MT_RA_RATE_DCM_EN BIT(4)
#define MT_RA_RATE_BW GENMASK(14, 13)
#define MCU_PQ_ID(p, q) (((p) << 15) | ((q) << 10))
#define MCU_PKT_ID 0xa0
enum {
MCU_Q_QUERY,
MCU_Q_SET,
MCU_Q_RESERVED,
MCU_Q_NA
};
enum {
MCU_S2D_H2N,
MCU_S2D_C2N,
MCU_S2D_H2C,
MCU_S2D_H2CN
};
enum {
MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01,
MCU_CMD_FW_START_REQ = 0x02,
MCU_CMD_INIT_ACCESS_REG = 0x3,
MCU_CMD_NIC_POWER_CTRL = 0x4,
MCU_CMD_PATCH_START_REQ = 0x05,
MCU_CMD_PATCH_FINISH_REQ = 0x07,
MCU_CMD_PATCH_SEM_CONTROL = 0x10,
MCU_CMD_EXT_CID = 0xED,
MCU_CMD_FW_SCATTER = 0xEE,
MCU_CMD_RESTART_DL_REQ = 0xEF,
};
enum {
MCU_EXT_CMD_EFUSE_ACCESS = 0x01,
MCU_EXT_CMD_PM_STATE_CTRL = 0x07,
MCU_EXT_CMD_CHANNEL_SWITCH = 0x08,
MCU_EXT_CMD_EFUSE_BUFFER_MODE = 0x21,
MCU_EXT_CMD_STA_REC_UPDATE = 0x25,
MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26,
MCU_EXT_CMD_EDCA_UPDATE = 0x27,
MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A,
MCU_EXT_CMD_THERMAL_CTRL = 0x2c,
MCU_EXT_CMD_SET_RDD_CTRL = 0x3a,
MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
MCU_EXT_CMD_MAC_INIT_CTRL = 0x46,
MCU_EXT_CMD_RX_HDR_TRANS = 0x47,
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
MCU_EXT_CMD_SET_SER_TRIGGER = 0x81,
MCU_EXT_CMD_SCS_CTRL = 0x82,
MCU_EXT_CMD_RATE_CTRL = 0x87,
MCU_EXT_CMD_SET_RDD_TH = 0x9d,
};
enum {
PATCH_SEM_RELEASE,
PATCH_SEM_GET
};
enum {
PATCH_NOT_DL_SEM_FAIL,
PATCH_IS_DL,
PATCH_NOT_DL_SEM_SUCCESS,
PATCH_REL_SEM_SUCCESS
};
enum {
FW_STATE_INITIAL,
FW_STATE_FW_DOWNLOAD,
FW_STATE_NORMAL_OPERATION,
FW_STATE_NORMAL_TRX,
FW_STATE_WACPU_RDY = 7
};
enum {
EE_MODE_EFUSE,
EE_MODE_BUFFER,
};
enum {
EE_FORMAT_BIN,
EE_FORMAT_WHOLE,
EE_FORMAT_MULTIPLE,
};
#define STA_TYPE_STA BIT(0)
#define STA_TYPE_AP BIT(1)
#define STA_TYPE_ADHOC BIT(2)
#define STA_TYPE_WDS BIT(4)
#define STA_TYPE_BC BIT(5)
#define NETWORK_INFRA BIT(16)
#define NETWORK_P2P BIT(17)
#define NETWORK_IBSS BIT(18)
#define NETWORK_WDS BIT(21)
#define CONNECTION_INFRA_STA (STA_TYPE_STA | NETWORK_INFRA)
#define CONNECTION_INFRA_AP (STA_TYPE_AP | NETWORK_INFRA)
#define CONNECTION_P2P_GC (STA_TYPE_STA | NETWORK_P2P)
#define CONNECTION_P2P_GO (STA_TYPE_AP | NETWORK_P2P)
#define CONNECTION_IBSS_ADHOC (STA_TYPE_ADHOC | NETWORK_IBSS)
#define CONNECTION_WDS (STA_TYPE_WDS | NETWORK_WDS)
#define CONNECTION_INFRA_BC (STA_TYPE_BC | NETWORK_INFRA)
#define CONN_STATE_DISCONNECT 0
#define CONN_STATE_CONNECT 1
#define CONN_STATE_PORT_SECURE 2
enum {
DEV_INFO_ACTIVE,
DEV_INFO_MAX_NUM
};
enum {
SCS_SEND_DATA,
SCS_SET_MANUAL_PD_TH,
SCS_CONFIG,
SCS_ENABLE,
SCS_SHOW_INFO,
SCS_GET_GLO_ADDR,
SCS_GET_GLO_ADDR_EVENT,
};
enum {
CMD_CBW_20MHZ = IEEE80211_STA_RX_BW_20,
CMD_CBW_40MHZ = IEEE80211_STA_RX_BW_40,
CMD_CBW_80MHZ = IEEE80211_STA_RX_BW_80,
CMD_CBW_160MHZ = IEEE80211_STA_RX_BW_160,
CMD_CBW_10MHZ,
CMD_CBW_5MHZ,
CMD_CBW_8080MHZ,
CMD_HE_MCS_BW80 = 0,
CMD_HE_MCS_BW160,
CMD_HE_MCS_BW8080,
CMD_HE_MCS_BW_NUM
};
struct tlv {
__le16 tag;
__le16 len;
} __packed;
struct bss_info_omac {
__le16 tag;
__le16 len;
u8 hw_bss_idx;
u8 omac_idx;
u8 band_idx;
u8 rsv0;
__le32 conn_type;
u32 rsv1;
} __packed;
struct bss_info_basic {
__le16 tag;
__le16 len;
__le32 network_type;
u8 active;
u8 rsv0;
__le16 bcn_interval;
u8 bssid[ETH_ALEN];
u8 wmm_idx;
u8 dtim_period;
u8 bmc_wcid_lo;
u8 cipher;
u8 phy_mode;
u8 max_bssid; /* max BSSID. range: 1 ~ 8, 0: MBSSID disabled */
u8 non_tx_bssid;/* non-transmitted BSSID, 0: transmitted BSSID */
u8 bmc_wcid_hi; /* high Byte and version */
u8 rsv[2];
} __packed;
struct bss_info_rf_ch {
__le16 tag;
__le16 len;
u8 pri_ch;
u8 center_ch0;
u8 center_ch1;
u8 bw;
u8 he_ru26_block; /* 1: don't send HETB in RU26, 0: allow */
u8 he_all_disable; /* 1: disallow all HETB, 0: allow */
u8 rsv[2];
} __packed;
struct bss_info_ext_bss {
__le16 tag;
__le16 len;
__le32 mbss_tsf_offset; /* in unit of us */
u8 rsv[8];
} __packed;
struct bss_info_sync_mode {
__le16 tag;
__le16 len;
__le16 bcn_interval;
u8 enable;
u8 dtim_period;
u8 rsv[8];
} __packed;
struct bss_info_bmc_rate {
__le16 tag;
__le16 len;
__le16 bc_trans;
__le16 mc_trans;
u8 short_preamble;
u8 rsv[7];
} __packed;
struct bss_info_ra {
__le16 tag;
__le16 len;
u8 op_mode;
u8 adhoc_en;
u8 short_preamble;
u8 tx_streams;
u8 rx_streams;
u8 algo;
u8 force_sgi;
u8 force_gf;
u8 ht_mode;
u8 has_20_sta; /* Check if any sta support GF. */
u8 bss_width_trigger_events;
u8 vht_nss_cap;
u8 vht_bw_signal; /* not use */
u8 vht_force_sgi; /* not use */
u8 se_off;
u8 antenna_idx;
u8 train_up_rule;
u8 rsv[3];
unsigned short train_up_high_thres;
short train_up_rule_rssi;
unsigned short low_traffic_thres;
__le16 max_phyrate;
__le32 phy_cap;
__le32 interval;
__le32 fast_interval;
} __packed;
struct bss_info_bcn {
__le16 tag;
__le16 len;
u8 ver;
u8 enable;
__le16 sub_ntlv;
} __packed __aligned(4);
struct bss_info_bcn_csa {
__le16 tag;
__le16 len;
u8 cnt;
u8 rsv[3];
} __packed __aligned(4);
struct bss_info_bcn_bcc {
__le16 tag;
__le16 len;
u8 cnt;
u8 rsv[3];
} __packed __aligned(4);
struct bss_info_bcn_mbss {
#define MAX_BEACON_NUM 32
__le16 tag;
__le16 len;
__le32 bitmap;
__le16 offset[MAX_BEACON_NUM];
u8 rsv[8];
} __packed __aligned(4);
struct bss_info_bcn_cont {
__le16 tag;
__le16 len;
__le16 tim_ofs;
__le16 csa_ofs;
__le16 bcc_ofs;
__le16 pkt_len;
} __packed __aligned(4);
enum {
BSS_INFO_BCN_CSA,
BSS_INFO_BCN_BCC,
BSS_INFO_BCN_MBSSID,
BSS_INFO_BCN_CONTENT,
BSS_INFO_BCN_MAX
};
enum {
BSS_INFO_OMAC,
BSS_INFO_BASIC,
BSS_INFO_RF_CH, /* optional, for BT/LTE coex */
BSS_INFO_PM, /* sta only */
BSS_INFO_UAPSD, /* sta only */
BSS_INFO_ROAM_DETECT, /* obsoleted */
BSS_INFO_LQ_RM, /* obsoleted */
BSS_INFO_EXT_BSS,
BSS_INFO_BMC_RATE, /* for bmc rate control in CR4 */
BSS_INFO_SYNC_MODE,
BSS_INFO_RA,
BSS_INFO_HW_AMSDU,
BSS_INFO_BSS_COLOR,
BSS_INFO_HE_BASIC,
BSS_INFO_PROTECT_INFO,
BSS_INFO_OFFLOAD,
BSS_INFO_11V_MBSSID,
BSS_INFO_MAX_NUM
};
enum {
WTBL_RESET_AND_SET = 1,
WTBL_SET,
WTBL_QUERY,
WTBL_RESET_ALL
};
struct wtbl_req_hdr {
u8 wlan_idx_lo;
u8 operation;
__le16 tlv_num;
u8 wlan_idx_hi;
u8 rsv[3];
} __packed;
struct wtbl_generic {
__le16 tag;
__le16 len;
u8 peer_addr[ETH_ALEN];
u8 muar_idx;
u8 skip_tx;
u8 cf_ack;
u8 qos;
u8 mesh;
u8 adm;
__le16 partial_aid;
u8 baf_en;
u8 aad_om;
} __packed;
struct wtbl_rx {
__le16 tag;
__le16 len;
u8 rcid;
u8 rca1;
u8 rca2;
u8 rv;
u8 rsv[4];
} __packed;
struct wtbl_ht {
__le16 tag;
__le16 len;
u8 ht;
u8 ldpc;
u8 af;
u8 mm;
u8 rsv[4];
} __packed;
struct wtbl_vht {
__le16 tag;
__le16 len;
u8 ldpc;
u8 dyn_bw;
u8 vht;
u8 txop_ps;
u8 rsv[4];
} __packed;
enum {
MT_BA_TYPE_INVALID,
MT_BA_TYPE_ORIGINATOR,
MT_BA_TYPE_RECIPIENT
};
enum {
RST_BA_MAC_TID_MATCH,
RST_BA_MAC_MATCH,
RST_BA_NO_MATCH
};
struct wtbl_ba {
__le16 tag;
__le16 len;
/* common */
u8 tid;
u8 ba_type;
u8 rsv0[2];
/* originator only */
__le16 sn;
u8 ba_en;
u8 ba_winsize_idx;
__le16 ba_winsize;
/* recipient only */
u8 peer_addr[ETH_ALEN];
u8 rst_ba_tid;
u8 rst_ba_sel;
u8 rst_ba_sb;
u8 band_idx;
u8 rsv1[4];
} __packed;
struct wtbl_bf {
__le16 tag;
__le16 len;
u8 ibf;
u8 ebf;
u8 ibf_vht;
u8 ebf_vht;
u8 gid;
u8 pfmu_idx;
u8 rsv[2];
} __packed;
struct wtbl_smps {
__le16 tag;
__le16 len;
u8 smps;
u8 rsv[3];
} __packed;
struct wtbl_spe {
__le16 tag;
__le16 len;
u8 spe_idx;
u8 rsv[3];
} __packed;
enum {
WTBL_GENERIC,
WTBL_RX,
WTBL_HT,
WTBL_VHT,
WTBL_PEER_PS, /* not used */
WTBL_TX_PS,
WTBL_HDR_TRANS,
WTBL_SEC_KEY,
WTBL_BA,
WTBL_RDG, /* obsoleted */
WTBL_PROTECT, /* not used */
WTBL_CLEAR, /* not used */
WTBL_BF,
WTBL_SMPS,
WTBL_RAW_DATA, /* debug only */
WTBL_PN,
WTBL_SPE,
WTBL_MAX_NUM
};
struct sta_ntlv_hdr {
u8 rsv[2];
__le16 tlv_num;
} __packed;
struct sta_req_hdr {
u8 bss_idx;
u8 wlan_idx_lo;
__le16 tlv_num;
u8 is_tlv_append;
u8 muar_idx;
u8 wlan_idx_hi;
u8 rsv;
} __packed;
struct sta_rec_basic {
__le16 tag;
__le16 len;
__le32 conn_type;
u8 conn_state;
u8 qos;
__le16 aid;
u8 peer_addr[ETH_ALEN];
__le16 extra_info;
} __packed;
struct sta_rec_ht {
__le16 tag;
__le16 len;
__le16 ht_cap;
u16 rsv;
} __packed;
struct sta_rec_vht {
__le16 tag;
__le16 len;
__le32 vht_cap;
__le16 vht_rx_mcs_map;
__le16 vht_tx_mcs_map;
u8 rts_bw_sig;
u8 rsv[3];
} __packed;
struct sta_rec_ba {
__le16 tag;
__le16 len;
u8 tid;
u8 ba_type;
u8 amsdu;
u8 ba_en;
__le16 ssn;
__le16 winsize;
} __packed;
struct sec_key {
u8 cipher_id;
u8 cipher_len;
u8 key_id;
u8 key_len;
u8 key[32];
} __packed;
struct sta_rec_sec {
__le16 tag;
__le16 len;
u8 add;
u8 n_cipher;
u8 rsv[2];
struct sec_key key[2];
} __packed;
struct ra_phy {
u8 type;
u8 flag;
u8 stbc;
u8 sgi;
u8 bw;
u8 ldpc;
u8 mcs;
u8 nss;
u8 he_ltf;
};
struct sta_rec_ra {
__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_status;
struct ra_phy phy;
} __packed;
enum {
STA_REC_BASIC,
STA_REC_RA,
STA_REC_RA_CMM_INFO,
STA_REC_RA_UPDATE,
STA_REC_BF,
STA_REC_AMSDU,
STA_REC_BA,
STA_REC_RED, /* not used */
STA_REC_TX_PROC, /* for hdr trans and CSO in CR4 */
STA_REC_HT,
STA_REC_VHT,
STA_REC_APPS,
STA_REC_KEY,
STA_REC_WTBL,
STA_REC_HE,
STA_REC_HW_AMSDU,
STA_REC_WTBL_AADOM,
STA_REC_KEY_V2,
STA_REC_MURU,
STA_REC_MUEDCA,
STA_REC_MAX_NUM
};
enum mt7915_cipher_type {
MT_CIPHER_NONE,
MT_CIPHER_WEP40,
MT_CIPHER_WEP104,
MT_CIPHER_WEP128,
MT_CIPHER_TKIP,
MT_CIPHER_AES_CCMP,
MT_CIPHER_CCMP_256,
MT_CIPHER_GCMP,
MT_CIPHER_GCMP_256,
MT_CIPHER_WAPI,
MT_CIPHER_BIP_CMAC_128,
};
enum {
CH_SWITCH_NORMAL = 0,
CH_SWITCH_SCAN = 3,
CH_SWITCH_MCC = 4,
CH_SWITCH_DFS = 5,
CH_SWITCH_BACKGROUND_SCAN_START = 6,
CH_SWITCH_BACKGROUND_SCAN_RUNNING = 7,
CH_SWITCH_BACKGROUND_SCAN_STOP = 8,
CH_SWITCH_SCAN_BYPASS_DPD = 9
};
enum {
THERMAL_SENSOR_TEMP_QUERY,
THERMAL_SENSOR_MANUAL_CTRL,
THERMAL_SENSOR_INFO_QUERY,
THERMAL_SENSOR_TASK_CTRL,
};
#define MT7915_WTBL_UPDATE_MAX_SIZE (sizeof(struct wtbl_req_hdr) + \
sizeof(struct wtbl_generic) + \
sizeof(struct wtbl_rx) + \
sizeof(struct wtbl_ht) + \
sizeof(struct wtbl_vht) + \
sizeof(struct wtbl_ba) + \
sizeof(struct wtbl_bf) + \
sizeof(struct wtbl_smps) + \
sizeof(struct wtbl_spe))
#define MT7915_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \
sizeof(struct sta_rec_basic) + \
sizeof(struct sta_rec_ht) + \
sizeof(struct sta_rec_ba) + \
sizeof(struct sta_rec_vht) + \
sizeof(struct tlv) + \
sizeof(struct sta_rec_sec) + \
sizeof(struct sta_rec_ra) + \
MT7915_WTBL_UPDATE_MAX_SIZE)
#define MT7915_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \
sizeof(struct wtbl_ba))
#define MT7915_BEACON_UPDATE_SIZE (sizeof(struct sta_req_hdr) + \
sizeof(struct bss_info_bcn_csa) + \
sizeof(struct bss_info_bcn_bcc) + \
sizeof(struct bss_info_bcn_mbss) + \
sizeof(struct bss_info_bcn_cont))
#define PHY_MODE_A BIT(0)
#define PHY_MODE_B BIT(1)
#define PHY_MODE_G BIT(2)
#define PHY_MODE_GN BIT(3)
#define PHY_MODE_AN BIT(4)
#define PHY_MODE_AC BIT(5)
#define MODE_CCK BIT(0)
#define MODE_OFDM BIT(1)
#define MODE_HT BIT(2)
#define MODE_VHT BIT(3)
#define STA_CAP_WMM BIT(0)
#define STA_CAP_SGI_20 BIT(4)
#define STA_CAP_SGI_40 BIT(5)
#define STA_CAP_TX_STBC BIT(6)
#define STA_CAP_RX_STBC BIT(7)
#define STA_CAP_VHT_SGI_80 BIT(16)
#define STA_CAP_VHT_SGI_160 BIT(17)
#define STA_CAP_VHT_TX_STBC BIT(18)
#define STA_CAP_VHT_RX_STBC BIT(19)
#define STA_CAP_VHT_LDPC BIT(23)
#define STA_CAP_LDPC BIT(24)
#define STA_CAP_HT BIT(26)
#define STA_CAP_VHT BIT(27)
#endif

View file

@ -0,0 +1,441 @@
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7915_H
#define __MT7915_H
#include <linux/interrupt.h>
#include <linux/ktime.h>
#include "../mt76.h"
#include "regs.h"
#define MT7915_MAX_INTERFACES 4
#define MT7915_MAX_WMM_SETS 4
#define MT7915_WTBL_SIZE 288
#define MT7915_WTBL_RESERVED (MT7915_WTBL_SIZE - 1)
#define MT7915_WTBL_STA (MT7915_WTBL_RESERVED - \
MT7915_MAX_INTERFACES)
#define MT7915_WATCHDOG_TIME (HZ / 10)
#define MT7915_RESET_TIMEOUT (30 * HZ)
#define MT7915_TX_RING_SIZE 2048
#define MT7915_TX_MCU_RING_SIZE 256
#define MT7915_TX_FWDL_RING_SIZE 128
#define MT7915_RX_RING_SIZE 1536
#define MT7915_RX_MCU_RING_SIZE 512
#define MT7915_FIRMWARE_WA "mediatek/mt7915_wa.bin"
#define MT7915_FIRMWARE_WM "mediatek/mt7915_wm.bin"
#define MT7915_ROM_PATCH "mediatek/mt7915_rom_patch.bin"
#define MT7915_EEPROM_SIZE 3584
#define MT7915_TOKEN_SIZE 8192
#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
#define MT7915_5G_RATE_DEFAULT 0x4b /* OFDM 6M */
#define MT7915_2G_RATE_DEFAULT 0x0 /* CCK 1M */
struct mt7915_vif;
struct mt7915_sta;
struct mt7915_dfs_pulse;
struct mt7915_dfs_pattern;
enum mt7915_txq_id {
MT7915_TXQ_FWDL = 16,
MT7915_TXQ_MCU_WM,
MT7915_TXQ_BAND0,
MT7915_TXQ_BAND1,
MT7915_TXQ_MCU_WA,
};
enum mt7915_rxq_id {
MT7915_RXQ_BAND0 = 0,
MT7915_RXQ_BAND1,
MT7915_RXQ_MCU_WM = 0,
MT7915_RXQ_MCU_WA,
};
enum mt7915_ampdu_state {
MT7915_AGGR_STOP,
MT7915_AGGR_PROGRESS,
MT7915_AGGR_START,
MT7915_AGGR_OPERATIONAL
};
struct mt7915_sta_stats {
struct rate_info prob_rate;
struct rate_info tx_rate;
unsigned long per;
unsigned long changed;
unsigned long jiffies;
};
struct mt7915_sta {
struct mt76_wcid wcid; /* must be first */
struct mt7915_vif *vif;
struct list_head poll_list;
u32 airtime_ac[8];
struct mt7915_sta_stats stats;
struct work_struct stats_work;
spinlock_t ampdu_lock;
enum mt7915_ampdu_state ampdu_state[IEEE80211_NUM_TIDS];
};
struct mt7915_vif {
u16 idx;
u8 omac_idx;
u8 band_idx;
u8 wmm_idx;
struct {
u16 cw_min;
u16 cw_max;
u16 txop;
u8 aifs;
} wmm[IEEE80211_NUM_ACS];
struct mt7915_sta sta;
struct mt7915_dev *dev;
};
struct mib_stats {
u16 ack_fail_cnt;
u16 fcs_err_cnt;
u16 rts_cnt;
u16 rts_retries_cnt;
u16 ba_miss_cnt;
};
struct mt7915_phy {
struct mt76_phy *mt76;
struct mt7915_dev *dev;
u32 rxfilter;
u32 vif_mask;
u32 omac_mask;
u16 noise;
u16 chainmask;
s16 coverage_class;
u8 slottime;
u8 rdd_state;
int dfs_state;
__le32 rx_ampdu_ts;
u32 ampdu_ref;
struct mib_stats mib;
};
struct mt7915_dev {
union { /* must be first */
struct mt76_dev mt76;
struct mt76_phy mphy;
};
struct mt7915_phy phy;
u16 chainmask;
struct work_struct init_work;
struct work_struct reset_work;
wait_queue_head_t reset_wait;
u32 reset_state;
struct list_head sta_poll_list;
spinlock_t sta_poll_lock;
u32 hw_pattern;
spinlock_t token_lock;
struct idr token;
u8 mac_work_count;
bool fw_debug;
};
enum {
HW_BSSID_0 = 0x0,
HW_BSSID_1,
HW_BSSID_2,
HW_BSSID_3,
HW_BSSID_MAX,
EXT_BSSID_START = 0x10,
EXT_BSSID_1,
EXT_BSSID_2,
EXT_BSSID_3,
EXT_BSSID_4,
EXT_BSSID_5,
EXT_BSSID_6,
EXT_BSSID_7,
EXT_BSSID_8,
EXT_BSSID_9,
EXT_BSSID_10,
EXT_BSSID_11,
EXT_BSSID_12,
EXT_BSSID_13,
EXT_BSSID_14,
EXT_BSSID_15,
EXT_BSSID_END
};
enum {
MT_RX_SEL0,
MT_RX_SEL1,
};
enum mt7915_rdd_cmd {
RDD_STOP,
RDD_START,
RDD_DET_MODE,
RDD_RADAR_EMULATE,
RDD_START_TXQ = 20,
RDD_CAC_START = 50,
RDD_CAC_END,
RDD_NORMAL_START,
RDD_DISABLE_DFS_CAL,
RDD_PULSE_DBG,
RDD_READ_PULSE,
RDD_RESUME_BF,
RDD_IRQ_OFF,
};
enum {
RATE_CTRL_RU_INFO,
RATE_CTRL_FIXED_RATE_INFO,
RATE_CTRL_DUMP_INFO,
RATE_CTRL_MU_INFO,
};
static inline struct mt7915_phy *
mt7915_hw_phy(struct ieee80211_hw *hw)
{
struct mt76_phy *phy = hw->priv;
return phy->priv;
}
static inline struct mt7915_dev *
mt7915_hw_dev(struct ieee80211_hw *hw)
{
struct mt76_phy *phy = hw->priv;
return container_of(phy->dev, struct mt7915_dev, mt76);
}
static inline struct mt7915_phy *
mt7915_ext_phy(struct mt7915_dev *dev)
{
struct mt76_phy *phy = dev->mt76.phy2;
if (!phy)
return NULL;
return phy->priv;
}
static inline void
mt7915_set_aggr_state(struct mt7915_sta *msta, u8 tid,
enum mt7915_ampdu_state state)
{
spin_lock_bh(&msta->ampdu_lock);
msta->ampdu_state[tid] = state;
spin_unlock_bh(&msta->ampdu_lock);
}
extern const struct ieee80211_ops mt7915_ops;
extern struct pci_driver mt7915_pci_driver;
u32 mt7915_reg_map(struct mt7915_dev *dev, u32 addr);
int mt7915_register_device(struct mt7915_dev *dev);
void mt7915_unregister_device(struct mt7915_dev *dev);
int mt7915_register_ext_phy(struct mt7915_dev *dev);
void mt7915_unregister_ext_phy(struct mt7915_dev *dev);
int mt7915_eeprom_init(struct mt7915_dev *dev);
u32 mt7915_eeprom_read(struct mt7915_dev *dev, u32 offset);
int mt7915_eeprom_get_target_power(struct mt7915_dev *dev,
struct ieee80211_channel *chan,
u8 chain_idx);
int mt7915_dma_init(struct mt7915_dev *dev);
void mt7915_dma_prefetch(struct mt7915_dev *dev);
void mt7915_dma_cleanup(struct mt7915_dev *dev);
int mt7915_mcu_init(struct mt7915_dev *dev);
int mt7915_mcu_add_dev_info(struct mt7915_dev *dev,
struct ieee80211_vif *vif, bool enable);
int mt7915_mcu_add_bss_info(struct mt7915_phy *phy,
struct ieee80211_vif *vif, int enable);
int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool enable);
int mt7915_mcu_add_tx_ba(struct mt7915_dev *dev,
struct ieee80211_ampdu_params *params,
bool add);
int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
struct ieee80211_ampdu_params *params,
bool add);
int mt7915_mcu_add_key(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct mt7915_sta *msta, struct ieee80211_key_conf *key,
enum set_key_cmd cmd);
int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int enable);
int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int mt7915_mcu_add_smps(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int mt7915_mcu_set_chan_info(struct mt7915_phy *phy, int cmd);
int mt7915_mcu_set_tx(struct mt7915_dev *dev, struct ieee80211_vif *vif);
int mt7915_mcu_set_eeprom(struct mt7915_dev *dev);
int mt7915_mcu_get_eeprom(struct mt7915_dev *dev, u32 offset);
int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
bool hdr_trans);
int mt7915_mcu_set_scs(struct mt7915_dev *dev, u8 band, bool enable);
int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band);
int mt7915_mcu_set_rts_thresh(struct mt7915_phy *phy, u32 val);
int mt7915_mcu_set_pm(struct mt7915_dev *dev, int band, int enter);
int mt7915_mcu_set_fcc5_lpn(struct mt7915_dev *dev, int val);
int mt7915_mcu_set_pulse_th(struct mt7915_dev *dev,
const struct mt7915_dfs_pulse *pulse);
int mt7915_mcu_set_radar_th(struct mt7915_dev *dev, int index,
const struct mt7915_dfs_pattern *pattern);
int mt7915_mcu_get_rate_info(struct mt7915_dev *dev, u32 cmd, u16 wlan_idx);
int mt7915_mcu_get_temperature(struct mt7915_dev *dev, int index);
int mt7915_mcu_rdd_cmd(struct mt7915_dev *dev, enum mt7915_rdd_cmd cmd,
u8 index, u8 rx_sel, u8 val);
void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb);
void mt7915_mcu_exit(struct mt7915_dev *dev);
static inline bool is_mt7915(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7915;
}
static inline void mt7915_irq_enable(struct mt7915_dev *dev, u32 mask)
{
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask);
}
static inline void mt7915_irq_disable(struct mt7915_dev *dev, u32 mask)
{
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
}
static inline u32
mt7915_reg_map_l1(struct mt7915_dev *dev, u32 addr)
{
u32 offset = FIELD_GET(MT_HIF_REMAP_L1_OFFSET, addr);
u32 base = FIELD_GET(MT_HIF_REMAP_L1_BASE, addr);
mt76_rmw_field(dev, MT_HIF_REMAP_L1, MT_HIF_REMAP_L1_MASK, base);
/* use read to push write */
mt76_rr(dev, MT_HIF_REMAP_L1);
return MT_HIF_REMAP_BASE_L1 + offset;
}
static inline u32
mt7915_l1_rr(struct mt7915_dev *dev, u32 addr)
{
return mt76_rr(dev, mt7915_reg_map_l1(dev, addr));
}
static inline void
mt7915_l1_wr(struct mt7915_dev *dev, u32 addr, u32 val)
{
mt76_wr(dev, mt7915_reg_map_l1(dev, addr), val);
}
static inline u32
mt7915_l1_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val)
{
val |= mt7915_l1_rr(dev, addr) & ~mask;
mt7915_l1_wr(dev, addr, val);
return val;
}
#define mt7915_l1_set(dev, addr, val) mt7915_l1_rmw(dev, addr, 0, val)
#define mt7915_l1_clear(dev, addr, val) mt7915_l1_rmw(dev, addr, val, 0)
static inline u32
mt7915_reg_map_l2(struct mt7915_dev *dev, u32 addr)
{
u32 offset = FIELD_GET(MT_HIF_REMAP_L2_OFFSET, addr);
u32 base = FIELD_GET(MT_HIF_REMAP_L2_BASE, addr);
mt76_rmw_field(dev, MT_HIF_REMAP_L2, MT_HIF_REMAP_L2_MASK, base);
/* use read to push write */
mt76_rr(dev, MT_HIF_REMAP_L2);
return MT_HIF_REMAP_BASE_L2 + offset;
}
static inline u32
mt7915_l2_rr(struct mt7915_dev *dev, u32 addr)
{
return mt76_rr(dev, mt7915_reg_map_l2(dev, addr));
}
static inline void
mt7915_l2_wr(struct mt7915_dev *dev, u32 addr, u32 val)
{
mt76_wr(dev, mt7915_reg_map_l2(dev, addr), val);
}
static inline u32
mt7915_l2_rmw(struct mt7915_dev *dev, u32 addr, u32 mask, u32 val)
{
val |= mt7915_l2_rr(dev, addr) & ~mask;
mt7915_l2_wr(dev, addr, val);
return val;
}
#define mt7915_l2_set(dev, addr, val) mt7915_l2_rmw(dev, addr, 0, val)
#define mt7915_l2_clear(dev, addr, val) mt7915_l2_rmw(dev, addr, val, 0)
bool mt7915_mac_wtbl_update(struct mt7915_dev *dev, int idx, u32 mask);
void mt7915_mac_reset_counters(struct mt7915_phy *phy);
void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);
void mt7915_mac_sta_poll(struct mt7915_dev *dev);
void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, bool beacon);
void mt7915_mac_set_timing(struct mt7915_phy *phy);
int mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb);
void mt7915_mac_tx_free(struct mt7915_dev *dev, struct sk_buff *skb);
int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7915_mac_work(struct work_struct *work);
void mt7915_mac_reset_work(struct work_struct *work);
void mt7915_mac_sta_stats_work(struct work_struct *work);
int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
struct mt76_tx_info *tx_info);
void mt7915_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
struct mt76_queue_entry *e);
void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
struct sk_buff *skb);
void mt7915_sta_ps(struct mt76_dev *mdev, struct ieee80211_sta *sta, bool ps);
void mt7915_stats_work(struct work_struct *work);
void mt7915_txp_skb_unmap(struct mt76_dev *dev,
struct mt76_txwi_cache *txwi);
int mt76_dfs_start_rdd(struct mt7915_dev *dev, bool force);
int mt7915_dfs_init_radar_detector(struct mt7915_phy *phy);
void mt7915_update_channel(struct mt76_dev *mdev);
int mt7915_init_debugfs(struct mt7915_dev *dev);
#endif

View file

@ -0,0 +1,166 @@
// SPDX-License-Identifier: ISC
/* Copyright (C) 2020 MediaTek Inc.
*
* Author: Ryder Lee <ryder.lee@mediatek.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "mt7915.h"
#include "mac.h"
#include "../trace.h"
static const struct pci_device_id mt7915_pci_device_table[] = {
{ PCI_DEVICE(0x14c3, 0x7915) },
{ },
};
static void
mt7915_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
{
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
mt7915_irq_enable(dev, MT_INT_RX_DONE(q));
}
/* TODO: support 2/4/6/8 MSI-X vectors */
static irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
{
struct mt7915_dev *dev = dev_instance;
u32 intr;
intr = mt76_rr(dev, MT_INT_SOURCE_CSR);
mt76_wr(dev, MT_INT_SOURCE_CSR, intr);
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
return IRQ_NONE;
trace_dev_irq(&dev->mt76, intr, dev->mt76.mmio.irqmask);
intr &= dev->mt76.mmio.irqmask;
if (intr & MT_INT_TX_DONE_ALL) {
mt7915_irq_disable(dev, MT_INT_TX_DONE_ALL);
napi_schedule(&dev->mt76.tx_napi);
}
if (intr & MT_INT_RX_DONE_DATA) {
mt7915_irq_disable(dev, MT_INT_RX_DONE_DATA);
napi_schedule(&dev->mt76.napi[0]);
}
if (intr & MT_INT_RX_DONE_WM) {
mt7915_irq_disable(dev, MT_INT_RX_DONE_WM);
napi_schedule(&dev->mt76.napi[1]);
}
if (intr & MT_INT_RX_DONE_WA) {
mt7915_irq_disable(dev, MT_INT_RX_DONE_WA);
napi_schedule(&dev->mt76.napi[2]);
}
if (intr & MT_INT_MCU_CMD) {
u32 val = mt76_rr(dev, MT_MCU_CMD);
mt76_wr(dev, MT_MCU_CMD, val);
if (val & MT_MCU_CMD_ERROR_MASK) {
dev->reset_state = val;
ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
wake_up(&dev->reset_wait);
}
}
return IRQ_HANDLED;
}
static int mt7915_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
static const struct mt76_driver_ops drv_ops = {
/* txwi_size = txd size + txp size */
.txwi_size = MT_TXD_SIZE + sizeof(struct mt7915_txp),
.drv_flags = MT_DRV_TXWI_NO_FREE,
.survey_flags = SURVEY_INFO_TIME_TX |
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
.tx_prepare_skb = mt7915_tx_prepare_skb,
.tx_complete_skb = mt7915_tx_complete_skb,
.rx_skb = mt7915_queue_rx_skb,
.rx_poll_complete = mt7915_rx_poll_complete,
.sta_ps = mt7915_sta_ps,
.sta_add = mt7915_mac_sta_add,
.sta_remove = mt7915_mac_sta_remove,
.update_survey = mt7915_update_channel,
};
struct mt7915_dev *dev;
struct mt76_dev *mdev;
int ret;
ret = pcim_enable_device(pdev);
if (ret)
return ret;
ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev));
if (ret)
return ret;
pci_set_master(pdev);
ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret)
return ret;
mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), &mt7915_ops,
&drv_ops);
if (!mdev)
return -ENOMEM;
dev = container_of(mdev, struct mt7915_dev, mt76);
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
mdev->rev = (mt7915_l1_rr(dev, MT_HW_CHIPID) << 16) |
(mt7915_l1_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
/* master switch of PCIe tnterrupt enable */
mt7915_l1_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
ret = devm_request_irq(mdev->dev, pdev->irq, mt7915_irq_handler,
IRQF_SHARED, KBUILD_MODNAME, dev);
if (ret)
goto error;
ret = mt7915_register_device(dev);
if (ret)
goto error;
return 0;
error:
ieee80211_free_hw(mt76_hw(dev));
return ret;
}
static void mt7915_pci_remove(struct pci_dev *pdev)
{
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
mt7915_unregister_device(dev);
}
struct pci_driver mt7915_pci_driver = {
.name = KBUILD_MODNAME,
.id_table = mt7915_pci_device_table,
.probe = mt7915_pci_probe,
.remove = mt7915_pci_remove,
};
module_pci_driver(mt7915_pci_driver);
MODULE_DEVICE_TABLE(pci, mt7915_pci_device_table);
MODULE_FIRMWARE(MT7915_FIRMWARE_WA);
MODULE_FIRMWARE(MT7915_FIRMWARE_WM);
MODULE_FIRMWARE(MT7915_ROM_PATCH);
MODULE_LICENSE("Dual BSD/GPL");

View file

@ -0,0 +1,343 @@
/* SPDX-License-Identifier: ISC */
/* Copyright (C) 2020 MediaTek Inc. */
#ifndef __MT7915_REGS_H
#define __MT7915_REGS_H
/* MCU WFDMA1 */
#define MT_MCU_WFDMA1_BASE 0x3000
#define MT_MCU_WFDMA1(ofs) (MT_MCU_WFDMA1_BASE + (ofs))
#define MT_MCU_INT_EVENT MT_MCU_WFDMA1(0x108)
#define MT_MCU_INT_EVENT_DMA_STOPPED BIT(0)
#define MT_MCU_INT_EVENT_DMA_INIT BIT(1)
#define MT_MCU_INT_EVENT_SER_TRIGGER BIT(2)
#define MT_MCU_INT_EVENT_RESET_DONE BIT(3)
#define MT_PLE_BASE 0x8000
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
#define MT_PLE_FL_Q0_CTRL MT_PLE(0x1b0)
#define MT_PLE_FL_Q1_CTRL MT_PLE(0x1b4)
#define MT_PLE_FL_Q2_CTRL MT_PLE(0x1b8)
#define MT_PLE_FL_Q3_CTRL MT_PLE(0x1bc)
#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \
((n) << 2))
#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
#define MT_MDP_BASE 0xf000
#define MT_MDP(ofs) (MT_MDP_BASE + (ofs))
#define MT_MDP_DCR0 MT_MDP(0x000)
#define MT_MDP_DCR0_DAMSDU_EN BIT(15)
#define MT_MDP_DCR1 MT_MDP(0x004)
#define MT_MDP_DCR1_MAX_RX_LEN GENMASK(15, 3)
#define MT_MDP_BNRCFR0(_band) MT_MDP(0x070 + ((_band) << 8))
#define MT_MDP_RCFR0_MCU_RX_MGMT GENMASK(5, 4)
#define MT_MDP_RCFR0_MCU_RX_CTL_NON_BAR GENMASK(7, 6)
#define MT_MDP_RCFR0_MCU_RX_CTL_BAR GENMASK(9, 8)
#define MT_MDP_BNRCFR1(_band) MT_MDP(0x074 + ((_band) << 8))
#define MT_MDP_RCFR1_MCU_RX_BYPASS GENMASK(23, 22)
#define MT_MDP_RCFR1_RX_DROPPED_UCAST GENMASK(28, 27)
#define MT_MDP_RCFR1_RX_DROPPED_MCAST GENMASK(30, 29)
#define MT_MDP_TO_HIF 0
#define MT_MDP_TO_WM 1
/* TMAC: band 0(0x21000), band 1(0xa1000) */
#define MT_WF_TMAC_BASE(_band) ((_band) ? 0xa1000 : 0x21000)
#define MT_WF_TMAC(_band, ofs) (MT_WF_TMAC_BASE(_band) + (ofs))
#define MT_TMAC_CDTR(_band) MT_WF_TMAC(_band, 0x090)
#define MT_TMAC_ODTR(_band) MT_WF_TMAC(_band, 0x094)
#define MT_TIMEOUT_VAL_PLCP GENMASK(15, 0)
#define MT_TIMEOUT_VAL_CCA GENMASK(31, 16)
#define MT_TMAC_ICR0(_band) MT_WF_TMAC(_band, 0x0a4)
#define MT_IFS_EIFS GENMASK(8, 0)
#define MT_IFS_RIFS GENMASK(14, 10)
#define MT_IFS_SIFS GENMASK(22, 16)
#define MT_IFS_SLOT GENMASK(30, 24)
#define MT_TMAC_CTCR0(_band) MT_WF_TMAC(_band, 0x0f4)
#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0)
#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18)
/* DMA Band 0 */
#define MT_WF_DMA_BASE 0x21e00
#define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs))
#define MT_DMA_DCR0 MT_WF_DMA(0x000)
#define MT_DMA_DCR0_MAX_RX_LEN GENMASK(15, 3)
/* MIB: band 0(0x24800), band 1(0xa4800) */
#define MT_WF_MIB_BASE(_band) ((_band) ? 0xa4800 : 0x24800)
#define MT_WF_MIB(_band, ofs) (MT_WF_MIB_BASE(_band) + (ofs))
#define MT_MIB_SDR3(_band) MT_WF_MIB(_band, 0x014)
#define MT_MIB_SDR3_FCS_ERR_MASK GENMASK(15, 0)
#define MT_MIB_SDR9(_band) MT_WF_MIB(_band, 0x02c)
#define MT_MIB_SDR9_BUSY_MASK GENMASK(23, 0)
#define MT_MIB_SDR16(_band) MT_WF_MIB(_band, 0x048)
#define MT_MIB_SDR16_BUSY_MASK GENMASK(23, 0)
#define MT_MIB_SDR36(_band) MT_WF_MIB(_band, 0x098)
#define MT_MIB_SDR36_TXTIME_MASK GENMASK(23, 0)
#define MT_MIB_SDR37(_band) MT_WF_MIB(_band, 0x09c)
#define MT_MIB_SDR37_RXTIME_MASK GENMASK(23, 0)
#define MT_MIB_MB_SDR0(_band, n) MT_WF_MIB(_band, 0x100 + ((n) << 4))
#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16)
#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0)
#define MT_MIB_MB_SDR1(_band, n) MT_WF_MIB(_band, 0x104 + ((n) << 4))
#define MT_MIB_BA_MISS_COUNT_MASK GENMASK(15, 0)
#define MT_MIB_ACK_FAIL_COUNT_MASK GENMASK(31, 16)
#define MT_MIB_MB_SDR2(_band, n) MT_WF_MIB(_band, 0x108 + ((n) << 4))
#define MT_MIB_FRAME_RETRIES_COUNT_MASK GENMASK(15, 0)
#define MT_TX_AGG_CNT(_band, n) MT_WF_MIB(_band, 0x0a8 + ((n) << 2))
#define MT_TX_AGG_CNT2(_band, n) MT_WF_MIB(_band, 0x164 + ((n) << 2))
#define MT_MIB_ARNG(_band, n) MT_WF_MIB(_band, 0x4b8 + ((n) << 2))
#define MT_MIB_ARNCR_RANGE(val, n) (((val) >> ((n) << 3)) & GENMASK(7, 0))
#define MT_WTBLON_TOP_BASE 0x34000
#define MT_WTBLON_TOP(ofs) (MT_WTBLON_TOP_BASE + (ofs))
#define MT_WTBLON_TOP_WDUCR MT_WTBLON_TOP(0x0)
#define MT_WTBLON_TOP_WDUCR_GROUP GENMASK(2, 0)
#define MT_WTBL_UPDATE MT_WTBLON_TOP(0x030)
#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(9, 0)
#define MT_WTBL_UPDATE_ADM_COUNT_CLEAR BIT(12)
#define MT_WTBL_UPDATE_BUSY BIT(31)
#define MT_WTBL_BASE 0x38000
#define MT_WTBL_LMAC_ID GENMASK(14, 8)
#define MT_WTBL_LMAC_DW GENMASK(7, 2)
#define MT_WTBL_LMAC_OFFS(_id, _dw) (MT_WTBL_BASE | \
FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \
FIELD_PREP(MT_WTBL_LMAC_DW, _dw))
/* AGG: band 0(0x20800), band 1(0xa0800) */
#define MT_WF_AGG_BASE(_band) ((_band) ? 0xa0800 : 0x20800)
#define MT_WF_AGG(_band, ofs) (MT_WF_AGG_BASE(_band) + (ofs))
#define MT_AGG_ACR0(_band) MT_WF_AGG(_band, 0x084)
#define MT_AGG_ACR_CFEND_RATE GENMASK(13, 0)
#define MT_AGG_ACR_BAR_RATE GENMASK(29, 16)
/* ARB: band 0(0x20c00), band 1(0xa0c00) */
#define MT_WF_ARB_BASE(_band) ((_band) ? 0xa0c00 : 0x20c00)
#define MT_WF_ARB(_band, ofs) (MT_WF_ARB_BASE(_band) + (ofs))
#define MT_ARB_SCR(_band) MT_WF_ARB(_band, 0x080)
#define MT_ARB_SCR_TX_DISABLE BIT(8)
#define MT_ARB_SCR_RX_DISABLE BIT(9)
/* RMAC: band 0(0x21400), band 1(0xa1400) */
#define MT_WF_RMAC_BASE(_band) ((_band) ? 0xa1400 : 0x21400)
#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
#define MT_WF_RFCR(_band) MT_WF_RMAC(_band, 0x000)
#define MT_WF_RFCR_DROP_STBC_MULTI BIT(0)
#define MT_WF_RFCR_DROP_FCSFAIL BIT(1)
#define MT_WF_RFCR_DROP_VERSION BIT(3)
#define MT_WF_RFCR_DROP_PROBEREQ BIT(4)
#define MT_WF_RFCR_DROP_MCAST BIT(5)
#define MT_WF_RFCR_DROP_BCAST BIT(6)
#define MT_WF_RFCR_DROP_MCAST_FILTERED BIT(7)
#define MT_WF_RFCR_DROP_A3_MAC BIT(8)
#define MT_WF_RFCR_DROP_A3_BSSID BIT(9)
#define MT_WF_RFCR_DROP_A2_BSSID BIT(10)
#define MT_WF_RFCR_DROP_OTHER_BEACON BIT(11)
#define MT_WF_RFCR_DROP_FRAME_REPORT BIT(12)
#define MT_WF_RFCR_DROP_CTL_RSV BIT(13)
#define MT_WF_RFCR_DROP_CTS BIT(14)
#define MT_WF_RFCR_DROP_RTS BIT(15)
#define MT_WF_RFCR_DROP_DUPLICATE BIT(16)
#define MT_WF_RFCR_DROP_OTHER_BSS BIT(17)
#define MT_WF_RFCR_DROP_OTHER_UC BIT(18)
#define MT_WF_RFCR_DROP_OTHER_TIM BIT(19)
#define MT_WF_RFCR_DROP_NDPA BIT(20)
#define MT_WF_RFCR_DROP_UNWANTED_CTL BIT(21)
#define MT_WF_RFCR1(_band) MT_WF_RMAC(_band, 0x004)
#define MT_WF_RFCR1_DROP_ACK BIT(4)
#define MT_WF_RFCR1_DROP_BF_POLL BIT(5)
#define MT_WF_RFCR1_DROP_BA BIT(6)
#define MT_WF_RFCR1_DROP_CFEND BIT(7)
#define MT_WF_RFCR1_DROP_CFACK BIT(8)
#define MT_WF_RMAC_MIB_TIME0(_band) MT_WF_RMAC(_band, 0x03c4)
#define MT_WF_RMAC_MIB_RXTIME_CLR BIT(31)
#define MT_WF_RMAC_MIB_RXTIME_EN BIT(30)
#define MT_WF_RMAC_MIB_AIRTIME14(_band) MT_WF_RMAC(_band, 0x03b8)
#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0)
#define MT_WF_RMAC_MIB_AIRTIME0(_band) MT_WF_RMAC(_band, 0x0380)
/* WFDMA0 */
#define MT_WFDMA0_BASE 0xd4000
#define MT_WFDMA0(ofs) (MT_WFDMA0_BASE + (ofs))
#define MT_WFDMA0_RST MT_WFDMA0(0x100)
#define MT_WFDMA0_RST_LOGIC_RST BIT(4)
#define MT_WFDMA0_RST_DMASHDL_ALL_RST BIT(5)
#define MT_WFDMA0_BUSY_ENA MT_WFDMA0(0x13c)
#define MT_WFDMA0_BUSY_ENA_TX_FIFO0 BIT(0)
#define MT_WFDMA0_BUSY_ENA_TX_FIFO1 BIT(1)
#define MT_WFDMA0_BUSY_ENA_RX_FIFO BIT(2)
#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_RST_DTX_PTR MT_WFDMA0(0x20c)
#define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0)
#define MT_RX_DATA_RING_BASE MT_WFDMA0(0x500)
#define MT_WFDMA0_RX_RING0_EXT_CTRL MT_WFDMA0(0x680)
#define MT_WFDMA0_RX_RING1_EXT_CTRL MT_WFDMA0(0x684)
#define MT_WFDMA0_RX_RING2_EXT_CTRL MT_WFDMA0(0x688)
/* WFDMA1 */
#define MT_WFDMA1_BASE 0xd5000
#define MT_WFDMA1(ofs) (MT_WFDMA1_BASE + (ofs))
#define MT_WFDMA1_RST MT_WFDMA1(0x100)
#define MT_WFDMA1_RST_LOGIC_RST BIT(4)
#define MT_WFDMA1_RST_DMASHDL_ALL_RST BIT(5)
#define MT_WFDMA1_BUSY_ENA MT_WFDMA1(0x13c)
#define MT_WFDMA1_BUSY_ENA_TX_FIFO0 BIT(0)
#define MT_WFDMA1_BUSY_ENA_TX_FIFO1 BIT(1)
#define MT_WFDMA1_BUSY_ENA_RX_FIFO BIT(2)
#define MT_MCU_CMD MT_WFDMA1(0x1f0)
#define MT_MCU_CMD_STOP_DMA_FW_RELOAD BIT(1)
#define MT_MCU_CMD_STOP_DMA BIT(2)
#define MT_MCU_CMD_RESET_DONE BIT(3)
#define MT_MCU_CMD_RECOVERY_DONE BIT(4)
#define MT_MCU_CMD_NORMAL_STATE BIT(5)
#define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
#define MT_WFDMA1_GLO_CFG MT_WFDMA1(0x208)
#define MT_WFDMA1_GLO_CFG_TX_DMA_EN BIT(0)
#define MT_WFDMA1_GLO_CFG_RX_DMA_EN BIT(2)
#define MT_WFDMA1_GLO_CFG_OMIT_TX_INFO BIT(28)
#define MT_WFDMA1_GLO_CFG_OMIT_RX_INFO BIT(27)
#define MT_WFDMA1_RST_DTX_PTR MT_WFDMA1(0x20c)
#define MT_WFDMA1_PRI_DLY_INT_CFG0 MT_WFDMA1(0x2f0)
#define MT_TX_RING_BASE MT_WFDMA1(0x300)
#define MT_RX_EVENT_RING_BASE MT_WFDMA1(0x500)
#define MT_WFDMA1_TX_RING0_EXT_CTRL MT_WFDMA1(0x600)
#define MT_WFDMA1_TX_RING1_EXT_CTRL MT_WFDMA1(0x604)
#define MT_WFDMA1_TX_RING2_EXT_CTRL MT_WFDMA1(0x608)
#define MT_WFDMA1_TX_RING3_EXT_CTRL MT_WFDMA1(0x60c)
#define MT_WFDMA1_TX_RING4_EXT_CTRL MT_WFDMA1(0x610)
#define MT_WFDMA1_TX_RING5_EXT_CTRL MT_WFDMA1(0x614)
#define MT_WFDMA1_TX_RING6_EXT_CTRL MT_WFDMA1(0x618)
#define MT_WFDMA1_TX_RING7_EXT_CTRL MT_WFDMA1(0x61c)
#define MT_WFDMA1_TX_RING16_EXT_CTRL MT_WFDMA1(0x640)
#define MT_WFDMA1_TX_RING17_EXT_CTRL MT_WFDMA1(0x644)
#define MT_WFDMA1_TX_RING18_EXT_CTRL MT_WFDMA1(0x648)
#define MT_WFDMA1_TX_RING19_EXT_CTRL MT_WFDMA1(0x64c)
#define MT_WFDMA1_TX_RING20_EXT_CTRL MT_WFDMA1(0x650)
#define MT_WFDMA1_TX_RING21_EXT_CTRL MT_WFDMA1(0x654)
#define MT_WFDMA1_TX_RING22_EXT_CTRL MT_WFDMA1(0x658)
#define MT_WFDMA1_TX_RING23_EXT_CTRL MT_WFDMA1(0x65c)
#define MT_WFDMA1_RX_RING0_EXT_CTRL MT_WFDMA1(0x680)
#define MT_WFDMA1_RX_RING1_EXT_CTRL MT_WFDMA1(0x684)
#define MT_WFDMA1_RX_RING2_EXT_CTRL MT_WFDMA1(0x688)
#define MT_WFDMA1_RX_RING3_EXT_CTRL MT_WFDMA1(0x68c)
/* WFDMA CSR */
#define MT_WFDMA_EXT_CSR_BASE 0xd7000
#define MT_WFDMA_EXT_CSR(ofs) (MT_WFDMA_EXT_CSR_BASE + (ofs))
#define MT_INT_SOURCE_CSR MT_WFDMA_EXT_CSR(0x10)
#define MT_INT_MASK_CSR MT_WFDMA_EXT_CSR(0x14)
#define MT_INT_RX_DONE_DATA BIT(16)
#define MT_INT_RX_DONE_WM BIT(0)
#define MT_INT_RX_DONE_WA BIT(1)
#define MT_INT_RX_DONE(_n) ((_n) ? BIT((_n) - 1) : BIT(16))
#define MT_INT_RX_DONE_ALL (BIT(0) | BIT(1) | BIT(16))
#define MT_INT_TX_DONE_ALL (BIT(15) | GENMASK(27, 26) | BIT(30))
#define MT_INT_MCU_CMD BIT(29)
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
/* WFDMA0 PCIE1 */
#define MT_WFDMA0_PCIE1_BASE 0xd8000
#define MT_WFDMA0_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs))
#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)
#define MT_WFDMA0_PCIE1_BUSY_ENA_RX_FIFO BIT(2)
/* WFDMA1 PCIE1 */
#define MT_WFDMA1_PCIE1_BASE 0xd9000
#define MT_WFDMA1_PCIE1(ofs) (MT_WFDMA0_PCIE1_BASE + (ofs))
#define MT_WFDMA1_PCIE1_BUSY_ENA MT_WFDMA1_PCIE1(0x13c)
#define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO0 BIT(0)
#define MT_WFDMA1_PCIE1_BUSY_ENA_TX_FIFO1 BIT(1)
#define MT_WFDMA1_PCIE1_BUSY_ENA_RX_FIFO BIT(2)
#define MT_INFRA_CFG_BASE 0xf1000
#define MT_INFRA(ofs) (MT_INFRA_CFG_BASE + (ofs))
#define MT_HIF_REMAP_L1 MT_INFRA(0x1ac)
#define MT_HIF_REMAP_L1_MASK GENMASK(15, 0)
#define MT_HIF_REMAP_L1_OFFSET GENMASK(15, 0)
#define MT_HIF_REMAP_L1_BASE GENMASK(31, 16)
#define MT_HIF_REMAP_BASE_L1 0xe0000
#define MT_HIF_REMAP_L2 MT_INFRA(0x1b0)
#define MT_HIF_REMAP_L2_MASK GENMASK(19, 0)
#define MT_HIF_REMAP_L2_OFFSET GENMASK(11, 0)
#define MT_HIF_REMAP_L2_BASE GENMASK(31, 12)
#define MT_HIF_REMAP_BASE_L2 0x00000
#define MT_TOP_BASE 0x18060000
#define MT_TOP(ofs) (MT_TOP_BASE + (ofs))
#define MT_TOP_LPCR_HOST_BAND0 MT_TOP(0x10)
#define MT_TOP_LPCR_HOST_FW_OWN BIT(0)
#define MT_TOP_LPCR_HOST_DRV_OWN BIT(1)
#define MT_TOP_MISC MT_TOP(0xf0)
#define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
#define MT_HW_BOUND 0x70010020
#define MT_HW_CHIPID 0x70010200
#define MT_HW_REV 0x70010204
#define MT_PCIE_MAC_BASE 0x74030000
#define MT_PCIE_MAC(ofs) (MT_PCIE_MAC_BASE + (ofs))
#define MT_PCIE_MAC_INT_ENABLE MT_PCIE_MAC(0x188)
/* PHY: band 0(0x83080000), band 1(0x83090000) */
#define MT_WF_PHY_BASE 0x83080000
#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))
#define MT_WF_PHY_RX_CTRL1(_phy) MT_WF_PHY(0x2004 + ((_phy) << 16))
#define MT_WF_PHY_RX_CTRL1_STSCNT_EN GENMASK(11, 9)
#endif