aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/net/wireless/mediatek
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/mediatek')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mcu.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c4
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/init.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mac.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mcu.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/dma.c50
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c66
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c161
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.c30
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.h11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c44
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.c2165
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.h144
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mmio.c67
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h66
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/regs.h87
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/soc.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/phy.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c36
24 files changed, 1955 insertions, 1018 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mcu.c b/drivers/net/wireless/mediatek/mt76/mcu.c
index 633ad948c21d..4048f446e3ee 100644
--- a/drivers/net/wireless/mediatek/mt76/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mcu.c
@@ -9,14 +9,16 @@ struct sk_buff *
mt76_mcu_msg_alloc(const void *data, int head_len,
int data_len, int tail_len)
{
+ int length = head_len + data_len + tail_len;
struct sk_buff *skb;
- skb = alloc_skb(head_len + data_len + tail_len,
- GFP_KERNEL);
+ skb = alloc_skb(length, GFP_KERNEL);
if (!skb)
return NULL;
+ memset(skb->head, 0, length);
skb_reserve(skb, head_len);
+
if (data && data_len)
skb_put_data(skb, data, data_len);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 2e57e7c6bd29..8e4759bc8f59 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -139,6 +139,8 @@ struct mt76_sw_queue {
struct mt76_mcu_ops {
int (*mcu_send_msg)(struct mt76_dev *dev, int cmd, const void *data,
int len, bool wait_resp);
+ int (*mcu_skb_send_msg)(struct mt76_dev *dev, struct sk_buff *skb,
+ int cmd, bool wait_resp);
int (*mcu_wr_rp)(struct mt76_dev *dev, u32 base,
const struct mt76_reg_pair *rp, int len);
int (*mcu_rd_rp)(struct mt76_dev *dev, u32 base,
@@ -403,7 +405,6 @@ struct mt76_mcu {
#define MCU_RESP_URB_SIZE 1024
struct mt76_usb {
struct mutex usb_ctrl_mtx;
- __le32 reg_val;
u8 *data;
u16 data_len;
@@ -589,7 +590,9 @@ enum mt76_phy_type {
#define mt76_rd_rp(dev, ...) (dev)->mt76.bus->rd_rp(&((dev)->mt76), __VA_ARGS__)
#define mt76_mcu_send_msg(dev, ...) (dev)->mt76.mcu_ops->mcu_send_msg(&((dev)->mt76), __VA_ARGS__)
+
#define __mt76_mcu_send_msg(dev, ...) (dev)->mcu_ops->mcu_send_msg((dev), __VA_ARGS__)
+#define __mt76_mcu_skb_send_msg(dev, ...) (dev)->mcu_ops->mcu_skb_send_msg((dev), __VA_ARGS__)
#define mt76_mcu_restart(dev, ...) (dev)->mt76.mcu_ops->mcu_restart(&((dev)->mt76))
#define __mt76_mcu_restart(dev, ...) (dev)->mcu_ops->mcu_restart((dev))
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
index 47c85a9fac28..cc7c788abedd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/debugfs.c
@@ -121,4 +121,8 @@ void mt7603_init_debugfs(struct mt7603_dev *dev)
mt7603_reset_read);
debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir,
mt7603_radio_read);
+ debugfs_create_u8("sensitivity_limit", 0600, dir,
+ &dev->sensitivity_limit);
+ debugfs_create_bool("dynamic_sensitivity", 0600, dir,
+ &dev->dynamic_sensitivity);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/init.c b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
index 9e40e81bcc29..f641a8b56b39 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/init.c
@@ -540,6 +540,8 @@ int mt7603_register_device(struct mt7603_dev *dev)
dev->mphy.antenna_mask = 1;
dev->slottime = 9;
+ dev->sensitivity_limit = 28;
+ dev->dynamic_sensitivity = true;
ret = mt7603_init_hardware(dev);
if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
index 8f5ca9283f7d..39b7c5d6e6cd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mac.c
@@ -1727,6 +1727,9 @@ mt7603_false_cca_check(struct mt7603_dev *dev)
int min_signal;
u32 val;
+ if (!dev->dynamic_sensitivity)
+ return;
+
val = mt76_rr(dev, MT_PHYCTRL_STAT_PD);
pd_cck = FIELD_GET(MT_PHYCTRL_STAT_PD_CCK, val);
pd_ofdm = FIELD_GET(MT_PHYCTRL_STAT_PD_OFDM, val);
@@ -1750,7 +1753,8 @@ mt7603_false_cca_check(struct mt7603_dev *dev)
min_signal -= 15;
false_cca = dev->false_cca_ofdm + dev->false_cca_cck;
- if (false_cca > 600) {
+ if (false_cca > 600 &&
+ dev->sensitivity < -100 + dev->sensitivity_limit) {
if (!dev->sensitivity)
dev->sensitivity = -92;
else
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
index b466b3ab8a2c..77985d81c447 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mcu.c
@@ -27,7 +27,6 @@ __mt7603_mcu_msg_send(struct mt7603_dev *dev, struct sk_buff *skb,
seq = ++mdev->mcu.msg_seq & 0xf;
txd = (struct mt7603_mcu_txd *)skb_push(skb, hdrlen);
- memset(txd, 0, hdrlen);
txd->len = cpu_to_le16(skb->len);
if (cmd == -MCU_CMD_FW_SCATTER)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
index ef374641fe80..7fadf094e9be 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/mt7603.h
@@ -142,7 +142,9 @@ struct mt7603_dev {
u8 ed_strict_mode;
u8 ed_strong_signal;
+ bool dynamic_sensitivity;
s8 sensitivity;
+ u8 sensitivity_limit;
u8 beacon_check;
u8 tx_hang_check;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 1bc71f5081ce..b19f208e3d54 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -101,8 +101,12 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
__le32 *rxd = (__le32 *)skb->data;
__le32 *end = (__le32 *)&skb->data[skb->len];
enum rx_pkt_type type;
+ u16 flag;
type = FIELD_GET(MT_RXD0_PKT_TYPE, le32_to_cpu(rxd[0]));
+ flag = FIELD_GET(MT_RXD0_PKT_FLAG, le32_to_cpu(rxd[0]));
+ if (type == PKT_TYPE_RX_EVENT && flag == 0x1)
+ type = PKT_TYPE_NORMAL_MCU;
switch (type) {
case PKT_TYPE_TXS:
@@ -116,6 +120,7 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
case PKT_TYPE_RX_EVENT:
mt7615_mcu_rx_event(dev, skb);
break;
+ case PKT_TYPE_NORMAL_MCU:
case PKT_TYPE_NORMAL:
if (!mt7615_mac_fill_rx(dev, skb)) {
mt76_rx(&dev->mt76, q, skb);
@@ -186,6 +191,41 @@ static void mt7622_dma_sched_init(struct mt7615_dev *dev)
mt76_wr(dev, reg + MT_DMASHDL_SCHED_SET1, 0xedcba987);
}
+static void mt7663_dma_sched_init(struct mt7615_dev *dev)
+{
+ int i;
+
+ mt76_rmw(dev, MT_DMA_SHDL(MT_DMASHDL_PKT_MAX_SIZE),
+ MT_DMASHDL_PKT_MAX_SIZE_PLE | MT_DMASHDL_PKT_MAX_SIZE_PSE,
+ FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PLE, 1) |
+ FIELD_PREP(MT_DMASHDL_PKT_MAX_SIZE_PSE, 8));
+
+ /* enable refill control group 0, 1, 2, 4, 5 */
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_REFILL), 0xffc80000);
+ /* enable group 0, 1, 2, 4, 5, 15 */
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_OPTIONAL), 0x70068037);
+
+ /* each group min quota must larger then PLE_PKT_MAX_SIZE_NUM */
+ for (i = 0; i < 5; i++)
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(i)),
+ FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x40) |
+ FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x800));
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(5)),
+ FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x40) |
+ FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x40));
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_GROUP_QUOTA(15)),
+ FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MIN, 0x20) |
+ FIELD_PREP(MT_DMASHDL_GROUP_QUOTA_MAX, 0x20));
+
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(0)), 0x42104210);
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(1)), 0x42104210);
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(2)), 0x00050005);
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_Q_MAP(3)), 0);
+ /* ALTX0 and ALTX1 QID mapping to group 5 */
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET0), 0x6012345f);
+ mt76_wr(dev, MT_DMA_SHDL(MT_DMASHDL_SCHED_SET1), 0xedcba987);
+}
+
int mt7615_dma_init(struct mt7615_dev *dev)
{
int rx_ring_size = MT7615_RX_RING_SIZE;
@@ -198,10 +238,6 @@ int mt7615_dma_init(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN |
MT_WPDMA_GLO_CFG_OMIT_TX_INFO);
- if (!is_mt7622(&dev->mt76))
- mt76_set(dev, MT_WPDMA_GLO_CFG,
- MT_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY);
-
mt76_rmw_field(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_BT_SIZE_BIT0, 0x1);
@@ -215,6 +251,9 @@ int mt7615_dma_init(struct mt7615_dev *dev)
MT_WPDMA_GLO_CFG_MULTI_DMA_EN, 0x3);
if (is_mt7615(&dev->mt76)) {
+ mt76_set(dev, MT_WPDMA_GLO_CFG,
+ MT_WPDMA_GLO_CFG_FIRST_TOKEN_ONLY);
+
mt76_wr(dev, MT_WPDMA_GLO_CFG1, 0x1);
mt76_wr(dev, MT_WPDMA_TX_PRE_CFG, 0xf0000);
mt76_wr(dev, MT_WPDMA_RX_PRE_CFG, 0xf7f0000);
@@ -271,6 +310,9 @@ int mt7615_dma_init(struct mt7615_dev *dev)
if (is_mt7622(&dev->mt76))
mt7622_dma_sched_init(dev);
+ if (is_mt7663(&dev->mt76))
+ mt7663_dma_sched_init(dev);
+
return 0;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
index 5220c18e711f..dfa9a08b896d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
@@ -91,11 +91,23 @@ static int mt7615_check_eeprom(struct mt76_dev *dev)
}
}
-static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
+static void
+mt7615_eeprom_parse_hw_band_cap(struct mt7615_dev *dev)
{
- u8 *eeprom = dev->mt76.eeprom.data;
- u8 tx_mask, max_nss;
- u32 val;
+ u8 val, *eeprom = dev->mt76.eeprom.data;
+
+ if (is_mt7663(&dev->mt76)) {
+ /* dual band */
+ dev->mt76.cap.has_2ghz = true;
+ dev->mt76.cap.has_5ghz = true;
+ return;
+ }
+
+ if (is_mt7622(&dev->mt76)) {
+ /* 2GHz only */
+ dev->mt76.cap.has_2ghz = true;
+ return;
+ }
val = FIELD_GET(MT_EE_NIC_WIFI_CONF_BAND_SEL,
eeprom[MT_EE_WIFI_CONF]);
@@ -111,18 +123,30 @@ static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
dev->mt76.cap.has_5ghz = true;
break;
}
+}
+
+static void mt7615_eeprom_parse_hw_cap(struct mt7615_dev *dev)
+{
+ u8 *eeprom = dev->mt76.eeprom.data;
+ u8 tx_mask;
+
+ mt7615_eeprom_parse_hw_band_cap(dev);
- if (is_mt7622(&dev->mt76))
- dev->mt76.cap.has_5ghz = false;
+ if (is_mt7663(&dev->mt76)) {
+ tx_mask = 2;
+ } else {
+ u8 max_nss;
+ u32 val;
- /* read tx-rx mask from eeprom */
- val = mt76_rr(dev, MT_TOP_STRAP_STA);
- max_nss = val & MT_TOP_3NSS ? 3 : 4;
+ /* read tx-rx mask from eeprom */
+ val = mt76_rr(dev, MT_TOP_STRAP_STA);
+ max_nss = val & MT_TOP_3NSS ? 3 : 4;
- tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK,
- eeprom[MT_EE_NIC_CONF_0]);
- if (!tx_mask || tx_mask > max_nss)
- tx_mask = max_nss;
+ tx_mask = FIELD_GET(MT_EE_NIC_CONF_TX_MASK,
+ eeprom[MT_EE_NIC_CONF_0]);
+ if (!tx_mask || tx_mask > max_nss)
+ tx_mask = max_nss;
+ }
dev->chainmask = BIT(tx_mask) - 1;
dev->mphy.antenna_mask = dev->chainmask;
@@ -229,6 +253,18 @@ static void mt7622_apply_cal_free_data(struct mt7615_dev *dev)
}
}
+static void mt7615_cal_free_data(struct mt7615_dev *dev)
+{
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7622:
+ mt7622_apply_cal_free_data(dev);
+ break;
+ case 0x7615:
+ mt7615_apply_cal_free_data(dev);
+ break;
+ }
+}
+
int mt7615_eeprom_init(struct mt7615_dev *dev)
{
int ret;
@@ -241,10 +277,8 @@ int mt7615_eeprom_init(struct mt7615_dev *dev)
if (ret && dev->mt76.otp.data)
memcpy(dev->mt76.eeprom.data, dev->mt76.otp.data,
MT7615_EEPROM_SIZE);
- else if (is_mt7622(&dev->mt76))
- mt7622_apply_cal_free_data(dev);
else
- mt7615_apply_cal_free_data(dev);
+ mt7615_cal_free_data(dev);
mt7615_eeprom_parse_hw_cap(dev);
memcpy(dev->mt76.macaddr, dev->mt76.eeprom.data + MT_EE_MAC_ADDR,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
index 18c7301521b7..8a2a64b7fcd3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.h
@@ -18,11 +18,13 @@ enum mt7615_eeprom_field {
MT_EE_TX1_5G_G0_TARGET_POWER = 0x098,
MT_EE_EXT_PA_2G_TARGET_POWER = 0x0f2,
MT_EE_EXT_PA_5G_TARGET_POWER = 0x0f3,
+ MT7663_EE_TX0_2G_TARGET_POWER = 0x123,
MT_EE_TX2_5G_G0_TARGET_POWER = 0x142,
MT_EE_TX3_5G_G0_TARGET_POWER = 0x16a,
MT7615_EE_MAX = 0x3bf,
MT7622_EE_MAX = 0x3db,
+ MT7663_EE_MAX = 0x400,
};
#define MT_EE_NIC_CONF_TX_MASK GENMASK(7, 4)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 889eb72ad6bd..03b1e56534d6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -4,6 +4,7 @@
* Author: Roy Luo <royluo@google.com>
* Ryder Lee <ryder.lee@mediatek.com>
* Felix Fietkau <nbd@nbd.name>
+ * Lorenzo Bianconi <lorenzo@kernel.org>
*/
#include <linux/etherdevice.h>
@@ -18,27 +19,65 @@ static void mt7615_phy_init(struct mt7615_dev *dev)
mt76_set(dev, MT_WF_PHY_WF2_RFCTRL0(1), MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN);
}
-static void mt7615_mac_init(struct mt7615_dev *dev)
+static void
+mt7615_init_mac_chain(struct mt7615_dev *dev, int chain)
{
u32 val, mask, set;
- int i;
+
+ if (!chain)
+ val = MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN;
+ else
+ val = MT_CFG_CCR_MAC_D1_1X_GC_EN | MT_CFG_CCR_MAC_D1_2X_GC_EN;
/* enable band 0/1 clk */
- mt76_set(dev, MT_CFG_CCR,
- MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN |
- MT_CFG_CCR_MAC_D1_1X_GC_EN | MT_CFG_CCR_MAC_D1_2X_GC_EN);
-
- val = mt76_rmw(dev, MT_TMAC_TRCR(0),
- MT_TMAC_TRCR_CCA_SEL | MT_TMAC_TRCR_SEC_CCA_SEL,
- FIELD_PREP(MT_TMAC_TRCR_CCA_SEL, 2) |
- FIELD_PREP(MT_TMAC_TRCR_SEC_CCA_SEL, 0));
- mt76_wr(dev, MT_TMAC_TRCR(1), val);
-
- val = MT_AGG_ACR_PKT_TIME_EN | MT_AGG_ACR_NO_BA_AR_RULE |
- FIELD_PREP(MT_AGG_ACR_CFEND_RATE, MT7615_CFEND_RATE_DEFAULT) |
- FIELD_PREP(MT_AGG_ACR_BAR_RATE, MT7615_BAR_RATE_DEFAULT);
- mt76_wr(dev, MT_AGG_ACR(0), val);
- mt76_wr(dev, MT_AGG_ACR(1), val);
+ mt76_set(dev, MT_CFG_CCR, val);
+
+ mt76_rmw(dev, MT_TMAC_TRCR(chain),
+ MT_TMAC_TRCR_CCA_SEL | MT_TMAC_TRCR_SEC_CCA_SEL,
+ FIELD_PREP(MT_TMAC_TRCR_CCA_SEL, 2) |
+ FIELD_PREP(MT_TMAC_TRCR_SEC_CCA_SEL, 0));
+
+ mt76_wr(dev, MT_AGG_ACR(chain),
+ MT_AGG_ACR_PKT_TIME_EN | MT_AGG_ACR_NO_BA_AR_RULE |
+ FIELD_PREP(MT_AGG_ACR_CFEND_RATE, MT7615_CFEND_RATE_DEFAULT) |
+ FIELD_PREP(MT_AGG_ACR_BAR_RATE, MT7615_BAR_RATE_DEFAULT));
+
+ mt76_wr(dev, MT_AGG_ARUCR(chain),
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), 2) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), 2) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), 2) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), 1));
+
+ mt76_wr(dev, MT_AGG_ARDCR(chain),
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), MT7615_RATE_RETRY - 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), MT7615_RATE_RETRY - 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), MT7615_RATE_RETRY - 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), MT7615_RATE_RETRY - 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), MT7615_RATE_RETRY - 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), MT7615_RATE_RETRY - 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7615_RATE_RETRY - 1) |
+ FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1));
+
+ mask = MT_DMA_RCFR0_MCU_RX_MGMT |
+ MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR |
+ MT_DMA_RCFR0_MCU_RX_CTL_BAR |
+ MT_DMA_RCFR0_MCU_RX_BYPASS |
+ MT_DMA_RCFR0_RX_DROPPED_UCAST |
+ MT_DMA_RCFR0_RX_DROPPED_MCAST;
+ set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) |
+ FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2);
+ mt76_rmw(dev, MT_DMA_RCFR0(chain), mask, set);
+}
+
+static void mt7615_mac_init(struct mt7615_dev *dev)
+{
+ int i;
+
+ mt7615_init_mac_chain(dev, 0);
mt76_rmw_field(dev, MT_TMAC_CTCR0,
MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
@@ -56,47 +95,11 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS,
MT_AGG_SCR_NLNAV_MID_PTEC_DIS);
- mt76_wr(dev, MT_DMA_DCR0, MT_DMA_DCR0_RX_VEC_DROP |
- FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072));
-
- val = FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), 2) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), 2) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), 2) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), 1);
- mt76_wr(dev, MT_AGG_ARUCR(0), val);
- mt76_wr(dev, MT_AGG_ARUCR(1), val);
-
- val = FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), MT7615_RATE_RETRY - 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(1), MT7615_RATE_RETRY - 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(2), MT7615_RATE_RETRY - 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(3), MT7615_RATE_RETRY - 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(4), MT7615_RATE_RETRY - 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(5), MT7615_RATE_RETRY - 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(6), MT7615_RATE_RETRY - 1) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1);
- mt76_wr(dev, MT_AGG_ARDCR(0), val);
- mt76_wr(dev, MT_AGG_ARDCR(1), val);
-
mt76_wr(dev, MT_AGG_ARCR,
- (FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) |
- MT_AGG_ARCR_RATE_DOWN_RATIO_EN |
- FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) |
- FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4)));
-
- mask = MT_DMA_RCFR0_MCU_RX_MGMT |
- MT_DMA_RCFR0_MCU_RX_CTL_NON_BAR |
- MT_DMA_RCFR0_MCU_RX_CTL_BAR |
- MT_DMA_RCFR0_MCU_RX_BYPASS |
- MT_DMA_RCFR0_RX_DROPPED_UCAST |
- MT_DMA_RCFR0_RX_DROPPED_MCAST;
- set = FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_UCAST, 2) |
- FIELD_PREP(MT_DMA_RCFR0_RX_DROPPED_MCAST, 2);
- mt76_rmw(dev, MT_DMA_RCFR0(0), mask, set);
- mt76_rmw(dev, MT_DMA_RCFR0(1), mask, set);
+ FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) |
+ MT_AGG_ARCR_RATE_DOWN_RATIO_EN |
+ FIELD_PREP(MT_AGG_ARCR_RATE_DOWN_RATIO, 1) |
+ FIELD_PREP(MT_AGG_ARCR_RATE_UP_EXTRA_TH, 4));
for (i = 0; i < MT7615_WTBL_SIZE; i++)
mt7615_mac_wtbl_update(dev, i,
@@ -104,6 +107,19 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
mt76_set(dev, MT_WF_RMAC_MIB_TIME0, MT_WF_RMAC_MIB_RXTIME_EN);
mt76_set(dev, MT_WF_RMAC_MIB_AIRTIME0, MT_WF_RMAC_MIB_RXTIME_EN);
+
+ /* disable hdr translation and hw AMSDU */
+ mt76_wr(dev, MT_DMA_DCR0,
+ FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072) |
+ MT_DMA_DCR0_RX_VEC_DROP);
+ if (is_mt7663(&dev->mt76)) {
+ mt76_wr(dev, MT_CSR(0x010), 0x8208);
+ mt76_wr(dev, 0x44064, 0x2000000);
+ mt76_wr(dev, MT_WF_AGG(0x160), 0x5c341c02);
+ mt76_wr(dev, MT_WF_AGG(0x164), 0x70708040);
+ } else {
+ mt7615_init_mac_chain(dev, 1);
+ }
}
bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev)
@@ -350,6 +366,8 @@ mt7615_cap_dbdc_enable(struct mt7615_dev *dev)
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);
}
@@ -361,6 +379,8 @@ mt7615_cap_dbdc_disable(struct mt7615_dev *dev)
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);
}
@@ -425,11 +445,9 @@ void mt7615_unregister_ext_phy(struct mt7615_dev *dev)
ieee80211_free_hw(mphy->hw);
}
-
-int mt7615_register_device(struct mt7615_dev *dev)
+void mt7615_init_device(struct mt7615_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
- int ret;
dev->phy.dev = dev;
dev->phy.mt76 = &dev->mt76.phy;
@@ -440,14 +458,6 @@ int mt7615_register_device(struct mt7615_dev *dev)
init_waitqueue_head(&dev->reset_wait);
INIT_WORK(&dev->reset_work, mt7615_mac_reset_work);
- ret = mt7622_wmac_init(dev);
- if (ret)
- return ret;
-
- ret = mt7615_init_hardware(dev);
- if (ret)
- return ret;
-
mt7615_init_wiphy(hw);
dev->mphy.sband_2g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
dev->mphy.sband_5g.sband.ht_cap.cap |= IEEE80211_HT_CAP_LDPC_CODING;
@@ -456,6 +466,13 @@ int mt7615_register_device(struct mt7615_dev *dev)
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK;
mt7615_cap_dbdc_disable(dev);
dev->phy.dfs_state = -1;
+}
+
+int mt7615_register_device(struct mt7615_dev *dev)
+{
+ int ret;
+
+ mt7615_init_device(dev);
/* init led callbacks */
if (IS_ENABLED(CONFIG_MT76_LEDS)) {
@@ -463,6 +480,14 @@ int mt7615_register_device(struct mt7615_dev *dev)
dev->mt76.led_cdev.blink_set = mt7615_led_set_blink;
}
+ ret = mt7622_wmac_init(dev);
+ if (ret)
+ return ret;
+
+ ret = mt7615_init_hardware(dev);
+ if (ret)
+ return ret;
+
ret = mt76_register_device(&dev->mt76, true, mt7615_rates,
ARRAY_SIZE(mt7615_rates));
if (ret)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 145366dbc39b..a27a6d164009 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -503,7 +503,7 @@ mt7615_mac_tx_rate_val(struct mt7615_dev *dev,
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta, int pid,
- struct ieee80211_key_conf *key)
+ struct ieee80211_key_conf *key, bool beacon)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rate = &info->control.rates[0];
@@ -541,7 +541,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
q_idx = wmm_idx * MT7615_MAX_WMM_SETS +
skb_get_queue_mapping(skb);
p_fmt = MT_TX_TYPE_CT;
- } else if (ieee80211_is_beacon(fc)) {
+ } else if (beacon) {
if (ext_phy)
q_idx = MT_LMAC_BCN1;
else
@@ -703,9 +703,9 @@ void mt7615_txp_skb_unmap(struct mt76_dev *dev,
mt7615_txp_skb_unmap_hw(dev, &txp->hw);
}
-static u32 mt7615_mac_wtbl_addr(int wcid)
+static u32 mt7615_mac_wtbl_addr(struct mt7615_dev *dev, int wcid)
{
- return MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE;
+ return MT_WTBL_BASE(dev) + wcid * MT_WTBL_ENTRY_SIZE;
}
bool mt7615_mac_wtbl_update(struct mt7615_dev *dev, int idx, u32 mask)
@@ -751,7 +751,7 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev)
list_del_init(&msta->poll_list);
spin_unlock_bh(&dev->sta_poll_lock);
- addr = mt7615_mac_wtbl_addr(msta->wcid.idx) + 19 * 4;
+ addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4;
for (i = 0; i < 4; i++, addr += 8) {
u32 tx_last = msta->airtime_ac[i];
@@ -801,7 +801,7 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
struct mt76_phy *mphy = phy->mt76;
struct ieee80211_tx_rate *ref;
int wcid = sta->wcid.idx;
- u32 addr = mt7615_mac_wtbl_addr(wcid);
+ u32 addr = mt7615_mac_wtbl_addr(dev, wcid);
bool stbc = false;
int n_rates = sta->n_rates;
u8 bw, bw_prev, bw_idx = 0;
@@ -966,7 +966,7 @@ mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
enum mt7615_cipher_type cipher,
enum set_key_cmd cmd)
{
- u32 addr = mt7615_mac_wtbl_addr(wcid->idx) + 30 * 4;
+ u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx) + 30 * 4;
u8 data[32] = {};
if (key->keylen > sizeof(data))
@@ -1004,7 +1004,7 @@ mt7615_mac_wtbl_update_pk(struct mt7615_dev *dev, struct mt76_wcid *wcid,
enum mt7615_cipher_type cipher, int keyidx,
enum set_key_cmd cmd)
{
- u32 addr = mt7615_mac_wtbl_addr(wcid->idx), w0, w1;
+ u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx), w0, w1;
if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
return -ETIMEDOUT;
@@ -1040,7 +1040,7 @@ mt7615_mac_wtbl_update_cipher(struct mt7615_dev *dev, struct mt76_wcid *wcid,
enum mt7615_cipher_type cipher,
enum set_key_cmd cmd)
{
- u32 addr = mt7615_mac_wtbl_addr(wcid->idx);
+ u32 addr = mt7615_mac_wtbl_addr(dev, wcid->idx);
if (cmd == SET_KEY) {
if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher)
@@ -1208,7 +1208,7 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
return id;
mt7615_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, sta,
- pid, key);
+ pid, key, false);
txp = txwi + MT_TXD_SIZE;
memset(txp, 0, sizeof(struct mt7615_txp_common));
@@ -1524,6 +1524,9 @@ void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable)
if (dev->scs_en == enable)
goto out;
+ if (is_mt7663(&dev->mt76))
+ goto out;
+
if (enable) {
mt76_set(dev, MT_WF_PHY_MIN_PRI_PWR(0),
MT_WF_PHY_PD_BLK(0));
@@ -1555,6 +1558,9 @@ void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy)
{
u32 rxtd;
+ if (is_mt7663(&dev->mt76))
+ return;
+
if (ext_phy)
rxtd = MT_WF_PHY_RXTD2(10);
else
@@ -1630,7 +1636,6 @@ mt7615_mac_adjust_sensitivity(struct mt7615_phy *phy,
MT_WF_PHY_PD_OFDM(ext_phy, val));
} else {
val = *sensitivity + 256;
- if (!ext_phy)
mt76_rmw(dev, MT_WF_PHY_RXTD_CCK_PD(ext_phy),
MT_WF_PHY_PD_CCK_MASK(ext_phy),
MT_WF_PHY_PD_CCK(ext_phy, val));
@@ -1823,8 +1828,9 @@ static void
mt7615_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
struct ieee80211_hw *hw = priv;
+ struct mt7615_dev *dev = mt7615_hw_dev(hw);
- mt7615_mcu_set_bcn(hw, vif, vif->bss_conf.enable_beacon);
+ mt7615_mcu_add_beacon(dev, hw, vif, vif->bss_conf.enable_beacon);
}
static void
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
index 6fa7e3dd6a3a..e0b89257db90 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
@@ -8,6 +8,7 @@
#define MT_CT_DMA_BUF_NUM 2
#define MT_RXD0_LENGTH GENMASK(15, 0)
+#define MT_RXD0_PKT_FLAG GENMASK(19, 16)
#define MT_RXD0_PKT_TYPE GENMASK(31, 29)
#define MT_RXD0_NORMAL_ETH_TYPE_OFS GENMASK(22, 16)
@@ -26,7 +27,8 @@ enum rx_pkt_type {
PKT_TYPE_RX_TMR,
PKT_TYPE_RETRIEVE,
PKT_TYPE_TXRX_NOTIFY,
- PKT_TYPE_RX_EVENT
+ PKT_TYPE_RX_EVENT,
+ PKT_TYPE_NORMAL_MCU,
};
#define MT_RXD1_NORMAL_BSSID GENMASK(31, 26)
@@ -229,8 +231,15 @@ enum tx_phy_bandwidth {
#define MT_TXD6_FIXED_BW BIT(2)
#define MT_TXD6_BW GENMASK(1, 0)
+/* MT7663 DW7 HW-AMSDU */
+#define MT_TXD7_HW_AMSDU_CAP BIT(30)
#define MT_TXD7_TYPE GENMASK(21, 20)
#define MT_TXD7_SUB_TYPE GENMASK(19, 16)
+#define MT_TXD7_SPE_IDX GENMASK(15, 11)
+#define MT_TXD7_SPE_IDX_SLE BIT(10)
+
+#define MT_TXD8_L_TYPE GENMASK(5, 4)
+#define MT_TXD8_L_SUB_TYPE GENMASK(3, 0)
#define MT_TX_RATE_STBC BIT(11)
#define MT_TX_RATE_NSS GENMASK(10, 9)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 01194ed79869..6586176c29af 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -39,13 +39,13 @@ static int mt7615_start(struct ieee80211_hw *hw)
running = mt7615_dev_running(dev);
if (!running) {
- mt7615_mcu_ctrl_pm_state(dev, 0, 0);
+ mt7615_mcu_set_pm(dev, 0, 0);
mt7615_mcu_set_mac_enable(dev, 0, true);
mt7615_mac_enable_nf(dev, 0);
}
if (phy != &dev->phy) {
- mt7615_mcu_ctrl_pm_state(dev, 1, 0);
+ mt7615_mcu_set_pm(dev, 1, 0);
mt7615_mcu_set_mac_enable(dev, 1, true);
mt7615_mac_enable_nf(dev, 1);
}
@@ -78,14 +78,14 @@ static void mt7615_stop(struct ieee80211_hw *hw)
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
if (phy != &dev->phy) {
- mt7615_mcu_ctrl_pm_state(dev, 1, 1);
+ mt7615_mcu_set_pm(dev, 1, 1);
mt7615_mcu_set_mac_enable(dev, 1, false);
}
if (!mt7615_dev_running(dev)) {
cancel_delayed_work_sync(&dev->mt76.mac_work);
- mt7615_mcu_ctrl_pm_state(dev, 0, 1);
+ mt7615_mcu_set_pm(dev, 0, 1);
mt7615_mcu_set_mac_enable(dev, 0, false);
}
@@ -157,7 +157,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
else
mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS;
- ret = mt7615_mcu_set_dev_info(dev, vif, 1);
+ ret = mt7615_mcu_add_dev_info(dev, vif, true);
if (ret)
goto out;
@@ -200,7 +200,7 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
/* TODO: disable beacon for the bss */
- mt7615_mcu_set_dev_info(dev, vif, 0);
+ mt7615_mcu_add_dev_info(dev, vif, false);
rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
if (vif->txq)
@@ -412,7 +412,7 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
mutex_lock(&dev->mt76.mutex);
if (changed & BSS_CHANGED_ASSOC)
- mt7615_mcu_set_bss_info(dev, vif, info->assoc);
+ mt7615_mcu_add_bss_info(dev, vif, info->assoc);
if (changed & BSS_CHANGED_ERP_SLOT) {
int slottime = info->use_short_slot ? 9 : 20;
@@ -425,13 +425,13 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
}
if (changed & BSS_CHANGED_BEACON_ENABLED) {
- mt7615_mcu_set_bss_info(dev, vif, info->enable_beacon);
- mt7615_mcu_set_bmc(dev, vif, info->enable_beacon);
+ mt7615_mcu_add_bss_info(dev, vif, info->enable_beacon);
+ mt7615_mcu_sta_add(dev, vif, NULL, info->enable_beacon);
}
if (changed & (BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED))
- mt7615_mcu_set_bcn(hw, vif, info->enable_beacon);
+ mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon);
mutex_unlock(&dev->mt76.mutex);
}
@@ -444,7 +444,7 @@ mt7615_channel_switch_beacon(struct ieee80211_hw *hw,
struct mt7615_dev *dev = mt7615_hw_dev(hw);
mutex_lock(&dev->mt76.mutex);
- mt7615_mcu_set_bcn(hw, vif, true);
+ mt7615_mcu_add_beacon(dev, hw, vif, true);
mutex_unlock(&dev->mt76.mutex);
}
@@ -469,7 +469,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
mt7615_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
- mt7615_mcu_set_sta(dev, vif, sta, 1);
+ mt7615_mcu_sta_add(dev, vif, sta, true);
return 0;
}
@@ -480,7 +480,7 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
- mt7615_mcu_set_sta(dev, vif, sta, 0);
+ mt7615_mcu_sta_add(dev, vif, sta, false);
mt7615_mac_wtbl_update(dev, msta->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@@ -578,21 +578,21 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
params->buf_size);
- mt7615_mcu_set_rx_ba(dev, params, 1);
+ mt7615_mcu_add_rx_ba(dev, params, true);
break;
case IEEE80211_AMPDU_RX_STOP:
mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
- mt7615_mcu_set_rx_ba(dev, params, 0);
+ mt7615_mcu_add_rx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
mtxq->aggr = true;
mtxq->send_bar = false;
- mt7615_mcu_set_tx_ba(dev, params, 1);
+ mt7615_mcu_add_tx_ba(dev, params, true);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
- mt7615_mcu_set_tx_ba(dev, params, 0);
+ mt7615_mcu_add_tx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_START:
mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
@@ -600,7 +600,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
- mt7615_mcu_set_tx_ba(dev, params, 0);
+ mt7615_mcu_add_tx_ba(dev, params, false);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
@@ -686,7 +686,13 @@ mt7615_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
mutex_lock(&dev->mt76.mutex);
phy->mt76->antenna_mask = tx_ant;
- phy->chainmask = ext_phy ? tx_ant << 2 : 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);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index 7218a3041ead..610cfa918c7b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -29,8 +29,37 @@ struct mt7615_fw_trailer {
__le32 len;
} __packed;
+#define FW_V3_COMMON_TAILER_SIZE 36
+#define FW_V3_REGION_TAILER_SIZE 40
+#define FW_START_OVERRIDE BIT(0)
+#define FW_START_DLYCAL BIT(1)
+#define FW_START_WORKING_PDA_CR4 BIT(2)
+
+struct mt7663_fw_trailer {
+ u8 chip_id;
+ u8 eco_code;
+ u8 n_region;
+ u8 format_ver;
+ u8 format_flag;
+ u8 reserv[2];
+ char fw_ver[10];
+ char build_date[15];
+ __le32 crc;
+} __packed;
+
+struct mt7663_fw_buf {
+ __le32 crc;
+ __le32 d_img_size;
+ __le32 block_size;
+ u8 rsv[4];
+ __le32 img_dest_addr;
+ __le32 img_size;
+ u8 feature_set;
+};
+
#define MT7615_PATCH_ADDRESS 0x80000
#define MT7622_PATCH_ADDRESS 0x9c000
+#define MT7663_PATCH_ADDRESS 0xdc000
#define N9_REGION_NUM 2
#define CR4_REGION_NUM 1
@@ -44,29 +73,32 @@ struct mt7615_fw_trailer {
#define DL_MODE_KEY_IDX GENMASK(2, 1)
#define DL_MODE_RESET_SEC_IV BIT(3)
#define DL_MODE_WORKING_PDA_CR4 BIT(4)
+#define DL_MODE_VALID_RAM_ENTRY BIT(5)
#define DL_MODE_NEED_RSP BIT(31)
#define FW_START_OVERRIDE BIT(0)
#define FW_START_WORKING_PDA_CR4 BIT(2)
-static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
- int cmd, int *wait_seq)
+void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
+ int cmd, int *wait_seq)
{
+ int txd_len, mcu_cmd = cmd & MCU_CMD_MASK;
+ struct mt7615_uni_txd *uni_txd;
struct mt7615_mcu_txd *mcu_txd;
u8 seq, q_idx, pkt_fmt;
- enum mt76_txq_id qid;
- u32 val;
__le32 *txd;
+ u32 val;
seq = ++dev->mt76.mcu.msg_seq & 0xf;
if (!seq)
seq = ++dev->mt76.mcu.msg_seq & 0xf;
+ if (wait_seq)
+ *wait_seq = seq;
- mcu_txd = (struct mt7615_mcu_txd *)skb_push(skb,
- sizeof(struct mt7615_mcu_txd));
- memset(mcu_txd, 0, sizeof(struct mt7615_mcu_txd));
+ txd_len = cmd & MCU_UNI_PREFIX ? sizeof(*uni_txd) : sizeof(*mcu_txd);
+ txd = (__le32 *)skb_push(skb, txd_len);
- if (cmd != -MCU_CMD_FW_SCATTER) {
+ if (cmd != MCU_CMD_FW_SCATTER) {
q_idx = MT_TX_MCU_PORT_RX_Q0;
pkt_fmt = MT_TX_TYPE_CMD;
} else {
@@ -74,8 +106,6 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
pkt_fmt = MT_TX_TYPE_FW;
}
- txd = mcu_txd->txd;
-
val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len) |
FIELD_PREP(MT_TXD0_P_IDX, MT_TX_PORT_IDX_MCU) |
FIELD_PREP(MT_TXD0_Q_IDX, q_idx);
@@ -86,25 +116,42 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
FIELD_PREP(MT_TXD1_PKT_FMT, pkt_fmt);
txd[1] = cpu_to_le32(val);
+ if (cmd & MCU_UNI_PREFIX) {
+ uni_txd = (struct mt7615_uni_txd *)txd;
+ uni_txd->len = cpu_to_le16(skb->len - sizeof(uni_txd->txd));
+ uni_txd->option = MCU_CMD_UNI_EXT_ACK;
+ uni_txd->cid = cpu_to_le16(mcu_cmd);
+ uni_txd->s2d_index = MCU_S2D_H2N;
+ uni_txd->pkt_type = MCU_PKT_ID;
+ uni_txd->seq = seq;
+
+ return;
+ }
+
+ mcu_txd = (struct mt7615_mcu_txd *)txd;
mcu_txd->len = cpu_to_le16(skb->len - sizeof(mcu_txd->txd));
mcu_txd->pq_id = cpu_to_le16(MCU_PQ_ID(MT_TX_PORT_IDX_MCU, q_idx));
+ mcu_txd->s2d_index = MCU_S2D_H2N;
mcu_txd->pkt_type = MCU_PKT_ID;
mcu_txd->seq = seq;
- if (cmd < 0) {
+ if (cmd & MCU_FW_PREFIX) {
mcu_txd->set_query = MCU_Q_NA;
- mcu_txd->cid = -cmd;
+ mcu_txd->cid = mcu_cmd;
} else {
mcu_txd->cid = MCU_CMD_EXT_CID;
mcu_txd->set_query = MCU_Q_SET;
mcu_txd->ext_cid = cmd;
mcu_txd->ext_cid_ack = 1;
}
- mcu_txd->s2d_index = MCU_S2D_H2N;
+}
- if (wait_seq)
- *wait_seq = seq;
+static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
+ int cmd, int *wait_seq)
+{
+ enum mt76_txq_id qid;
+ mt7615_mcu_fill_msg(dev, skb, cmd, wait_seq);
if (test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
qid = MT_TXQ_MCU;
else
@@ -124,7 +171,7 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd,
return -EAGAIN;
switch (cmd) {
- case -MCU_CMD_PATCH_SEM_CONTROL:
+ case MCU_CMD_PATCH_SEM_CONTROL:
skb_pull(skb, sizeof(*rxd) - 4);
ret = *skb->data;
break;
@@ -140,32 +187,18 @@ mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd,
return ret;
}
-static int
-mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
- int len, bool wait_resp)
+int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq)
{
- struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
unsigned long expires = jiffies + 20 * HZ;
struct sk_buff *skb;
- int ret, seq;
-
- skb = mt7615_mcu_msg_alloc(data, len);
- if (!skb)
- return -ENOMEM;
-
- mutex_lock(&mdev->mcu.mutex);
-
- ret = __mt7615_mcu_msg_send(dev, skb, cmd, &seq);
- if (ret)
- goto out;
+ int ret = 0;
- while (wait_resp) {
- skb = mt76_mcu_get_response(mdev, expires);
+ while (true) {
+ skb = mt76_mcu_get_response(&dev->mt76, expires);
if (!skb) {
- dev_err(mdev->dev, "Message %d (seq %d) timeout\n",
- cmd, seq);
- ret = -ETIMEDOUT;
- break;
+ dev_err(dev->mt76.dev, "Message %ld (seq %d) timeout\n",
+ cmd & MCU_CMD_MASK, seq);
+ return -ETIMEDOUT;
}
ret = mt7615_mcu_parse_response(dev, cmd, skb, seq);
@@ -173,12 +206,44 @@ mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
break;
}
+ return ret;
+}
+
+static int
+mt7615_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
+ int cmd, bool wait_resp)
+{
+ struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+ int ret, seq;
+
+ mutex_lock(&mdev->mcu.mutex);
+
+ ret = __mt7615_mcu_msg_send(dev, skb, cmd, &seq);
+ if (ret)
+ goto out;
+
+ if (wait_resp)
+ ret = mt7615_mcu_wait_response(dev, cmd, seq);
+
out:
mutex_unlock(&mdev->mcu.mutex);
return ret;
}
+static int
+mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
+ int len, bool wait_resp)
+{
+ struct sk_buff *skb;
+
+ skb = mt7615_mcu_msg_alloc(data, len);
+ if (!skb)
+ return -ENOMEM;
+
+ return __mt76_mcu_skb_send_msg(mdev, skb, cmd, wait_resp);
+}
+
static void
mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
{
@@ -287,10 +352,1095 @@ static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr,
.mode = cpu_to_le32(mode),
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_TARGET_ADDRESS_LEN_REQ,
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_TARGET_ADDRESS_LEN_REQ,
+ &req, sizeof(req), true);
+}
+
+static int
+mt7615_mcu_add_dev(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct {
+ struct req_hdr {
+ u8 omac_idx;
+ u8 band_idx;
+ __le16 tlv_num;
+ u8 is_tlv_append;
+ u8 rsv[3];
+ } __packed hdr;
+ struct req_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 active;
+ u8 band_idx;
+ u8 omac_addr[ETH_ALEN];
+ } __packed tlv;
+ } data = {
+ .hdr = {
+ .omac_idx = mvif->omac_idx,
+ .band_idx = mvif->band_idx,
+ .tlv_num = cpu_to_le16(1),
+ .is_tlv_append = 1,
+ },
+ .tlv = {
+ .tag = cpu_to_le16(DEV_INFO_ACTIVE),
+ .len = cpu_to_le16(sizeof(struct req_tlv)),
+ .active = enable,
+ .band_idx = mvif->band_idx,
+ },
+ };
+
+ memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE,
+ &data, sizeof(data), true);
+}
+
+static int
+mt7615_mcu_add_beacon_offload(struct mt7615_dev *dev,
+ struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+ struct ieee80211_mutable_offsets offs;
+ struct ieee80211_tx_info *info;
+ struct req {
+ u8 omac_idx;
+ u8 enable;
+ u8 wlan_idx;
+ u8 band_idx;
+ u8 pkt_type;
+ u8 need_pre_tbtt_int;
+ __le16 csa_ie_pos;
+ __le16 pkt_len;
+ __le16 tim_ie_pos;
+ u8 pkt[512];
+ u8 csa_cnt;
+ /* bss color change */
+ u8 bcc_cnt;
+ __le16 bcc_ie_pos;
+ } __packed req = {
+ .omac_idx = mvif->omac_idx,
+ .enable = enable,
+ .wlan_idx = wcid->idx,
+ .band_idx = mvif->band_idx,
+ };
+ struct sk_buff *skb;
+
+ skb = ieee80211_beacon_get_template(hw, vif, &offs);
+ if (!skb)
+ return -EINVAL;
+
+ if (skb->len > 512 - MT_TXD_SIZE) {
+ dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ if (mvif->band_idx) {
+ info = IEEE80211_SKB_CB(skb);
+ info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
+ }
+
+ mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL,
+ 0, NULL, true);
+ memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len);
+ req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
+ req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
+ if (offs.csa_counter_offs[0]) {
+ u16 csa_offs;
+
+ csa_offs = MT_TXD_SIZE + offs.csa_counter_offs[0] - 4;
+ req.csa_ie_pos = cpu_to_le16(csa_offs);
+ req.csa_cnt = skb->data[offs.csa_counter_offs[0]];
+ }
+ dev_kfree_skb(skb);
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD,
+ &req, sizeof(req), true);
+}
+
+static int
+mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
+{
+#define ENTER_PM_STATE 1
+#define EXIT_PM_STATE 2
+ struct {
+ u8 pm_number;
+ u8 pm_state;
+ u8 bssid[ETH_ALEN];
+ u8 dtim_period;
+ u8 wlan_idx;
+ __le16 bcn_interval;
+ __le32 aid;
+ __le32 rx_filter;
+ u8 band_idx;
+ u8 rsv[3];
+ __le32 feature;
+ u8 omac_idx;
+ u8 wmm_idx;
+ u8 bcn_loss_cnt;
+ u8 bcn_sp_duration;
+ } __packed req = {
+ .pm_number = 5,
+ .pm_state = state ? ENTER_PM_STATE : EXIT_PM_STATE,
+ .band_idx = band,
+ };
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL,
&req, sizeof(req), true);
}
+static struct sk_buff *
+mt7615_mcu_alloc_sta_req(struct mt7615_vif *mvif, struct mt7615_sta *msta)
+{
+ struct sta_req_hdr hdr = {
+ .bss_idx = mvif->idx,
+ .wlan_idx = msta ? msta->wcid.idx : 0,
+ .muar_idx = msta ? mvif->omac_idx : 0,
+ .is_tlv_append = 1,
+ };
+ struct sk_buff *skb;
+
+ skb = mt7615_mcu_msg_alloc(NULL, MT7615_STA_UPDATE_MAX_SIZE);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ skb_put_data(skb, &hdr, sizeof(hdr));
+
+ return skb;
+}
+
+static struct wtbl_req_hdr *
+mt7615_mcu_alloc_wtbl_req(struct mt7615_sta *msta, int cmd,
+ void *sta_wtbl, struct sk_buff **skb)
+{
+ struct tlv *sta_hdr = sta_wtbl;
+ struct wtbl_req_hdr hdr = {
+ .wlan_idx = msta->wcid.idx,
+ .operation = cmd,
+ };
+ struct sk_buff *nskb = *skb;
+
+ if (!nskb) {
+ nskb = mt7615_mcu_msg_alloc(NULL, MT7615_WTBL_UPDATE_BA_SIZE);
+ if (!nskb)
+ return ERR_PTR(-ENOMEM);
+
+ *skb = nskb;
+ }
+
+ if (sta_hdr)
+ sta_hdr->len = cpu_to_le16(sizeof(hdr));
+
+ return skb_put_data(nskb, &hdr, sizeof(hdr));
+}
+
+static struct tlv *
+mt7615_mcu_add_nested_tlv(struct sk_buff *skb, int tag, int len,
+ void *sta_ntlv, void *sta_wtbl)
+{
+ struct sta_ntlv_hdr *ntlv_hdr = sta_ntlv;
+ struct tlv *sta_hdr = sta_wtbl;
+ struct tlv *ptlv, tlv = {
+ .tag = cpu_to_le16(tag),
+ .len = cpu_to_le16(len),
+ };
+ u16 ntlv;
+
+ ptlv = skb_put(skb, len);
+ memcpy(ptlv, &tlv, sizeof(tlv));
+
+ ntlv = le16_to_cpu(ntlv_hdr->tlv_num);
+ ntlv_hdr->tlv_num = cpu_to_le16(ntlv + 1);
+
+ if (sta_hdr) {
+ u16 size = le16_to_cpu(sta_hdr->len);
+
+ sta_hdr->len = cpu_to_le16(size + len);
+ }
+
+ return ptlv;
+}
+
+static struct tlv *
+mt7615_mcu_add_tlv(struct sk_buff *skb, int tag, int len)
+{
+ return mt7615_mcu_add_nested_tlv(skb, tag, len, skb->data, NULL);
+}
+
+static int
+mt7615_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct bss_info_basic *bss;
+ u8 wlan_idx = mvif->sta.wcid.idx;
+ u32 type = NETWORK_INFRA;
+ struct tlv *tlv;
+
+ tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_BASIC, sizeof(*bss));
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ break;
+ case NL80211_IFTYPE_STATION:
+ /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
+ if (enable) {
+ struct ieee80211_sta *sta;
+ struct mt7615_sta *msta;
+
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+ if (!sta) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ msta = (struct mt7615_sta *)sta->drv_priv;
+ wlan_idx = msta->wcid.idx;
+ rcu_read_unlock();
+ }
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ type = NETWORK_IBSS;
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ bss = (struct bss_info_basic *)tlv;
+ memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);
+ bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
+ bss->network_type = cpu_to_le32(type);
+ bss->dtim_period = vif->bss_conf.dtim_period;
+ bss->bmc_tx_wlan_idx = wlan_idx;
+ bss->wmm_idx = mvif->wmm_idx;
+ bss->active = enable;
+
+ return 0;
+}
+
+static void
+mt7615_mcu_bss_omac_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct bss_info_omac *omac;
+ struct tlv *tlv;
+ u32 type = 0;
+ u8 idx;
+
+ tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_OMAC, sizeof(*omac));
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ type = CONNECTION_INFRA_AP;
+ break;
+ case NL80211_IFTYPE_STATION:
+ type = CONNECTION_INFRA_STA;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ type = CONNECTION_IBSS_ADHOC;
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ omac = (struct bss_info_omac *)tlv;
+ idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;
+ omac->conn_type = cpu_to_le32(type);
+ omac->omac_idx = mvif->omac_idx;
+ omac->band_idx = mvif->band_idx;
+ omac->hw_bss_idx = idx;
+}
+
+/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */
+#define BCN_TX_ESTIMATE_TIME (4096 + 20)
+static void
+mt7615_mcu_bss_ext_tlv(struct sk_buff *skb, struct mt7615_vif *mvif)
+{
+ struct bss_info_ext_bss *ext;
+ int ext_bss_idx, tsf_offset;
+ struct tlv *tlv;
+
+ ext_bss_idx = mvif->omac_idx - EXT_BSSID_START;
+ if (ext_bss_idx < 0)
+ return;
+
+ tlv = mt7615_mcu_add_tlv(skb, BSS_INFO_EXT_BSS, sizeof(*ext));
+
+ ext = (struct bss_info_ext_bss *)tlv;
+ tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME;
+ ext->mbss_tsf_offset = cpu_to_le32(tsf_offset);
+}
+
+static void
+mt7615_mcu_sta_ba_tlv(struct sk_buff *skb,
+ struct ieee80211_ampdu_params *params,
+ bool enable, bool tx)
+{
+ struct sta_rec_ba *ba;
+ struct tlv *tlv;
+
+ tlv = mt7615_mcu_add_tlv(skb, STA_REC_BA, sizeof(*ba));
+
+ ba = (struct sta_rec_ba *)tlv;
+ ba->ba_type = tx ? MT_BA_TYPE_ORIGINATOR : MT_BA_TYPE_RECIPIENT,
+ ba->winsize = cpu_to_le16(params->buf_size);
+ ba->ssn = cpu_to_le16(params->ssn);
+ ba->ba_en = enable << params->tid;
+ ba->amsdu = params->amsdu;
+ ba->tid = params->tid;
+}
+
+static void
+mt7615_mcu_sta_basic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enable)
+{
+ struct sta_rec_basic *basic;
+ struct tlv *tlv;
+
+ tlv = mt7615_mcu_add_tlv(skb, STA_REC_BASIC, sizeof(*basic));
+
+ basic = (struct sta_rec_basic *)tlv;
+ basic->extra_info = cpu_to_le16(EXTRA_INFO_VER);
+
+ if (enable) {
+ basic->extra_info |= cpu_to_le16(EXTRA_INFO_NEW);
+ basic->conn_state = CONN_STATE_PORT_SECURE;
+ } else {
+ basic->conn_state = CONN_STATE_DISCONNECT;
+ }
+
+ if (!sta) {
+ basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC);
+ eth_broadcast_addr(basic->peer_addr);
+ return;
+ }
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ basic->conn_type = cpu_to_le32(CONNECTION_INFRA_STA);
+ break;
+ case NL80211_IFTYPE_STATION:
+ basic->conn_type = cpu_to_le32(CONNECTION_INFRA_AP);
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ basic->conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ memcpy(basic->peer_addr, sta->addr, ETH_ALEN);
+ basic->aid = cpu_to_le16(sta->aid);
+ basic->qos = sta->wme;
+}
+
+static void
+mt7615_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+{
+ struct tlv *tlv;
+
+ if (sta->ht_cap.ht_supported) {
+ struct sta_rec_ht *ht;
+
+ tlv = mt7615_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
+ ht = (struct sta_rec_ht *)tlv;
+ ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
+ }
+ if (sta->vht_cap.vht_supported) {
+ struct sta_rec_vht *vht;
+
+ tlv = mt7615_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
+ vht = (struct sta_rec_vht *)tlv;
+ vht->vht_rx_mcs_map = sta->vht_cap.vht_mcs.rx_mcs_map;
+ vht->vht_tx_mcs_map = sta->vht_cap.vht_mcs.tx_mcs_map;
+ vht->vht_cap = cpu_to_le32(sta->vht_cap.cap);
+ }
+}
+
+static void
+mt7615_mcu_wtbl_ba_tlv(struct sk_buff *skb,
+ struct ieee80211_ampdu_params *params,
+ bool enable, bool tx, void *sta_wtbl,
+ void *wtbl_tlv)
+{
+ struct wtbl_ba *ba;
+ struct tlv *tlv;
+
+ tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_BA, sizeof(*ba),
+ wtbl_tlv, sta_wtbl);
+
+ ba = (struct wtbl_ba *)tlv;
+ ba->tid = params->tid;
+
+ if (tx) {
+ ba->ba_type = MT_BA_TYPE_ORIGINATOR;
+ ba->sn = enable ? cpu_to_le16(params->ssn) : 0;
+ ba->ba_winsize = cpu_to_le16(params->buf_size);
+ ba->ba_en = enable;
+ } else {
+ memcpy(ba->peer_addr, params->sta->addr, ETH_ALEN);
+ ba->ba_type = MT_BA_TYPE_RECIPIENT;
+ ba->rst_ba_tid = params->tid;
+ ba->rst_ba_sel = RST_BA_MAC_TID_MATCH;
+ ba->rst_ba_sb = 1;
+ }
+
+ if (enable && tx) {
+ u8 ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 };
+ int i;
+
+ for (i = 7; i > 0; i--) {
+ if (params->buf_size >= ba_range[i])
+ break;
+ }
+ ba->ba_winsize_idx = i;
+ }
+}
+
+static void
+mt7615_mcu_wtbl_generic_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, void *sta_wtbl,
+ void *wtbl_tlv)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct wtbl_generic *generic;
+ struct wtbl_rx *rx;
+ struct tlv *tlv;
+
+ tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_GENERIC, sizeof(*generic),
+ wtbl_tlv, sta_wtbl);
+
+ generic = (struct wtbl_generic *)tlv;
+
+ if (sta) {
+ memcpy(generic->peer_addr, sta->addr, ETH_ALEN);
+ generic->partial_aid = cpu_to_le16(sta->aid);
+ generic->muar_idx = mvif->omac_idx;
+ generic->qos = sta->wme;
+ } else {
+ eth_broadcast_addr(generic->peer_addr);
+ generic->muar_idx = 0xe;
+ }
+
+ tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_RX, sizeof(*rx),
+ wtbl_tlv, sta_wtbl);
+
+ rx = (struct wtbl_rx *)tlv;
+ rx->rca1 = sta ? vif->type != NL80211_IFTYPE_AP : 1;
+ rx->rca2 = 1;
+ rx->rv = 1;
+}
+
+static void
+mt7615_mcu_wtbl_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
+ void *sta_wtbl, void *wtbl_tlv)
+{
+ struct tlv *tlv;
+ u32 flags = 0;
+
+ if (sta->ht_cap.ht_supported) {
+ struct wtbl_ht *ht;
+
+ tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_HT, sizeof(*ht),
+ wtbl_tlv, sta_wtbl);
+ ht = (struct wtbl_ht *)tlv;
+ ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING;
+ ht->af = sta->ht_cap.ampdu_factor;
+ ht->mm = sta->ht_cap.ampdu_density;
+ ht->ht = 1;
+
+ if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
+ flags |= MT_WTBL_W5_SHORT_GI_20;
+ if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+ flags |= MT_WTBL_W5_SHORT_GI_40;
+ }
+
+ if (sta->vht_cap.vht_supported) {
+ struct wtbl_vht *vht;
+
+ tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_VHT, sizeof(*vht),
+ wtbl_tlv, sta_wtbl);
+ vht = (struct wtbl_vht *)tlv;
+ vht->ldpc = sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC,
+ vht->vht = 1;
+
+ if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
+ flags |= MT_WTBL_W5_SHORT_GI_80;
+ if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
+ flags |= MT_WTBL_W5_SHORT_GI_160;
+ }
+
+ /* wtbl smps */
+ if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) {
+ struct wtbl_smps *smps;
+
+ tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_SMPS, sizeof(*smps),
+ wtbl_tlv, sta_wtbl);
+ smps = (struct wtbl_smps *)tlv;
+ smps->smps = 1;
+ }
+
+ if (sta->ht_cap.ht_supported) {
+ /* sgi */
+ u32 msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 |
+ MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160;
+ struct wtbl_raw *raw;
+
+ tlv = mt7615_mcu_add_nested_tlv(skb, WTBL_RAW_DATA,
+ sizeof(*raw), wtbl_tlv,
+ sta_wtbl);
+ raw = (struct wtbl_raw *)tlv;
+ raw->val = cpu_to_le32(flags);
+ raw->msk = cpu_to_le32(~msk);
+ raw->wtbl_idx = 1;
+ raw->dw = 5;
+ }
+}
+
+static int
+mt7615_mcu_add_bss(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct sk_buff *skb;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, NULL);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ if (enable)
+ mt7615_mcu_bss_omac_tlv(skb, vif);
+
+ mt7615_mcu_bss_basic_tlv(skb, vif, enable);
+
+ if (enable && mvif->omac_idx > EXT_BSSID_START)
+ mt7615_mcu_bss_ext_tlv(skb, mvif);
+
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_BSS_INFO_UPDATE, true);
+}
+
+static int
+mt7615_mcu_wtbl_tx_ba(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable)
+{
+ struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
+ struct mt7615_vif *mvif = msta->vif;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct sk_buff *skb = NULL;
+ int err;
+
+ wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, NULL, &skb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ mt7615_mcu_wtbl_ba_tlv(skb, params, enable, true, NULL, wtbl_hdr);
+
+ err = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_WTBL_UPDATE, true);
+ if (err < 0)
+ return err;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7615_mcu_sta_ba_tlv(skb, params, enable, true);
+
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
+}
+
+static int
+mt7615_mcu_wtbl_rx_ba(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable)
+{
+ struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
+ struct mt7615_vif *mvif = msta->vif;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct sk_buff *skb;
+ int err;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7615_mcu_sta_ba_tlv(skb, params, enable, false);
+
+ err = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
+ if (err < 0 || !enable)
+ return err;
+
+ skb = NULL;
+ wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, NULL, &skb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ mt7615_mcu_wtbl_ba_tlv(skb, params, enable, false, NULL, wtbl_hdr);
+
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_WTBL_UPDATE, true);
+}
+
+static int
+mt7615_mcu_wtbl_sta_add(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct sk_buff *skb, *sskb, *wskb = NULL;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct mt7615_sta *msta;
+ int cmd, err;
+
+ msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta;
+
+ sskb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(sskb))
+ return PTR_ERR(sskb);
+
+ mt7615_mcu_sta_basic_tlv(sskb, vif, sta, enable);
+ if (enable && sta)
+ mt7615_mcu_sta_ht_tlv(sskb, sta);
+
+ wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_RESET_AND_SET, NULL,
+ &wskb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ if (enable) {
+ mt7615_mcu_wtbl_generic_tlv(wskb, vif, sta, NULL, wtbl_hdr);
+ if (sta)
+ mt7615_mcu_wtbl_ht_tlv(wskb, sta, NULL, wtbl_hdr);
+ }
+
+ cmd = enable ? MCU_EXT_CMD_WTBL_UPDATE : MCU_EXT_CMD_STA_REC_UPDATE;
+ skb = enable ? wskb : sskb;
+
+ err = __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
+ if (err < 0)
+ return err;
+
+ cmd = enable ? MCU_EXT_CMD_STA_REC_UPDATE : MCU_EXT_CMD_WTBL_UPDATE;
+ skb = enable ? sskb : wskb;
+
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
+}
+
+static const struct mt7615_mcu_ops wtbl_update_ops = {
+ .add_beacon_offload = mt7615_mcu_add_beacon_offload,
+ .set_pm_state = mt7615_mcu_ctrl_pm_state,
+ .add_dev_info = mt7615_mcu_add_dev,
+ .add_bss_info = mt7615_mcu_add_bss,
+ .add_tx_ba = mt7615_mcu_wtbl_tx_ba,
+ .add_rx_ba = mt7615_mcu_wtbl_rx_ba,
+ .sta_add = mt7615_mcu_wtbl_sta_add,
+};
+
+static int
+mt7615_mcu_sta_ba(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable, bool tx)
+{
+ struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
+ struct mt7615_vif *mvif = msta->vif;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct tlv *sta_wtbl;
+ struct sk_buff *skb;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7615_mcu_sta_ba_tlv(skb, params, enable, tx);
+
+ sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
+
+ wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, sta_wtbl, &skb);
+ mt7615_mcu_wtbl_ba_tlv(skb, params, enable, tx, sta_wtbl, wtbl_hdr);
+
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_STA_REC_UPDATE, true);
+}
+
+static int
+mt7615_mcu_sta_tx_ba(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable)
+{
+ return mt7615_mcu_sta_ba(dev, params, enable, true);
+}
+
+static int
+mt7615_mcu_sta_rx_ba(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable)
+{
+ return mt7615_mcu_sta_ba(dev, params, enable, false);
+}
+
+static int
+mt7615_mcu_add_sta_cmd(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enable, int cmd)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct mt7615_sta *msta;
+ struct tlv *sta_wtbl;
+ struct sk_buff *skb;
+
+ msta = sta ? (struct mt7615_sta *)sta->drv_priv : &mvif->sta;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7615_mcu_sta_basic_tlv(skb, vif, sta, enable);
+ if (enable && sta)
+ mt7615_mcu_sta_ht_tlv(skb, sta);
+
+ sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
+
+ wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_RESET_AND_SET,
+ sta_wtbl, &skb);
+ if (enable) {
+ mt7615_mcu_wtbl_generic_tlv(skb, vif, sta, sta_wtbl, wtbl_hdr);
+ if (sta)
+ mt7615_mcu_wtbl_ht_tlv(skb, sta, sta_wtbl, wtbl_hdr);
+ }
+
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb, cmd, true);
+}
+
+static int
+mt7615_mcu_add_sta(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enable)
+{
+ return mt7615_mcu_add_sta_cmd(dev, vif, sta, enable,
+ MCU_EXT_CMD_STA_REC_UPDATE);
+}
+
+static const struct mt7615_mcu_ops sta_update_ops = {
+ .add_beacon_offload = mt7615_mcu_add_beacon_offload,
+ .set_pm_state = mt7615_mcu_ctrl_pm_state,
+ .add_dev_info = mt7615_mcu_add_dev,
+ .add_bss_info = mt7615_mcu_add_bss,
+ .add_tx_ba = mt7615_mcu_sta_tx_ba,
+ .add_rx_ba = mt7615_mcu_sta_rx_ba,
+ .sta_add = mt7615_mcu_add_sta,
+};
+
+static int
+mt7615_mcu_uni_add_dev(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif, bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct {
+ struct req_hdr {
+ u8 omac_idx;
+ u8 band_idx;
+ __le16 pad;
+ } __packed hdr;
+ struct req_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 active;
+ u8 pad;
+ u8 omac_addr[ETH_ALEN];
+ } __packed tlv;
+ } data = {
+ .hdr = {
+ .omac_idx = mvif->omac_idx,
+ .band_idx = mvif->band_idx,
+ },
+ .tlv = {
+ .tag = cpu_to_le16(DEV_INFO_ACTIVE),
+ .len = cpu_to_le16(sizeof(struct req_tlv)),
+ .active = enable,
+ },
+ };
+
+ memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_DEV_INFO_UPDATE,
+ &data, sizeof(data), true);
+}
+
+static int
+mt7615_mcu_uni_ctrl_pm_state(struct mt7615_dev *dev, int band, int state)
+{
+ return 0;
+}
+
+static int
+mt7615_mcu_uni_add_bss(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif, bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct {
+ struct req_hdr {
+ u8 bss_idx;
+ u8 pad[3];
+ } __packed hdr;
+ struct basic_tlv {
+ __le16 tag;
+ __le16 len;
+ u8 active;
+ u8 omac_idx;
+ u8 hw_bss_idx;
+ u8 band_idx;
+ __le32 conn_type;
+ u8 conn_state;
+ u8 wmm_idx;
+ u8 bssid[ETH_ALEN];
+ __le16 bmc_tx_wlan_idx;
+ __le16 bcn_interval;
+ u8 dtim_period;
+ u8 phymode;
+ __le16 sta_idx;
+ u8 nonht_basic_phy;
+ u8 pad[3];
+ } __packed basic;
+ } req = {
+ .hdr = {
+ .bss_idx = mvif->idx,
+ },
+ .basic = {
+ .tag = cpu_to_le16(UNI_BSS_INFO_BASIC),
+ .len = cpu_to_le16(sizeof(struct basic_tlv)),
+ .bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
+ .dtim_period = vif->bss_conf.dtim_period,
+ .omac_idx = mvif->omac_idx,
+ .band_idx = mvif->band_idx,
+ .wmm_idx = mvif->wmm_idx,
+ .active = enable,
+ },
+ };
+ u8 idx, tx_wlan_idx = 0;
+
+ idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;
+ req.basic.hw_bss_idx = idx;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_AP:
+ req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP);
+ tx_wlan_idx = mvif->sta.wcid.idx;
+ break;
+ case NL80211_IFTYPE_STATION:
+ if (enable) {
+ struct ieee80211_sta *sta;
+ struct mt7615_sta *msta;
+
+ rcu_read_lock();
+ sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
+ if (!sta) {
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+
+ msta = (struct mt7615_sta *)sta->drv_priv;
+ tx_wlan_idx = msta->wcid.idx;
+ rcu_read_unlock();
+ }
+ req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA);
+ break;
+ default:
+ WARN_ON(1);
+ break;
+ }
+
+ memcpy(req.basic.bssid, vif->bss_conf.bssid, ETH_ALEN);
+ req.basic.bmc_tx_wlan_idx = cpu_to_le16(tx_wlan_idx);
+ req.basic.sta_idx = cpu_to_le16(tx_wlan_idx);
+ req.basic.conn_state = !enable;
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
+ &req, sizeof(req), true);
+}
+
+static int
+mt7615_mcu_uni_add_beacon_offload(struct mt7615_dev *dev,
+ struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ bool enable)
+{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+ struct ieee80211_mutable_offsets offs;
+ struct {
+ struct req_hdr {
+ u8 bss_idx;
+ u8 pad[3];
+ } __packed hdr;
+ struct bcn_content_tlv {
+ __le16 tag;
+ __le16 len;
+ __le16 tim_ie_pos;
+ __le16 csa_ie_pos;
+ __le16 bcc_ie_pos;
+ /* 0: enable beacon offload
+ * 1: disable beacon offload
+ * 2: update probe respond offload
+ */
+ u8 enable;
+ /* 0: legacy format (TXD + payload)
+ * 1: only cap field IE
+ */
+ u8 type;
+ __le16 pkt_len;
+ u8 pkt[512];
+ } __packed beacon_tlv;
+ } req = {
+ .hdr = {
+ .bss_idx = mvif->idx,
+ },
+ .beacon_tlv = {
+ .tag = cpu_to_le16(UNI_BSS_INFO_BCN_CONTENT),
+ .len = cpu_to_le16(sizeof(struct bcn_content_tlv)),
+ .enable = enable,
+ },
+ };
+ struct sk_buff *skb;
+
+ skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs);
+ if (!skb)
+ return -EINVAL;
+
+ if (skb->len > 512 - MT_TXD_SIZE) {
+ dev_err(dev->mt76.dev, "beacon size limit exceed\n");
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ mt7615_mac_write_txwi(dev, (__le32 *)(req.beacon_tlv.pkt), skb,
+ wcid, NULL, 0, NULL, true);
+ memcpy(req.beacon_tlv.pkt + MT_TXD_SIZE, skb->data, skb->len);
+ req.beacon_tlv.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
+ req.beacon_tlv.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
+
+ if (offs.csa_counter_offs[0]) {
+ u16 csa_offs;
+
+ csa_offs = MT_TXD_SIZE + offs.csa_counter_offs[0] - 4;
+ req.beacon_tlv.csa_ie_pos = cpu_to_le16(csa_offs);
+ }
+ dev_kfree_skb(skb);
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD_BSS_INFO_UPDATE,
+ &req, sizeof(req), true);
+}
+
+static int
+mt7615_mcu_uni_tx_ba(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable)
+{
+ struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
+ struct mt7615_vif *mvif = msta->vif;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct tlv *sta_wtbl;
+ struct sk_buff *skb;
+ int err;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
+
+ wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, sta_wtbl, &skb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ mt7615_mcu_wtbl_ba_tlv(skb, params, enable, true, sta_wtbl,
+ wtbl_hdr);
+
+ err = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
+ if (err < 0)
+ return err;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7615_mcu_sta_ba_tlv(skb, params, enable, true);
+
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
+}
+
+static int
+mt7615_mcu_uni_rx_ba(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable)
+{
+ struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
+ struct mt7615_vif *mvif = msta->vif;
+ struct wtbl_req_hdr *wtbl_hdr;
+ struct tlv *sta_wtbl;
+ struct sk_buff *skb;
+ int err;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ mt7615_mcu_sta_ba_tlv(skb, params, enable, false);
+
+ err = __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
+ if (err < 0 || !enable)
+ return err;
+
+ skb = mt7615_mcu_alloc_sta_req(mvif, msta);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ sta_wtbl = mt7615_mcu_add_tlv(skb, STA_REC_WTBL, sizeof(struct tlv));
+
+ wtbl_hdr = mt7615_mcu_alloc_wtbl_req(msta, WTBL_SET, sta_wtbl, &skb);
+ if (IS_ERR(wtbl_hdr))
+ return PTR_ERR(wtbl_hdr);
+
+ mt7615_mcu_wtbl_ba_tlv(skb, params, enable, false, sta_wtbl,
+ wtbl_hdr);
+
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD_STA_REC_UPDATE, true);
+}
+
+static int
+mt7615_mcu_uni_add_sta(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enable)
+{
+ return mt7615_mcu_add_sta_cmd(dev, vif, sta, enable,
+ MCU_UNI_CMD_STA_REC_UPDATE);
+}
+
+static const struct mt7615_mcu_ops uni_update_ops = {
+ .add_beacon_offload = mt7615_mcu_uni_add_beacon_offload,
+ .set_pm_state = mt7615_mcu_uni_ctrl_pm_state,
+ .add_dev_info = mt7615_mcu_uni_add_dev,
+ .add_bss_info = mt7615_mcu_uni_add_bss,
+ .add_tx_ba = mt7615_mcu_uni_tx_ba,
+ .add_rx_ba = mt7615_mcu_uni_rx_ba,
+ .sta_add = mt7615_mcu_uni_add_sta,
+};
+
static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data,
int len)
{
@@ -300,14 +1450,16 @@ static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data,
cur_len = min_t(int, 4096 - sizeof(struct mt7615_mcu_txd),
len);
- ret = __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_SCATTER,
+ ret = __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_SCATTER,
data, cur_len, false);
if (ret)
break;
data += cur_len;
len -= cur_len;
- mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false);
+
+ if (mt76_is_mmio(&dev->mt76))
+ mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false);
}
return ret;
@@ -324,13 +1476,13 @@ static int mt7615_mcu_start_firmware(struct mt7615_dev *dev, u32 addr,
.addr = cpu_to_le32(addr),
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_FW_START_REQ,
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_FW_START_REQ,
&req, sizeof(req), true);
}
static int mt7615_mcu_restart(struct mt76_dev *dev)
{
- return __mt76_mcu_send_msg(dev, -MCU_CMD_RESTART_DL_REQ, NULL,
+ return __mt76_mcu_send_msg(dev, MCU_CMD_RESTART_DL_REQ, NULL,
0, true);
}
@@ -342,7 +1494,7 @@ static int mt7615_mcu_patch_sem_ctrl(struct mt7615_dev *dev, bool get)
.op = cpu_to_le32(get ? PATCH_SEM_GET : PATCH_SEM_RELEASE),
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_SEM_CONTROL,
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_SEM_CONTROL,
&req, sizeof(req), true);
}
@@ -355,7 +1507,7 @@ static int mt7615_mcu_start_patch(struct mt7615_dev *dev)
.check_crc = 0,
};
- return __mt76_mcu_send_msg(&dev->mt76, -MCU_CMD_PATCH_FINISH_REQ,
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_CMD_PATCH_FINISH_REQ,
&req, sizeof(req), true);
}
@@ -371,11 +1523,13 @@ static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)
static int mt7615_driver_own(struct mt7615_dev *dev)
{
- mt76_wr(dev, MT_CFG_LPCR_HOST, MT_CFG_LPCR_HOST_DRV_OWN);
+ u32 addr;
+
+ addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
+ mt76_wr(dev, addr, MT_CFG_LPCR_HOST_DRV_OWN);
mt7622_trigger_hif_int(dev, true);
- if (!mt76_poll_msec(dev, MT_CFG_LPCR_HOST,
- MT_CFG_LPCR_HOST_FW_OWN, 0, 3000)) {
+ if (!mt76_poll_msec(dev, addr, MT_CFG_LPCR_HOST_FW_OWN, 0, 3000)) {
dev_err(dev->mt76.dev, "Timeout for driver own\n");
return -EIO;
}
@@ -386,9 +1540,12 @@ static int mt7615_driver_own(struct mt7615_dev *dev)
static int mt7615_firmware_own(struct mt7615_dev *dev)
{
+ u32 addr;
+
+ addr = is_mt7663(&dev->mt76) ? MT_CONN_HIF_ON_LPCTL : MT_CFG_LPCR_HOST;
mt7622_trigger_hif_int(dev, true);
- mt76_wr(dev, MT_CFG_LPCR_HOST, MT_CFG_LPCR_HOST_FW_OWN);
+ mt76_wr(dev, addr, MT_CFG_LPCR_HOST_FW_OWN);
if (is_mt7622(&dev->mt76) &&
!mt76_poll_msec(dev, MT_CFG_LPCR_HOST,
@@ -551,10 +1708,13 @@ static int mt7615_load_n9(struct mt7615_dev *dev, const char *name)
sizeof(dev->mt76.hw->wiphy->fw_version),
"%.10s-%.15s", hdr->fw_ver, hdr->build_date);
- if (!strncmp(hdr->fw_ver, "2.0", sizeof(hdr->fw_ver)))
+ if (!strncmp(hdr->fw_ver, "2.0", sizeof(hdr->fw_ver))) {
dev->fw_ver = MT7615_FIRMWARE_V2;
- else
+ dev->mcu_ops = &sta_update_ops;
+ } else {
dev->fw_ver = MT7615_FIRMWARE_V1;
+ dev->mcu_ops = &wtbl_update_ops;
+ }
out:
release_firmware(fw);
@@ -686,9 +1846,125 @@ int mt7615_mcu_fw_log_2_host(struct mt7615_dev *dev, u8 ctrl)
&data, sizeof(data), true);
}
+static int mt7663_load_n9(struct mt7615_dev *dev, const char *name)
+{
+ u32 offset = 0, override_addr = 0, flag = 0;
+ const struct mt7663_fw_trailer *hdr;
+ const struct mt7663_fw_buf *buf;
+ const struct firmware *fw;
+ const u8 *base_addr;
+ int i, ret;
+
+ ret = request_firmware(&fw, name, dev->mt76.dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data || fw->size < FW_V3_COMMON_TAILER_SIZE) {
+ dev_err(dev->mt76.dev, "Invalid firmware\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ hdr = (const struct mt7663_fw_trailer *)(fw->data + fw->size -
+ FW_V3_COMMON_TAILER_SIZE);
+
+ dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
+ hdr->fw_ver, hdr->build_date);
+ dev_info(dev->mt76.dev, "Region number: 0x%x\n", hdr->n_region);
+
+ base_addr = fw->data + fw->size - FW_V3_COMMON_TAILER_SIZE;
+ for (i = 0; i < hdr->n_region; i++) {
+ u32 shift = (hdr->n_region - i) * FW_V3_REGION_TAILER_SIZE;
+ u32 len, addr, mode;
+
+ dev_info(dev->mt76.dev, "Parsing tailer Region: %d\n", i);
+
+ buf = (const struct mt7663_fw_buf *)(base_addr - shift);
+ mode = mt7615_mcu_gen_dl_mode(buf->feature_set, false);
+ addr = le32_to_cpu(buf->img_dest_addr);
+ len = le32_to_cpu(buf->img_size);
+
+ ret = mt7615_mcu_init_download(dev, addr, len, mode);
+ if (ret) {
+ dev_err(dev->mt76.dev, "Download request failed\n");
+ goto out;
+ }
+
+ ret = mt7615_mcu_send_firmware(dev, fw->data + offset, len);
+ if (ret) {
+ dev_err(dev->mt76.dev, "Failed to send firmware\n");
+ goto out;
+ }
+
+ offset += le32_to_cpu(buf->img_size);
+ if (buf->feature_set & DL_MODE_VALID_RAM_ENTRY) {
+ override_addr = le32_to_cpu(buf->img_dest_addr);
+ dev_info(dev->mt76.dev, "Region %d, override_addr = 0x%08x\n",
+ i, override_addr);
+ }
+ }
+
+ if (is_mt7663(&dev->mt76)) {
+ flag |= FW_START_DLYCAL;
+ if (override_addr)
+ flag |= FW_START_OVERRIDE;
+
+ dev_info(dev->mt76.dev, "override_addr = 0x%08x, option = %d\n",
+ override_addr, flag);
+ }
+
+ ret = mt7615_mcu_start_firmware(dev, override_addr, flag);
+ if (ret)
+ dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
+
+out:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int mt7663_load_firmware(struct mt7615_dev *dev)
+{
+ int ret;
+
+ mt76_set(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
+
+ ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
+ if (ret) {
+ dev_dbg(dev->mt76.dev, "Firmware is already download\n");
+ return -EIO;
+ }
+
+ ret = mt7615_load_patch(dev, MT7663_PATCH_ADDRESS, MT7663_ROM_PATCH);
+ if (ret)
+ return ret;
+
+ dev->fw_ver = MT7615_FIRMWARE_V3;
+ dev->mcu_ops = &uni_update_ops;
+
+ ret = mt7663_load_n9(dev, MT7663_FIRMWARE_N9);
+ if (ret)
+ return ret;
+
+ if (!mt76_poll_msec(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY,
+ MT_TOP_MISC2_FW_N9_RDY, 1500)) {
+ ret = mt76_get_field(dev, MT_CONN_ON_MISC,
+ MT7663_TOP_MISC2_FW_STATE);
+ dev_err(dev->mt76.dev, "Timeout for initializing firmware\n");
+ return -EIO;
+ }
+
+ mt76_clear(dev, MT_WPDMA_GLO_CFG, MT_WPDMA_GLO_CFG_BYPASS_TX_SCH);
+
+ dev_dbg(dev->mt76.dev, "Firmware init done\n");
+
+ return 0;
+}
+
int mt7615_mcu_init(struct mt7615_dev *dev)
{
static const struct mt76_mcu_ops mt7615_mcu_ops = {
+ .mcu_skb_send_msg = mt7615_mcu_send_message,
.mcu_send_msg = mt7615_mcu_msg_send,
.mcu_restart = mt7615_mcu_restart,
};
@@ -700,10 +1976,17 @@ int mt7615_mcu_init(struct mt7615_dev *dev)
if (ret)
return ret;
- if (is_mt7622(&dev->mt76))
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7622:
ret = mt7622_load_firmware(dev);
- else
+ break;
+ case 0x7663:
+ ret = mt7663_load_firmware(dev);
+ break;
+ default:
ret = mt7615_load_firmware(dev);
+ break;
+ }
if (ret)
return ret;
@@ -726,33 +2009,42 @@ int mt7615_mcu_set_eeprom(struct mt7615_dev *dev)
{
struct {
u8 buffer_mode;
- u8 pad;
+ u8 content_format;
__le16 len;
} __packed req_hdr = {
.buffer_mode = 1,
};
- int ret, len, eep_len;
- u8 *req, *eep = (u8 *)dev->mt76.eeprom.data;
+ u8 *eep = (u8 *)dev->mt76.eeprom.data;
+ struct sk_buff *skb;
+ int eep_len, offset;
- if (is_mt7622(&dev->mt76))
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7622:
eep_len = MT7622_EE_MAX - MT_EE_NIC_CONF_0;
- else
+ offset = MT_EE_NIC_CONF_0;
+ break;
+ case 0x7663:
+ eep_len = MT7663_EE_MAX - MT_EE_CHIP_ID;
+ req_hdr.content_format = 1;
+ offset = MT_EE_CHIP_ID;
+ break;
+ default:
eep_len = MT7615_EE_MAX - MT_EE_NIC_CONF_0;
-
- len = sizeof(req_hdr) + eep_len;
- req = kzalloc(len, GFP_KERNEL);
- if (!req)
- return -ENOMEM;
+ offset = MT_EE_NIC_CONF_0;
+ break;
+ }
req_hdr.len = cpu_to_le16(eep_len);
- memcpy(req, &req_hdr, sizeof(req_hdr));
- memcpy(req + sizeof(req_hdr), eep + MT_EE_NIC_CONF_0, eep_len);
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EFUSE_BUFFER_MODE,
- req, len, true);
- kfree(req);
+ skb = mt7615_mcu_msg_alloc(NULL, sizeof(req_hdr) + eep_len);
+ if (!skb)
+ return -ENOMEM;
+
+ skb_put_data(skb, &req_hdr, sizeof(req_hdr));
+ skb_put_data(skb, eep + offset, eep_len);
- return ret;
+ return __mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD_EFUSE_BUFFER_MODE, true);
}
int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable)
@@ -827,36 +2119,6 @@ int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
&req, sizeof(req), true);
}
-int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int enter)
-{
-#define ENTER_PM_STATE 1
-#define EXIT_PM_STATE 2
- struct {
- u8 pm_number;
- u8 pm_state;
- u8 bssid[ETH_ALEN];
- u8 dtim_period;
- u8 wlan_idx;
- __le16 bcn_interval;
- __le32 aid;
- __le32 rx_filter;
- u8 band_idx;
- u8 rsv[3];
- __le32 feature;
- u8 omac_idx;
- u8 wmm_idx;
- u8 bcn_loss_cnt;
- u8 bcn_sp_duration;
- } __packed req = {
- .pm_number = 5,
- .pm_state = (enter) ? ENTER_PM_STATE : EXIT_PM_STATE,
- .band_idx = band,
- };
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_PM_STATE_CTRL,
- &req, sizeof(req), true);
-}
-
int mt7615_mcu_set_dbdc(struct mt7615_dev *dev)
{
struct mt7615_phy *ext_phy = mt7615_ext_phy(dev);
@@ -916,202 +2178,6 @@ out:
&req, sizeof(req), true);
}
-int mt7615_mcu_set_dev_info(struct mt7615_dev *dev,
- struct ieee80211_vif *vif, bool enable)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct {
- struct req_hdr {
- u8 omac_idx;
- u8 band_idx;
- __le16 tlv_num;
- u8 is_tlv_append;
- u8 rsv[3];
- } __packed hdr;
- struct req_tlv {
- __le16 tag;
- __le16 len;
- u8 active;
- u8 band_idx;
- u8 omac_addr[ETH_ALEN];
- } __packed tlv;
- } data = {
- .hdr = {
- .omac_idx = mvif->omac_idx,
- .band_idx = mvif->band_idx,
- .tlv_num = cpu_to_le16(1),
- .is_tlv_append = 1,
- },
- .tlv = {
- .tag = cpu_to_le16(DEV_INFO_ACTIVE),
- .len = cpu_to_le16(sizeof(struct req_tlv)),
- .active = enable,
- .band_idx = mvif->band_idx,
- },
- };
-
- memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_DEV_INFO_UPDATE,
- &data, sizeof(data), true);
-}
-
-static void
-mt7615_mcu_bss_info_omac_header(struct mt7615_vif *mvif, u8 *data,
- u32 conn_type)
-{
- struct bss_info_omac *hdr = (struct bss_info_omac *)data;
- u8 idx;
-
- idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;
- hdr->tag = cpu_to_le16(BSS_INFO_OMAC);
- hdr->len = cpu_to_le16(sizeof(struct bss_info_omac));
- hdr->hw_bss_idx = idx;
- hdr->omac_idx = mvif->omac_idx;
- hdr->band_idx = mvif->band_idx;
- hdr->conn_type = cpu_to_le32(conn_type);
-}
-
-static void
-mt7615_mcu_bss_info_basic_header(struct ieee80211_vif *vif, u8 *data,
- u32 net_type, u8 tx_wlan_idx,
- bool enable)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct bss_info_basic *hdr = (struct bss_info_basic *)data;
-
- hdr->tag = cpu_to_le16(BSS_INFO_BASIC);
- hdr->len = cpu_to_le16(sizeof(struct bss_info_basic));
- hdr->network_type = cpu_to_le32(net_type);
- hdr->active = enable;
- hdr->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
- memcpy(hdr->bssid, vif->bss_conf.bssid, ETH_ALEN);
- hdr->wmm_idx = mvif->wmm_idx;
- hdr->dtim_period = vif->bss_conf.dtim_period;
- hdr->bmc_tx_wlan_idx = tx_wlan_idx;
-}
-
-static void
-mt7615_mcu_bss_info_ext_header(struct mt7615_vif *mvif, u8 *data)
-{
-/* SIFS 20us + 512 byte beacon tranmitted by 1Mbps (3906us) */
-#define BCN_TX_ESTIMATE_TIME (4096 + 20)
- struct bss_info_ext_bss *hdr = (struct bss_info_ext_bss *)data;
- int ext_bss_idx, tsf_offset;
-
- ext_bss_idx = mvif->omac_idx - EXT_BSSID_START;
- if (ext_bss_idx < 0)
- return;
-
- hdr->tag = cpu_to_le16(BSS_INFO_EXT_BSS);
- hdr->len = cpu_to_le16(sizeof(struct bss_info_ext_bss));
- tsf_offset = ext_bss_idx * BCN_TX_ESTIMATE_TIME;
- hdr->mbss_tsf_offset = cpu_to_le32(tsf_offset);
-}
-
-int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
- struct ieee80211_vif *vif, int en)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct req_hdr {
- u8 bss_idx;
- u8 rsv0;
- __le16 tlv_num;
- u8 is_tlv_append;
- u8 rsv1[3];
- } __packed;
- int len = sizeof(struct req_hdr) + sizeof(struct bss_info_basic);
- int ret, i, features = BIT(BSS_INFO_BASIC), ntlv = 1;
- u32 conn_type = 0, net_type = NETWORK_INFRA;
- u8 *buf, *data, tx_wlan_idx = 0;
- struct req_hdr *hdr;
-
- if (en) {
- len += sizeof(struct bss_info_omac);
- features |= BIT(BSS_INFO_OMAC);
- if (mvif->omac_idx > EXT_BSSID_START) {
- len += sizeof(struct bss_info_ext_bss);
- features |= BIT(BSS_INFO_EXT_BSS);
- ntlv++;
- }
- ntlv++;
- }
-
- switch (vif->type) {
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_MESH_POINT:
- tx_wlan_idx = mvif->sta.wcid.idx;
- conn_type = CONNECTION_INFRA_AP;
- break;
- case NL80211_IFTYPE_STATION: {
- /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
- if (en) {
- struct ieee80211_sta *sta;
- struct mt7615_sta *msta;
-
- rcu_read_lock();
- sta = ieee80211_find_sta(vif, vif->bss_conf.bssid);
- if (!sta) {
- rcu_read_unlock();
- return -EINVAL;
- }
-
- msta = (struct mt7615_sta *)sta->drv_priv;
- tx_wlan_idx = msta->wcid.idx;
- rcu_read_unlock();
- }
- conn_type = CONNECTION_INFRA_STA;
- break;
- }
- case NL80211_IFTYPE_ADHOC:
- conn_type = CONNECTION_IBSS_ADHOC;
- tx_wlan_idx = mvif->sta.wcid.idx;
- net_type = NETWORK_IBSS;
- break;
- default:
- WARN_ON(1);
- break;
- }
-
- buf = kzalloc(len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- hdr = (struct req_hdr *)buf;
- hdr->bss_idx = mvif->idx;
- hdr->tlv_num = cpu_to_le16(ntlv);
- hdr->is_tlv_append = 1;
-
- data = buf + sizeof(*hdr);
- for (i = 0; i < BSS_INFO_MAX_NUM; i++) {
- int tag = ffs(features & BIT(i)) - 1;
-
- switch (tag) {
- case BSS_INFO_OMAC:
- mt7615_mcu_bss_info_omac_header(mvif, data,
- conn_type);
- data += sizeof(struct bss_info_omac);
- break;
- case BSS_INFO_BASIC:
- mt7615_mcu_bss_info_basic_header(vif, data, net_type,
- tx_wlan_idx, en);
- data += sizeof(struct bss_info_basic);
- break;
- case BSS_INFO_EXT_BSS:
- mt7615_mcu_bss_info_ext_header(mvif, data);
- data += sizeof(struct bss_info_ext_bss);
- break;
- default:
- break;
- }
- }
-
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BSS_INFO_UPDATE,
- buf, len, true);
- kfree(buf);
-
- return ret;
-}
-
int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
{
struct wtbl_req_hdr req = {
@@ -1122,377 +2188,6 @@ int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev)
&req, sizeof(req), true);
}
-static int
-mt7615_mcu_send_sta_rec(struct mt7615_dev *dev, u8 *req, u8 *wreq,
- u8 wlen, bool enable)
-{
- bool is_v1 = (dev->fw_ver == MT7615_FIRMWARE_V1);
- u32 slen = is_v1 ? wreq - req : wreq - req + wlen;
- int ret;
-
- if (is_v1 && !enable) {
- ret = __mt76_mcu_send_msg(&dev->mt76,
- MCU_EXT_CMD_STA_REC_UPDATE,
- req, slen, true);
- if (ret)
- return ret;
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
- wreq, wlen, true);
- }
-
- if (is_v1) {
- ret = __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
- wreq, wlen, true);
- if (ret)
- return ret;
- }
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_STA_REC_UPDATE,
- req, slen, true);
-}
-
-int mt7615_mcu_set_bmc(struct mt7615_dev *dev,
- struct ieee80211_vif *vif, bool en)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct {
- struct sta_req_hdr hdr;
- struct sta_rec_basic basic;
- u8 buf[MT7615_WTBL_UPDATE_MAX_SIZE];
- } __packed req = {
- .hdr = {
- .bss_idx = mvif->idx,
- .wlan_idx = mvif->sta.wcid.idx,
- .tlv_num = cpu_to_le16(1),
- .is_tlv_append = 1,
- .muar_idx = mvif->omac_idx,
- },
- .basic = {
- .tag = cpu_to_le16(STA_REC_BASIC),
- .len = cpu_to_le16(sizeof(struct sta_rec_basic)),
- .conn_type = cpu_to_le32(CONNECTION_INFRA_BC),
- },
- };
- struct sta_rec_wtbl *wtbl = NULL;
- struct wtbl_req_hdr *wtbl_hdr;
- struct wtbl_generic *wtbl_g;
- struct wtbl_rx *wtbl_rx;
- u8 *buf = req.buf;
-
- eth_broadcast_addr(req.basic.peer_addr);
-
- if (dev->fw_ver > MT7615_FIRMWARE_V1) {
- req.hdr.tlv_num = cpu_to_le16(2);
- wtbl = (struct sta_rec_wtbl *)buf;
- wtbl->tag = cpu_to_le16(STA_REC_WTBL);
- buf += sizeof(*wtbl);
- }
-
- wtbl_hdr = (struct wtbl_req_hdr *)buf;
- buf += sizeof(*wtbl_hdr);
- wtbl_hdr->wlan_idx = mvif->sta.wcid.idx;
- wtbl_hdr->operation = WTBL_RESET_AND_SET;
-
- if (en) {
- req.basic.conn_state = CONN_STATE_PORT_SECURE;
- req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER |
- EXTRA_INFO_NEW);
- } else {
- req.basic.conn_state = CONN_STATE_DISCONNECT;
- req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER);
- goto out;
- }
-
- wtbl_g = (struct wtbl_generic *)buf;
- buf += sizeof(*wtbl_g);
- wtbl_g->tag = cpu_to_le16(WTBL_GENERIC);
- wtbl_g->len = cpu_to_le16(sizeof(*wtbl_g));
- wtbl_g->muar_idx = 0xe;
- eth_broadcast_addr(wtbl_g->peer_addr);
-
- wtbl_rx = (struct wtbl_rx *)buf;
- buf += sizeof(*wtbl_rx);
- wtbl_rx->tag = cpu_to_le16(WTBL_RX);
- wtbl_rx->len = cpu_to_le16(sizeof(*wtbl_rx));
- wtbl_rx->rv = 1;
- wtbl_rx->rca1 = 1;
- wtbl_rx->rca2 = 1;
-
- wtbl_hdr->tlv_num = cpu_to_le16(2);
-
-out:
- if (wtbl)
- wtbl->len = cpu_to_le16(buf - (u8 *)wtbl_hdr);
-
- return mt7615_mcu_send_sta_rec(dev, (u8 *)&req, (u8 *)wtbl_hdr,
- buf - (u8 *)wtbl_hdr, en);
-}
-
-int mt7615_mcu_set_sta(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, bool en)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
-
- struct {
- struct sta_req_hdr hdr;
- struct sta_rec_basic basic;
- u8 buf[MT7615_WTBL_UPDATE_MAX_SIZE];
- } __packed req = {
- .hdr = {
- .bss_idx = mvif->idx,
- .wlan_idx = msta->wcid.idx,
- .is_tlv_append = 1,
- .muar_idx = mvif->omac_idx,
- },
- .basic = {
- .tag = cpu_to_le16(STA_REC_BASIC),
- .len = cpu_to_le16(sizeof(struct sta_rec_basic)),
- .qos = sta->wme,
- .aid = cpu_to_le16(sta->aid),
- },
- };
- struct sta_rec_wtbl *wtbl = NULL;
- struct wtbl_req_hdr *wtbl_hdr;
- struct wtbl_generic *wtbl_g;
- struct wtbl_rx *wtbl_rx;
- u8 *buf = req.buf;
- u8 wtlv = 0, stlv = 1;
-
- memcpy(req.basic.peer_addr, sta->addr, ETH_ALEN);
-
- switch (vif->type) {
- case NL80211_IFTYPE_AP:
- case NL80211_IFTYPE_MESH_POINT:
- req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_STA);
- break;
- case NL80211_IFTYPE_STATION:
- req.basic.conn_type = cpu_to_le32(CONNECTION_INFRA_AP);
- break;
- case NL80211_IFTYPE_ADHOC:
- req.basic.conn_type = cpu_to_le32(CONNECTION_IBSS_ADHOC);
- break;
- default:
- WARN_ON(1);
- break;
- }
-
- if (en) {
- req.basic.conn_state = CONN_STATE_PORT_SECURE;
- req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER |
- EXTRA_INFO_NEW);
-
- /* sta_rec ht */
- if (sta->ht_cap.ht_supported) {
- struct sta_rec_ht *sta_ht;
-
- sta_ht = (struct sta_rec_ht *)buf;
- buf += sizeof(*sta_ht);
- sta_ht->tag = cpu_to_le16(STA_REC_HT);
- sta_ht->len = cpu_to_le16(sizeof(*sta_ht));
- sta_ht->ht_cap = cpu_to_le16(sta->ht_cap.cap);
- stlv++;
-
- /* sta_rec vht */
- if (sta->vht_cap.vht_supported) {
- struct sta_rec_vht *sta_vht;
-
- sta_vht = (struct sta_rec_vht *)buf;
- buf += sizeof(*sta_vht);
- sta_vht->tag = cpu_to_le16(STA_REC_VHT);
- sta_vht->len = cpu_to_le16(sizeof(*sta_vht));
- sta_vht->vht_cap =
- cpu_to_le32(sta->vht_cap.cap);
- sta_vht->vht_rx_mcs_map =
- sta->vht_cap.vht_mcs.rx_mcs_map;
- sta_vht->vht_tx_mcs_map =
- sta->vht_cap.vht_mcs.tx_mcs_map;
- stlv++;
- }
- }
- } else {
- req.basic.conn_state = CONN_STATE_DISCONNECT;
- req.basic.extra_info = cpu_to_le16(EXTRA_INFO_VER);
- }
-
- /* wtbl */
- if (dev->fw_ver > MT7615_FIRMWARE_V1) {
- wtbl = (struct sta_rec_wtbl *)buf;
- wtbl->tag = cpu_to_le16(STA_REC_WTBL);
- buf += sizeof(*wtbl);
- stlv++;
- }
-
- wtbl_hdr = (struct wtbl_req_hdr *)buf;
- buf += sizeof(*wtbl_hdr);
- wtbl_hdr->wlan_idx = msta->wcid.idx;
- wtbl_hdr->operation = WTBL_RESET_AND_SET;
-
- if (!en)
- goto out;
-
- wtbl_g = (struct wtbl_generic *)buf;
- buf += sizeof(*wtbl_g);
- wtbl_g->tag = cpu_to_le16(WTBL_GENERIC);
- wtbl_g->len = cpu_to_le16(sizeof(*wtbl_g));
- wtbl_g->muar_idx = mvif->omac_idx;
- wtbl_g->qos = sta->wme;
- wtbl_g->partial_aid = cpu_to_le16(sta->aid);
- memcpy(wtbl_g->peer_addr, sta->addr, ETH_ALEN);
- wtlv++;
-
- wtbl_rx = (struct wtbl_rx *)buf;
- buf += sizeof(*wtbl_rx);
- wtbl_rx->tag = cpu_to_le16(WTBL_RX);
- wtbl_rx->len = cpu_to_le16(sizeof(*wtbl_rx));
- wtbl_rx->rv = 1;
- wtbl_rx->rca1 = vif->type != NL80211_IFTYPE_AP;
- wtbl_rx->rca2 = 1;
- wtlv++;
-
- /* wtbl ht */
- if (sta->ht_cap.ht_supported) {
- struct wtbl_ht *wtbl_ht;
- struct wtbl_raw *wtbl_raw;
- u32 val = 0, msk;
-
- wtbl_ht = (struct wtbl_ht *)buf;
- buf += sizeof(*wtbl_ht);
- wtbl_ht->tag = cpu_to_le16(WTBL_HT);
- wtbl_ht->len = cpu_to_le16(sizeof(*wtbl_ht));
- wtbl_ht->ht = 1;
- wtbl_ht->ldpc = sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING;
- wtbl_ht->af = sta->ht_cap.ampdu_factor;
- wtbl_ht->mm = sta->ht_cap.ampdu_density;
- wtlv++;
-
- /* wtbl vht */
- if (sta->vht_cap.vht_supported) {
- struct wtbl_vht *wtbl_vht;
-
- wtbl_vht = (struct wtbl_vht *)buf;
- buf += sizeof(*wtbl_vht);
- wtbl_vht->tag = cpu_to_le16(WTBL_VHT);
- wtbl_vht->len = cpu_to_le16(sizeof(*wtbl_vht));
- wtbl_vht->vht = 1;
- wtbl_vht->ldpc = sta->vht_cap.cap &
- IEEE80211_VHT_CAP_RXLDPC;
- wtlv++;
-
- if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
- val |= MT_WTBL_W5_SHORT_GI_80;
- if (sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
- val |= MT_WTBL_W5_SHORT_GI_160;
- }
-
- /* wtbl smps */
- if (sta->smps_mode == IEEE80211_SMPS_DYNAMIC) {
- struct wtbl_smps *wtbl_smps;
-
- wtbl_smps = (struct wtbl_smps *)buf;
- buf += sizeof(*wtbl_smps);
- wtbl_smps->tag = cpu_to_le16(WTBL_SMPS);
- wtbl_smps->len = cpu_to_le16(sizeof(*wtbl_smps));
- wtbl_smps->smps = 1;
- wtlv++;
- }
-
- /* sgi */
- msk = MT_WTBL_W5_SHORT_GI_20 | MT_WTBL_W5_SHORT_GI_40 |
- MT_WTBL_W5_SHORT_GI_80 | MT_WTBL_W5_SHORT_GI_160;
-
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
- val |= MT_WTBL_W5_SHORT_GI_20;
- if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
- val |= MT_WTBL_W5_SHORT_GI_40;
-
- wtbl_raw = (struct wtbl_raw *)buf;
- buf += sizeof(*wtbl_raw);
- wtbl_raw->tag = cpu_to_le16(WTBL_RAW_DATA);
- wtbl_raw->len = cpu_to_le16(sizeof(*wtbl_raw));
- wtbl_raw->wtbl_idx = 1;
- wtbl_raw->dw = 5;
- wtbl_raw->msk = cpu_to_le32(~msk);
- wtbl_raw->val = cpu_to_le32(val);
- wtlv++;
- }
-
-out:
- if (wtbl)
- wtbl->len = cpu_to_le16(buf - (u8 *)wtbl_hdr);
-
- wtbl_hdr->tlv_num = cpu_to_le16(wtlv);
- req.hdr.tlv_num = cpu_to_le16(stlv);
-
- return mt7615_mcu_send_sta_rec(dev, (u8 *)&req, (u8 *)wtbl_hdr,
- buf - (u8 *)wtbl_hdr, en);
-}
-
-int mt7615_mcu_set_bcn(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- int en)
-{
- struct mt7615_dev *dev = mt7615_hw_dev(hw);
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- struct mt76_wcid *wcid = &dev->mt76.global_wcid;
- struct ieee80211_mutable_offsets offs;
- struct ieee80211_tx_info *info;
- struct req {
- u8 omac_idx;
- u8 enable;
- u8 wlan_idx;
- u8 band_idx;
- u8 pkt_type;
- u8 need_pre_tbtt_int;
- __le16 csa_ie_pos;
- __le16 pkt_len;
- __le16 tim_ie_pos;
- u8 pkt[512];
- u8 csa_cnt;
- /* bss color change */
- u8 bcc_cnt;
- __le16 bcc_ie_pos;
- } __packed req = {
- .omac_idx = mvif->omac_idx,
- .enable = en,
- .wlan_idx = wcid->idx,
- .band_idx = mvif->band_idx,
- };
- struct sk_buff *skb;
-
- skb = ieee80211_beacon_get_template(hw, vif, &offs);
- if (!skb)
- return -EINVAL;
-
- if (skb->len > 512 - MT_TXD_SIZE) {
- dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
- dev_kfree_skb(skb);
- return -EINVAL;
- }
-
- if (mvif->band_idx) {
- info = IEEE80211_SKB_CB(skb);
- info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
- }
-
- mt7615_mac_write_txwi(dev, (__le32 *)(req.pkt), skb, wcid, NULL,
- 0, NULL);
- memcpy(req.pkt + MT_TXD_SIZE, skb->data, skb->len);
- req.pkt_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
- req.tim_ie_pos = cpu_to_le16(MT_TXD_SIZE + offs.tim_offset);
- if (offs.csa_counter_offs[0]) {
- u16 csa_offs;
-
- csa_offs = MT_TXD_SIZE + offs.csa_counter_offs[0] - 4;
- req.csa_ie_pos = cpu_to_le16(csa_offs);
- req.csa_cnt = skb->data[offs.csa_counter_offs[0]];
- }
- dev_kfree_skb(skb);
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_BCN_OFFLOAD,
- &req, sizeof(req), true);
-}
-
int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev,
enum mt7615_rdd_cmd cmd, u8 index,
u8 rx_sel, u8 val)
@@ -1690,146 +2385,6 @@ int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd)
return __mt76_mcu_send_msg(&dev->mt76, cmd, &req, sizeof(req), true);
}
-int mt7615_mcu_set_tx_ba(struct mt7615_dev *dev,
- struct ieee80211_ampdu_params *params,
- bool add)
-{
- struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
- struct mt7615_vif *mvif = msta->vif;
- struct {
- struct sta_req_hdr hdr;
- struct sta_rec_ba ba;
- u8 buf[MT7615_WTBL_UPDATE_MAX_SIZE];
- } __packed req = {
- .hdr = {
- .bss_idx = mvif->idx,
- .wlan_idx = msta->wcid.idx,
- .tlv_num = cpu_to_le16(1),
- .is_tlv_append = 1,
- .muar_idx = mvif->omac_idx,
- },
- .ba = {
- .tag = cpu_to_le16(STA_REC_BA),
- .len = cpu_to_le16(sizeof(struct sta_rec_ba)),
- .tid = params->tid,
- .ba_type = MT_BA_TYPE_ORIGINATOR,
- .amsdu = params->amsdu,
- .ba_en = add << params->tid,
- .ssn = cpu_to_le16(params->ssn),
- .winsize = cpu_to_le16(params->buf_size),
- },
- };
- struct sta_rec_wtbl *wtbl = NULL;
- struct wtbl_req_hdr *wtbl_hdr;
- struct wtbl_ba *wtbl_ba;
- u8 *buf = req.buf;
-
- if (dev->fw_ver > MT7615_FIRMWARE_V1) {
- req.hdr.tlv_num = cpu_to_le16(2);
- wtbl = (struct sta_rec_wtbl *)buf;
- wtbl->tag = cpu_to_le16(STA_REC_WTBL);
- buf += sizeof(*wtbl);
- }
-
- wtbl_hdr = (struct wtbl_req_hdr *)buf;
- buf += sizeof(*wtbl_hdr);
- wtbl_hdr->wlan_idx = msta->wcid.idx;
- wtbl_hdr->operation = WTBL_SET;
- wtbl_hdr->tlv_num = cpu_to_le16(1);
-
- wtbl_ba = (struct wtbl_ba *)buf;
- buf += sizeof(*wtbl_ba);
- wtbl_ba->tag = cpu_to_le16(WTBL_BA);
- wtbl_ba->len = cpu_to_le16(sizeof(*wtbl_ba));
- wtbl_ba->tid = params->tid;
- wtbl_ba->ba_type = MT_BA_TYPE_ORIGINATOR;
- wtbl_ba->sn = add ? cpu_to_le16(params->ssn) : 0;
- wtbl_ba->ba_en = add;
-
- if (add) {
- u8 idx, ba_range[] = { 4, 8, 12, 24, 36, 48, 54, 64 };
-
- for (idx = 7; idx > 0; idx--) {
- if (params->buf_size >= ba_range[idx])
- break;
- }
-
- wtbl_ba->ba_winsize_idx = idx;
- }
-
- if (wtbl)
- wtbl->len = cpu_to_le16(buf - (u8 *)wtbl_hdr);
-
- return mt7615_mcu_send_sta_rec(dev, (u8 *)&req, (u8 *)wtbl_hdr,
- buf - (u8 *)wtbl_hdr, true);
-}
-
-int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev,
- struct ieee80211_ampdu_params *params,
- bool add)
-{
- struct mt7615_sta *msta = (struct mt7615_sta *)params->sta->drv_priv;
- struct mt7615_vif *mvif = msta->vif;
- struct {
- struct sta_req_hdr hdr;
- struct sta_rec_ba ba;
- u8 buf[MT7615_WTBL_UPDATE_MAX_SIZE];
- } __packed req = {
- .hdr = {
- .bss_idx = mvif->idx,
- .wlan_idx = msta->wcid.idx,
- .tlv_num = cpu_to_le16(1),
- .is_tlv_append = 1,
- .muar_idx = mvif->omac_idx,
- },
- .ba = {
- .tag = cpu_to_le16(STA_REC_BA),
- .len = cpu_to_le16(sizeof(struct sta_rec_ba)),
- .tid = params->tid,
- .ba_type = MT_BA_TYPE_RECIPIENT,
- .amsdu = params->amsdu,
- .ba_en = add << params->tid,
- .ssn = cpu_to_le16(params->ssn),
- .winsize = cpu_to_le16(params->buf_size),
- },
- };
- struct sta_rec_wtbl *wtbl = NULL;
- struct wtbl_req_hdr *wtbl_hdr;
- struct wtbl_ba *wtbl_ba;
- u8 *buf = req.buf;
-
- if (dev->fw_ver > MT7615_FIRMWARE_V1) {
- req.hdr.tlv_num = cpu_to_le16(2);
- wtbl = (struct sta_rec_wtbl *)buf;
- wtbl->tag = cpu_to_le16(STA_REC_WTBL);
- buf += sizeof(*wtbl);
- }
-
- wtbl_hdr = (struct wtbl_req_hdr *)buf;
- buf += sizeof(*wtbl_hdr);
- wtbl_hdr->wlan_idx = msta->wcid.idx;
- wtbl_hdr->operation = WTBL_SET;
- wtbl_hdr->tlv_num = cpu_to_le16(1);
-
- wtbl_ba = (struct wtbl_ba *)buf;
- buf += sizeof(*wtbl_ba);
- wtbl_ba->tag = cpu_to_le16(WTBL_BA);
- wtbl_ba->len = cpu_to_le16(sizeof(*wtbl_ba));
- wtbl_ba->tid = params->tid;
- wtbl_ba->ba_type = MT_BA_TYPE_RECIPIENT;
- wtbl_ba->rst_ba_tid = params->tid;
- wtbl_ba->rst_ba_sel = RST_BA_MAC_TID_MATCH;
- wtbl_ba->rst_ba_sb = 1;
-
- memcpy(wtbl_ba->peer_addr, params->sta->addr, ETH_ALEN);
-
- if (wtbl)
- wtbl->len = cpu_to_le16(buf - (u8 *)wtbl_hdr);
-
- return mt7615_mcu_send_sta_rec(dev, (u8 *)&req, (u8 *)wtbl_hdr,
- buf - (u8 *)wtbl_hdr, add);
-}
-
int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index)
{
struct {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
index db0199e60cb8..d1f7391472fc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
@@ -23,6 +23,57 @@ struct mt7615_mcu_txd {
u32 reserved[5];
} __packed __aligned(4);
+/**
+ * struct mt7615_uni_txd - mcu command descriptor for firmware v3
+ * @txd: hardware descriptor
+ * @len: total length not including txd
+ * @cid: command identifier
+ * @pkt_type: must be 0xa0 (cmd packet by long format)
+ * @frag_n: fragment number
+ * @seq: sequence number
+ * @checksum: 0 mean there is no checksum
+ * @s2d_index: index for command source and destination
+ * Definition | value | note
+ * CMD_S2D_IDX_H2N | 0x00 | command from HOST to WM
+ * CMD_S2D_IDX_C2N | 0x01 | command from WA to WM
+ * CMD_S2D_IDX_H2C | 0x02 | command from HOST to WA
+ * CMD_S2D_IDX_H2N_AND_H2C | 0x03 | command from HOST to WA and WM
+ *
+ * @option: command option
+ * BIT[0]: UNI_CMD_OPT_BIT_ACK
+ * set to 1 to request a fw reply
+ * if UNI_CMD_OPT_BIT_0_ACK is set and UNI_CMD_OPT_BIT_2_SET_QUERY
+ * is set, mcu firmware will send response event EID = 0x01
+ * (UNI_EVENT_ID_CMD_RESULT) to the host.
+ * BIT[1]: UNI_CMD_OPT_BIT_UNI_CMD
+ * 0: original command
+ * 1: unified command
+ * BIT[2]: UNI_CMD_OPT_BIT_SET_QUERY
+ * 0: QUERY command
+ * 1: SET command
+ */
+struct mt7615_uni_txd {
+ __le32 txd[8];
+
+ /* DW1 */
+ __le16 len;
+ __le16 cid;
+
+ /* DW2 */
+ u8 reserved;
+ u8 pkt_type;
+ u8 frag_n;
+ u8 seq;
+
+ /* DW3 */
+ __le16 checksum;
+ u8 s2d_index;
+ u8 option;
+
+ /* DW4 */
+ u8 reserved2[4];
+} __packed __aligned(4);
+
/* event table */
enum {
MCU_EVENT_TARGET_ADDRESS_LEN = 0x01,
@@ -179,16 +230,20 @@ enum {
MCU_S2D_H2CN
};
+#define MCU_FW_PREFIX BIT(31)
+#define MCU_UNI_PREFIX BIT(30)
+#define MCU_CMD_MASK ~(MCU_FW_PREFIX | MCU_UNI_PREFIX)
+
enum {
- MCU_CMD_TARGET_ADDRESS_LEN_REQ = 0x01,
- MCU_CMD_FW_START_REQ = 0x02,
+ MCU_CMD_TARGET_ADDRESS_LEN_REQ = MCU_FW_PREFIX | 0x01,
+ MCU_CMD_FW_START_REQ = MCU_FW_PREFIX | 0x02,
MCU_CMD_INIT_ACCESS_REG = 0x3,
MCU_CMD_PATCH_START_REQ = 0x05,
- MCU_CMD_PATCH_FINISH_REQ = 0x07,
- MCU_CMD_PATCH_SEM_CONTROL = 0x10,
+ MCU_CMD_PATCH_FINISH_REQ = MCU_FW_PREFIX | 0x07,
+ MCU_CMD_PATCH_SEM_CONTROL = MCU_FW_PREFIX | 0x10,
MCU_CMD_EXT_CID = 0xED,
- MCU_CMD_FW_SCATTER = 0xEE,
- MCU_CMD_RESTART_DL_REQ = 0xEF,
+ MCU_CMD_FW_SCATTER = MCU_FW_PREFIX | 0xEE,
+ MCU_CMD_RESTART_DL_REQ = MCU_FW_PREFIX | 0xEF,
};
enum {
@@ -215,6 +270,23 @@ enum {
};
enum {
+ MCU_UNI_CMD_DEV_INFO_UPDATE = MCU_UNI_PREFIX | 0x01,
+ MCU_UNI_CMD_BSS_INFO_UPDATE = MCU_UNI_PREFIX | 0x02,
+ MCU_UNI_CMD_STA_REC_UPDATE = MCU_UNI_PREFIX | 0x03,
+};
+
+#define MCU_CMD_ACK BIT(0)
+#define MCU_CMD_UNI BIT(1)
+#define MCU_CMD_QUERY BIT(2)
+
+#define MCU_CMD_UNI_EXT_ACK (MCU_CMD_ACK | MCU_CMD_UNI | MCU_CMD_QUERY)
+
+enum {
+ UNI_BSS_INFO_BASIC = 0,
+ UNI_BSS_INFO_BCN_CONTENT = 7,
+};
+
+enum {
PATCH_SEM_RELEASE = 0x0,
PATCH_SEM_GET = 0x1
};
@@ -274,6 +346,11 @@ enum {
__DBDC_TYPE_MAX,
};
+struct tlv {
+ __le16 tag;
+ __le16 len;
+} __packed;
+
struct bss_info_omac {
__le16 tag;
__le16 len;
@@ -483,18 +560,28 @@ struct wtbl_raw {
__le32 val;
} __packed;
-#define MT7615_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_tx_ps) + \
- sizeof(struct wtbl_hdr_trans) + \
- sizeof(struct wtbl_ba) + \
- sizeof(struct wtbl_bf) + \
- sizeof(struct wtbl_smps) + \
- sizeof(struct wtbl_pn) + \
- sizeof(struct wtbl_spe))
+#define MT7615_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_tx_ps) + \
+ sizeof(struct wtbl_hdr_trans) +\
+ sizeof(struct wtbl_ba) + \
+ sizeof(struct wtbl_bf) + \
+ sizeof(struct wtbl_smps) + \
+ sizeof(struct wtbl_pn) + \
+ sizeof(struct wtbl_spe))
+
+#define MT7615_STA_UPDATE_MAX_SIZE (sizeof(struct sta_req_hdr) + \
+ sizeof(struct sta_rec_basic) + \
+ sizeof(struct sta_rec_ht) + \
+ sizeof(struct sta_rec_vht) + \
+ sizeof(struct tlv) + \
+ MT7615_WTBL_UPDATE_MAX_SIZE)
+
+#define MT7615_WTBL_UPDATE_BA_SIZE (sizeof(struct wtbl_req_hdr) + \
+ sizeof(struct wtbl_ba))
enum {
WTBL_GENERIC,
@@ -517,6 +604,11 @@ enum {
WTBL_MAX_NUM
};
+struct sta_ntlv_hdr {
+ u8 rsv[2];
+ __le16 tlv_num;
+} __packed;
+
struct sta_req_hdr {
u8 bss_idx;
u8 wlan_idx;
@@ -526,6 +618,15 @@ struct sta_req_hdr {
u8 rsv[2];
} __packed;
+struct sta_rec_state {
+ __le16 tag;
+ __le16 len;
+ u8 state;
+ __le32 flags;
+ u8 vhtop;
+ u8 pad[2];
+} __packed;
+
struct sta_rec_basic {
__le16 tag;
__le16 len;
@@ -565,11 +666,6 @@ struct sta_rec_ba {
__le16 winsize;
} __packed;
-struct sta_rec_wtbl {
- __le16 tag;
- __le16 len;
-} __packed;
-
enum {
STA_REC_BASIC,
STA_REC_RA,
@@ -578,7 +674,7 @@ enum {
STA_REC_BF,
STA_REC_AMSDU, /* for CR4 */
STA_REC_BA,
- STA_REC_RED, /* not used */
+ STA_REC_STATE,
STA_REC_TX_PROC, /* for hdr trans and CSO in CR4 */
STA_REC_HT,
STA_REC_VHT,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
index 0b445471b6e8..d2eff5442824 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mmio.c
@@ -2,14 +2,68 @@
#include <linux/module.h>
#include "mt7615.h"
+#include "regs.h"
#include "mac.h"
#include "../trace.h"
+const u32 mt7615e_reg_map[] = {
+ [MT_TOP_CFG_BASE] = 0x01000,
+ [MT_HW_BASE] = 0x01000,
+ [MT_PCIE_REMAP_2] = 0x02504,
+ [MT_ARB_BASE] = 0x20c00,
+ [MT_HIF_BASE] = 0x04000,
+ [MT_CSR_BASE] = 0x07000,
+ [MT_PHY_BASE] = 0x10000,
+ [MT_CFG_BASE] = 0x20200,
+ [MT_AGG_BASE] = 0x20a00,
+ [MT_TMAC_BASE] = 0x21000,
+ [MT_RMAC_BASE] = 0x21200,
+ [MT_DMA_BASE] = 0x21800,
+ [MT_WTBL_BASE_ON] = 0x23000,
+ [MT_WTBL_BASE_OFF] = 0x23400,
+ [MT_LPON_BASE] = 0x24200,
+ [MT_MIB_BASE] = 0x24800,
+ [MT_WTBL_BASE_ADDR] = 0x30000,
+ [MT_PCIE_REMAP_BASE2] = 0x80000,
+ [MT_TOP_MISC_BASE] = 0xc0000,
+ [MT_EFUSE_ADDR_BASE] = 0x81070000,
+};
+
+const u32 mt7663e_reg_map[] = {
+ [MT_TOP_CFG_BASE] = 0x01000,
+ [MT_HW_BASE] = 0x02000,
+ [MT_DMA_SHDL_BASE] = 0x06000,
+ [MT_PCIE_REMAP_2] = 0x0700c,
+ [MT_ARB_BASE] = 0x20c00,
+ [MT_HIF_BASE] = 0x04000,
+ [MT_CSR_BASE] = 0x07000,
+ [MT_PHY_BASE] = 0x10000,
+ [MT_CFG_BASE] = 0x20000,
+ [MT_AGG_BASE] = 0x22000,
+ [MT_TMAC_BASE] = 0x24000,
+ [MT_RMAC_BASE] = 0x25000,
+ [MT_DMA_BASE] = 0x27000,
+ [MT_WTBL_BASE_ON] = 0x29000,
+ [MT_WTBL_BASE_OFF] = 0x29800,
+ [MT_LPON_BASE] = 0x2b000,
+ [MT_MIB_BASE] = 0x2d000,
+ [MT_WTBL_BASE_ADDR] = 0x30000,
+ [MT_PCIE_REMAP_BASE2] = 0x90000,
+ [MT_TOP_MISC_BASE] = 0xc0000,
+ [MT_EFUSE_ADDR_BASE] = 0x78011000,
+};
+
u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr)
{
- u32 base = addr & MT_MCU_PCIE_REMAP_2_BASE;
- u32 offset = addr & MT_MCU_PCIE_REMAP_2_OFFSET;
-
+ u32 base, offset;
+
+ if (is_mt7663(&dev->mt76)) {
+ base = addr & MT7663_MCU_PCIE_REMAP_2_BASE;
+ offset = addr & MT7663_MCU_PCIE_REMAP_2_OFFSET;
+ } else {
+ base = addr & MT_MCU_PCIE_REMAP_2_BASE;
+ offset = addr & MT_MCU_PCIE_REMAP_2_OFFSET;
+ }
mt76_wr(dev, MT_MCU_PCIE_REMAP_2, base);
return MT_PCIE_REMAP_BASE_2 + offset;
@@ -66,7 +120,8 @@ static irqreturn_t mt7615_irq_handler(int irq, void *dev_instance)
return IRQ_HANDLED;
}
-int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq)
+int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
+ int irq, const u32 *map)
{
static const struct mt76_driver_ops drv_ops = {
/* txwi_size = txd size + txp size */
@@ -95,6 +150,7 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq)
dev = container_of(mdev, struct mt7615_dev, mt76);
mt76_mmio_init(&dev->mt76, mem_base);
+ dev->reg_map = map;
mdev->rev = (mt76_rr(dev, MT_HW_CHIPID) << 16) |
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
@@ -104,6 +160,9 @@ int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq)
if (ret)
goto error;
+ if (is_mt7663(mdev))
+ mt76_wr(dev, MT_PCIE_IRQ_ENABLE, 1);
+
ret = mt7615_register_device(dev);
if (ret)
goto error;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index a84a9b4cbf4e..676ca622c35a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -38,6 +38,10 @@
#define MT7615_FIRMWARE_V1 1
#define MT7615_FIRMWARE_V2 2
+#define MT7615_FIRMWARE_V3 3
+
+#define MT7663_ROM_PATCH "mediatek/mt7663pr2h_v3.bin"
+#define MT7663_FIRMWARE_N9 "mediatek/mt7663_n9_v3.bin"
#define MT7615_EEPROM_SIZE 1024
#define MT7615_TOKEN_SIZE 4096
@@ -144,6 +148,33 @@ struct mt7615_phy {
struct mib_stats mib;
};
+#define mt7615_mcu_add_tx_ba(dev, ...) (dev)->mcu_ops->add_tx_ba((dev), __VA_ARGS__)
+#define mt7615_mcu_add_rx_ba(dev, ...) (dev)->mcu_ops->add_rx_ba((dev), __VA_ARGS__)
+#define mt7615_mcu_sta_add(dev, ...) (dev)->mcu_ops->sta_add((dev), __VA_ARGS__)
+#define mt7615_mcu_add_dev_info(dev, ...) (dev)->mcu_ops->add_dev_info((dev), __VA_ARGS__)
+#define mt7615_mcu_add_bss_info(dev, ...) (dev)->mcu_ops->add_bss_info((dev), __VA_ARGS__)
+#define mt7615_mcu_add_beacon(dev, ...) (dev)->mcu_ops->add_beacon_offload((dev), __VA_ARGS__)
+#define mt7615_mcu_set_pm(dev, ...) (dev)->mcu_ops->set_pm_state((dev), __VA_ARGS__)
+struct mt7615_mcu_ops {
+ int (*add_tx_ba)(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable);
+ int (*add_rx_ba)(struct mt7615_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable);
+ int (*sta_add)(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool enable);
+ int (*add_dev_info)(struct mt7615_dev *dev,
+ struct ieee80211_vif *vif, bool enable);
+ int (*add_bss_info)(struct mt7615_dev *dev, struct ieee80211_vif *vif,
+ bool enable);
+ int (*add_beacon_offload)(struct mt7615_dev *dev,
+ struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, bool enable);
+ int (*set_pm_state)(struct mt7615_dev *dev, int band, int state);
+};
+
struct mt7615_dev {
union { /* must be first */
struct mt76_dev mt76;
@@ -156,7 +187,9 @@ struct mt7615_dev {
u16 chainmask;
+ const struct mt7615_mcu_ops *mcu_ops;
struct regmap *infracfg;
+ const u32 *reg_map;
struct work_struct mcu_work;
@@ -257,6 +290,8 @@ mt7615_ext_phy(struct mt7615_dev *dev)
}
extern const struct ieee80211_ops mt7615_ops;
+extern const u32 mt7615e_reg_map[__MT_BASE_MAX];
+extern const u32 mt7663e_reg_map[__MT_BASE_MAX];
extern struct pci_driver mt7615_pci_driver;
extern struct platform_driver mt7622_wmac_driver;
@@ -269,9 +304,11 @@ static inline int mt7622_wmac_init(struct mt7615_dev *dev)
}
#endif
-int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base, int irq);
+int mt7615_mmio_probe(struct device *pdev, void __iomem *mem_base,
+ int irq, const u32 *map);
u32 mt7615_reg_map(struct mt7615_dev *dev, u32 addr);
+void mt7615_init_device(struct mt7615_dev *dev);
int mt7615_register_device(struct mt7615_dev *dev);
void mt7615_unregister_device(struct mt7615_dev *dev);
int mt7615_register_ext_phy(struct mt7615_dev *dev);
@@ -284,29 +321,13 @@ int mt7615_dma_init(struct mt7615_dev *dev);
void mt7615_dma_cleanup(struct mt7615_dev *dev);
int mt7615_mcu_init(struct mt7615_dev *dev);
bool mt7615_wait_for_mcu_init(struct mt7615_dev *dev);
-int mt7615_mcu_set_dev_info(struct mt7615_dev *dev,
- struct ieee80211_vif *vif, bool enable);
-int mt7615_mcu_set_bss_info(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- int en);
void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
struct ieee80211_tx_rate *probe_rate,
struct ieee80211_tx_rate *rates);
int mt7615_mcu_del_wtbl_all(struct mt7615_dev *dev);
-int mt7615_mcu_set_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- bool en);
-int mt7615_mcu_set_sta(struct mt7615_dev *dev, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, bool en);
-int mt7615_mcu_set_bcn(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- int en);
int mt7615_mcu_set_chan_info(struct mt7615_phy *phy, int cmd);
int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
const struct ieee80211_tx_queue_params *params);
-int mt7615_mcu_set_tx_ba(struct mt7615_dev *dev,
- struct ieee80211_ampdu_params *params,
- bool add);
-int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev,
- struct ieee80211_ampdu_params *params,
- bool add);
void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb);
int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev,
enum mt7615_rdd_cmd cmd, u8 index,
@@ -327,6 +348,11 @@ static inline bool is_mt7615(struct mt76_dev *dev)
return mt76_chip(dev) == 0x7615;
}
+static inline bool is_mt7663(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7663;
+}
+
static inline void mt7615_irq_enable(struct mt7615_dev *dev, u32 mask)
{
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, 0, mask);
@@ -347,7 +373,7 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev);
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_sta *sta, int pid,
- struct ieee80211_key_conf *key);
+ struct ieee80211_key_conf *key, bool beacon);
void mt7615_mac_set_timing(struct mt7615_phy *phy);
int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb);
void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data);
@@ -357,13 +383,15 @@ int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
enum set_key_cmd cmd);
void mt7615_mac_reset_work(struct work_struct *work);
+int mt7615_mcu_wait_response(struct mt7615_dev *dev, int cmd, int seq);
int mt7615_mcu_set_dbdc(struct mt7615_dev *dev);
int mt7615_mcu_set_eeprom(struct mt7615_dev *dev);
int mt7615_mcu_set_mac_enable(struct mt7615_dev *dev, int band, bool enable);
int mt7615_mcu_set_rts_thresh(struct mt7615_phy *phy, u32 val);
-int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int band, int enter);
int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index);
void mt7615_mcu_exit(struct mt7615_dev *dev);
+void mt7615_mcu_fill_msg(struct mt7615_dev *dev, struct sk_buff *skb,
+ int cmd, int *wait_seq);
int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
index 43e02128cc48..c8d0f893a47f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
@@ -13,12 +13,14 @@
static const struct pci_device_id mt7615_pci_device_table[] = {
{ PCI_DEVICE(0x14c3, 0x7615) },
+ { PCI_DEVICE(0x14c3, 0x7663) },
{ },
};
static int mt7615_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
+ const u32 *map;
int ret;
ret = pcim_enable_device(pdev);
@@ -35,7 +37,9 @@ static int mt7615_pci_probe(struct pci_dev *pdev,
if (ret)
return ret;
- return mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0], pdev->irq);
+ map = id->device == 0x7663 ? mt7663e_reg_map : mt7615e_reg_map;
+ return mt7615_mmio_probe(&pdev->dev, pcim_iomap_table(pdev)[0],
+ pdev->irq, map);
}
static void mt7615_pci_remove(struct pci_dev *pdev)
@@ -57,3 +61,5 @@ MODULE_DEVICE_TABLE(pci, mt7615_pci_device_table);
MODULE_FIRMWARE(MT7615_FIRMWARE_CR4);
MODULE_FIRMWARE(MT7615_FIRMWARE_N9);
MODULE_FIRMWARE(MT7615_ROM_PATCH);
+MODULE_FIRMWARE(MT7663_FIRMWARE_N9);
+MODULE_FIRMWARE(MT7663_ROM_PATCH);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index fe68f6b2cbf8..1e0d95b917e1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -4,17 +4,46 @@
#ifndef __MT7615_REGS_H
#define __MT7615_REGS_H
-#define MT_HW_REV 0x1000
-#define MT_HW_CHIPID 0x1008
-#define MT_TOP_STRAP_STA 0x1010
+enum mt7615_reg_base {
+ MT_TOP_CFG_BASE,
+ MT_HW_BASE,
+ MT_DMA_SHDL_BASE,
+ MT_PCIE_REMAP_2,
+ MT_ARB_BASE,
+ MT_HIF_BASE,
+ MT_CSR_BASE,
+ MT_PHY_BASE,
+ MT_CFG_BASE,
+ MT_AGG_BASE,
+ MT_TMAC_BASE,
+ MT_RMAC_BASE,
+ MT_DMA_BASE,
+ MT_WTBL_BASE_ON,
+ MT_WTBL_BASE_OFF,
+ MT_LPON_BASE,
+ MT_MIB_BASE,
+ MT_WTBL_BASE_ADDR,
+ MT_PCIE_REMAP_BASE2,
+ MT_TOP_MISC_BASE,
+ MT_EFUSE_ADDR_BASE,
+ __MT_BASE_MAX,
+};
+
+#define MT_HW_INFO_BASE ((dev)->reg_map[MT_HW_BASE])
+#define MT_HW_INFO(ofs) (MT_HW_INFO_BASE + (ofs))
+#define MT_HW_REV MT_HW_INFO(0x000)
+#define MT_HW_CHIPID MT_HW_INFO(0x008)
+#define MT_TOP_STRAP_STA MT_HW_INFO(0x010)
#define MT_TOP_3NSS BIT(24)
#define MT_TOP_OFF_RSV 0x1128
#define MT_TOP_OFF_RSV_FW_STATE GENMASK(18, 16)
-#define MT_TOP_MISC2 0x1134
+#define MT_TOP_MISC2 ((dev)->reg_map[MT_TOP_CFG_BASE] + 0x134)
#define MT_TOP_MISC2_FW_STATE GENMASK(2, 0)
+#define MT7663_TOP_MISC2_FW_STATE GENMASK(3, 1)
+
#define MT_MCU_BASE 0x2000
#define MT_MCU(ofs) (MT_MCU_BASE + (ofs))
@@ -23,13 +52,19 @@
#define MT_MCU_PCIE_REMAP_1_BASE GENMASK(31, 18)
#define MT_PCIE_REMAP_BASE_1 0x40000
-#define MT_MCU_PCIE_REMAP_2 MT_MCU(0x504)
+#define MT_MCU_PCIE_REMAP_2 ((dev)->reg_map[MT_PCIE_REMAP_2])
#define MT_MCU_PCIE_REMAP_2_OFFSET GENMASK(18, 0)
#define MT_MCU_PCIE_REMAP_2_BASE GENMASK(31, 19)
-#define MT_PCIE_REMAP_BASE_2 0x80000
+#define MT_PCIE_REMAP_BASE_2 ((dev)->reg_map[MT_PCIE_REMAP_BASE2])
+
+#define MT_HIF(ofs) ((dev)->reg_map[MT_HIF_BASE] + (ofs))
+
+#define MT7663_MCU_PCIE_REMAP_2_OFFSET GENMASK(15, 0)
+#define MT7663_MCU_PCIE_REMAP_2_BASE GENMASK(31, 16)
-#define MT_HIF_BASE 0x4000
-#define MT_HIF(ofs) (MT_HIF_BASE + (ofs))
+#define MT_HIF2_BASE 0xf0000
+#define MT_HIF2(ofs) (MT_HIF2_BASE + (ofs))
+#define MT_PCIE_IRQ_ENABLE MT_HIF2(0x188)
#define MT_CFG_LPCR_HOST MT_HIF(0x1f0)
#define MT_CFG_LPCR_HOST_FW_OWN BIT(0)
@@ -95,6 +130,9 @@
#define MT_WPDMA_ABT_CFG MT_HIF(0x530)
#define MT_WPDMA_ABT_CFG1 MT_HIF(0x534)
+#define MT_CSR(ofs) ((dev)->reg_map[MT_CSR_BASE] + (ofs))
+#define MT_CONN_HIF_ON_LPCTL MT_CSR(0x000)
+
#define MT_PLE_BASE 0x8000
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
@@ -106,7 +144,7 @@
#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x300 + 0x10 * (ac) + \
((n) << 2))
-#define MT_WF_PHY_BASE 0x10000
+#define MT_WF_PHY_BASE ((dev)->reg_map[MT_PHY_BASE])
#define MT_WF_PHY(ofs) (MT_WF_PHY_BASE + (ofs))
#define MT_WF_PHY_WF2_RFCTRL0(n) MT_WF_PHY(0x1900 + (n) * 0x400)
@@ -139,7 +177,7 @@
#define MT_WF_PHY_RXTD2_BASE MT_WF_PHY(0x2a00)
#define MT_WF_PHY_RXTD2(_n) (MT_WF_PHY_RXTD2_BASE + ((_n) << 2))
-#define MT_WF_CFG_BASE 0x20200
+#define MT_WF_CFG_BASE ((dev)->reg_map[MT_CFG_BASE])
#define MT_WF_CFG(ofs) (MT_WF_CFG_BASE + (ofs))
#define MT_CFG_CCR MT_WF_CFG(0x000)
@@ -148,7 +186,7 @@
#define MT_CFG_CCR_MAC_D1_2X_GC_EN BIT(30)
#define MT_CFG_CCR_MAC_D0_2X_GC_EN BIT(31)
-#define MT_WF_AGG_BASE 0x20a00
+#define MT_WF_AGG_BASE ((dev)->reg_map[MT_AGG_BASE])
#define MT_WF_AGG(ofs) (MT_WF_AGG_BASE + (ofs))
#define MT_AGG_ARCR MT_WF_AGG(0x010)
@@ -179,7 +217,7 @@
#define MT_AGG_SCR MT_WF_AGG(0x0fc)
#define MT_AGG_SCR_NLNAV_MID_PTEC_DIS BIT(3)
-#define MT_WF_ARB_BASE 0x20c00
+#define MT_WF_ARB_BASE ((dev)->reg_map[MT_ARB_BASE])
#define MT_WF_ARB(ofs) (MT_WF_ARB_BASE + (ofs))
#define MT_ARB_SCR MT_WF_ARB(0x080)
@@ -188,7 +226,7 @@
#define MT_ARB_SCR_TX1_DISABLE BIT(10)
#define MT_ARB_SCR_RX1_DISABLE BIT(11)
-#define MT_WF_TMAC_BASE 0x21000
+#define MT_WF_TMAC_BASE ((dev)->reg_map[MT_TMAC_BASE])
#define MT_WF_TMAC(ofs) (MT_WF_TMAC_BASE + (ofs))
#define MT_TMAC_CDTR MT_WF_TMAC(0x090)
@@ -212,7 +250,7 @@
#define MT_TMAC_CTCR0_INS_DDLMT_EN BIT(17)
#define MT_TMAC_CTCR0_INS_DDLMT_VHT_SMPDU_EN BIT(18)
-#define MT_WF_RMAC_BASE 0x21200
+#define MT_WF_RMAC_BASE ((dev)->reg_map[MT_RMAC_BASE])
#define MT_WF_RMAC(ofs) (MT_WF_RMAC_BASE + (ofs))
#define MT_WF_RFCR(_band) MT_WF_RMAC((_band) ? 0x100 : 0x000)
@@ -257,7 +295,7 @@
#define MT_WF_RMAC_MIB_TIME6 MT_WF_RMAC(0x03dc)
#define MT_MIB_OBSSTIME_MASK GENMASK(23, 0)
-#define MT_WF_DMA_BASE 0x21800
+#define MT_WF_DMA_BASE ((dev)->reg_map[MT_DMA_BASE])
#define MT_WF_DMA(ofs) (MT_WF_DMA_BASE + (ofs))
#define MT_DMA_DCR0 MT_WF_DMA(0x000)
@@ -272,10 +310,10 @@
#define MT_DMA_RCFR0_RX_DROPPED_UCAST GENMASK(25, 24)
#define MT_DMA_RCFR0_RX_DROPPED_MCAST GENMASK(27, 26)
-#define MT_WTBL_BASE 0x30000
+#define MT_WTBL_BASE(dev) ((dev)->reg_map[MT_WTBL_BASE_ADDR])
#define MT_WTBL_ENTRY_SIZE 256
-#define MT_WTBL_OFF_BASE 0x23400
+#define MT_WTBL_OFF_BASE ((dev)->reg_map[MT_WTBL_BASE_OFF])
#define MT_WTBL_OFF(n) (MT_WTBL_OFF_BASE + (n))
#define MT_WTBL_W0_KEY_IDX GENMASK(24, 23)
@@ -292,7 +330,11 @@
#define MT_WTBL_UPDATE_TX_COUNT_CLEAR BIT(14)
#define MT_WTBL_UPDATE_BUSY BIT(31)
-#define MT_WTBL_ON_BASE 0x23000
+#define MT_TOP_MISC(ofs) ((dev)->reg_map[MT_TOP_MISC_BASE] + (ofs))
+#define MT_CONN_ON_MISC MT_TOP_MISC(0x1140)
+#define MT_TOP_MISC2_FW_N9_RDY BIT(2)
+
+#define MT_WTBL_ON_BASE ((dev)->reg_map[MT_WTBL_BASE_ON])
#define MT_WTBL_ON(_n) (MT_WTBL_ON_BASE + (_n))
#define MT_WTBL_RICR0 MT_WTBL_ON(0x010)
@@ -328,8 +370,7 @@
#define MT_WTBL_W27_CC_BW_SEL GENMASK(6, 5)
-#define MT_LPON_BASE 0x24200
-#define MT_LPON(_n) (MT_LPON_BASE + (_n))
+#define MT_LPON(_n) ((dev)->reg_map[MT_LPON_BASE] + (_n))
#define MT_LPON_T0CR MT_LPON(0x010)
#define MT_LPON_T0CR_MODE GENMASK(1, 0)
@@ -337,7 +378,7 @@
#define MT_LPON_UTTR0 MT_LPON(0x018)
#define MT_LPON_UTTR1 MT_LPON(0x01c)
-#define MT_WF_MIB_BASE 0x24800
+#define MT_WF_MIB_BASE (dev->reg_map[MT_MIB_BASE])
#define MT_WF_MIB(ofs) (MT_WF_MIB_BASE + (ofs))
#define MT_MIB_M0_MISC_CR MT_WF_MIB(0x00c)
@@ -367,6 +408,8 @@
#define MT_TX_AGG_CNT(n) MT_WF_MIB(0xa8 + ((n) << 2))
+#define MT_DMA_SHDL(ofs) (dev->reg_map[MT_DMA_SHDL_BASE] + (ofs))
+
#define MT_DMASHDL_BASE 0x5000a000
#define MT_DMASHDL_OPTIONAL 0x008
#define MT_DMASHDL_PAGE 0x00c
@@ -406,7 +449,7 @@
#define MT_LED_STATUS_ON GENMASK(23, 16)
#define MT_LED_STATUS_DURATION GENMASK(15, 0)
-#define MT_EFUSE_BASE 0x81070000
+#define MT_EFUSE_BASE ((dev)->reg_map[MT_EFUSE_ADDR_BASE])
#define MT_EFUSE_BASE_CTRL 0x000
#define MT_EFUSE_BASE_CTRL_EMPTY BIT(30)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
index 07ec9ec282f5..43aa49706c66 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/soc.c
@@ -47,7 +47,7 @@ static int mt7622_wmac_probe(struct platform_device *pdev)
return PTR_ERR(mem_base);
}
- return mt7615_mmio_probe(&pdev->dev, mem_base, irq);
+ return mt7615_mmio_probe(&pdev->dev, mem_base, irq, mt7615e_reg_map);
}
static int mt7622_wmac_remove(struct platform_device *pdev)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
index b56397c05218..09f34deb6ba1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/phy.c
@@ -1155,7 +1155,6 @@ static void mt76x0_rf_patch_reg_array(struct mt76x02_dev *dev,
static void mt76x0_phy_rf_init(struct mt76x02_dev *dev)
{
int i;
- u8 val;
mt76x0_rf_patch_reg_array(dev, mt76x0_rf_central_tab,
ARRAY_SIZE(mt76x0_rf_central_tab));
@@ -1188,7 +1187,7 @@ static void mt76x0_phy_rf_init(struct mt76x02_dev *dev)
*/
mt76x0_rf_wr(dev, MT_RF(0, 22),
min_t(u8, dev->cal.rx.freq_offset, 0xbf));
- val = mt76x0_rf_rr(dev, MT_RF(0, 22));
+ mt76x0_rf_rr(dev, MT_RF(0, 22));
/* Reset procedure DAC during power-up:
* - set B0.R73<7>
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
index c7f028e73b6b..7dcc5d342e9f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_mmio.c
@@ -461,6 +461,7 @@ static void mt76x02_watchdog_reset(struct mt76x02_dev *dev)
mutex_lock(&dev->mt76.mutex);
+ dev->mcu_timeout = 0;
if (restart)
mt76x02_reset_state(dev);
@@ -544,10 +545,6 @@ static void mt76x02_check_tx_hang(struct mt76x02_dev *dev)
restart:
mt76x02_watchdog_reset(dev);
- mutex_lock(&dev->mt76.mcu.mutex);
- dev->mcu_timeout = 0;
- mutex_unlock(&dev->mt76.mcu.mutex);
-
dev->tx_hang_reset++;
dev->tx_hang_check = 0;
memset(dev->mt76.tx_dma_idx, 0xff,
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index 36ba81d63f12..a981da6c35a5 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -70,10 +70,10 @@ static u32 ___mt76u_rr(struct mt76_dev *dev, u8 req, u32 addr)
ret = __mt76u_vendor_request(dev, req,
USB_DIR_IN | USB_TYPE_VENDOR,
- addr >> 16, addr, &usb->reg_val,
+ addr >> 16, addr, usb->data,
sizeof(__le32));
if (ret == sizeof(__le32))
- data = le32_to_cpu(usb->reg_val);
+ data = get_unaligned_le32(usb->data);
trace_usb_reg_rr(dev, addr, data);
return data;
@@ -125,10 +125,10 @@ static void ___mt76u_wr(struct mt76_dev *dev, u8 req,
{
struct mt76_usb *usb = &dev->usb;
- usb->reg_val = cpu_to_le32(val);
+ put_unaligned_le32(val, usb->data);
__mt76u_vendor_request(dev, req,
USB_DIR_OUT | USB_TYPE_VENDOR,
- addr >> 16, addr, &usb->reg_val,
+ addr >> 16, addr, usb->data,
sizeof(__le32));
trace_usb_reg_wr(dev, addr, val);
}
@@ -672,10 +672,17 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
static void mt76u_rx_tasklet(unsigned long data)
{
struct mt76_dev *dev = (struct mt76_dev *)data;
- struct mt76_queue *q = &dev->q_rx[MT_RXQ_MAIN];
+ struct mt76_queue *q;
+ int i;
rcu_read_lock();
- mt76u_process_rx_queue(dev, q);
+ for (i = 0; i < __MT_RXQ_MAX; i++) {
+ q = &dev->q_rx[i];
+ if (!q->ndesc)
+ continue;
+
+ mt76u_process_rx_queue(dev, q);
+ }
rcu_read_unlock();
}
@@ -1150,6 +1157,7 @@ int mt76u_init(struct mt76_dev *dev,
};
struct usb_device *udev = interface_to_usbdev(intf);
struct mt76_usb *usb = &dev->usb;
+ int err = -ENOMEM;
mt76u_ops.rr = ext ? mt76u_rr_ext : mt76u_rr;
mt76u_ops.wr = ext ? mt76u_wr_ext : mt76u_wr;
@@ -1169,10 +1177,8 @@ int mt76u_init(struct mt76_dev *dev,
usb->data_len = 32;
usb->data = devm_kmalloc(dev->dev, usb->data_len, GFP_KERNEL);
- if (!usb->data) {
- mt76u_deinit(dev);
- return -ENOMEM;
- }
+ if (!usb->data)
+ goto error;
mutex_init(&usb->usb_ctrl_mtx);
dev->bus = &mt76u_ops;
@@ -1182,7 +1188,15 @@ int mt76u_init(struct mt76_dev *dev,
usb->sg_en = mt76u_check_sg(dev);
- return mt76u_set_endpoints(intf, usb);
+ err = mt76u_set_endpoints(intf, usb);
+ if (err < 0)
+ goto error;
+
+ return 0;
+
+error:
+ mt76u_deinit(dev);
+ return err;
}
EXPORT_SYMBOL_GPL(mt76u_init);