summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/mediatek/mt76/mt7615
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-18 12:34:53 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-18 12:34:53 -0700
commit81160dda9a7aad13c04e78bb2cfd3c4630e3afab (patch)
tree4bf79ffa9fc7dc5e2915ff978778c3402c491113 /drivers/net/wireless/mediatek/mt76/mt7615
parent8b53c76533aa4356602aea98f98a2f3b4051464c (diff)
parent1bab8d4c488be22d57f9dd09968c90a0ddc413bf (diff)
downloadlinux-81160dda9a7aad13c04e78bb2cfd3c4630e3afab.tar.bz2
Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next
Pull networking updates from David Miller: 1) Support IPV6 RA Captive Portal Identifier, from Maciej Żenczykowski. 2) Use bio_vec in the networking instead of custom skb_frag_t, from Matthew Wilcox. 3) Make use of xmit_more in r8169 driver, from Heiner Kallweit. 4) Add devmap_hash to xdp, from Toke Høiland-Jørgensen. 5) Support all variants of 5750X bnxt_en chips, from Michael Chan. 6) More RTNL avoidance work in the core and mlx5 driver, from Vlad Buslov. 7) Add TCP syn cookies bpf helper, from Petar Penkov. 8) Add 'nettest' to selftests and use it, from David Ahern. 9) Add extack support to drop_monitor, add packet alert mode and support for HW drops, from Ido Schimmel. 10) Add VLAN offload to stmmac, from Jose Abreu. 11) Lots of devm_platform_ioremap_resource() conversions, from YueHaibing. 12) Add IONIC driver, from Shannon Nelson. 13) Several kTLS cleanups, from Jakub Kicinski. * git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1930 commits) mlxsw: spectrum_buffers: Add the ability to query the CPU port's shared buffer mlxsw: spectrum: Register CPU port with devlink mlxsw: spectrum_buffers: Prevent changing CPU port's configuration net: ena: fix incorrect update of intr_delay_resolution net: ena: fix retrieval of nonadaptive interrupt moderation intervals net: ena: fix update of interrupt moderation register net: ena: remove all old adaptive rx interrupt moderation code from ena_com net: ena: remove ena_restore_ethtool_params() and relevant fields net: ena: remove old adaptive interrupt moderation code from ena_netdev net: ena: remove code duplication in ena_com_update_nonadaptive_moderation_interval _*() net: ena: enable the interrupt_moderation in driver_supported_features net: ena: reimplement set/get_coalesce() net: ena: switch to dim algorithm for rx adaptive interrupt moderation net: ena: add intr_moder_rx_interval to struct ena_com_dev and use it net: phy: adin: implement Energy Detect Powerdown mode via phy-tunable ethtool: implement Energy Detect Powerdown support via phy-tunable xen-netfront: do not assume sk_buff_head list is empty in error handling s390/ctcm: Delete unnecessary checks before the macro call “dev_kfree_skb” net: ena: don't wake up tx queue when down drop_monitor: Better sanitize notified packets ...
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/mt7615')
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/Kconfig7
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/Makefile3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c91
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/dma.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c38
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c80
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.c733
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mac.h28
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/main.c111
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.c474
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mcu.h54
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h99
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/pci.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/regs.h75
14 files changed, 1387 insertions, 419 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
index 2ed47b309b6e..4cabba9aa2ea 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Kconfig
@@ -5,4 +5,9 @@ config MT7615E
depends on MAC80211
depends on PCI
help
- This adds support for MT7615-based wireless PCIe devices.
+ This adds support for MT7615-based wireless PCIe devices,
+ which support concurrent dual-band operation at both 5GHz
+ and 2.4GHz, IEEE 802.11ac 4x4:4SS 1733Mbps PHY rate, wave2
+ MU-MIMO up to 4 users/group and 160MHz channels.
+
+ To compile this driver as a module, choose M here.
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
index 6397552f6ee3..5aaac69849d6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/Makefile
@@ -2,4 +2,5 @@
obj-$(CONFIG_MT7615E) += mt7615e.o
-mt7615e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o
+mt7615e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
+ debugfs.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
new file mode 100644
index 000000000000..2428a4659a1c
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: ISC
+
+#include "mt7615.h"
+
+static int
+mt7615_radar_pattern_set(void *data, u64 val)
+{
+ struct mt7615_dev *dev = data;
+
+ return mt7615_mcu_rdd_send_pattern(dev);
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_radar_pattern, NULL,
+ mt7615_radar_pattern_set, "%lld\n");
+
+static int
+mt7615_scs_set(void *data, u64 val)
+{
+ struct mt7615_dev *dev = data;
+
+ mt7615_mac_set_scs(dev, val);
+
+ return 0;
+}
+
+static int
+mt7615_scs_get(void *data, u64 *val)
+{
+ struct mt7615_dev *dev = data;
+
+ *val = dev->scs_en;
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(fops_scs, mt7615_scs_get,
+ mt7615_scs_set, "%lld\n");
+
+static int
+mt7615_radio_read(struct seq_file *s, void *data)
+{
+ struct mt7615_dev *dev = dev_get_drvdata(s->private);
+
+ seq_printf(s, "Sensitivity: ofdm=%d cck=%d\n",
+ dev->ofdm_sensitivity, dev->cck_sensitivity);
+ seq_printf(s, "False CCA: ofdm=%d cck=%d\n",
+ dev->false_cca_ofdm, dev->false_cca_cck);
+
+ return 0;
+}
+
+static int mt7615_read_temperature(struct seq_file *s, void *data)
+{
+ struct mt7615_dev *dev = dev_get_drvdata(s->private);
+ int temp;
+
+ /* cpu */
+ temp = mt7615_mcu_get_temperature(dev, 0);
+ seq_printf(s, "Temperature: %d\n", temp);
+
+ return 0;
+}
+
+int mt7615_init_debugfs(struct mt7615_dev *dev)
+{
+ struct dentry *dir;
+
+ dir = mt76_register_debugfs(&dev->mt76);
+ if (!dir)
+ return -ENOMEM;
+
+ debugfs_create_file("scs", 0600, dir, dev, &fops_scs);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "radio", dir,
+ mt7615_radio_read);
+ debugfs_create_u32("dfs_hw_pattern", 0400, dir, &dev->hw_pattern);
+ /* test pattern knobs */
+ debugfs_create_u8("pattern_len", 0600, dir,
+ &dev->radar_pattern.n_pulses);
+ debugfs_create_u32("pulse_period", 0600, dir,
+ &dev->radar_pattern.period);
+ debugfs_create_u16("pulse_width", 0600, dir,
+ &dev->radar_pattern.width);
+ debugfs_create_u16("pulse_power", 0600, dir,
+ &dev->radar_pattern.power);
+ debugfs_create_file("radar_trigger", 0200, dir, dev,
+ &fops_radar_pattern);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "temperature", dir,
+ mt7615_read_temperature);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
index 6a70273d4a69..fe532cecbbdd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/dma.c
@@ -76,7 +76,7 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
mt7615_mac_tx_free(dev, skb);
break;
case PKT_TYPE_RX_EVENT:
- mt76_mcu_rx_event(&dev->mt76, skb);
+ mt7615_mcu_rx_event(dev, skb);
break;
case PKT_TYPE_NORMAL:
if (!mt7615_mac_fill_rx(dev, skb)) {
@@ -90,13 +90,6 @@ void mt7615_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
}
}
-static void mt7615_tx_tasklet(unsigned long data)
-{
- struct mt7615_dev *dev = (struct mt7615_dev *)data;
-
- mt76_txq_schedule_all(&dev->mt76);
-}
-
static int mt7615_poll_tx(struct napi_struct *napi, int budget)
{
static const u8 queue_map[] = {
@@ -128,9 +121,6 @@ int mt7615_dma_init(struct mt7615_dev *dev)
mt76_dma_attach(&dev->mt76);
- tasklet_init(&dev->mt76.tx_tasklet, mt7615_tx_tasklet,
- (unsigned long)dev);
-
mt76_wr(dev, MT_WPDMA_GLO_CFG,
MT_WPDMA_GLO_CFG_TX_WRITEBACK_DONE |
MT_WPDMA_GLO_CFG_FIFO_LITTLE_ENDIAN |
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
index dc94f52e6e8b..515bb58e19fd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/eeprom.c
@@ -154,6 +154,42 @@ int mt7615_eeprom_get_power_index(struct mt7615_dev *dev,
return index;
}
+static void mt7615_apply_cal_free_data(struct mt7615_dev *dev)
+{
+ static const u16 ical[] = {
+ 0x53, 0x54, 0x55, 0x56, 0x57, 0x5c, 0x5d, 0x62, 0x63, 0x68,
+ 0x69, 0x6e, 0x6f, 0x73, 0x74, 0x78, 0x79, 0x82, 0x83, 0x87,
+ 0x88, 0x8c, 0x8d, 0x91, 0x92, 0x96, 0x97, 0x9b, 0x9c, 0xa0,
+ 0xa1, 0xaa, 0xab, 0xaf, 0xb0, 0xb4, 0xb5, 0xb9, 0xba, 0xf4,
+ 0xf7, 0xff,
+ 0x140, 0x141, 0x145, 0x146, 0x14a, 0x14b, 0x154, 0x155, 0x159,
+ 0x15a, 0x15e, 0x15f, 0x163, 0x164, 0x168, 0x169, 0x16d, 0x16e,
+ 0x172, 0x173, 0x17c, 0x17d, 0x181, 0x182, 0x186, 0x187, 0x18b,
+ 0x18c
+ };
+ static const u16 ical_nocheck[] = {
+ 0x110, 0x111, 0x112, 0x113, 0x114, 0x115, 0x116, 0x117, 0x118,
+ 0x1b5, 0x1b6, 0x1b7, 0x3ac, 0x3ad, 0x3ae, 0x3af, 0x3b0, 0x3b1,
+ 0x3b2
+ };
+ u8 *eeprom = dev->mt76.eeprom.data;
+ u8 *otp = dev->mt76.otp.data;
+ int i;
+
+ if (!otp)
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(ical); i++)
+ if (!otp[ical[i]])
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(ical); i++)
+ eeprom[ical[i]] = otp[ical[i]];
+
+ for (i = 0; i < ARRAY_SIZE(ical_nocheck); i++)
+ eeprom[ical_nocheck[i]] = otp[ical_nocheck[i]];
+}
+
int mt7615_eeprom_init(struct mt7615_dev *dev)
{
int ret;
@@ -166,6 +202,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
+ mt7615_apply_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/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 859de2454ec6..1104e4c8aaa6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -20,10 +20,24 @@ static void mt7615_phy_init(struct mt7615_dev *dev)
static void mt7615_mac_init(struct mt7615_dev *dev)
{
- /* enable band 0 clk */
- mt76_rmw(dev, MT_CFG_CCR,
- MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN,
- MT_CFG_CCR_MAC_D0_1X_GC_EN | MT_CFG_CCR_MAC_D0_2X_GC_EN);
+ u32 val;
+
+ /* 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_TRCR0,
+ 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_TRCR1, val);
+
+ val = MT_AGG_ACR_PKT_TIME_EN | MT_AGG_ACR_NO_BA_AR_RULE |
+ FIELD_PREP(MT_AGG_ACR_CFEND_RATE, 0x49) | /* 24M */
+ FIELD_PREP(MT_AGG_ACR_BAR_RATE, 0x4b); /* 6M */
+ mt76_wr(dev, MT_AGG_ACR0, val);
+ mt76_wr(dev, MT_AGG_ACR1, val);
mt76_rmw_field(dev, MT_TMAC_CTCR0,
MT_TMAC_CTCR0_INS_DDLMT_REFTIME, 0x3f);
@@ -36,6 +50,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
MT_TMAC_CTCR0_INS_DDLMT_EN);
mt7615_mcu_set_rts_thresh(dev, 0x92b);
+ mt7615_mac_set_scs(dev, false);
mt76_rmw(dev, MT_AGG_SCR, MT_AGG_SCR_NLNAV_MID_PTEC_DIS,
MT_AGG_SCR_NLNAV_MID_PTEC_DIS);
@@ -45,11 +60,19 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
mt76_wr(dev, MT_DMA_DCR0, MT_DMA_DCR0_RX_VEC_DROP |
FIELD_PREP(MT_DMA_DCR0_MAX_RX_LEN, 3072));
- mt76_wr(dev, MT_AGG_ARUCR, FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 7));
+ mt76_wr(dev, MT_AGG_ARUCR,
+ 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,
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(0), 0) |
- FIELD_PREP(MT_AGG_ARxCR_LIMIT(1),
- max_t(int, 0, MT7615_RATE_RETRY - 2)) |
+ 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) |
@@ -58,8 +81,7 @@ static void mt7615_mac_init(struct mt7615_dev *dev)
FIELD_PREP(MT_AGG_ARxCR_LIMIT(7), MT7615_RATE_RETRY - 1));
mt76_wr(dev, MT_AGG_ARCR,
- (MT_AGG_ARCR_INIT_RATE1 |
- FIELD_PREP(MT_AGG_ARCR_RTS_RATE_THR, 2) |
+ (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)));
@@ -155,17 +177,6 @@ static const struct ieee80211_iface_combination if_comb[] = {
}
};
-static int mt7615_init_debugfs(struct mt7615_dev *dev)
-{
- struct dentry *dir;
-
- dir = mt76_register_debugfs(&dev->mt76);
- if (!dir)
- return -ENOMEM;
-
- return 0;
-}
-
static void
mt7615_init_txpower(struct mt7615_dev *dev,
struct ieee80211_supported_band *sband)
@@ -208,6 +219,30 @@ mt7615_init_txpower(struct mt7615_dev *dev,
}
}
+static void
+mt7615_regd_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct mt7615_dev *dev = hw->priv;
+ struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
+
+ if (request->dfs_region == dev->mt76.region)
+ return;
+
+ dev->mt76.region = request->dfs_region;
+
+ if (!(chandef->chan->flags & IEEE80211_CHAN_RADAR))
+ return;
+
+ mt7615_dfs_stop_radar_detector(dev);
+ if (request->dfs_region == NL80211_DFS_UNSET)
+ mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, MT_HW_RDD0,
+ MT_RX_SEL0, 0);
+ else
+ mt7615_dfs_start_radar_detector(dev);
+}
+
int mt7615_register_device(struct mt7615_dev *dev)
{
struct ieee80211_hw *hw = mt76_hw(dev);
@@ -230,6 +265,8 @@ int mt7615_register_device(struct mt7615_dev *dev)
wiphy->iface_combinations = if_comb;
wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+ wiphy->reg_notifier = mt7615_regd_notifier;
+ wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
ieee80211_hw_set(hw, SUPPORTS_REORDERING_BUFFER);
ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
@@ -243,6 +280,7 @@ int mt7615_register_device(struct mt7615_dev *dev)
IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
dev->mt76.chainmask = 0x404;
dev->mt76.antenna_mask = 0xf;
+ dev->dfs_state = -1;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
#ifdef CONFIG_MAC80211_MESH
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index 1eb0e9c9970c..e07ce2c10013 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -232,11 +232,9 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
struct mt76_txwi_cache *t;
struct mt7615_dev *dev;
struct mt7615_txp *txp;
- u8 *txwi_ptr;
- txwi_ptr = mt76_get_txwi_ptr(mdev, e->txwi);
- txp = (struct mt7615_txp *)(txwi_ptr + MT_TXD_SIZE);
dev = container_of(mdev, struct mt7615_dev, mt76);
+ txp = mt7615_txwi_to_txp(mdev, e->txwi);
spin_lock_bh(&dev->token_lock);
t = idr_remove(&dev->token, le16_to_cpu(txp->token));
@@ -248,12 +246,13 @@ void mt7615_tx_complete_skb(struct mt76_dev *mdev, enum mt76_txq_id qid,
mt76_tx_complete_skb(mdev, e->skb);
}
-u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev,
- const struct ieee80211_tx_rate *rate,
- bool stbc, u8 *bw)
+static u16
+mt7615_mac_tx_rate_val(struct mt7615_dev *dev,
+ const struct ieee80211_tx_rate *rate,
+ bool stbc, u8 *bw)
{
u8 phy, nss, rate_idx;
- u16 rateval;
+ u16 rateval = 0;
*bw = 0;
@@ -291,12 +290,14 @@ u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev,
rate_idx = val & 0xff;
}
- rateval = (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
- FIELD_PREP(MT_TX_RATE_MODE, phy) |
- FIELD_PREP(MT_TX_RATE_NSS, nss - 1));
-
- if (stbc && nss == 1)
+ if (stbc && nss == 1) {
+ nss++;
rateval |= MT_TX_RATE_STBC;
+ }
+
+ rateval |= (FIELD_PREP(MT_TX_RATE_IDX, rate_idx) |
+ FIELD_PREP(MT_TX_RATE_MODE, phy) |
+ FIELD_PREP(MT_TX_RATE_NSS, nss - 1));
return rateval;
}
@@ -309,9 +310,10 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_tx_rate *rate = &info->control.rates[0];
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ bool multicast = is_multicast_ether_addr(hdr->addr1);
struct ieee80211_vif *vif = info->control.vif;
int tx_count = 8;
- u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0;
+ u8 fc_type, fc_stype, p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
__le16 fc = hdr->frame_control;
u16 seqno = 0;
u32 val;
@@ -320,6 +322,7 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
omac_idx = mvif->omac_idx;
+ wmm_idx = mvif->wmm_idx;
}
if (sta) {
@@ -331,8 +334,9 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
fc_type = (le16_to_cpu(fc) & IEEE80211_FCTL_FTYPE) >> 2;
fc_stype = (le16_to_cpu(fc) & IEEE80211_FCTL_STYPE) >> 4;
- if (ieee80211_is_data(fc)) {
- q_idx = skb_get_queue_mapping(skb);
+ if (ieee80211_is_data(fc) || ieee80211_is_bufferable_mmpdu(fc)) {
+ 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)) {
q_idx = MT_LMAC_BCN0;
@@ -360,8 +364,18 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
val = FIELD_PREP(MT_TXD2_FRAME_TYPE, fc_type) |
FIELD_PREP(MT_TXD2_SUB_TYPE, fc_stype) |
- FIELD_PREP(MT_TXD2_MULTICAST,
- is_multicast_ether_addr(hdr->addr1));
+ FIELD_PREP(MT_TXD2_MULTICAST, multicast);
+ if (key) {
+ if (multicast && ieee80211_is_robust_mgmt_frame(skb) &&
+ key->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
+ val |= MT_TXD2_BIP;
+ txwi[3] = 0;
+ } else {
+ txwi[3] = cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+ }
+ } else {
+ txwi[3] = 0;
+ }
txwi[2] = cpu_to_le32(val);
if (!(info->flags & IEEE80211_TX_CTL_AMPDU))
@@ -418,14 +432,11 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
}
val |= FIELD_PREP(MT_TXD3_SEQ, seqno);
- txwi[3] = cpu_to_le32(val);
+ txwi[3] |= cpu_to_le32(val);
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
txwi[3] |= cpu_to_le32(MT_TXD3_NO_ACK);
- if (key)
- txwi[3] |= cpu_to_le32(MT_TXD3_PROTECT_FRAME);
-
txwi[7] = FIELD_PREP(MT_TXD7_TYPE, fc_type) |
FIELD_PREP(MT_TXD7_SUB_TYPE, fc_stype);
@@ -436,16 +447,318 @@ void mt7615_txp_skb_unmap(struct mt76_dev *dev,
struct mt76_txwi_cache *t)
{
struct mt7615_txp *txp;
- u8 *txwi;
int i;
- txwi = mt76_get_txwi_ptr(dev, t);
- txp = (struct mt7615_txp *)(txwi + MT_TXD_SIZE);
+ txp = mt7615_txwi_to_txp(dev, t);
for (i = 1; i < txp->nbuf; i++)
dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]),
le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
}
+static u32 mt7615_mac_wtbl_addr(int wcid)
+{
+ return MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE;
+}
+
+void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
+ struct ieee80211_tx_rate *probe_rate,
+ struct ieee80211_tx_rate *rates)
+{
+ struct ieee80211_tx_rate *ref;
+ int wcid = sta->wcid.idx;
+ u32 addr = mt7615_mac_wtbl_addr(wcid);
+ bool stbc = false;
+ int n_rates = sta->n_rates;
+ u8 bw, bw_prev, bw_idx = 0;
+ u16 val[4];
+ u16 probe_val;
+ u32 w5, w27;
+ bool rateset;
+ int i, k;
+
+ if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
+ return;
+
+ for (i = n_rates; i < 4; i++)
+ rates[i] = rates[n_rates - 1];
+
+ rateset = !(sta->rate_set_tsf & BIT(0));
+ memcpy(sta->rateset[rateset].rates, rates,
+ sizeof(sta->rateset[rateset].rates));
+ if (probe_rate) {
+ sta->rateset[rateset].probe_rate = *probe_rate;
+ ref = &sta->rateset[rateset].probe_rate;
+ } else {
+ sta->rateset[rateset].probe_rate.idx = -1;
+ ref = &sta->rateset[rateset].rates[0];
+ }
+
+ rates = sta->rateset[rateset].rates;
+ for (i = 0; i < ARRAY_SIZE(sta->rateset[rateset].rates); i++) {
+ /*
+ * We don't support switching between short and long GI
+ * within the rate set. For accurate tx status reporting, we
+ * need to make sure that flags match.
+ * For improved performance, avoid duplicate entries by
+ * decrementing the MCS index if necessary
+ */
+ if ((ref->flags ^ rates[i].flags) & IEEE80211_TX_RC_SHORT_GI)
+ rates[i].flags ^= IEEE80211_TX_RC_SHORT_GI;
+
+ for (k = 0; k < i; k++) {
+ if (rates[i].idx != rates[k].idx)
+ continue;
+ if ((rates[i].flags ^ rates[k].flags) &
+ (IEEE80211_TX_RC_40_MHZ_WIDTH |
+ IEEE80211_TX_RC_80_MHZ_WIDTH |
+ IEEE80211_TX_RC_160_MHZ_WIDTH))
+ continue;
+
+ if (!rates[i].idx)
+ continue;
+
+ rates[i].idx--;
+ }
+ }
+
+ val[0] = mt7615_mac_tx_rate_val(dev, &rates[0], stbc, &bw);
+ bw_prev = bw;
+
+ if (probe_rate) {
+ probe_val = mt7615_mac_tx_rate_val(dev, probe_rate, stbc, &bw);
+ if (bw)
+ bw_idx = 1;
+ else
+ bw_prev = 0;
+ } else {
+ probe_val = val[0];
+ }
+
+ val[1] = mt7615_mac_tx_rate_val(dev, &rates[1], stbc, &bw);
+ if (bw_prev) {
+ bw_idx = 3;
+ bw_prev = bw;
+ }
+
+ val[2] = mt7615_mac_tx_rate_val(dev, &rates[2], stbc, &bw);
+ if (bw_prev) {
+ bw_idx = 5;
+ bw_prev = bw;
+ }
+
+ val[3] = mt7615_mac_tx_rate_val(dev, &rates[3], stbc, &bw);
+ if (bw_prev)
+ bw_idx = 7;
+
+ w27 = mt76_rr(dev, addr + 27 * 4);
+ w27 &= ~MT_WTBL_W27_CC_BW_SEL;
+ w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, bw);
+
+ w5 = mt76_rr(dev, addr + 5 * 4);
+ w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE |
+ MT_WTBL_W5_MPDU_OK_COUNT |
+ MT_WTBL_W5_MPDU_FAIL_COUNT |
+ MT_WTBL_W5_RATE_IDX);
+ w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, bw) |
+ FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, bw_idx ? bw_idx - 1 : 7);
+
+ mt76_wr(dev, MT_WTBL_RIUCR0, w5);
+
+ mt76_wr(dev, MT_WTBL_RIUCR1,
+ FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) |
+ FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) |
+ FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[1]));
+
+ mt76_wr(dev, MT_WTBL_RIUCR2,
+ FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[1] >> 8) |
+ FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) |
+ FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[2]) |
+ FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2]));
+
+ mt76_wr(dev, MT_WTBL_RIUCR3,
+ FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) |
+ FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[3]) |
+ FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3]));
+
+ mt76_wr(dev, MT_WTBL_UPDATE,
+ FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) |
+ MT_WTBL_UPDATE_RATE_UPDATE |
+ MT_WTBL_UPDATE_TX_COUNT_CLEAR);
+
+ mt76_wr(dev, addr + 27 * 4, w27);
+
+ mt76_set(dev, MT_LPON_T0CR, MT_LPON_T0CR_MODE); /* TSF read */
+ sta->rate_set_tsf = (mt76_rr(dev, MT_LPON_UTTR0) & ~BIT(0)) | rateset;
+
+ if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET))
+ mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
+
+ sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates;
+ sta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
+}
+
+static enum mt7615_cipher_type
+mt7615_mac_get_cipher(int cipher)
+{
+ switch (cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ return MT_CIPHER_WEP40;
+ case WLAN_CIPHER_SUITE_WEP104:
+ return MT_CIPHER_WEP104;
+ case WLAN_CIPHER_SUITE_TKIP:
+ return MT_CIPHER_TKIP;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ return MT_CIPHER_BIP_CMAC_128;
+ case WLAN_CIPHER_SUITE_CCMP:
+ return MT_CIPHER_AES_CCMP;
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ return MT_CIPHER_CCMP_256;
+ case WLAN_CIPHER_SUITE_GCMP:
+ return MT_CIPHER_GCMP;
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ return MT_CIPHER_GCMP_256;
+ case WLAN_CIPHER_SUITE_SMS4:
+ return MT_CIPHER_WAPI;
+ default:
+ return MT_CIPHER_NONE;
+ }
+}
+
+static int
+mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key,
+ enum mt7615_cipher_type cipher,
+ enum set_key_cmd cmd)
+{
+ u32 addr = mt7615_mac_wtbl_addr(wcid->idx) + 30 * 4;
+ u8 data[32] = {};
+
+ if (key->keylen > sizeof(data))
+ return -EINVAL;
+
+ mt76_rr_copy(dev, addr, data, sizeof(data));
+ if (cmd == SET_KEY) {
+ if (cipher == MT_CIPHER_TKIP) {
+ /* Rx/Tx MIC keys are swapped */
+ memcpy(data + 16, key->key + 24, 8);
+ memcpy(data + 24, key->key + 16, 8);
+ }
+ if (cipher != MT_CIPHER_BIP_CMAC_128 && wcid->cipher)
+ memmove(data + 16, data, 16);
+ if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher)
+ memcpy(data, key->key, key->keylen);
+ else if (cipher == MT_CIPHER_BIP_CMAC_128)
+ memcpy(data + 16, key->key, 16);
+ } else {
+ if (wcid->cipher & ~BIT(cipher)) {
+ if (cipher != MT_CIPHER_BIP_CMAC_128)
+ memmove(data, data + 16, 16);
+ memset(data + 16, 0, 16);
+ } else {
+ memset(data, 0, sizeof(data));
+ }
+ }
+ mt76_wr_copy(dev, addr, data, sizeof(data));
+
+ return 0;
+}
+
+static int
+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;
+
+ if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
+ return -ETIMEDOUT;
+
+ w0 = mt76_rr(dev, addr);
+ w1 = mt76_rr(dev, addr + 4);
+ if (cmd == SET_KEY) {
+ w0 |= MT_WTBL_W0_RX_KEY_VALID |
+ FIELD_PREP(MT_WTBL_W0_RX_IK_VALID,
+ cipher == MT_CIPHER_BIP_CMAC_128);
+ if (cipher != MT_CIPHER_BIP_CMAC_128 ||
+ !wcid->cipher)
+ w0 |= FIELD_PREP(MT_WTBL_W0_KEY_IDX, keyidx);
+ } else {
+ if (!(wcid->cipher & ~BIT(cipher)))
+ w0 &= ~(MT_WTBL_W0_RX_KEY_VALID |
+ MT_WTBL_W0_KEY_IDX);
+ if (cipher == MT_CIPHER_BIP_CMAC_128)
+ w0 &= ~MT_WTBL_W0_RX_IK_VALID;
+ }
+ mt76_wr(dev, MT_WTBL_RICR0, w0);
+ mt76_wr(dev, MT_WTBL_RICR1, w1);
+
+ mt76_wr(dev, MT_WTBL_UPDATE,
+ FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid->idx) |
+ MT_WTBL_UPDATE_RXINFO_UPDATE);
+
+ if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static void
+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);
+
+ if (cmd == SET_KEY) {
+ if (cipher != MT_CIPHER_BIP_CMAC_128 || !wcid->cipher)
+ mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE,
+ FIELD_PREP(MT_WTBL_W2_KEY_TYPE, cipher));
+ } else {
+ if (cipher != MT_CIPHER_BIP_CMAC_128 &&
+ wcid->cipher & BIT(MT_CIPHER_BIP_CMAC_128))
+ mt76_rmw(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE,
+ FIELD_PREP(MT_WTBL_W2_KEY_TYPE,
+ MT_CIPHER_BIP_CMAC_128));
+ else if (!(wcid->cipher & ~BIT(cipher)))
+ mt76_clear(dev, addr + 2 * 4, MT_WTBL_W2_KEY_TYPE);
+ }
+}
+
+int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev,
+ struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key,
+ enum set_key_cmd cmd)
+{
+ enum mt7615_cipher_type cipher;
+ int err;
+
+ cipher = mt7615_mac_get_cipher(key->cipher);
+ if (cipher == MT_CIPHER_NONE)
+ return -EOPNOTSUPP;
+
+ spin_lock_bh(&dev->mt76.lock);
+
+ mt7615_mac_wtbl_update_cipher(dev, wcid, cipher, cmd);
+ err = mt7615_mac_wtbl_update_key(dev, wcid, key, cipher, cmd);
+ if (err < 0)
+ goto out;
+
+ err = mt7615_mac_wtbl_update_pk(dev, wcid, cipher, key->keyidx,
+ cmd);
+ if (err < 0)
+ goto out;
+
+ if (cmd == SET_KEY)
+ wcid->cipher |= BIT(cipher);
+ else
+ wcid->cipher &= ~BIT(cipher);
+
+out:
+ spin_unlock_bh(&dev->mt76.lock);
+
+ return err;
+}
+
int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,
struct ieee80211_sta *sta,
@@ -469,9 +782,9 @@ int mt7615_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
spin_lock_bh(&dev->mt76.lock);
- msta->rate_probe = true;
- mt7615_mcu_set_rates(dev, msta, &info->control.rates[0],
+ mt7615_mac_set_rates(dev, msta, &info->control.rates[0],
msta->rates);
+ msta->rate_probe = true;
spin_unlock_bh(&dev->mt76.lock);
}
@@ -523,9 +836,13 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
struct ieee80211_tx_info *info, __le32 *txs_data)
{
struct ieee80211_supported_band *sband;
- int i, idx, count, final_idx = 0;
+ struct mt7615_rate_set *rs;
+ int first_idx = 0, last_idx;
+ int i, idx, count;
bool fixed_rate, ack_timeout;
bool probe, ampdu, cck = false;
+ bool rs_idx;
+ u32 rate_set_tsf;
u32 final_rate, final_rate_flags, final_nss, txs;
fixed_rate = info->status.rates[0].count;
@@ -536,6 +853,7 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
txs = le32_to_cpu(txs_data[3]);
count = FIELD_GET(MT_TXS3_TX_COUNT, txs);
+ last_idx = FIELD_GET(MT_TXS3_LAST_TX_RATE, txs);
txs = le32_to_cpu(txs_data[0]);
final_rate = FIELD_GET(MT_TXS0_TX_RATE, txs);
@@ -557,38 +875,57 @@ static bool mt7615_fill_txs(struct mt7615_dev *dev, struct mt7615_sta *sta,
if (ampdu || (info->flags & IEEE80211_TX_CTL_AMPDU))
info->flags |= IEEE80211_TX_STAT_AMPDU | IEEE80211_TX_CTL_AMPDU;
+ first_idx = max_t(int, 0, last_idx - (count + 1) / MT7615_RATE_RETRY);
+
if (fixed_rate && !probe) {
info->status.rates[0].count = count;
+ i = 0;
goto out;
}
- for (i = 0, idx = 0; i < ARRAY_SIZE(info->status.rates); i++) {
- int cur_count = min_t(int, count, 2 * MT7615_RATE_RETRY);
+ rate_set_tsf = READ_ONCE(sta->rate_set_tsf);
+ rs_idx = !((u32)(FIELD_GET(MT_TXS4_F0_TIMESTAMP, le32_to_cpu(txs_data[4])) -
+ rate_set_tsf) < 1000000);
+ rs_idx ^= rate_set_tsf & BIT(0);
+ rs = &sta->rateset[rs_idx];
- if (!i && probe) {
- cur_count = 1;
- } else {
- info->status.rates[i] = sta->rates[idx];
- idx++;
- }
+ if (!first_idx && rs->probe_rate.idx >= 0) {
+ info->status.rates[0] = rs->probe_rate;
- if (i && info->status.rates[i].idx < 0) {
- info->status.rates[i - 1].count += count;
- break;
+ spin_lock_bh(&dev->mt76.lock);
+ if (sta->rate_probe) {
+ mt7615_mac_set_rates(dev, sta, NULL, sta->rates);
+ sta->rate_probe = false;
}
+ spin_unlock_bh(&dev->mt76.lock);
+ } else {
+ info->status.rates[0] = rs->rates[first_idx / 2];
+ }
+ info->status.rates[0].count = 0;
- if (!count) {
- info->status.rates[i].idx = -1;
- break;
- }
+ for (i = 0, idx = first_idx; count && idx <= last_idx; idx++) {
+ struct ieee80211_tx_rate *cur_rate;
+ int cur_count;
- info->status.rates[i].count = cur_count;
- final_idx = i;
+ cur_rate = &rs->rates[idx / 2];
+ cur_count = min_t(int, MT7615_RATE_RETRY, count);
count -= cur_count;
+
+ if (idx && (cur_rate->idx != info->status.rates[i].idx ||
+ cur_rate->flags != info->status.rates[i].flags)) {
+ i++;
+ if (i == ARRAY_SIZE(info->status.rates))
+ break;
+
+ info->status.rates[i] = *cur_rate;
+ info->status.rates[i].count = 0;
+ }
+
+ info->status.rates[i].count += cur_count;
}
out:
- final_rate_flags = info->status.rates[final_idx].flags;
+ final_rate_flags = info->status.rates[i].flags;
switch (FIELD_GET(MT_TX_RATE_MODE, final_rate)) {
case MT_PHY_TYPE_CCK:
@@ -613,6 +950,10 @@ out:
break;
case MT_PHY_TYPE_VHT:
final_nss = FIELD_GET(MT_TX_RATE_NSS, final_rate);
+
+ if ((final_rate & MT_TX_RATE_STBC) && final_nss)
+ final_nss--;
+
final_rate_flags |= IEEE80211_TX_RC_VHT_MCS;
final_rate = (final_rate & MT_TX_RATE_IDX) | (final_nss << 4);
break;
@@ -620,8 +961,8 @@ out:
return false;
}
- info->status.rates[final_idx].idx = final_rate;
- info->status.rates[final_idx].flags = final_rate_flags;
+ info->status.rates[i].idx = final_rate;
+ info->status.rates[i].flags = final_rate_flags;
return true;
}
@@ -642,16 +983,6 @@ static bool mt7615_mac_add_txs_skb(struct mt7615_dev *dev,
if (skb) {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) {
- spin_lock_bh(&dev->mt76.lock);
- if (sta->rate_probe) {
- mt7615_mcu_set_rates(dev, sta, NULL,
- sta->rates);
- sta->rate_probe = false;
- }
- spin_unlock_bh(&dev->mt76.lock);
- }
-
if (!mt7615_fill_txs(dev, sta, info, txs_data)) {
ieee80211_tx_info_clear_status(info);
info->status.rates[0].idx = -1;
@@ -735,6 +1066,198 @@ void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb)
dev_kfree_skb(skb);
}
+static void
+mt7615_mac_set_default_sensitivity(struct mt7615_dev *dev)
+{
+ mt76_rmw(dev, MT_WF_PHY_B0_MIN_PRI_PWR,
+ MT_WF_PHY_B0_PD_OFDM_MASK,
+ MT_WF_PHY_B0_PD_OFDM(0x13c));
+ mt76_rmw(dev, MT_WF_PHY_B1_MIN_PRI_PWR,
+ MT_WF_PHY_B1_PD_OFDM_MASK,
+ MT_WF_PHY_B1_PD_OFDM(0x13c));
+
+ mt76_rmw(dev, MT_WF_PHY_B0_RXTD_CCK_PD,
+ MT_WF_PHY_B0_PD_CCK_MASK,
+ MT_WF_PHY_B0_PD_CCK(0x92));
+ mt76_rmw(dev, MT_WF_PHY_B1_RXTD_CCK_PD,
+ MT_WF_PHY_B1_PD_CCK_MASK,
+ MT_WF_PHY_B1_PD_CCK(0x92));
+
+ dev->ofdm_sensitivity = -98;
+ dev->cck_sensitivity = -110;
+ dev->last_cca_adj = jiffies;
+}
+
+void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable)
+{
+ mutex_lock(&dev->mt76.mutex);
+
+ if (dev->scs_en == enable)
+ goto out;
+
+ if (enable) {
+ /* DBDC not supported */
+ mt76_set(dev, MT_WF_PHY_B0_MIN_PRI_PWR,
+ MT_WF_PHY_B0_PD_BLK);
+ if (is_mt7622(&dev->mt76)) {
+ mt76_set(dev, MT_MIB_M0_MISC_CR, 0x7 << 8);
+ mt76_set(dev, MT_MIB_M0_MISC_CR, 0x7);
+ }
+ } else {
+ mt76_clear(dev, MT_WF_PHY_B0_MIN_PRI_PWR,
+ MT_WF_PHY_B0_PD_BLK);
+ mt76_clear(dev, MT_WF_PHY_B1_MIN_PRI_PWR,
+ MT_WF_PHY_B1_PD_BLK);
+ }
+
+ mt7615_mac_set_default_sensitivity(dev);
+ dev->scs_en = enable;
+
+out:
+ mutex_unlock(&dev->mt76.mutex);
+}
+
+void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev)
+{
+ mt76_clear(dev, MT_WF_PHY_R0_B0_PHYMUX_5, GENMASK(22, 20));
+ mt76_set(dev, MT_WF_PHY_R0_B0_PHYMUX_5, BIT(22) | BIT(20));
+}
+
+static void
+mt7615_mac_adjust_sensitivity(struct mt7615_dev *dev,
+ u32 rts_err_rate, bool ofdm)
+{
+ int false_cca = ofdm ? dev->false_cca_ofdm : dev->false_cca_cck;
+ u16 def_th = ofdm ? -98 : -110;
+ bool update = false;
+ s8 *sensitivity;
+ int signal;
+
+ sensitivity = ofdm ? &dev->ofdm_sensitivity : &dev->cck_sensitivity;
+ signal = mt76_get_min_avg_rssi(&dev->mt76);
+ if (!signal) {
+ mt7615_mac_set_default_sensitivity(dev);
+ return;
+ }
+
+ signal = min(signal, -72);
+ if (false_cca > 500) {
+ if (rts_err_rate > MT_FRAC(40, 100))
+ return;
+
+ /* decrease coverage */
+ if (*sensitivity == def_th && signal > -90) {
+ *sensitivity = -90;
+ update = true;
+ } else if (*sensitivity + 2 < signal) {
+ *sensitivity += 2;
+ update = true;
+ }
+ } else if ((false_cca > 0 && false_cca < 50) ||
+ rts_err_rate > MT_FRAC(60, 100)) {
+ /* increase coverage */
+ if (*sensitivity - 2 >= def_th) {
+ *sensitivity -= 2;
+ update = true;
+ }
+ }
+
+ if (*sensitivity > signal) {
+ *sensitivity = signal;
+ update = true;
+ }
+
+ if (update) {
+ u16 val;
+
+ if (ofdm) {
+ /* DBDC not supported */
+ val = *sensitivity * 2 + 512;
+ mt76_rmw(dev, MT_WF_PHY_B0_MIN_PRI_PWR,
+ MT_WF_PHY_B0_PD_OFDM_MASK,
+ MT_WF_PHY_B0_PD_OFDM(val));
+ } else {
+ val = *sensitivity + 256;
+ mt76_rmw(dev, MT_WF_PHY_B0_RXTD_CCK_PD,
+ MT_WF_PHY_B0_PD_CCK_MASK,
+ MT_WF_PHY_B0_PD_CCK(val));
+ mt76_rmw(dev, MT_WF_PHY_B1_RXTD_CCK_PD,
+ MT_WF_PHY_B1_PD_CCK_MASK,
+ MT_WF_PHY_B1_PD_CCK(val));
+ }
+ dev->last_cca_adj = jiffies;
+ }
+}
+
+static void
+mt7615_mac_scs_check(struct mt7615_dev *dev)
+{
+ u32 val, rts_cnt = 0, rts_retries_cnt = 0, rts_err_rate = 0;
+ u32 mdrdy_cck, mdrdy_ofdm, pd_cck, pd_ofdm;
+ int i;
+
+ if (!dev->scs_en)
+ return;
+
+ for (i = 0; i < 4; i++) {
+ u32 data;
+
+ val = mt76_rr(dev, MT_MIB_MB_SDR0(i));
+ data = FIELD_GET(MT_MIB_RTS_RETRIES_COUNT_MASK, val);
+ if (data > rts_retries_cnt) {
+ rts_cnt = FIELD_GET(MT_MIB_RTS_COUNT_MASK, val);
+ rts_retries_cnt = data;
+ }
+ }
+
+ val = mt76_rr(dev, MT_WF_PHY_R0_B0_PHYCTRL_STS0);
+ pd_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_CCK, val);
+ pd_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_PD_OFDM, val);
+
+ val = mt76_rr(dev, MT_WF_PHY_R0_B0_PHYCTRL_STS5);
+ mdrdy_cck = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_CCK, val);
+ mdrdy_ofdm = FIELD_GET(MT_WF_PHYCTRL_STAT_MDRDY_OFDM, val);
+
+ dev->false_cca_ofdm = pd_ofdm - mdrdy_ofdm;
+ dev->false_cca_cck = pd_cck - mdrdy_cck;
+ mt7615_mac_cca_stats_reset(dev);
+
+ if (rts_cnt + rts_retries_cnt)
+ rts_err_rate = MT_FRAC(rts_retries_cnt,
+ rts_cnt + rts_retries_cnt);
+
+ /* cck */
+ mt7615_mac_adjust_sensitivity(dev, rts_err_rate, false);
+ /* ofdm */
+ mt7615_mac_adjust_sensitivity(dev, rts_err_rate, true);
+
+ if (time_after(jiffies, dev->last_cca_adj + 10 * HZ))
+ mt7615_mac_set_default_sensitivity(dev);
+}
+
+void mt7615_update_channel(struct mt76_dev *mdev)
+{
+ struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
+ struct mt76_channel_state *state;
+ ktime_t cur_time;
+ u32 busy;
+
+ if (!test_bit(MT76_STATE_RUNNING, &mdev->state))
+ return;
+
+ state = mt76_channel_state(mdev, mdev->chandef.chan);
+ /* TODO: add DBDC support */
+ busy = mt76_get_field(dev, MT_MIB_SDR16(0), MT_MIB_BUSY_MASK);
+
+ spin_lock_bh(&mdev->cc_lock);
+ cur_time = ktime_get_boottime();
+ state->cc_busy += busy;
+ state->cc_active += ktime_to_us(ktime_sub(cur_time,
+ mdev->survey_time));
+ mdev->survey_time = cur_time;
+ spin_unlock_bh(&mdev->cc_lock);
+}
+
void mt7615_mac_work(struct work_struct *work)
{
struct mt7615_dev *dev;
@@ -742,7 +1265,103 @@ void mt7615_mac_work(struct work_struct *work)
dev = (struct mt7615_dev *)container_of(work, struct mt76_dev,
mac_work.work);
+ mutex_lock(&dev->mt76.mutex);
+ mt7615_update_channel(&dev->mt76);
+ if (++dev->mac_work_count == 5) {
+ mt7615_mac_scs_check(dev);
+ dev->mac_work_count = 0;
+ }
+ mutex_unlock(&dev->mt76.mutex);
+
mt76_tx_status_check(&dev->mt76, NULL, false);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
MT7615_WATCHDOG_TIME);
}
+
+int mt7615_dfs_stop_radar_detector(struct mt7615_dev *dev)
+{
+ struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
+ int err;
+
+ err = mt7615_mcu_rdd_cmd(dev, RDD_STOP, MT_HW_RDD0,
+ MT_RX_SEL0, 0);
+ if (err < 0)
+ return err;
+
+ if (chandef->width == NL80211_CHAN_WIDTH_160 ||
+ chandef->width == NL80211_CHAN_WIDTH_80P80)
+ err = mt7615_mcu_rdd_cmd(dev, RDD_STOP, MT_HW_RDD1,
+ MT_RX_SEL0, 0);
+ return err;
+}
+
+static int mt7615_dfs_start_rdd(struct mt7615_dev *dev, int chain)
+{
+ int err;
+
+ err = mt7615_mcu_rdd_cmd(dev, RDD_START, chain, MT_RX_SEL0, 0);
+ if (err < 0)
+ return err;
+
+ return mt7615_mcu_rdd_cmd(dev, RDD_DET_MODE, chain,
+ MT_RX_SEL0, 1);
+}
+
+int mt7615_dfs_start_radar_detector(struct mt7615_dev *dev)
+{
+ struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
+ int err;
+
+ /* start CAC */
+ err = mt7615_mcu_rdd_cmd(dev, RDD_CAC_START, MT_HW_RDD0,
+ MT_RX_SEL0, 0);
+ if (err < 0)
+ return err;
+
+ /* TODO: DBDC support */
+
+ err = mt7615_dfs_start_rdd(dev, MT_HW_RDD0);
+ if (err < 0)
+ return err;
+
+ if (chandef->width == NL80211_CHAN_WIDTH_160 ||
+ chandef->width == NL80211_CHAN_WIDTH_80P80) {
+ err = mt7615_dfs_start_rdd(dev, MT_HW_RDD1);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+int mt7615_dfs_init_radar_detector(struct mt7615_dev *dev)
+{
+ struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
+ int err;
+
+ if (dev->mt76.region == NL80211_DFS_UNSET)
+ return 0;
+
+ if (test_bit(MT76_SCANNING, &dev->mt76.state))
+ return 0;
+
+ if (dev->dfs_state == chandef->chan->dfs_state)
+ return 0;
+
+ dev->dfs_state = chandef->chan->dfs_state;
+
+ if (chandef->chan->flags & IEEE80211_CHAN_RADAR) {
+ if (chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
+ return mt7615_dfs_start_radar_detector(dev);
+ else
+ return mt7615_mcu_rdd_cmd(dev, RDD_CAC_END, MT_HW_RDD0,
+ MT_RX_SEL0, 0);
+ } else {
+ err = mt7615_mcu_rdd_cmd(dev, RDD_NORMAL_START,
+ MT_HW_RDD0, MT_RX_SEL0, 0);
+ if (err < 0)
+ return err;
+
+ return mt7615_dfs_stop_radar_detector(dev);
+ }
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
index b00ce8db58e9..38695d4f92e2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.h
@@ -302,4 +302,32 @@ struct mt7615_tx_free {
#define MT_TXS6_F1_RCPI_1 GENMASK(15, 8)
#define MT_TXS6_F1_RCPI_0 GENMASK(7, 0)
+enum mt7615_cipher_type {
+ MT_CIPHER_NONE,
+ MT_CIPHER_WEP40,
+ MT_CIPHER_TKIP,
+ MT_CIPHER_TKIP_NO_MIC,
+ MT_CIPHER_AES_CCMP,
+ MT_CIPHER_WEP104,
+ MT_CIPHER_BIP_CMAC_128,
+ MT_CIPHER_WEP128,
+ MT_CIPHER_WAPI,
+ MT_CIPHER_CCMP_256 = 10,
+ MT_CIPHER_GCMP,
+ MT_CIPHER_GCMP_256,
+};
+
+static inline struct mt7615_txp *
+mt7615_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
+{
+ u8 *txwi;
+
+ if (!t)
+ return NULL;
+
+ txwi = mt76_get_txwi_ptr(dev, t);
+
+ return (struct mt7615_txp *)(txwi + MT_TXD_SIZE);
+}
+
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index b4d6af812c54..87c748715b5d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -16,6 +16,7 @@ static int mt7615_start(struct ieee80211_hw *hw)
{
struct mt7615_dev *dev = hw->priv;
+ dev->mt76.survey_time = ktime_get_boottime();
set_bit(MT76_STATE_RUNNING, &dev->mt76.state);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
MT7615_WATCHDOG_TIME);
@@ -85,9 +86,9 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
}
mvif->omac_idx = idx;
- /* TODO: DBDC support. Use band 0 and wmm 0 for now */
+ /* TODO: DBDC support. Use band 0 for now */
mvif->band_idx = 0;
- mvif->wmm_idx = 0;
+ mvif->wmm_idx = mvif->idx % MT7615_MAX_WMM_SETS;
ret = mt7615_mcu_set_dev_info(dev, vif, 1);
if (ret)
@@ -135,20 +136,32 @@ static int mt7615_set_channel(struct mt7615_dev *dev)
int ret;
cancel_delayed_work_sync(&dev->mt76.mac_work);
+
+ mutex_lock(&dev->mt76.mutex);
set_bit(MT76_RESET, &dev->mt76.state);
+ mt7615_dfs_check_channel(dev);
+
mt76_set_channel(&dev->mt76);
ret = mt7615_mcu_set_channel(dev);
if (ret)
- return ret;
+ goto out;
+
+ ret = mt7615_dfs_init_radar_detector(dev);
+ mt7615_mac_cca_stats_reset(dev);
+ dev->mt76.survey_time = ktime_get_boottime();
+ /* TODO: add DBDC support */
+ mt76_rr(dev, MT_MIB_SDR16(0));
+out:
clear_bit(MT76_RESET, &dev->mt76.state);
+ mutex_unlock(&dev->mt76.mutex);
mt76_txq_schedule_all(&dev->mt76);
ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mt76.mac_work,
MT7615_WATCHDOG_TIME);
- return 0;
+ return ret;
}
static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
@@ -172,18 +185,34 @@ static int mt7615_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
return -EOPNOTSUPP;
+ /* fall back to sw encryption for unsupported ciphers */
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
+ break;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP_256:
+ case WLAN_CIPHER_SUITE_GCMP:
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ case WLAN_CIPHER_SUITE_SMS4:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
if (cmd == SET_KEY) {
key->hw_key_idx = wcid->idx;
wcid->hw_key_idx = idx;
- } else {
- if (idx == wcid->hw_key_idx)
- wcid->hw_key_idx = -1;
-
- key = NULL;
+ } else if (idx == wcid->hw_key_idx) {
+ wcid->hw_key_idx = -1;
}
- mt76_wcid_key_setup(&dev->mt76, wcid, key);
+ mt76_wcid_key_setup(&dev->mt76, wcid,
+ cmd == SET_KEY ? key : NULL);
- return mt7615_mcu_set_wtbl_key(dev, wcid->idx, key, cmd);
+ return mt7615_mac_wtbl_set_key(dev, wcid, key, cmd);
}
static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
@@ -191,14 +220,14 @@ static int mt7615_config(struct ieee80211_hw *hw, u32 changed)
struct mt7615_dev *dev = hw->priv;
int ret = 0;
- mutex_lock(&dev->mt76.mutex);
-
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
ieee80211_stop_queues(hw);
ret = mt7615_set_channel(dev);
ieee80211_wake_queues(hw);
}
+ mutex_lock(&dev->mt76.mutex);
+
if (changed & IEEE80211_CONF_CHANGE_POWER)
ret = mt7615_mcu_set_tx_power(dev);
@@ -220,16 +249,12 @@ static int
mt7615_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue,
const struct ieee80211_tx_queue_params *params)
{
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
struct mt7615_dev *dev = hw->priv;
- static const u8 wmm_queue_map[] = {
- [IEEE80211_AC_BK] = 0,
- [IEEE80211_AC_BE] = 1,
- [IEEE80211_AC_VI] = 2,
- [IEEE80211_AC_VO] = 3,
- };
- /* TODO: hw wmm_set 1~3 */
- return mt7615_mcu_set_wmm(dev, wmm_queue_map[queue], params);
+ queue += mvif->wmm_idx * MT7615_MAX_WMM_SETS;
+
+ return mt7615_mcu_set_wmm(dev, queue, params);
}
static void mt7615_configure_filter(struct ieee80211_hw *hw,
@@ -299,6 +324,18 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
mutex_unlock(&dev->mt76.mutex);
}
+static void
+mt7615_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *chandef)
+{
+ struct mt7615_dev *dev = hw->priv;
+
+ mutex_lock(&dev->mt76.mutex);
+ mt7615_mcu_set_bcn(dev, vif, true);
+ mutex_unlock(&dev->mt76.mutex);
+}
+
int mt7615_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
@@ -358,7 +395,7 @@ static void mt7615_sta_rate_tbl_update(struct ieee80211_hw *hw,
break;
}
msta->n_rates = i;
- mt7615_mcu_set_rates(dev, msta, NULL, msta->rates);
+ mt7615_mac_set_rates(dev, msta, NULL, msta->rates);
msta->rate_probe = false;
spin_unlock_bh(&dev->mt76.lock);
}
@@ -410,7 +447,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_txq *txq = sta->txq[params->tid];
struct mt7615_sta *msta = (struct mt7615_sta *)sta->drv_priv;
u16 tid = params->tid;
- u16 *ssn = &params->ssn;
+ u16 ssn = params->ssn;
struct mt76_txq *mtxq;
if (!txq)
@@ -420,7 +457,7 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
switch (action) {
case IEEE80211_AMPDU_RX_START:
- mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, *ssn,
+ mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
params->buf_size);
mt7615_mcu_set_rx_ba(dev, params, 1);
break;
@@ -436,11 +473,10 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
- ieee80211_send_bar(vif, sta->addr, tid, mtxq->agg_ssn);
mt7615_mcu_set_tx_ba(dev, params, 0);
break;
case IEEE80211_AMPDU_TX_START:
- mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(*ssn);
+ mtxq->agg_ssn = IEEE80211_SN_TO_SEQ(ssn);
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_STOP_CONT:
@@ -453,23 +489,6 @@ mt7615_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return 0;
}
-static void
-mt7615_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- const u8 *mac)
-{
- struct mt7615_dev *dev = hw->priv;
-
- set_bit(MT76_SCANNING, &dev->mt76.state);
-}
-
-static void
-mt7615_sw_scan_complete(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
-{
- struct mt7615_dev *dev = hw->priv;
-
- clear_bit(MT76_SCANNING, &dev->mt76.state);
-}
-
const struct ieee80211_ops mt7615_ops = {
.tx = mt7615_tx,
.start = mt7615_start,
@@ -486,8 +505,10 @@ const struct ieee80211_ops mt7615_ops = {
.set_rts_threshold = mt7615_set_rts_threshold,
.wake_tx_queue = mt76_wake_tx_queue,
.sta_rate_tbl_update = mt7615_sta_rate_tbl_update,
- .sw_scan_start = mt7615_sw_scan,
- .sw_scan_complete = mt7615_sw_scan_complete,
+ .sw_scan_start = mt76_sw_scan,
+ .sw_scan_complete = mt76_sw_scan_complete,
.release_buffered_frames = mt76_release_buffered_frames,
.get_txpower = mt76_get_txpower,
+ .channel_switch_beacon = mt7615_channel_switch_beacon,
+ .get_survey = mt76_get_survey,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index cdad2c8dc297..275d5eaed3b7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -75,7 +75,7 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
txd = mcu_txd->txd;
- val = FIELD_PREP(MT_TXD0_TX_BYTES, cpu_to_le16(skb->len)) |
+ 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);
txd[0] = cpu_to_le32(val);
@@ -113,12 +113,38 @@ static int __mt7615_mcu_msg_send(struct mt7615_dev *dev, struct sk_buff *skb,
}
static int
+mt7615_mcu_parse_response(struct mt7615_dev *dev, int cmd,
+ struct sk_buff *skb, int seq)
+{
+ struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
+ int ret = 0;
+
+ if (seq != rxd->seq)
+ return -EAGAIN;
+
+ switch (cmd) {
+ case -MCU_CMD_PATCH_SEM_CONTROL:
+ skb_pull(skb, sizeof(*rxd) - 4);
+ ret = *skb->data;
+ break;
+ case MCU_EXT_CMD_GET_TEMP:
+ skb_pull(skb, sizeof(*rxd));
+ ret = le32_to_cpu(*(__le32 *)skb->data);
+ break;
+ default:
+ break;
+ }
+ dev_kfree_skb(skb);
+
+ return ret;
+}
+
+static int
mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
int len, bool wait_resp)
{
struct mt7615_dev *dev = container_of(mdev, struct mt7615_dev, mt76);
unsigned long expires = jiffies + 10 * HZ;
- struct mt7615_mcu_rxd *rxd;
struct sk_buff *skb;
int ret, seq;
@@ -141,16 +167,9 @@ mt7615_mcu_msg_send(struct mt76_dev *mdev, int cmd, const void *data,
break;
}
- rxd = (struct mt7615_mcu_rxd *)skb->data;
- if (seq != rxd->seq)
- continue;
-
- if (cmd == -MCU_CMD_PATCH_SEM_CONTROL) {
- skb_pull(skb, sizeof(*rxd) - 4);
- ret = *skb->data;
- }
- dev_kfree_skb(skb);
- break;
+ ret = mt7615_mcu_parse_response(dev, cmd, skb, seq);
+ if (ret != -EAGAIN)
+ break;
}
out:
@@ -159,6 +178,62 @@ out:
return ret;
}
+static void
+mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+{
+ if (vif->csa_active)
+ ieee80211_csa_finish(vif);
+}
+
+static void
+mt7615_mcu_rx_ext_event(struct mt7615_dev *dev, struct sk_buff *skb)
+{
+ struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
+
+ switch (rxd->ext_eid) {
+ case MCU_EXT_EVENT_RDD_REPORT:
+ ieee80211_radar_detected(dev->mt76.hw);
+ dev->hw_pattern++;
+ break;
+ case MCU_EXT_EVENT_CSA_NOTIFY:
+ ieee80211_iterate_active_interfaces_atomic(dev->mt76.hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7615_mcu_csa_finish, dev);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+mt7615_mcu_rx_unsolicited_event(struct mt7615_dev *dev, struct sk_buff *skb)
+{
+ struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
+
+ switch (rxd->eid) {
+ case MCU_EVENT_EXT:
+ mt7615_mcu_rx_ext_event(dev, skb);
+ break;
+ default:
+ break;
+ }
+ dev_kfree_skb(skb);
+}
+
+void mt7615_mcu_rx_event(struct mt7615_dev *dev, struct sk_buff *skb)
+{
+ struct mt7615_mcu_rxd *rxd = (struct mt7615_mcu_rxd *)skb->data;
+
+ if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
+ rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
+ rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
+ rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
+ !rxd->seq)
+ mt7615_mcu_rx_unsolicited_event(dev, skb);
+ else
+ mt76_mcu_rx_event(&dev->mt76, skb);
+}
+
static int mt7615_mcu_init_download(struct mt7615_dev *dev, u32 addr,
u32 len, u32 mode)
{
@@ -192,6 +267,7 @@ static int mt7615_mcu_send_firmware(struct mt7615_dev *dev, const void *data,
data += cur_len;
len -= cur_len;
+ mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false);
}
return ret;
@@ -257,9 +333,9 @@ static int mt7615_driver_own(struct mt7615_dev *dev)
static int mt7615_load_patch(struct mt7615_dev *dev)
{
- const struct firmware *fw;
- const struct mt7615_patch_hdr *hdr;
const char *firmware = MT7615_ROM_PATCH;
+ const struct mt7615_patch_hdr *hdr;
+ const struct firmware *fw = NULL;
int len, ret, sem;
sem = mt7615_mcu_patch_sem_ctrl(dev, 1);
@@ -275,7 +351,7 @@ static int mt7615_load_patch(struct mt7615_dev *dev)
ret = request_firmware(&fw, firmware, dev->mt76.dev);
if (ret)
- return ret;
+ goto out;
if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
dev_err(dev->mt76.dev, "Invalid firmware\n");
@@ -323,7 +399,7 @@ out:
return ret;
}
-static u32 gen_dl_mode(u8 feature_set, bool is_cr4)
+static u32 mt7615_mcu_gen_dl_mode(u8 feature_set, bool is_cr4)
{
u32 ret = 0;
@@ -337,14 +413,45 @@ static u32 gen_dl_mode(u8 feature_set, bool is_cr4)
return ret;
}
+static int
+mt7615_mcu_send_ram_firmware(struct mt7615_dev *dev,
+ const struct mt7615_fw_trailer *hdr,
+ const u8 *data, bool is_cr4)
+{
+ int n_region = is_cr4 ? CR4_REGION_NUM : N9_REGION_NUM;
+ int err, i, offset = 0;
+ u32 len, addr, mode;
+
+ for (i = 0; i < n_region; i++) {
+ mode = mt7615_mcu_gen_dl_mode(hdr[i].feature_set, is_cr4);
+ len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
+ addr = le32_to_cpu(hdr[i].addr);
+
+ err = mt7615_mcu_init_download(dev, addr, len, mode);
+ if (err) {
+ dev_err(dev->mt76.dev, "Download request failed\n");
+ return err;
+ }
+
+ err = mt7615_mcu_send_firmware(dev, data + offset, len);
+ if (err) {
+ dev_err(dev->mt76.dev, "Failed to send firmware to device\n");
+ return err;
+ }
+
+ offset += len;
+ }
+
+ return 0;
+}
+
static int mt7615_load_ram(struct mt7615_dev *dev)
{
const struct firmware *fw;
const struct mt7615_fw_trailer *hdr;
const char *n9_firmware = MT7615_FIRMWARE_N9;
const char *cr4_firmware = MT7615_FIRMWARE_CR4;
- u32 n9_ilm_addr, offset;
- int i, ret;
+ int ret;
ret = request_firmware(&fw, n9_firmware, dev->mt76.dev);
if (ret)
@@ -362,31 +469,12 @@ static int mt7615_load_ram(struct mt7615_dev *dev)
dev_info(dev->mt76.dev, "N9 Firmware Version: %.10s, Build Time: %.15s\n",
hdr->fw_ver, hdr->build_date);
- n9_ilm_addr = le32_to_cpu(hdr->addr);
-
- for (offset = 0, i = 0; i < N9_REGION_NUM; i++) {
- u32 len, addr, mode;
-
- len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
- addr = le32_to_cpu(hdr[i].addr);
- mode = gen_dl_mode(hdr[i].feature_set, false);
-
- 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 to device\n");
- goto out;
- }
-
- offset += len;
- }
+ ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, false);
+ if (ret)
+ goto out;
- ret = mt7615_mcu_start_firmware(dev, n9_ilm_addr, FW_START_OVERRIDE);
+ ret = mt7615_mcu_start_firmware(dev, le32_to_cpu(hdr->addr),
+ FW_START_OVERRIDE);
if (ret) {
dev_err(dev->mt76.dev, "Failed to start N9 firmware\n");
goto out;
@@ -410,27 +498,9 @@ static int mt7615_load_ram(struct mt7615_dev *dev)
dev_info(dev->mt76.dev, "CR4 Firmware Version: %.10s, Build Time: %.15s\n",
hdr->fw_ver, hdr->build_date);
- for (offset = 0, i = 0; i < CR4_REGION_NUM; i++) {
- u32 len, addr, mode;
-
- len = le32_to_cpu(hdr[i].len) + IMG_CRC_LEN;
- addr = le32_to_cpu(hdr[i].addr);
- mode = gen_dl_mode(hdr[i].feature_set, true);
-
- 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 to device\n");
- goto out;
- }
-
- offset += len;
- }
+ ret = mt7615_mcu_send_ram_firmware(dev, hdr, fw->data, true);
+ if (ret)
+ goto out;
ret = mt7615_mcu_start_firmware(dev, 0, FW_START_WORKING_PDA_CR4);
if (ret)
@@ -469,6 +539,8 @@ static int mt7615_load_firmware(struct mt7615_dev *dev)
return -EIO;
}
+ mt76_queue_tx_cleanup(dev, MT_TXQ_FWDL, false);
+
dev_dbg(dev->mt76.dev, "Firmware init done\n");
return 0;
@@ -573,6 +645,8 @@ int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
#define WMM_CW_MIN_SET BIT(1)
#define WMM_CW_MAX_SET BIT(2)
#define WMM_TXOP_SET BIT(3)
+#define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \
+ WMM_CW_MAX_SET | WMM_TXOP_SET)
struct req_data {
u8 number;
u8 rsv[3];
@@ -585,19 +659,17 @@ int mt7615_mcu_set_wmm(struct mt7615_dev *dev, u8 queue,
} __packed req = {
.number = 1,
.queue = queue,
- .valid = WMM_AIFS_SET | WMM_TXOP_SET,
+ .valid = WMM_PARAM_SET,
.aifs = params->aifs,
+ .cw_min = 5,
+ .cw_max = cpu_to_le16(10),
.txop = cpu_to_le16(params->txop),
};
- if (params->cw_min) {
- req.valid |= WMM_CW_MIN_SET;
- req.cw_min = params->cw_min;
- }
- if (params->cw_max) {
- req.valid |= WMM_CW_MAX_SET;
- req.cw_max = cpu_to_le16(params->cw_max);
- }
+ if (params->cw_min)
+ req.cw_min = fls(params->cw_min);
+ if (params->cw_max)
+ req.cw_max = cpu_to_le16(fls(params->cw_max));
return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_EDCA_UPDATE,
&req, sizeof(req), true);
@@ -824,78 +896,6 @@ int mt7615_mcu_set_bss_info(struct mt7615_dev *dev,
return ret;
}
-static enum mt7615_cipher_type
-mt7615_get_key_info(struct ieee80211_key_conf *key, u8 *key_data)
-{
- if (!key || key->keylen > 32)
- return MT_CIPHER_NONE;
-
- memcpy(key_data, key->key, key->keylen);
-
- switch (key->cipher) {
- case WLAN_CIPHER_SUITE_WEP40:
- return MT_CIPHER_WEP40;
- case WLAN_CIPHER_SUITE_WEP104:
- return MT_CIPHER_WEP104;
- case WLAN_CIPHER_SUITE_TKIP:
- /* Rx/Tx MIC keys are swapped */
- memcpy(key_data + 16, key->key + 24, 8);
- memcpy(key_data + 24, key->key + 16, 8);
- return MT_CIPHER_TKIP;
- case WLAN_CIPHER_SUITE_CCMP:
- return MT_CIPHER_AES_CCMP;
- case WLAN_CIPHER_SUITE_CCMP_256:
- return MT_CIPHER_CCMP_256;
- case WLAN_CIPHER_SUITE_GCMP:
- return MT_CIPHER_GCMP;
- case WLAN_CIPHER_SUITE_GCMP_256:
- return MT_CIPHER_GCMP_256;
- case WLAN_CIPHER_SUITE_SMS4:
- return MT_CIPHER_WAPI;
- default:
- return MT_CIPHER_NONE;
- }
-}
-
-int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid,
- struct ieee80211_key_conf *key,
- enum set_key_cmd cmd)
-{
- struct {
- struct wtbl_req_hdr hdr;
- struct wtbl_sec_key key;
- } req = {
- .hdr = {
- .wlan_idx = wcid,
- .operation = WTBL_SET,
- .tlv_num = cpu_to_le16(1),
- },
- .key = {
- .tag = cpu_to_le16(WTBL_SEC_KEY),
- .len = cpu_to_le16(sizeof(struct wtbl_sec_key)),
- .add = cmd,
- },
- };
-
- if (cmd == SET_KEY) {
- u8 cipher;
-
- cipher = mt7615_get_key_info(key, req.key.key_material);
- if (cipher == MT_CIPHER_NONE)
- return -EOPNOTSUPP;
-
- req.key.rkv = 1;
- req.key.cipher_id = cipher;
- req.key.key_id = key->keyidx;
- req.key.key_len = key->keylen;
- } else {
- req.key.key_len = sizeof(req.key.key_material);
- }
-
- return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_WTBL_UPDATE,
- &req, sizeof(req), true);
-}
-
static int
mt7615_mcu_add_wtbl_bmc(struct mt7615_dev *dev,
struct mt7615_vif *mvif)
@@ -1099,6 +1099,7 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
{
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+ struct ieee80211_mutable_offsets offs;
struct req {
u8 omac_idx;
u8 enable;
@@ -1119,13 +1120,10 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
.enable = en,
.wlan_idx = wcid->idx,
.band_idx = mvif->band_idx,
- /* pky_type: 0 for bcn, 1 for tim */
- .pkt_type = 0,
};
struct sk_buff *skb;
- u16 tim_off;
- skb = ieee80211_beacon_get_tim(mt76_hw(dev), vif, &tim_off, NULL);
+ skb = ieee80211_beacon_get_template(mt76_hw(dev), vif, &offs);
if (!skb)
return -EINVAL;
@@ -1139,8 +1137,14 @@ int mt7615_mcu_set_bcn(struct mt7615_dev *dev, struct ieee80211_vif *vif,
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 + tim_off);
+ 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,
@@ -1213,9 +1217,62 @@ out:
return ret;
}
+int mt7615_mcu_rdd_cmd(struct mt7615_dev *dev,
+ enum mt7615_rdd_cmd cmd, u8 index,
+ u8 rx_sel, u8 val)
+{
+ struct {
+ u8 ctrl;
+ u8 rdd_idx;
+ u8 rdd_rx_sel;
+ u8 val;
+ u8 rsv[4];
+ } req = {
+ .ctrl = cmd,
+ .rdd_idx = index,
+ .rdd_rx_sel = rx_sel,
+ .val = val,
+ };
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_CTRL,
+ &req, sizeof(req), true);
+}
+
+int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev)
+{
+ struct {
+ u8 pulse_num;
+ u8 rsv[3];
+ struct {
+ u32 start_time;
+ u16 width;
+ s16 power;
+ } pattern[32];
+ } req = {
+ .pulse_num = dev->radar_pattern.n_pulses,
+ };
+ u32 start_time = ktime_to_ms(ktime_get_boottime());
+ int i;
+
+ if (dev->radar_pattern.n_pulses > ARRAY_SIZE(req.pattern))
+ return -EINVAL;
+
+ /* TODO: add some noise here */
+ for (i = 0; i < dev->radar_pattern.n_pulses; i++) {
+ req.pattern[i].width = dev->radar_pattern.width;
+ req.pattern[i].power = dev->radar_pattern.power;
+ req.pattern[i].start_time = start_time +
+ i * dev->radar_pattern.period;
+ }
+
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_SET_RDD_PATTERN,
+ &req, sizeof(req), false);
+}
+
int mt7615_mcu_set_channel(struct mt7615_dev *dev)
{
- struct cfg80211_chan_def *chdef = &dev->mt76.chandef;
+ struct cfg80211_chan_def *chandef = &dev->mt76.chandef;
+ int freq1 = chandef->center_freq1, freq2 = chandef->center_freq2;
struct {
u8 control_chan;
u8 center_chan;
@@ -1234,17 +1291,20 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev)
u8 rsv1[3];
u8 txpower_sku[53];
u8 rsv2[3];
- } req = {0};
+ } req = {
+ .control_chan = chandef->chan->hw_value,
+ .center_chan = ieee80211_frequency_to_channel(freq1),
+ .tx_streams = (dev->mt76.chainmask >> 8) & 0xf,
+ .rx_streams_mask = dev->mt76.antenna_mask,
+ .center_chan2 = ieee80211_frequency_to_channel(freq2),
+ };
int ret;
- req.control_chan = chdef->chan->hw_value;
- req.center_chan = ieee80211_frequency_to_channel(chdef->center_freq1);
- req.tx_streams = (dev->mt76.chainmask >> 8) & 0xf;
- req.rx_streams_mask = dev->mt76.antenna_mask;
- req.switch_reason = CH_SWITCH_NORMAL;
- req.band_idx = 0;
- req.center_chan2 = ieee80211_frequency_to_channel(chdef->center_freq2);
- req.txpower_drop = 0;
+ if ((chandef->chan->flags & IEEE80211_CHAN_RADAR) &&
+ chandef->chan->dfs_state != NL80211_DFS_AVAILABLE)
+ req.switch_reason = CH_SWITCH_DFS;
+ else
+ req.switch_reason = CH_SWITCH_NORMAL;
switch (dev->mt76.chandef.width) {
case NL80211_CHAN_WIDTH_40:
@@ -1269,6 +1329,7 @@ int mt7615_mcu_set_channel(struct mt7615_dev *dev)
case NL80211_CHAN_WIDTH_20:
default:
req.bw = CMD_CBW_20MHZ;
+ break;
}
memset(req.txpower_sku, 0x3f, 49);
@@ -1533,92 +1594,15 @@ int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev,
&wtbl_req, sizeof(wtbl_req), true);
}
-void mt7615_mcu_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
- struct ieee80211_tx_rate *probe_rate,
- struct ieee80211_tx_rate *rates)
+int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index)
{
- int wcid = sta->wcid.idx;
- u32 addr = MT_WTBL_BASE + wcid * MT_WTBL_ENTRY_SIZE;
- bool stbc = false;
- int n_rates = sta->n_rates;
- u8 bw, bw_prev, bw_idx = 0;
- u16 val[4];
- u16 probe_val;
- u32 w5, w27;
- int i;
-
- if (!mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000))
- return;
-
- for (i = n_rates; i < 4; i++)
- rates[i] = rates[n_rates - 1];
-
- val[0] = mt7615_mac_tx_rate_val(dev, &rates[0], stbc, &bw);
- bw_prev = bw;
-
- if (probe_rate) {
- probe_val = mt7615_mac_tx_rate_val(dev, probe_rate, stbc, &bw);
- if (bw)
- bw_idx = 1;
- else
- bw_prev = 0;
- } else {
- probe_val = val[0];
- }
-
- val[1] = mt7615_mac_tx_rate_val(dev, &rates[1], stbc, &bw);
- if (bw_prev) {
- bw_idx = 3;
- bw_prev = bw;
- }
-
- val[2] = mt7615_mac_tx_rate_val(dev, &rates[2], stbc, &bw);
- if (bw_prev) {
- bw_idx = 5;
- bw_prev = bw;
- }
-
- val[3] = mt7615_mac_tx_rate_val(dev, &rates[3], stbc, &bw);
- if (bw_prev)
- bw_idx = 7;
-
- w27 = mt76_rr(dev, addr + 27 * 4);
- w27 &= ~MT_WTBL_W27_CC_BW_SEL;
- w27 |= FIELD_PREP(MT_WTBL_W27_CC_BW_SEL, bw);
-
- w5 = mt76_rr(dev, addr + 5 * 4);
- w5 &= ~(MT_WTBL_W5_BW_CAP | MT_WTBL_W5_CHANGE_BW_RATE);
- w5 |= FIELD_PREP(MT_WTBL_W5_BW_CAP, bw) |
- FIELD_PREP(MT_WTBL_W5_CHANGE_BW_RATE, bw_idx ? bw_idx - 1 : 7);
-
- mt76_wr(dev, MT_WTBL_RIUCR0, w5);
-
- mt76_wr(dev, MT_WTBL_RIUCR1,
- FIELD_PREP(MT_WTBL_RIUCR1_RATE0, probe_val) |
- FIELD_PREP(MT_WTBL_RIUCR1_RATE1, val[0]) |
- FIELD_PREP(MT_WTBL_RIUCR1_RATE2_LO, val[0]));
-
- mt76_wr(dev, MT_WTBL_RIUCR2,
- FIELD_PREP(MT_WTBL_RIUCR2_RATE2_HI, val[0] >> 8) |
- FIELD_PREP(MT_WTBL_RIUCR2_RATE3, val[1]) |
- FIELD_PREP(MT_WTBL_RIUCR2_RATE4, val[1]) |
- FIELD_PREP(MT_WTBL_RIUCR2_RATE5_LO, val[2]));
-
- mt76_wr(dev, MT_WTBL_RIUCR3,
- FIELD_PREP(MT_WTBL_RIUCR3_RATE5_HI, val[2] >> 4) |
- FIELD_PREP(MT_WTBL_RIUCR3_RATE6, val[2]) |
- FIELD_PREP(MT_WTBL_RIUCR3_RATE7, val[3]));
-
- mt76_wr(dev, MT_WTBL_UPDATE,
- FIELD_PREP(MT_WTBL_UPDATE_WLAN_IDX, wcid) |
- MT_WTBL_UPDATE_RATE_UPDATE |
- MT_WTBL_UPDATE_TX_COUNT_CLEAR);
-
- mt76_wr(dev, addr + 27 * 4, w27);
-
- if (!(sta->wcid.tx_info & MT_WCID_TX_INFO_SET))
- mt76_poll(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_BUSY, 0, 5000);
+ struct {
+ u8 action;
+ u8 rsv[3];
+ } req = {
+ .action = index,
+ };
- sta->rate_count = 2 * MT7615_RATE_RETRY * n_rates;
- sta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
+ return __mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD_GET_TEMP, &req,
+ sizeof(req), true);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
index f8b51ad25220..1fd7dffa6eef 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.h
@@ -23,6 +23,28 @@ struct mt7615_mcu_txd {
u32 reserved[5];
} __packed __aligned(4);
+/* event table */
+enum {
+ MCU_EVENT_TARGET_ADDRESS_LEN = 0x01,
+ MCU_EVENT_FW_START = 0x01,
+ MCU_EVENT_GENERIC = 0x01,
+ MCU_EVENT_ACCESS_REG = 0x02,
+ MCU_EVENT_MT_PATCH_SEM = 0x04,
+ MCU_EVENT_CH_PRIVILEGE = 0x18,
+ MCU_EVENT_EXT = 0xed,
+ MCU_EVENT_RESTART_DL = 0xef,
+};
+
+/* ext event table */
+enum {
+ MCU_EXT_EVENT_PS_SYNC = 0x5,
+ MCU_EXT_EVENT_FW_LOG_2_HOST = 0x13,
+ MCU_EXT_EVENT_THERMAL_PROTECT = 0x22,
+ MCU_EXT_EVENT_ASSERT_DUMP = 0x23,
+ MCU_EXT_EVENT_RDD_REPORT = 0x3a,
+ MCU_EXT_EVENT_CSA_NOTIFY = 0x4f,
+};
+
struct mt7615_mcu_rxd {
__le32 rxd[4];
@@ -76,11 +98,14 @@ enum {
MCU_EXT_CMD_BSS_INFO_UPDATE = 0x26,
MCU_EXT_CMD_EDCA_UPDATE = 0x27,
MCU_EXT_CMD_DEV_INFO_UPDATE = 0x2A,
+ MCU_EXT_CMD_GET_TEMP = 0x2c,
MCU_EXT_CMD_WTBL_UPDATE = 0x32,
+ MCU_EXT_CMD_SET_RDD_CTRL = 0x3a,
MCU_EXT_CMD_PROTECT_CTRL = 0x3e,
MCU_EXT_CMD_MAC_INIT_CTRL = 0x46,
MCU_EXT_CMD_BCN_OFFLOAD = 0x49,
MCU_EXT_CMD_SET_RX_PATH = 0x4e,
+ MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d,
};
enum {
@@ -264,34 +289,6 @@ struct wtbl_hdr_trans {
u8 rsv;
} __packed;
-enum mt7615_cipher_type {
- MT_CIPHER_NONE,
- MT_CIPHER_WEP40,
- MT_CIPHER_TKIP,
- MT_CIPHER_TKIP_NO_MIC,
- MT_CIPHER_AES_CCMP,
- MT_CIPHER_WEP104,
- MT_CIPHER_BIP_CMAC_128,
- MT_CIPHER_WEP128,
- MT_CIPHER_WAPI,
- MT_CIPHER_CCMP_256 = 10,
- MT_CIPHER_GCMP,
- MT_CIPHER_GCMP_256,
-};
-
-struct wtbl_sec_key {
- __le16 tag;
- __le16 len;
- u8 add; /* 0: add, 1: remove */
- u8 rkv;
- u8 ikv;
- u8 cipher_id;
- u8 key_id;
- u8 key_len;
- u8 rsv[2];
- u8 key_material[32];
-} __packed;
-
enum {
MT_BA_TYPE_INVALID,
MT_BA_TYPE_ORIGINATOR,
@@ -375,7 +372,6 @@ struct wtbl_raw {
sizeof(struct wtbl_vht) + \
sizeof(struct wtbl_tx_ps) + \
sizeof(struct wtbl_hdr_trans) + \
- sizeof(struct wtbl_sec_key) + \
sizeof(struct wtbl_ba) + \
sizeof(struct wtbl_bf) + \
sizeof(struct wtbl_smps) + \
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index f02ffcffe637..cef3fd43cb00 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -10,12 +10,13 @@
#include "regs.h"
#define MT7615_MAX_INTERFACES 4
+#define MT7615_MAX_WMM_SETS 4
#define MT7615_WTBL_SIZE 128
#define MT7615_WTBL_RESERVED (MT7615_WTBL_SIZE - 1)
#define MT7615_WTBL_STA (MT7615_WTBL_RESERVED - \
MT7615_MAX_INTERFACES)
-#define MT7615_WATCHDOG_TIME 100 /* ms */
+#define MT7615_WATCHDOG_TIME (HZ / 10)
#define MT7615_RATE_RETRY 2
#define MT7615_TX_RING_SIZE 1024
@@ -32,6 +33,9 @@
#define MT7615_EEPROM_SIZE 1024
#define MT7615_TOKEN_SIZE 4096
+#define MT_FRAC_SCALE 12
+#define MT_FRAC(val, div) (((val) << MT_FRAC_SCALE) / (div))
+
struct mt7615_vif;
struct mt7615_sta;
@@ -42,12 +46,21 @@ enum mt7615_hw_txq_id {
MT7615_TXQ_FWDL,
};
+struct mt7615_rate_set {
+ struct ieee80211_tx_rate probe_rate;
+ struct ieee80211_tx_rate rates[4];
+};
+
struct mt7615_sta {
struct mt76_wcid wcid; /* must be first */
struct mt7615_vif *vif;
- struct ieee80211_tx_rate rates[8];
+ struct ieee80211_tx_rate rates[4];
+
+ struct mt7615_rate_set rateset[2];
+ u32 rate_set_tsf;
+
u8 rate_count;
u8 n_rates;
@@ -68,6 +81,22 @@ struct mt7615_dev {
u32 vif_mask;
u32 omac_mask;
+ struct {
+ u8 n_pulses;
+ u32 period;
+ u16 width;
+ s16 power;
+ } radar_pattern;
+ u32 hw_pattern;
+ int dfs_state;
+
+ int false_cca_ofdm, false_cca_cck;
+ unsigned long last_cca_adj;
+ u8 mac_work_count;
+ s8 ofdm_sensitivity;
+ s8 cck_sensitivity;
+ bool scs_en;
+
spinlock_t token_lock;
struct idr token;
};
@@ -97,6 +126,30 @@ enum {
EXT_BSSID_END
};
+enum {
+ MT_HW_RDD0,
+ MT_HW_RDD1,
+};
+
+enum {
+ MT_RX_SEL0,
+ MT_RX_SEL1,
+};
+
+enum mt7615_rdd_cmd {
+ RDD_STOP,
+ RDD_START,
+ RDD_DET_MODE,
+ RDD_DET_STOP,
+ RDD_CAC_START,
+ RDD_CAC_END,
+ RDD_NORMAL_START,
+ RDD_DISABLE_DFS_CAL,
+ RDD_PULSE_DBG,
+ RDD_READ_PULSE,
+ RDD_RESUME_BF,
+};
+
extern const struct ieee80211_ops mt7615_ops;
extern struct pci_driver mt7615_pci_driver;
@@ -115,10 +168,7 @@ 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);
-int mt7615_mcu_set_wtbl_key(struct mt7615_dev *dev, int wcid,
- struct ieee80211_key_conf *key,
- enum set_key_cmd cmd);
-void mt7615_mcu_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
+void mt7615_mac_set_rates(struct mt7615_dev *dev, struct mt7615_sta *sta,
struct ieee80211_tx_rate *probe_rate,
struct ieee80211_tx_rate *rates);
int mt7615_mcu_wtbl_bmc(struct mt7615_dev *dev, struct ieee80211_vif *vif,
@@ -144,6 +194,29 @@ int mt7615_mcu_set_rx_ba(struct mt7615_dev *dev,
bool add);
int mt7615_mcu_set_ht_cap(struct mt7615_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
+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,
+ u8 rx_sel, u8 val);
+int mt7615_dfs_start_radar_detector(struct mt7615_dev *dev);
+int mt7615_dfs_stop_radar_detector(struct mt7615_dev *dev);
+int mt7615_mcu_rdd_send_pattern(struct mt7615_dev *dev);
+
+static inline bool is_mt7622(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7622;
+}
+
+static inline void mt7615_dfs_check_channel(struct mt7615_dev *dev)
+{
+ enum nl80211_chan_width width = dev->mt76.chandef.width;
+ u32 freq = dev->mt76.chandef.chan->center_freq;
+ struct ieee80211_hw *hw = mt76_hw(dev);
+
+ if (hw->conf.chandef.chan->center_freq != freq ||
+ hw->conf.chandef.width != width)
+ dev->dfs_state = -1;
+}
static inline void mt7615_irq_enable(struct mt7615_dev *dev, u32 mask)
{
@@ -155,9 +228,9 @@ static inline void mt7615_irq_disable(struct mt7615_dev *dev, u32 mask)
mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
}
-u16 mt7615_mac_tx_rate_val(struct mt7615_dev *dev,
- const struct ieee80211_tx_rate *rate,
- bool stbc, u8 *bw);
+void mt7615_update_channel(struct mt76_dev *mdev);
+void mt7615_mac_cca_stats_reset(struct mt7615_dev *dev);
+void mt7615_mac_set_scs(struct mt7615_dev *dev, bool enable);
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,
@@ -165,11 +238,15 @@ int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb);
void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data);
void mt7615_mac_tx_free(struct mt7615_dev *dev, struct sk_buff *skb);
+int mt7615_mac_wtbl_set_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key,
+ enum set_key_cmd cmd);
int mt7615_mcu_set_eeprom(struct mt7615_dev *dev);
int mt7615_mcu_init_mac(struct mt7615_dev *dev);
int mt7615_mcu_set_rts_thresh(struct mt7615_dev *dev, u32 val);
int mt7615_mcu_ctrl_pm_state(struct mt7615_dev *dev, int enter);
+int mt7615_mcu_get_temperature(struct mt7615_dev *dev, int index);
int mt7615_mcu_set_tx_power(struct mt7615_dev *dev);
void mt7615_mcu_exit(struct mt7615_dev *dev);
@@ -193,5 +270,9 @@ void mt7615_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
void mt7615_mac_work(struct work_struct *work);
void mt7615_txp_skb_unmap(struct mt76_dev *dev,
struct mt76_txwi_cache *txwi);
+int mt76_dfs_start_rdd(struct mt7615_dev *dev, bool force);
+int mt7615_dfs_init_radar_detector(struct mt7615_dev *dev);
+
+int mt7615_init_debugfs(struct mt7615_dev *dev);
#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
index 9e82cb53fd60..e250607e0a80 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/pci.c
@@ -81,6 +81,7 @@ static int mt7615_pci_probe(struct pci_dev *pdev,
.sta_add = mt7615_sta_add,
.sta_assoc = mt7615_sta_assoc,
.sta_remove = mt7615_sta_remove,
+ .update_survey = mt7615_update_channel,
};
struct mt7615_dev *dev;
struct mt76_dev *mdev;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index 70e5ace33cc3..b193814d5cf8 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -71,6 +71,34 @@
#define MT_WF_PHY_WF2_RFCTRL0 MT_WF_PHY(0x1900)
#define MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN BIT(9)
+#define MT_WF_PHY_R0_B0_PHYMUX_5 MT_WF_PHY(0x0614)
+
+#define MT_WF_PHY_R0_B0_PHYCTRL_STS0 MT_WF_PHY(0x020c)
+#define MT_WF_PHYCTRL_STAT_PD_OFDM GENMASK(31, 16)
+#define MT_WF_PHYCTRL_STAT_PD_CCK GENMASK(15, 0)
+
+#define MT_WF_PHY_R0_B0_PHYCTRL_STS5 MT_WF_PHY(0x0220)
+#define MT_WF_PHYCTRL_STAT_MDRDY_OFDM GENMASK(31, 16)
+#define MT_WF_PHYCTRL_STAT_MDRDY_CCK GENMASK(15, 0)
+
+#define MT_WF_PHY_B0_MIN_PRI_PWR MT_WF_PHY(0x229c)
+#define MT_WF_PHY_B0_PD_OFDM_MASK GENMASK(28, 20)
+#define MT_WF_PHY_B0_PD_OFDM(v) ((v) << 20)
+#define MT_WF_PHY_B0_PD_BLK BIT(19)
+
+#define MT_WF_PHY_B1_MIN_PRI_PWR MT_WF_PHY(0x084)
+#define MT_WF_PHY_B1_PD_OFDM_MASK GENMASK(24, 16)
+#define MT_WF_PHY_B1_PD_OFDM(v) ((v) << 16)
+#define MT_WF_PHY_B1_PD_BLK BIT(25)
+
+#define MT_WF_PHY_B0_RXTD_CCK_PD MT_WF_PHY(0x2310)
+#define MT_WF_PHY_B0_PD_CCK_MASK GENMASK(8, 1)
+#define MT_WF_PHY_B0_PD_CCK(v) ((v) << 1)
+
+#define MT_WF_PHY_B1_RXTD_CCK_PD MT_WF_PHY(0x2314)
+#define MT_WF_PHY_B1_PD_CCK_MASK GENMASK(31, 24)
+#define MT_WF_PHY_B1_PD_CCK(v) ((v) << 24)
+
#define MT_WF_CFG_BASE 0x20200
#define MT_WF_CFG(ofs) (MT_WF_CFG_BASE + (ofs))
@@ -97,12 +125,25 @@
MT_AGG_ARxCR_LIMIT_SHIFT(_n), \
MT_AGG_ARxCR_LIMIT_SHIFT(_n))
+#define MT_AGG_ACR0 MT_WF_AGG(0x070)
+#define MT_AGG_ACR1 MT_WF_AGG(0x170)
+#define MT_AGG_ACR_NO_BA_RULE BIT(0)
+#define MT_AGG_ACR_NO_BA_AR_RULE BIT(1)
+#define MT_AGG_ACR_PKT_TIME_EN BIT(2)
+#define MT_AGG_ACR_CFEND_RATE GENMASK(15, 4)
+#define MT_AGG_ACR_BAR_RATE GENMASK(31, 20)
+
#define MT_AGG_SCR MT_WF_AGG(0x0fc)
#define MT_AGG_SCR_NLNAV_MID_PTEC_DIS BIT(3)
#define MT_WF_TMAC_BASE 0x21000
#define MT_WF_TMAC(ofs) (MT_WF_TMAC_BASE + (ofs))
+#define MT_TMAC_TRCR0 MT_WF_TMAC(0x09c)
+#define MT_TMAC_TRCR1 MT_WF_TMAC(0x070)
+#define MT_TMAC_TRCR_CCA_SEL GENMASK(31, 30)
+#define MT_TMAC_TRCR_SEC_CCA_SEL GENMASK(29, 28)
+
#define MT_TMAC_CTCR0 MT_WF_TMAC(0x0f4)
#define MT_TMAC_CTCR0_INS_DDLMT_REFTIME GENMASK(5, 0)
#define MT_TMAC_CTCR0_INS_DDLMT_DENSITY GENMASK(15, 12)
@@ -148,8 +189,15 @@
#define MT_WTBL_OFF_BASE 0x23400
#define MT_WTBL_OFF(n) (MT_WTBL_OFF_BASE + (n))
+#define MT_WTBL_W0_KEY_IDX GENMASK(24, 23)
+#define MT_WTBL_W0_RX_KEY_VALID BIT(26)
+#define MT_WTBL_W0_RX_IK_VALID BIT(27)
+
+#define MT_WTBL_W2_KEY_TYPE GENMASK(7, 4)
+
#define MT_WTBL_UPDATE MT_WTBL_OFF(0x030)
#define MT_WTBL_UPDATE_WLAN_IDX GENMASK(7, 0)
+#define MT_WTBL_UPDATE_RXINFO_UPDATE BIT(11)
#define MT_WTBL_UPDATE_RATE_UPDATE BIT(13)
#define MT_WTBL_UPDATE_TX_COUNT_CLEAR BIT(14)
#define MT_WTBL_UPDATE_BUSY BIT(31)
@@ -157,6 +205,9 @@
#define MT_WTBL_ON_BASE 0x23000
#define MT_WTBL_ON(_n) (MT_WTBL_ON_BASE + (_n))
+#define MT_WTBL_RICR0 MT_WTBL_ON(0x010)
+#define MT_WTBL_RICR1 MT_WTBL_ON(0x014)
+
#define MT_WTBL_RIUCR0 MT_WTBL_ON(0x020)
#define MT_WTBL_RIUCR1 MT_WTBL_ON(0x024)
@@ -181,8 +232,32 @@
#define MT_WTBL_W5_SHORT_GI_80 BIT(10)
#define MT_WTBL_W5_SHORT_GI_160 BIT(11)
#define MT_WTBL_W5_BW_CAP GENMASK(13, 12)
+#define MT_WTBL_W5_MPDU_FAIL_COUNT GENMASK(25, 23)
+#define MT_WTBL_W5_MPDU_OK_COUNT GENMASK(28, 26)
+#define MT_WTBL_W5_RATE_IDX GENMASK(31, 29)
+
#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_T0CR MT_LPON(0x010)
+#define MT_LPON_T0CR_MODE GENMASK(1, 0)
+
+#define MT_LPON_UTTR0 MT_LPON(0x018)
+#define MT_LPON_UTTR1 MT_LPON(0x01c)
+
+#define MT_WF_MIB_BASE 0x24800
+#define MT_WF_MIB(ofs) (MT_WF_MIB_BASE + (ofs))
+
+#define MT_MIB_M0_MISC_CR MT_WF_MIB(0x00c)
+#define MT_MIB_MB_SDR0(n) MT_WF_MIB(0x100 + ((n) << 4))
+#define MT_MIB_RTS_RETRIES_COUNT_MASK GENMASK(31, 16)
+#define MT_MIB_RTS_COUNT_MASK GENMASK(15, 0)
+
+#define MT_MIB_SDR16(n) MT_WF_MIB(0x48 + ((n) << 9))
+#define MT_MIB_BUSY_MASK GENMASK(23, 0)
+
#define MT_EFUSE_BASE 0x81070000
#define MT_EFUSE_BASE_CTRL 0x000
#define MT_EFUSE_BASE_CTRL_EMPTY BIT(30)