summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2026-06-09 15:24:56 +0200
committerJohannes Berg <johannes.berg@intel.com>2026-06-09 15:25:18 +0200
commit0ccb7c3bb1012080cb0ad9f5804441bff8431f4e (patch)
tree1c61b533a17ab05e7c3db501eac95f0bc2c58bb2
parentb224d18b1e5d1cddfc67f63f41d80023b2ec8889 (diff)
parent50a7f9f9d48eb50c0e95bef53358acb5af5cb3c6 (diff)
Merge tag 'mt76-next-2026-06-09' of https://github.com/nbd168/wireless
Felix Fietkau says: =================== mt76 patches for 7.2 - fixes - mt792x broken usb transport detection - mt7921 regd improvements - mt7927 support =================== Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--drivers/net/wireless/mediatek/mt76/channel.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/eeprom.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mac80211.c19
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/init.c1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7615/usb.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac.h21
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c13
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c49
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h29
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x0/usb.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt76x2/usb.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mac.c10
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/main.c3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7915/mcu.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/Makefile2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/init.c98
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mac.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/main.c29
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mcu.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h1
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/pci.c18
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/regd.c206
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/regd.h19
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7921/usb.c11
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/init.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/mac.c29
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/main.c101
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/mcu.c116
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/mcu.h3
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h29
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/pci.c137
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c12
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/testmode.c5
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7925/usb.c22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x.h33
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_core.c56
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_dma.c198
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_regs.h23
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt792x_usb.c79
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c6
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/dma.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mac.c51
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/main.c29
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mcu.c36
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h22
-rw-r--r--drivers/net/wireless/mediatek/mt76/mt7996/pci.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/pci.c8
-rw-r--r--drivers/net/wireless/mediatek/mt76/tx.c2
-rw-r--r--drivers/net/wireless/mediatek/mt76/usb.c2
-rw-r--r--drivers/net/wireless/mediatek/mt7601u/usb.c3
55 files changed, 1262 insertions, 342 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/channel.c b/drivers/net/wireless/mediatek/mt76/channel.c
index 05eee64706ea..6edcb3b8f279 100644
--- a/drivers/net/wireless/mediatek/mt76/channel.c
+++ b/drivers/net/wireless/mediatek/mt76/channel.c
@@ -307,7 +307,7 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
rcu_assign_pointer(mvif->offchannel_link, NULL);
dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
- kfree(mlink);
+ kfree_rcu(mlink, rcu_head);
}
void mt76_roc_complete(struct mt76_phy *phy)
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c
index afdb73661866..b99d7452800f 100644
--- a/drivers/net/wireless/mediatek/mt76/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/eeprom.c
@@ -181,7 +181,7 @@ mt76_eeprom_override(struct mt76_phy *phy)
if (err == -EPROBE_DEFER)
return err;
- if (!is_valid_ether_addr(phy->macaddr)) {
+ if (err) {
eth_random_addr(phy->macaddr);
dev_info(dev->dev,
"Invalid MAC address, using random address %pM\n",
diff --git a/drivers/net/wireless/mediatek/mt76/mac80211.c b/drivers/net/wireless/mediatek/mt76/mac80211.c
index 4ae5e4715a9c..13c4e8abe281 100644
--- a/drivers/net/wireless/mediatek/mt76/mac80211.c
+++ b/drivers/net/wireless/mediatek/mt76/mac80211.c
@@ -449,6 +449,8 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
+ if (!wiphy->max_remain_on_channel_duration)
+ wiphy->max_remain_on_channel_duration = 5000;
if (!wiphy->available_antennas_tx)
wiphy->available_antennas_tx = phy->antenna_mask;
if (!wiphy->available_antennas_rx)
@@ -1321,7 +1323,7 @@ mt76_check_ccmp_pn(struct sk_buff *skb)
* All further fragments will be validated by mac80211 only.
*/
if (ieee80211_is_frag(hdr) &&
- !ieee80211_is_first_frag(hdr->frame_control))
+ !ieee80211_is_first_frag(hdr->seq_ctrl))
return;
}
@@ -1576,6 +1578,7 @@ mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
{
struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
struct mt76_dev *dev = phy->dev;
+ struct mt76_wcid *published;
int ret;
int i;
@@ -1595,11 +1598,19 @@ mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
mtxq->wcid = wcid->idx;
}
- ewma_signal_init(&wcid->rssi);
- rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
+ published = rcu_dereference_protected(dev->wcid[wcid->idx],
+ lockdep_is_held(&dev->mutex));
+ if (published != wcid) {
+ WARN_ON_ONCE(published);
+ ewma_signal_init(&wcid->rssi);
+ rcu_assign_pointer(dev->wcid[wcid->idx], wcid);
+ mt76_wcid_init(wcid, phy->band_idx);
+ } else {
+ wcid->phy_idx = phy->band_idx;
+ }
+
phy->num_sta++;
- mt76_wcid_init(wcid, phy->band_idx);
out:
mutex_unlock(&dev->mutex);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index 527bef97e122..07955555f84d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -361,6 +361,7 @@ enum mt76_wcid_flags {
MT_WCID_FLAG_PS,
MT_WCID_FLAG_4ADDR,
MT_WCID_FLAG_HDR_TRANS,
+ MT_WCID_FLAG_TDLS_PEER,
};
#define MT76_N_WCIDS 1088
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
index 0f7b20152279..6a1475e3c899 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/debugfs.c
@@ -550,8 +550,6 @@ int mt7615_init_debugfs(struct mt7615_dev *dev)
struct dentry *dir;
dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval);
- if (!dir)
- return -ENOMEM;
if (is_mt7615(&dev->mt76))
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues", dir,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/init.c b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
index 42e11ba1206e..e437e088b2e9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/init.c
@@ -195,7 +195,6 @@ mt7615_check_offload_capability(struct mt7615_dev *dev)
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
wiphy->flags &= ~WIPHY_FLAG_4ADDR_STATION;
- wiphy->max_remain_on_channel_duration = 5000;
wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
index d91feffadda9..bab7b91f14be 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/usb.c
@@ -151,7 +151,6 @@ static int mt7663u_probe(struct usb_interface *usb_intf,
return -ENOMEM;
dev = container_of(mdev, struct mt7615_dev, mt76);
- udev = usb_get_dev(udev);
usb_reset_device(udev);
usb_set_intfdata(usb_intf, dev);
@@ -193,7 +192,6 @@ static int mt7663u_probe(struct usb_interface *usb_intf,
error:
mt76u_queues_deinit(&dev->mt76);
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
mt76_free_device(&dev->mt76);
@@ -211,7 +209,6 @@ static void mt7663u_disconnect(struct usb_interface *usb_intf)
mt7663u_cleanup(dev);
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
mt76_free_device(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac.h b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
index 51423c7740bd..2aa6078993e9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac.h
@@ -172,11 +172,26 @@ struct mt76_connac_tx_free {
extern const struct wiphy_wowlan_support mt76_connac_wowlan_support;
+static inline bool is_connac3(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7925 || mt76_chip(dev) == 0x7927;
+}
+
static inline bool is_mt7925(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7925;
}
+static inline bool is_mt7927(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7927;
+}
+
+static inline bool is_320mhz_supported(struct mt76_dev *dev)
+{
+ return mt76_chip(dev) == 0x7927;
+}
+
static inline bool is_mt7920(struct mt76_dev *dev)
{
return mt76_chip(dev) == 0x7920;
@@ -279,6 +294,7 @@ static inline bool is_mt76_fw_txp(struct mt76_dev *dev)
case 0x7922:
case 0x7902:
case 0x7925:
+ case 0x7927:
case 0x7663:
case 0x7622:
return false;
@@ -420,7 +436,10 @@ mt76_connac_mutex_release(struct mt76_dev *dev, struct mt76_connac_pm *pm)
void mt76_connac_gen_ppe_thresh(u8 *he_ppet, int nss, enum nl80211_band band);
int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,
int ring_base, void *wed, u32 flags);
-
+void mt76_connac_set_txpower_cur(struct mt76_phy *phy, s8 max_power);
+s8 mt76_connac_get_rate_power_limit(struct mt76_phy *phy,
+ struct ieee80211_channel *chan,
+ struct mt76_power_limits *limits);
void mt76_connac_write_hw_txp(struct mt76_dev *dev,
struct mt76_tx_info *tx_info,
void *txp_ptr, u32 id);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
index 0339e2e7ab60..fc9f782032ef 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mac.c
@@ -173,7 +173,7 @@ void mt76_connac_write_hw_txp(struct mt76_dev *dev,
txp->msdu_id[0] = cpu_to_le16(id | MT_MSDU_ID_VALID);
- if (is_mt7663(dev) || is_connac2(dev) || is_mt7925(dev))
+ if (is_mt7663(dev) || is_connac2(dev) || is_connac3(dev))
last_mask = MT_TXD_LEN_LAST;
else
last_mask = MT_TXD_LEN_AMSDU_LAST |
@@ -217,7 +217,7 @@ mt76_connac_txp_skb_unmap_hw(struct mt76_dev *dev,
u32 last_mask;
int i;
- if (is_mt7663(dev) || is_connac2(dev) || is_mt7925(dev))
+ if (is_mt7663(dev) || is_connac2(dev) || is_connac3(dev))
last_mask = MT_TXD_LEN_LAST;
else
last_mask = MT_TXD_LEN_MSDU_LAST;
@@ -275,6 +275,15 @@ int mt76_connac_init_tx_queues(struct mt76_phy *phy, int idx, int n_desc,
}
EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues);
+void mt76_connac_set_txpower_cur(struct mt76_phy *phy, s8 max_power)
+{
+ int delta;
+
+ delta = mt76_tx_power_path_delta(hweight16(phy->chainmask));
+ phy->txpower_cur = max_power - delta;
+}
+EXPORT_SYMBOL_GPL(mt76_connac_set_txpower_cur);
+
#define __bitrate_mask_check(_mcs, _mode) \
({ \
u8 i = 0; \
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
index 89bd52ea8bf7..6596c9e198f4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c
@@ -67,7 +67,7 @@ int mt76_connac_mcu_init_download(struct mt76_dev *dev, u32 addr, u32 len,
if ((!is_connac_v1(dev) && addr == MCU_PATCH_ADDRESS) ||
(is_connac2(dev) && addr == 0x900000) ||
- (is_mt7925(dev) && (addr == 0x900000 || addr == 0xe0002800)) ||
+ (is_connac3(dev) && (addr == 0x900000 || addr == 0xe0002800)) ||
(is_mt799x(dev) && addr == 0x900000))
cmd = MCU_CMD(PATCH_START_REQ);
else
@@ -491,6 +491,11 @@ void mt76_connac_mcu_wtbl_hdr_trans_tlv(struct sk_buff *skb,
htr->to_ds = true;
htr->from_ds = true;
}
+
+ if (test_bit(MT_WCID_FLAG_TDLS_PEER, &wcid->flags)) {
+ htr->to_ds = false;
+ htr->from_ds = false;
+ }
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_wtbl_hdr_trans_tlv);
@@ -1227,6 +1232,9 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy,
len = enable ? sizeof(dev_req) : sizeof(basic_req);
err = mt76_mcu_send_msg(dev, cmd, data, len, true);
+ if (err && cmd == MCU_UNI_CMD(BSS_INFO_UPDATE))
+ err = mt76_connac_mcu_bss_deact_err(dev, err, enable);
+
if (err < 0)
return err;
@@ -1234,7 +1242,11 @@ int mt76_connac_mcu_uni_add_dev(struct mt76_phy *phy,
data = enable ? (void *)&basic_req : (void *)&dev_req;
len = enable ? sizeof(basic_req) : sizeof(dev_req);
- return mt76_mcu_send_msg(dev, cmd, data, len, true);
+ err = mt76_mcu_send_msg(dev, cmd, data, len, true);
+ if (err && cmd == MCU_UNI_CMD(BSS_INFO_UPDATE))
+ err = mt76_connac_mcu_bss_deact_err(dev, err, enable);
+
+ return err;
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_uni_add_dev);
@@ -2223,14 +2235,14 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
.hw_value = ch_list[idx],
.band = band,
};
- s8 reg_power, sar_power;
+ s8 max_power;
- reg_power = mt76_connac_get_ch_power(phy, &chan,
- tx_power);
- sar_power = mt76_get_sar_power(phy, &chan, reg_power);
-
- mt76_get_rate_power_limits(phy, &chan, limits,
- sar_power);
+ max_power = mt76_connac_get_rate_power_limit(phy, &chan,
+ limits);
+ if (phy->chandef.chan &&
+ phy->chandef.chan->hw_value == ch_list[idx] &&
+ phy->chandef.chan->band == band)
+ mt76_connac_set_txpower_cur(phy, max_power);
tx_power_tlv.last_msg = ch_list[idx] == last_ch;
sku_tlbv.channel = ch_list[idx];
@@ -2962,6 +2974,23 @@ int mt76_connac_mcu_rdd_cmd(struct mt76_dev *dev, int cmd, u8 index,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_rdd_cmd);
+s8 mt76_connac_get_rate_power_limit(struct mt76_phy *phy,
+ struct ieee80211_channel *chan,
+ struct mt76_power_limits *limits)
+{
+ s8 reg_power, sar_power;
+ int tx_power;
+
+ tx_power = 2 * phy->hw->conf.power_level;
+ if (!tx_power)
+ tx_power = 127;
+
+ reg_power = mt76_connac_get_ch_power(phy, chan, tx_power);
+ sar_power = mt76_get_sar_power(phy, chan, reg_power);
+ return mt76_get_rate_power_limits(phy, chan, limits, sar_power);
+}
+EXPORT_SYMBOL_GPL(mt76_connac_get_rate_power_limit);
+
static int
mt76_connac_mcu_send_ram_firmware(struct mt76_dev *dev,
const struct mt76_connac2_fw_trailer *hdr,
@@ -3084,7 +3113,7 @@ static u32 mt76_connac2_get_data_mode(struct mt76_dev *dev, u32 info)
{
u32 mode = DL_MODE_NEED_RSP;
- if ((!is_connac2(dev) && !is_mt7925(dev)) || info == PATCH_SEC_NOT_SUPPORT)
+ if ((!is_connac2(dev) && !is_connac3(dev)) || info == PATCH_SEC_NOT_SUPPORT)
return mode;
switch (FIELD_GET(PATCH_SEC_ENC_TYPE_MASK, info)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index ac5126ab68ff..78f633ad81a0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1069,6 +1069,7 @@ enum {
MCU_UNI_EVENT_SCAN_DONE = 0x0e,
MCU_UNI_EVENT_RDD_REPORT = 0x11,
MCU_UNI_EVENT_ROC = 0x27,
+ MCU_UNI_EVENT_MBMC = 0x28,
MCU_UNI_EVENT_TX_DONE = 0x2d,
MCU_UNI_EVENT_THERMAL = 0x35,
MCU_UNI_EVENT_RSSI_MONITOR = 0x41,
@@ -1598,7 +1599,7 @@ struct mt76_connac_hw_scan_done {
u8 pno_enabled;
u8 pad2[3];
u8 sparse_channel_valid_num;
- u8 pad3[3];
+ u8 alpha2[3];
u8 channel_num[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM];
/* idle format for channel_idle_time
* 0: first bytes: idle time(ms) 2nd byte: dwell time(ms)
@@ -1611,6 +1612,7 @@ struct mt76_connac_hw_scan_done {
u8 mdrdy_count[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM];
__le32 beacon_2g_num;
__le32 beacon_5g_num;
+ __le16 channel_scan_time[MT76_CONNAC_SCAN_DONE_EVENT_MAX_CHANNEL_NUM];
} __packed;
struct mt76_connac_sched_scan_req {
@@ -1878,7 +1880,7 @@ mt76_connac_mcu_gen_dl_mode(struct mt76_dev *dev, u8 feature_set, bool is_wa)
ret |= feature_set & FW_FEATURE_SET_ENCRYPT ?
DL_MODE_ENCRYPT | DL_MODE_RESET_SEC_IV : 0;
- if (is_connac2(dev) || is_mt7925(dev))
+ if (is_connac2(dev) || is_connac3(dev))
ret |= feature_set & FW_FEATURE_ENCRY_MODE ?
DL_CONFIG_ENCRY_MODE_SEL : 0;
ret |= FIELD_PREP(DL_MODE_KEY_IDX,
@@ -1906,6 +1908,29 @@ mt76_connac_mcu_get_wlan_idx(struct mt76_dev *dev, struct mt76_wcid *wcid,
}
}
+#define MT76_CONNAC_MCU_STATUS_WLAN_FAILURE 0xc0000001
+
+static inline int
+mt76_connac_mcu_bss_deact_err(struct mt76_dev *mdev, int err, bool enable)
+{
+ if (err != (int)MT76_CONNAC_MCU_STATUS_WLAN_FAILURE)
+ return err;
+
+ /* Ignore wlan_failure state false alarm when deactivating an
+ * inactive network. It does not harm the firmware state.
+ */
+ if (!enable) {
+ dev_dbg(mdev->dev,
+ "ignore wlan_failure when bss is deactivated\n");
+ return 0;
+ }
+
+ dev_warn(mdev->dev,
+ "wlan_failure when bss is activated\n");
+
+ return err;
+}
+
struct sk_buff *
__mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif_link *mvif,
struct mt76_wcid *wcid, int len);
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
index 90e5666c0857..2acce121fb14 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x0/usb.c
@@ -245,7 +245,6 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
if (id->driver_info)
dev->no_2ghz = true;
- usb_dev = usb_get_dev(usb_dev);
usb_reset_device(usb_dev);
usb_set_intfdata(usb_intf, dev);
@@ -284,7 +283,6 @@ static int mt76x0u_probe(struct usb_interface *usb_intf,
err:
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
mt76u_queues_deinit(&dev->mt76);
mt76_free_device(&dev->mt76);
@@ -303,7 +301,6 @@ static void mt76x0_disconnect(struct usb_interface *usb_intf)
mt76x0u_cleanup(dev);
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
mt76_free_device(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
index 01cb3b2830f3..ade15bddefc5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x2/usb.c
@@ -16,6 +16,7 @@ static const struct usb_device_id mt76x2u_device_table[] = {
{ USB_DEVICE(0x0e8d, 0x7612) }, /* Aukey USBAC1200 - Alfa AWUS036ACM */
{ USB_DEVICE(0x057c, 0x8503) }, /* Avm FRITZ!WLAN AC860 */
{ USB_DEVICE(0x7392, 0xb711) }, /* Edimax EW 7722 UAC */
+ { USB_DEVICE(0x056e, 0x400a) }, /* ELECOM WDC-867SU3S */
{ USB_DEVICE(0x0e8d, 0x7632) }, /* HC-M7662BU1 */
{ USB_DEVICE(0x0471, 0x2126) }, /* LiteOn WN4516R module, nonstandard USB connector */
{ USB_DEVICE(0x0471, 0x7600) }, /* LiteOn WN4519R module, nonstandard USB connector */
@@ -57,7 +58,6 @@ static int mt76x2u_probe(struct usb_interface *intf,
dev = container_of(mdev, struct mt76x02_dev, mt76);
- udev = usb_get_dev(udev);
usb_reset_device(udev);
usb_set_intfdata(intf, dev);
@@ -84,14 +84,12 @@ err:
mt76u_queues_deinit(&dev->mt76);
mt76_free_device(&dev->mt76);
usb_set_intfdata(intf, NULL);
- usb_put_dev(udev);
return err;
}
static void mt76x2u_disconnect(struct usb_interface *intf)
{
- struct usb_device *udev = interface_to_usbdev(intf);
struct mt76x02_dev *dev = usb_get_intfdata(intf);
struct ieee80211_hw *hw = mt76_hw(dev);
@@ -100,7 +98,6 @@ static void mt76x2u_disconnect(struct usb_interface *intf)
mt76x2u_cleanup(dev);
mt76_free_device(&dev->mt76);
usb_set_intfdata(intf, NULL);
- usb_put_dev(udev);
}
static int __maybe_unused mt76x2u_suspend(struct usb_interface *intf,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
index 26ed3745af43..4d0854fe785b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/debugfs.c
@@ -1296,8 +1296,7 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
struct dentry *dir;
dir = mt76_register_debugfs_fops(phy->mt76, NULL);
- if (!dir)
- return -ENOMEM;
+
debugfs_create_file("muru_debug", 0600, dir, dev, &fops_muru_debug);
debugfs_create_file("muru_stats", 0400, dir, phy,
&mt7915_muru_stats_fops);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index cec2c4208255..334c19ab2b22 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -912,16 +912,16 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
}
if (!mtk_wed_device_active(&mdev->mmio.wed) && wcid) {
- u32 tx_retries = 0, tx_failed = 0;
+ u32 tx_retries = 0, tx_failed = 0, count;
if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) {
- tx_retries =
- FIELD_GET(MT_TX_FREE_COUNT_V3, info) - 1;
+ count = FIELD_GET(MT_TX_FREE_COUNT_V3, info);
+ tx_retries = count ? count - 1 : 0;
tx_failed = tx_retries +
!!FIELD_GET(MT_TX_FREE_STAT_V3, info);
} else if (!v3 && (info & MT_TX_FREE_MPDU_HEADER)) {
- tx_retries =
- FIELD_GET(MT_TX_FREE_COUNT, info) - 1;
+ count = FIELD_GET(MT_TX_FREE_COUNT, info);
+ tx_retries = count ? count - 1 : 0;
tx_failed = tx_retries +
!!FIELD_GET(MT_TX_FREE_STAT, info);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index e1d83052aa6d..51643a48ed15 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -760,6 +760,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
msta->wcid.phy_idx = ext_phy;
msta->jiffies = jiffies;
+ if (sta->tdls)
+ set_bit(MT_WCID_FLAG_TDLS_PEER, &msta->wcid.flags);
+
ewma_avg_signal_init(&msta->avg_ack_signal);
mt7915_mac_wtbl_update(dev, idx,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 318c38149463..4a381d351e61 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -3534,10 +3534,18 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len,
if (category == TX_POWER_INFO_RATE) {
s8 res[MT7915_SKU_RATE_NUM][2];
+ if (skb->len < sizeof(res) + 4) {
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
memcpy(res, skb->data + 4, sizeof(res));
for (i = 0; i < len; i++)
txpower[i] = res[i][req.band_idx];
} else if (category == TX_POWER_INFO_PATH) {
+ if (skb->len < len + 4) {
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
memcpy(txpower, skb->data + 4, len);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
index 2ad3c1cc3779..3ef7c9c45386 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/Makefile
@@ -5,7 +5,7 @@ obj-$(CONFIG_MT7921E) += mt7921e.o
obj-$(CONFIG_MT7921S) += mt7921s.o
obj-$(CONFIG_MT7921U) += mt7921u.o
-mt7921-common-y := mac.o mcu.o main.o init.o debugfs.o
+mt7921-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o
mt7921-common-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt7921e-y := pci.o pci_mac.o pci_mcu.o
mt7921s-y := sdio.o sdio_mac.o sdio_mcu.o
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
index 4333005b3ad9..a5a70d8e8544 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/debugfs.c
@@ -266,8 +266,6 @@ int mt7921_init_debugfs(struct mt792x_dev *dev)
struct dentry *dir;
dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval);
- if (!dir)
- return -ENOMEM;
if (mt76_is_mmio(&dev->mt76))
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues",
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/init.c b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
index 8e7790702191..49be2fa4e3fa 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/init.c
@@ -9,6 +9,7 @@
#include "mt7921.h"
#include "../mt76_connac2_mac.h"
#include "mcu.h"
+#include "regd.h"
static ssize_t mt7921_thermal_temp_show(struct device *dev,
struct device_attribute *attr,
@@ -60,103 +61,6 @@ static int mt7921_thermal_init(struct mt792x_phy *phy)
return PTR_ERR_OR_ZERO(hwmon);
}
-static void
-mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
-{
-#define IS_UNII_INVALID(idx, sfreq, efreq) \
- (!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq))
- struct ieee80211_supported_band *sband;
- struct mt76_dev *mdev = &dev->mt76;
- struct device_node *np, *band_np;
- struct ieee80211_channel *ch;
- int i, cfreq;
-
- np = mt76_find_power_limits_node(mdev);
-
- sband = wiphy->bands[NL80211_BAND_5GHZ];
- band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL;
- for (i = 0; i < sband->n_channels; i++) {
- ch = &sband->channels[i];
- cfreq = ch->center_freq;
-
- if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) {
- ch->flags |= IEEE80211_CHAN_DISABLED;
- continue;
- }
-
- /* UNII-4 */
- if (IS_UNII_INVALID(0, 5845, 5925))
- ch->flags |= IEEE80211_CHAN_DISABLED;
- }
-
- sband = wiphy->bands[NL80211_BAND_6GHZ];
- if (!sband)
- return;
-
- band_np = np ? of_get_child_by_name(np, "txpower-6g") : NULL;
- for (i = 0; i < sband->n_channels; i++) {
- ch = &sband->channels[i];
- cfreq = ch->center_freq;
-
- if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) {
- ch->flags |= IEEE80211_CHAN_DISABLED;
- continue;
- }
-
- /* UNII-5/6/7/8 */
- if (IS_UNII_INVALID(1, 5925, 6425) ||
- IS_UNII_INVALID(2, 6425, 6525) ||
- IS_UNII_INVALID(3, 6525, 6875) ||
- IS_UNII_INVALID(4, 6875, 7125))
- ch->flags |= IEEE80211_CHAN_DISABLED;
- }
-}
-
-void mt7921_regd_update(struct mt792x_dev *dev)
-{
- struct mt76_dev *mdev = &dev->mt76;
- struct ieee80211_hw *hw = mdev->hw;
- struct wiphy *wiphy = hw->wiphy;
-
- mt7921_mcu_set_clc(dev, mdev->alpha2, dev->country_ie_env);
- mt7921_regd_channel_update(wiphy, dev);
- mt76_connac_mcu_set_channel_domain(hw->priv);
- mt7921_set_tx_sar_pwr(hw, NULL);
-}
-EXPORT_SYMBOL_GPL(mt7921_regd_update);
-
-static void
-mt7921_regd_notifier(struct wiphy *wiphy,
- struct regulatory_request *request)
-{
- struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
- struct mt792x_dev *dev = mt792x_hw_dev(hw);
- struct mt76_connac_pm *pm = &dev->pm;
-
- memcpy(dev->mt76.alpha2, request->alpha2, sizeof(dev->mt76.alpha2));
- dev->mt76.region = request->dfs_region;
- dev->country_ie_env = request->country_ie_env;
-
- if (request->initiator == NL80211_REGDOM_SET_BY_USER) {
- if (dev->mt76.alpha2[0] == '0' && dev->mt76.alpha2[1] == '0')
- wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE;
- else
- wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
- }
-
- if (pm->suspended)
- return;
-
- dev->regd_in_progress = true;
-
- mt792x_mutex_acquire(dev);
- mt7921_regd_update(dev);
- mt792x_mutex_release(dev);
-
- dev->regd_in_progress = false;
- wake_up(&dev->wait);
-}
-
int mt7921_mac_init(struct mt792x_dev *dev)
{
int i;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 03b4960db73f..1c2377d0a53d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -7,6 +7,7 @@
#include "mt7921.h"
#include "../dma.h"
#include "../mt76_connac2_mac.h"
+#include "regd.h"
#include "mcu.h"
#define MT_WTBL_TXRX_CAP_RATE_OFFSET 7
@@ -530,8 +531,9 @@ static void mt7921_mac_tx_free(struct mt792x_dev *dev, void *data, int len)
stat = FIELD_GET(MT_TX_FREE_STATUS, info);
if (wcid) {
- wcid->stats.tx_retries +=
- FIELD_GET(MT_TX_FREE_COUNT, info) - 1;
+ u32 count = FIELD_GET(MT_TX_FREE_COUNT, info);
+
+ wcid->stats.tx_retries += count ? count - 1 : 0;
wcid->stats.tx_failed += !!stat;
}
@@ -675,7 +677,9 @@ void mt7921_mac_reset_work(struct work_struct *work)
if (!ret)
break;
}
- if (mt76_is_sdio(&dev->mt76) && atomic_read(&dev->mt76.bus_hung))
+
+ if ((mt76_is_sdio(&dev->mt76) || mt76_is_usb(&dev->mt76)) &&
+ atomic_read(&dev->mt76.bus_hung))
return;
if (i == 10)
@@ -697,6 +701,8 @@ void mt7921_mac_reset_work(struct work_struct *work)
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_vif_connect_iter, NULL);
mt76_connac_power_save_sched(&dev->mt76.phy, pm);
+
+ mt7921_regd_change(&dev->phy, "00");
}
void mt7921_coredump_work(struct work_struct *work)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 3d74fabe7408..3480205d5fb9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <net/ipv6.h>
#include "mt7921.h"
+#include "regd.h"
#include "mcu.h"
static int
@@ -801,7 +802,7 @@ mt7921_regd_set_6ghz_power_type(struct ieee80211_vif *vif, bool is_add)
out:
if (vif->bss_conf.chanreq.oper.chan->band == NL80211_BAND_6GHZ)
- mt7921_regd_update(dev);
+ mt7921_mcu_regd_update(dev, dev->mt76.alpha2, dev->country_ie_env);
}
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
@@ -828,6 +829,9 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
msta->deflink.last_txs = jiffies;
msta->deflink.sta = msta;
+ if (sta->tdls)
+ set_bit(MT_WCID_FLAG_TDLS_PEER, &msta->deflink.wcid.flags);
+
ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm);
if (ret)
return ret;
@@ -1027,8 +1031,16 @@ void mt7921_scan_work(struct work_struct *work)
rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
if (rxd->eid == MCU_EVENT_SCHED_SCAN_DONE) {
ieee80211_sched_scan_results(phy->mt76->hw);
- } else if (test_and_clear_bit(MT76_HW_SCANNING,
- &phy->mt76->state)) {
+ } else if (rxd->eid == MCU_EVENT_SCAN_DONE) {
+ struct mt76_connac_hw_scan_done *event = NULL;
+
+ skb_pull(skb, sizeof(*rxd));
+ event = (struct mt76_connac_hw_scan_done *)skb->data;
+ mt7921_regd_change(phy, event->alpha2);
+ }
+
+ if (test_and_clear_bit(MT76_HW_SCANNING,
+ &phy->mt76->state)) {
struct cfg80211_scan_info info = {
.aborted = false,
};
@@ -1405,10 +1417,12 @@ mt7921_change_chanctx(struct ieee80211_hw *hw,
vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
mt792x_mutex_acquire(phy->dev);
- if (vif->type == NL80211_IFTYPE_MONITOR)
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+ mt7921_mcu_set_sniffer(mvif->phy->dev, vif, true);
mt7921_mcu_config_sniffer(mvif, ctx);
- else
+ } else {
mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx);
+ }
mt792x_mutex_release(phy->dev);
}
@@ -1508,6 +1522,9 @@ static void mt7921_channel_switch_rx_beacon(struct ieee80211_hw *hw,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
u16 beacon_interval = vif->bss_conf.beacon_int;
+ if (!dev->new_ctx)
+ return;
+
if (cfg80211_chandef_identical(&chsw->chandef,
&dev->new_ctx->def) &&
chsw->count) {
@@ -1552,7 +1569,7 @@ const struct ieee80211_ops mt7921_ops = {
.wake_tx_queue = mt76_wake_tx_queue,
.release_buffered_frames = mt76_release_buffered_frames,
.channel_switch_beacon = mt7921_channel_switch_beacon,
- .get_txpower = mt76_get_txpower,
+ .get_txpower = mt792x_get_txpower,
.get_stats = mt792x_get_stats,
.get_et_sset_count = mt792x_get_et_sset_count,
.get_et_strings = mt792x_get_et_strings,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
index 8442dbd2ee23..25b9437250f7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mcu.c
@@ -4,6 +4,7 @@
#include <linux/fs.h>
#include <linux/firmware.h>
#include "mt7921.h"
+#include "regd.h"
#include "mcu.h"
#include "../mt76_connac2_mac.h"
#include "../mt792x_trace.h"
@@ -11,10 +12,6 @@
#define MT_STA_BFER BIT(0)
#define MT_STA_BFEE BIT(1)
-static bool mt7921_disable_clc;
-module_param_named(disable_clc, mt7921_disable_clc, bool, 0644);
-MODULE_PARM_DESC(disable_clc, "disable CLC support");
-
int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
struct sk_buff *skb, int seq)
{
@@ -422,8 +419,8 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
u8 *clc_base = NULL, hw_encap = 0;
dev->phy.clc_chan_conf = 0xff;
- if (mt7921_disable_clc ||
- mt76_is_usb(&dev->mt76))
+ dev->regd_user = false;
+ if (!mt7921_regd_clc_supported(dev))
return 0;
if (mt76_is_mmio(&dev->mt76)) {
@@ -488,7 +485,8 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
goto out;
}
}
- ret = mt7921_mcu_set_clc(dev, "00", ENVIRON_INDOOR);
+
+ ret = mt7921_regd_init(phy);
out:
release_firmware(fw);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
index 64f60c4fc60c..fb8654b7c5e7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mt7921.h
@@ -260,7 +260,6 @@ mt7921_l1_rmw(struct mt792x_dev *dev, u32 addr, u32 mask, u32 val)
#define mt7921_l1_set(dev, addr, val) mt7921_l1_rmw(dev, addr, 0, val)
#define mt7921_l1_clear(dev, addr, val) mt7921_l1_rmw(dev, addr, val, 0)
-void mt7921_regd_update(struct mt792x_dev *dev);
int mt7921_mac_init(struct mt792x_dev *dev);
bool mt7921_mac_wtbl_update(struct mt792x_dev *dev, int idx, u32 mask);
int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
index 7a790ddf43bb..7728c5ae6791 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/pci.c
@@ -12,6 +12,7 @@
#include "../mt76_connac2_mac.h"
#include "../dma.h"
#include "mcu.h"
+#include "regd.h"
static const struct pci_device_id mt7921_pci_device_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7961),
@@ -343,11 +344,14 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, mdev);
+ dev = container_of(mdev, struct mt792x_dev, mt76);
+
regs = pcim_iomap_region(pdev, 0, pci_name(pdev));
- if (IS_ERR(regs))
- return PTR_ERR(regs);
+ if (IS_ERR(regs)) {
+ ret = PTR_ERR(regs);
+ goto err_free_dev;
+ }
- dev = container_of(mdev, struct mt792x_dev, mt76);
dev->fw_features = features;
dev->hif_ops = &mt7921_pcie_ops;
dev->irq_map = &irq_map;
@@ -359,8 +363,10 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
/* MT7902 needs a mutable copy because wm2_complete_mask differs */
map = devm_kmemdup(&pdev->dev, &irq_map,
sizeof(irq_map), GFP_KERNEL);
- if (!map)
- return -ENOMEM;
+ if (!map) {
+ ret = -ENOMEM;
+ goto err_free_dev;
+ }
map->rx.wm2_complete_mask = 0;
dev->irq_map = map;
@@ -583,7 +589,7 @@ static int mt7921_pci_resume(struct device *device)
if (err < 0)
goto failed;
- mt7921_regd_update(dev);
+ mt7921_mcu_regd_update(dev, mdev->alpha2, dev->country_ie_env);
err = mt7921_mcu_radio_led_ctrl(dev, EXT_CMD_RADIO_ON_LED);
failed:
pm->suspended = false;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.c b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c
new file mode 100644
index 000000000000..c0e2b48a50bf
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: BSD-3-Clause-Clear
+/* Copyright (C) 2025 MediaTek Inc. */
+
+#include <linux/of.h>
+#include "mt7921.h"
+#include "regd.h"
+#include "mcu.h"
+
+static bool mt7921_disable_clc;
+module_param_named(disable_clc, mt7921_disable_clc, bool, 0644);
+MODULE_PARM_DESC(disable_clc, "disable CLC support");
+
+bool mt7921_regd_clc_supported(struct mt792x_dev *dev)
+{
+ if (mt7921_disable_clc ||
+ mt76_is_usb(&dev->mt76))
+ return false;
+
+ return true;
+}
+
+static void
+mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
+{
+#define IS_UNII_INVALID(idx, sfreq, efreq) \
+ (!(dev->phy.clc_chan_conf & BIT(idx)) && (cfreq) >= (sfreq) && (cfreq) <= (efreq))
+ struct ieee80211_supported_band *sband;
+ struct mt76_dev *mdev = &dev->mt76;
+ struct device_node *np, *band_np;
+ struct ieee80211_channel *ch;
+ int i, cfreq;
+
+ np = mt76_find_power_limits_node(mdev);
+
+ sband = wiphy->bands[NL80211_BAND_5GHZ];
+ band_np = np ? of_get_child_by_name(np, "txpower-5g") : NULL;
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ cfreq = ch->center_freq;
+
+ if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) {
+ ch->flags |= IEEE80211_CHAN_DISABLED;
+ continue;
+ }
+
+ /* UNII-4 */
+ if (IS_UNII_INVALID(0, 5845, 5925))
+ ch->flags |= IEEE80211_CHAN_DISABLED;
+ }
+
+ sband = wiphy->bands[NL80211_BAND_6GHZ];
+ if (!sband)
+ return;
+
+ band_np = np ? of_get_child_by_name(np, "txpower-6g") : NULL;
+ for (i = 0; i < sband->n_channels; i++) {
+ ch = &sband->channels[i];
+ cfreq = ch->center_freq;
+
+ if (np && (!band_np || !mt76_find_channel_node(band_np, ch))) {
+ ch->flags |= IEEE80211_CHAN_DISABLED;
+ continue;
+ }
+
+ /* UNII-5/6/7/8 */
+ if (IS_UNII_INVALID(1, 5925, 6425) ||
+ IS_UNII_INVALID(2, 6425, 6525) ||
+ IS_UNII_INVALID(3, 6525, 6875) ||
+ IS_UNII_INVALID(4, 6875, 7125))
+ ch->flags |= IEEE80211_CHAN_DISABLED;
+ }
+}
+
+int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
+ enum environment_cap country_ie_env)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ struct ieee80211_hw *hw = mdev->hw;
+ struct wiphy *wiphy = hw->wiphy;
+ int ret = 0;
+
+ dev->regd_in_progress = true;
+
+ mt792x_mutex_acquire(dev);
+ if (!dev->regd_change)
+ goto err;
+
+ ret = mt7921_mcu_set_clc(dev, alpha2, country_ie_env);
+ if (ret < 0)
+ goto err;
+
+ mt7921_regd_channel_update(wiphy, dev);
+
+ ret = mt76_connac_mcu_set_channel_domain(hw->priv);
+ if (ret < 0)
+ goto err;
+
+ ret = mt7921_set_tx_sar_pwr(hw, NULL);
+ if (ret < 0)
+ goto err;
+
+err:
+ mt792x_mutex_release(dev);
+ dev->regd_change = false;
+ dev->regd_in_progress = false;
+ wake_up(&dev->wait);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt7921_mcu_regd_update);
+
+void mt7921_regd_notifier(struct wiphy *wiphy,
+ struct regulatory_request *req)
+{
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt76_connac_pm *pm = &dev->pm;
+ struct mt76_dev *mdev = &dev->mt76;
+
+ if (req->initiator == NL80211_REGDOM_SET_BY_USER &&
+ !dev->regd_user)
+ dev->regd_user = true;
+
+ /* do not need to update the same country twice */
+ if (!memcmp(req->alpha2, mdev->alpha2, 2) &&
+ dev->country_ie_env == req->country_ie_env)
+ return;
+
+ memcpy(mdev->alpha2, req->alpha2, 2);
+ mdev->region = req->dfs_region;
+ dev->country_ie_env = req->country_ie_env;
+
+ if (req->initiator == NL80211_REGDOM_SET_BY_USER) {
+ if (dev->mt76.alpha2[0] == '0' && dev->mt76.alpha2[1] == '0')
+ wiphy->regulatory_flags &= ~REGULATORY_COUNTRY_IE_IGNORE;
+ else
+ wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE;
+ }
+
+ dev->regd_change = true;
+
+ if (pm->suspended)
+ return;
+
+ mt7921_mcu_regd_update(dev, req->alpha2,
+ req->country_ie_env);
+}
+
+static bool
+mt7921_regd_is_valid_alpha2(const char *alpha2)
+{
+ if (!alpha2)
+ return false;
+
+ if (alpha2[0] == '0' && alpha2[1] == '0')
+ return true;
+
+ if (isalpha(alpha2[0]) && isalpha(alpha2[1]))
+ return true;
+
+ return false;
+}
+
+int mt7921_regd_change(struct mt792x_phy *phy, char *alpha2)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt76_dev *mdev = &dev->mt76;
+
+ if (dev->hw_full_reset)
+ return 0;
+
+ if (!mt7921_regd_is_valid_alpha2(alpha2) ||
+ !mt7921_regd_clc_supported(dev) ||
+ dev->regd_user)
+ return -EINVAL;
+
+ if (mdev->alpha2[0] != '0' && mdev->alpha2[1] != '0')
+ return 0;
+
+ /* do not need to update the same country twice */
+ if (!memcmp(alpha2, mdev->alpha2, 2))
+ return 0;
+
+ if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN)
+ return regulatory_hint(wiphy, alpha2);
+ else
+ return mt7921_mcu_set_clc(dev, alpha2, ENVIRON_INDOOR);
+}
+
+int mt7921_regd_init(struct mt792x_phy *phy)
+{
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+ struct mt792x_dev *dev = mt792x_hw_dev(hw);
+ struct mt76_dev *mdev = &dev->mt76;
+
+ if (phy->chip_cap & MT792x_CHIP_CAP_11D_EN)
+ wiphy->regulatory_flags |= REGULATORY_COUNTRY_IE_IGNORE |
+ REGULATORY_DISABLE_BEACON_HINTS;
+ else
+ memzero_explicit(&mdev->alpha2, sizeof(mdev->alpha2));
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/regd.h b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h
new file mode 100644
index 000000000000..571f31629e9e
--- /dev/null
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/regd.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/* Copyright (C) 2025 MediaTek Inc. */
+
+#ifndef __MT7921_REGD_H
+#define __MT7921_REGD_H
+
+struct mt792x_dev;
+struct wiphy;
+struct regulatory_request;
+
+int mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,
+ enum environment_cap country_ie_env);
+void mt7921_regd_notifier(struct wiphy *wiphy,
+ struct regulatory_request *request);
+bool mt7921_regd_clc_supported(struct mt792x_dev *dev);
+int mt7921_regd_change(struct mt792x_phy *phy, char *alpha2);
+int mt7921_regd_init(struct mt792x_phy *phy);
+
+#endif
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
index 17057e68bf21..2fdecf239125 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/usb.c
@@ -13,6 +13,8 @@
#include "../mt76_connac2_mac.h"
static const struct usb_device_id mt7921u_device_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7902, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)MT7902_FIRMWARE_WM },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7961, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)MT7921_FIRMWARE_WM },
/* Comfast CF-952AX */
@@ -88,6 +90,10 @@ static int mt7921u_mac_reset(struct mt792x_dev *dev)
{
int err;
+ mt792xu_reset_on_bus_error(dev);
+ if (atomic_read(&dev->mt76.bus_hung))
+ return 0;
+
mt76_txq_schedule_all(&dev->mphy);
mt76_worker_disable(&dev->mt76.tx_worker);
@@ -196,8 +202,9 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
dev = container_of(mdev, struct mt792x_dev, mt76);
dev->fw_features = features;
dev->hif_ops = &hif_ops;
+ atomic_set(&dev->mt76.bus_hung, false);
+ mt792xu_reset_work_init(dev);
- udev = usb_get_dev(udev);
usb_reset_device(udev);
usb_set_intfdata(usb_intf, dev);
@@ -244,9 +251,9 @@ static int mt7921u_probe(struct usb_interface *usb_intf,
error:
mt76u_queues_deinit(&dev->mt76);
+ mt792xu_reset_work_cleanup(dev);
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
mt76_free_device(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
index e2498659c884..d01ff49de47a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/debugfs.c
@@ -291,8 +291,6 @@ int mt7925_init_debugfs(struct mt792x_dev *dev)
struct dentry *dir;
dir = mt76_register_debugfs_fops(&dev->mphy, &fops_regval);
- if (!dir)
- return -ENOMEM;
if (mt76_is_mmio(&dev->mt76))
debugfs_create_devm_seqfile(dev->mt76.dev, "xmit-queues",
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/init.c b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
index c0c5cb9aff75..e85b0d104fbe 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/init.c
@@ -117,6 +117,15 @@ static int __mt7925_init_hardware(struct mt792x_dev *dev)
if (ret)
goto out;
+ if (is_mt7927(&dev->mt76)) {
+ ret = mt7925_mcu_set_dbdc(&dev->mphy, true);
+ if (ret) {
+ dev_warn(dev->mt76.dev,
+ "MT7927 DBDC enable failed: %d\n", ret);
+ ret = 0;
+ }
+ }
+
out:
return ret;
}
@@ -232,7 +241,8 @@ int mt7925_register_device(struct mt792x_dev *dev)
dev->pm.idle_timeout = MT792x_PM_TIMEOUT;
dev->pm.stats.last_wake_event = jiffies;
dev->pm.stats.last_doze_event = jiffies;
- if (!mt76_is_usb(&dev->mt76)) {
+ /* MT7927: runtime PM crashes BT firmware on the shared CONNINFRA domain */
+ if (!mt76_is_usb(&dev->mt76) && !is_mt7927(&dev->mt76)) {
dev->pm.enable_user = true;
dev->pm.enable = true;
dev->pm.ds_enable_user = true;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index c47bd812b66b..0641a7131d7c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -339,6 +339,11 @@ mt7925_mac_fill_rx_rate(struct mt792x_dev *dev,
case IEEE80211_STA_RX_BW_160:
status->bw = RATE_INFO_BW_160;
break;
+ /* RXV can report 320 in two positions */
+ case IEEE80211_STA_RX_BW_320:
+ case IEEE80211_STA_RX_BW_320 + 1:
+ status->bw = RATE_INFO_BW_320;
+ break;
default:
return -EINVAL;
}
@@ -841,7 +846,6 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb,
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_link_sta *link_sta;
- struct mt792x_link_sta *mlink;
struct mt792x_sta *msta;
bool is_8023;
u16 fc, tid;
@@ -880,14 +884,14 @@ static void mt7925_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb,
msta = (struct mt792x_sta *)sta->drv_priv;
- if (sta->mlo && msta->deflink_id != IEEE80211_LINK_UNSPECIFIED)
- mlink = rcu_dereference(msta->link[msta->deflink_id]);
- else
- mlink = &msta->deflink;
-
- if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state)) {
+ /* Packets belonging to the same TID can be transmitted over multiple
+ * links. Keep the TX BA session state in the primary link so all links
+ * share the same AMPDU bookkeeping.
+ */
+ if (!test_and_set_bit(tid, &msta->deflink.wcid.ampdu_state)) {
if (ieee80211_start_tx_ba_session(sta, tid, 0))
- clear_bit(tid, &mlink->wcid.ampdu_state);
+ clear_bit(tid, &msta->deflink.wcid.ampdu_state);
+
}
}
@@ -997,6 +1001,10 @@ mt7925_mac_add_txs_skb(struct mt792x_dev *dev, struct mt76_wcid *wcid,
stats->tx_mode[mode]++;
switch (FIELD_GET(MT_TXS0_BW, txs)) {
+ case IEEE80211_STA_RX_BW_320:
+ rate.bw = RATE_INFO_BW_320;
+ stats->tx_bw[4]++;
+ break;
case IEEE80211_STA_RX_BW_160:
rate.bw = RATE_INFO_BW_160;
stats->tx_bw[3]++;
@@ -1141,8 +1149,9 @@ mt7925_mac_tx_free(struct mt792x_dev *dev, void *data, int len)
if (info & MT_TXFREE_INFO_HEADER) {
if (wcid) {
- wcid->stats.tx_retries +=
- FIELD_GET(MT_TXFREE_INFO_COUNT, info) - 1;
+ u32 count = FIELD_GET(MT_TXFREE_INFO_COUNT, info);
+
+ wcid->stats.tx_retries += count ? count - 1 : 0;
wcid->stats.tx_failed +=
!!FIELD_GET(MT_TXFREE_INFO_STAT, info);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 73d3722739d0..a9059866b701 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -183,6 +183,10 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band,
IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER |
IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE;
+ if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76))
+ eht_cap_elem->phy_cap_info[0] |=
+ IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
+
eht_cap_elem->phy_cap_info[0] |=
u8_encode_bits(u8_get_bits(sts - 1, BIT(0)),
IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK);
@@ -193,10 +197,20 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band,
u8_encode_bits(sts - 1,
IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK);
+ if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76))
+ eht_cap_elem->phy_cap_info[1] |=
+ u8_encode_bits(sts - 1,
+ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK);
+
eht_cap_elem->phy_cap_info[2] =
u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK) |
u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK);
+ if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76))
+ eht_cap_elem->phy_cap_info[2] |=
+ u8_encode_bits(sts - 1,
+ IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK);
+
eht_cap_elem->phy_cap_info[3] =
IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK |
IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK |
@@ -217,7 +231,8 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band,
u8_encode_bits(u8_get_bits(0x11, GENMASK(1, 0)),
IEEE80211_EHT_PHY_CAP5_MAX_NUM_SUPP_EHT_LTF_MASK);
- val = width == NL80211_CHAN_WIDTH_160 ? 0x7 :
+ val = width == NL80211_CHAN_WIDTH_320 ? 0xf :
+ width == NL80211_CHAN_WIDTH_160 ? 0x7 :
width == NL80211_CHAN_WIDTH_80 ? 0x3 : 0x1;
eht_cap_elem->phy_cap_info[6] =
u8_encode_bits(u8_get_bits(0x11, GENMASK(4, 2)),
@@ -239,6 +254,11 @@ mt7925_init_eht_caps(struct mt792x_phy *phy, enum nl80211_band band,
eht_nss->bw._160.rx_tx_mcs9_max_nss = val;
eht_nss->bw._160.rx_tx_mcs11_max_nss = val;
eht_nss->bw._160.rx_tx_mcs13_max_nss = val;
+ if (band == NL80211_BAND_6GHZ && is_320mhz_supported(&phy->dev->mt76)) {
+ eht_nss->bw._320.rx_tx_mcs9_max_nss = val;
+ eht_nss->bw._320.rx_tx_mcs11_max_nss = val;
+ eht_nss->bw._320.rx_tx_mcs13_max_nss = val;
+ }
}
int mt7925_init_mlo_caps(struct mt792x_phy *phy)
@@ -376,6 +396,18 @@ static int mt7925_mac_link_bss_add(struct mt792x_dev *dev,
mconf->mt76.omac_idx = ieee80211_vif_is_mld(vif) ?
0 : mconf->mt76.idx;
mconf->mt76.band_idx = 0xff;
+
+ if (is_mt7927(&dev->mt76)) {
+ struct ieee80211_channel *chan;
+
+ if (link_conf->chanreq.oper.chan)
+ chan = link_conf->chanreq.oper.chan;
+ else
+ chan = mvif->phy->mt76->chandef.chan;
+
+ mconf->mt76.band_idx = mt7927_band_idx(chan->band);
+ }
+
mconf->mt76.wmm_idx = ieee80211_vif_is_mld(vif) ?
0 : mconf->mt76.idx % MT76_CONNAC_MAX_WMM_SETS;
mconf->mt76.link_idx = hweight16(mvif->valid_links);
@@ -887,6 +919,9 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
mlink->wcid.link_valid = !!link_sta->sta->valid_links;
mlink->sta = msta;
+ if (link_sta->sta->tdls)
+ set_bit(MT_WCID_FLAG_TDLS_PEER, &mlink->wcid.flags);
+
wcid = &mlink->wcid;
ewma_signal_init(&wcid->rssi);
rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid);
@@ -1265,6 +1300,9 @@ mt7925_mac_sta_remove_links(struct mt792x_dev *dev, struct ieee80211_vif *vif,
if (vif->type == NL80211_IFTYPE_AP)
break;
+ if (vif->type == NL80211_IFTYPE_STATION && sta->tdls)
+ continue;
+
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
if (!link_sta)
continue;
@@ -1318,14 +1356,14 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
- unsigned long rem;
-
- rem = ieee80211_vif_is_mld(vif) ? msta->valid_links : BIT(0);
- mt7925_mac_sta_remove_links(dev, vif, sta, rem);
-
- if (ieee80211_vif_is_mld(vif))
+ if (ieee80211_vif_is_mld(vif)) {
+ mt7925_mac_sta_remove_links(dev, vif, sta, msta->valid_links);
mt7925_mcu_del_dev(mdev, vif);
+ } else {
+ mt7925_mac_link_sta_remove(mdev, vif, &sta->deflink,
+ &msta->deflink);
+ }
if (vif->type == NL80211_IFTYPE_STATION) {
mvif->wep_sta = NULL;
@@ -1372,22 +1410,22 @@ mt7925_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn,
params->buf_size);
- mt7925_mcu_uni_rx_ba(dev, params, true);
+ mt7925_mcu_uni_rx_ba(dev, params, vif, true);
break;
case IEEE80211_AMPDU_RX_STOP:
mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid);
- mt7925_mcu_uni_rx_ba(dev, params, false);
+ mt7925_mcu_uni_rx_ba(dev, params, vif, false);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
mtxq->aggr = true;
mtxq->send_bar = false;
- mt7925_mcu_uni_tx_ba(dev, params, true);
+ mt7925_mcu_uni_tx_ba(dev, params, vif, true);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
clear_bit(tid, &msta->deflink.wcid.ampdu_state);
- mt7925_mcu_uni_tx_ba(dev, params, false);
+ mt7925_mcu_uni_tx_ba(dev, params, vif, false);
break;
case IEEE80211_AMPDU_TX_START:
set_bit(tid, &msta->deflink.wcid.ampdu_state);
@@ -1396,7 +1434,7 @@ mt7925_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
clear_bit(tid, &msta->deflink.wcid.ampdu_state);
- mt7925_mcu_uni_tx_ba(dev, params, false);
+ mt7925_mcu_uni_tx_ba(dev, params, vif, false);
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
@@ -2179,9 +2217,9 @@ free:
rcu_assign_pointer(mvif->link_conf[link_id], NULL);
rcu_assign_pointer(mvif->sta.link[link_id], NULL);
- if (mconf != &mvif->bss_conf)
+ if (mconfs[link_id] != &mvif->bss_conf)
devm_kfree(dev->mt76.dev, mconfs[link_id]);
- if (mlink != &mvif->sta.deflink)
+ if (mlinks[link_id] != &mvif->sta.deflink)
devm_kfree(dev->mt76.dev, mlinks[link_id]);
}
@@ -2218,6 +2256,29 @@ out:
return err;
}
+static int
+mt7927_reconfig_band(struct mt792x_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_bss_conf *link_conf,
+ struct mt792x_bss_conf *mconf,
+ u8 band_idx)
+{
+ struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
+ struct mt792x_link_sta *mlink = &mvif->sta.deflink;
+ int ret;
+
+ ret = mt76_connac_mcu_uni_add_dev(&dev->mphy, link_conf,
+ &mconf->mt76, &mlink->wcid,
+ false);
+ if (ret)
+ return ret;
+
+ mconf->mt76.band_idx = band_idx;
+
+ return mt76_connac_mcu_uni_add_dev(&dev->mphy, link_conf,
+ &mconf->mt76, &mlink->wcid,
+ true);
+}
+
static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
@@ -2228,6 +2289,7 @@ static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw,
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct ieee80211_bss_conf *pri_link_conf;
struct mt792x_bss_conf *mconf;
+ u8 band_idx;
mutex_lock(&dev->mt76.mutex);
@@ -2241,6 +2303,12 @@ static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw,
NULL, true);
} else {
mconf = &mvif->bss_conf;
+
+ if (is_mt7927(&dev->mt76)) {
+ band_idx = mt7927_band_idx(ctx->def.chan->band);
+
+ mt7927_reconfig_band(dev, vif, link_conf, mconf, band_idx);
+ }
}
mconf->mt76.ctx = ctx;
@@ -2400,6 +2468,9 @@ static void mt7925_channel_switch_rx_beacon(struct ieee80211_hw *hw,
if (ieee80211_vif_is_mld(vif))
return;
+ if (!dev->new_ctx)
+ return;
+
beacon_interval = vif->bss_conf.beacon_int;
if (cfg80211_chandef_identical(&chsw->chandef,
@@ -2433,7 +2504,7 @@ const struct ieee80211_ops mt7925_ops = {
.wake_tx_queue = mt76_wake_tx_queue,
.release_buffered_frames = mt76_release_buffered_frames,
.channel_switch_beacon = mt7925_channel_switch_beacon,
- .get_txpower = mt76_get_txpower,
+ .get_txpower = mt792x_get_txpower,
.get_stats = mt792x_get_stats,
.get_et_sset_count = mt792x_get_et_sset_count,
.get_et_strings = mt792x_get_et_strings,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 22bad3cba8df..e94fa544ff20 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -567,6 +567,34 @@ mt7925_mcu_uni_debug_msg_event(struct mt792x_dev *dev, struct sk_buff *skb)
}
static void
+mt7925_mcu_handle_mbmc_event(struct mt792x_dev *dev, struct sk_buff *skb)
+{
+ struct mbmc_conf_tlv *tlv;
+ u32 tlv_len;
+
+ skb_pull(skb, sizeof(struct mt7925_mcu_rxd) + 4);
+ tlv_len = skb->len;
+ tlv = (struct mbmc_conf_tlv *)skb->data;
+
+ while (tlv_len >= sizeof(*tlv) &&
+ le16_to_cpu(tlv->len) >= sizeof(*tlv) &&
+ le16_to_cpu(tlv->len) <= tlv_len) {
+ u16 tag = le16_to_cpu(tlv->tag);
+
+ if (tag == UNI_MBMC_SETTING || tag == UNI_MBMC_NO_RESP_SETTING) {
+ dev_dbg(dev->mt76.dev,
+ "MBMC event: tag=%u mbmc_en=%u\n",
+ tag, tlv->mbmc_en);
+ break;
+ }
+
+ tlv_len -= le16_to_cpu(tlv->len);
+ tlv = (struct mbmc_conf_tlv *)
+ ((u8 *)tlv + le16_to_cpu(tlv->len));
+ }
+}
+
+static void
mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,
struct sk_buff *skb)
{
@@ -584,6 +612,9 @@ mt7925_mcu_uni_rx_unsolicited_event(struct mt792x_dev *dev,
case MCU_UNI_EVENT_ROC:
mt7925_mcu_uni_roc_event(dev, skb);
break;
+ case MCU_UNI_EVENT_MBMC:
+ mt7925_mcu_handle_mbmc_event(dev, skb);
+ break;
case MCU_UNI_EVENT_SCAN_DONE:
mt7925_mcu_scan_event(dev, skb);
return;
@@ -624,9 +655,8 @@ void mt7925_mcu_rx_event(struct mt792x_dev *dev, struct sk_buff *skb)
static int
mt7925_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,
struct ieee80211_ampdu_params *params,
- bool enable, bool tx)
+ struct mt76_wcid *wcid, bool enable, bool tx)
{
- struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv;
struct sta_rec_ba_uni *ba;
struct sk_buff *skb;
struct tlv *tlv;
@@ -652,30 +682,69 @@ mt7925_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif_link *mvif,
MCU_UNI_CMD(STA_REC_UPDATE), true);
}
-/** starec & wtbl **/
int mt7925_mcu_uni_tx_ba(struct mt792x_dev *dev,
struct ieee80211_ampdu_params *params,
- bool enable)
+ struct ieee80211_vif *vif, bool enable)
{
- struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;
- struct mt792x_vif *mvif = msta->vif;
+ struct ieee80211_sta *sta = params->sta;
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct ieee80211_link_sta *link_sta;
+ unsigned int link_id;
- if (enable && !params->amsdu)
- msta->deflink.wcid.amsdu = false;
+ for_each_sta_active_link(vif, sta, link_sta, link_id) {
+ struct mt792x_link_sta *mlink;
+ struct mt792x_bss_conf *mconf;
+ int ret;
- return mt7925_mcu_sta_ba(&dev->mt76, &mvif->bss_conf.mt76, params,
- enable, true);
+ mlink = mt792x_sta_to_link(msta, link_id);
+ if (!mlink)
+ return -EINVAL;
+
+ mconf = mt792x_vif_to_link(msta->vif, link_id);
+ if (!mconf)
+ return -EINVAL;
+
+ if (enable && !params->amsdu)
+ mlink->wcid.amsdu = false;
+
+ ret = mt7925_mcu_sta_ba(&dev->mt76, &mconf->mt76, params,
+ &mlink->wcid, enable, true);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev,
struct ieee80211_ampdu_params *params,
- bool enable)
+ struct ieee80211_vif *vif, bool enable)
{
- struct mt792x_sta *msta = (struct mt792x_sta *)params->sta->drv_priv;
- struct mt792x_vif *mvif = msta->vif;
+ struct ieee80211_sta *sta = params->sta;
+ struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
+ struct ieee80211_link_sta *link_sta;
+ unsigned int link_id;
+
+ for_each_sta_active_link(vif, sta, link_sta, link_id) {
+ struct mt792x_link_sta *mlink;
+ struct mt792x_bss_conf *mconf;
+ int ret;
+
+ mlink = mt792x_sta_to_link(msta, link_id);
+ if (!mlink)
+ return -EINVAL;
+
+ mconf = mt792x_vif_to_link(msta->vif, link_id);
+ if (!mconf)
+ return -EINVAL;
- return mt7925_mcu_sta_ba(&dev->mt76, &mvif->bss_conf.mt76, params,
- enable, false);
+ ret = mt7925_mcu_sta_ba(&dev->mt76, &mconf->mt76, params,
+ &mlink->wcid, enable, false);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
static int mt7925_mcu_read_eeprom(struct mt792x_dev *dev, u32 offset, u8 *val)
@@ -1091,6 +1160,11 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
hdr_trans->to_ds = true;
hdr_trans->from_ds = true;
}
+
+ if (test_bit(MT_WCID_FLAG_TDLS_PEER, &wcid->flags)) {
+ hdr_trans->to_ds = false;
+ hdr_trans->from_ds = false;
+ }
}
int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
@@ -1667,6 +1741,7 @@ mt7925_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)
memcpy(eht->mcs_map_bw20, &mcs_map->only_20mhz, sizeof(eht->mcs_map_bw20));
memcpy(eht->mcs_map_bw80, &mcs_map->bw._80, sizeof(eht->mcs_map_bw80));
memcpy(eht->mcs_map_bw160, &mcs_map->bw._160, sizeof(eht->mcs_map_bw160));
+ memcpy(eht->mcs_map_bw320, &mcs_map->bw._320, sizeof(eht->mcs_map_bw320));
}
static void
@@ -2334,6 +2409,10 @@ void mt7925_mcu_bss_rlm_tlv(struct sk_buff *skb, struct mt76_phy *phy,
case NL80211_CHAN_WIDTH_160:
req->bw = CMD_CBW_160MHZ;
break;
+ case NL80211_CHAN_WIDTH_320:
+ req->bw = CMD_CBW_320MHZ;
+ req->center_chan2 = ieee80211_frequency_to_channel(freq2);
+ break;
case NL80211_CHAN_WIDTH_5:
req->bw = CMD_CBW_5MHZ;
break;
@@ -2827,6 +2906,7 @@ int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy,
struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);
struct mt792x_dev *dev = phy->dev;
struct sk_buff *skb;
+ int err;
skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
MT7925_BSS_UPDATE_MAX_SIZE);
@@ -2852,8 +2932,9 @@ int mt7925_mcu_add_bss_info_sta(struct mt792x_phy *phy,
mt7925_mcu_bss_mbssid_tlv(skb, link_conf, enable);
}
- return mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_UNI_CMD(BSS_INFO_UPDATE), true);
+ err = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_UNI_CMD(BSS_INFO_UPDATE), true);
+ return mt76_connac_mcu_bss_deact_err(&dev->mt76, err, enable);
}
int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
@@ -2911,6 +2992,7 @@ int mt7925_mcu_set_dbdc(struct mt76_phy *phy, bool enable)
return err;
}
+EXPORT_SYMBOL_GPL(mt7925_mcu_set_dbdc);
static void
mt7925_mcu_build_scan_ie_tlv(struct mt76_dev *mdev,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
index 56e2772f3ffe..293f173b23dd 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.h
@@ -143,7 +143,8 @@ enum {
};
enum {
- UNI_MBMC_SETTING,
+ UNI_MBMC_SETTING = 0,
+ UNI_MBMC_NO_RESP_SETTING = 1,
};
enum {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
index 46b480f7d813..4cc259418afc 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mt7925.h
@@ -126,6 +126,19 @@ enum mt7925_rxq_id {
MT7925_RXQ_MCU_WM2, /* for tx done */
};
+enum mt7927_txq_id {
+ MT7927_TXQ_BAND0 = MT7925_TXQ_BAND0,
+ MT7927_TXQ_BAND1 = MT7925_TXQ_BAND1,
+ MT7927_TXQ_MCU_WM = MT7925_TXQ_MCU_WM,
+ MT7927_TXQ_FWDL = MT7925_TXQ_FWDL,
+};
+
+enum mt7927_rxq_id {
+ MT7927_RXQ_BAND0 = 4,
+ MT7927_RXQ_MCU_WM = 6,
+ MT7927_RXQ_DATA2 = 7,
+};
+
enum {
MODE_OPEN = 0,
MODE_SHARED = 1,
@@ -239,6 +252,18 @@ struct mt7925_txpwr {
s8 eht996x3_484[16][2];
};
+static inline u8 mt7927_band_idx(enum nl80211_band band)
+{
+ switch (band) {
+ case NL80211_BAND_2GHZ:
+ return 0;
+ case NL80211_BAND_5GHZ:
+ case NL80211_BAND_6GHZ:
+ default:
+ return 1;
+ }
+}
+
extern const struct ieee80211_ops mt7925_ops;
int __mt7925_start(struct mt792x_phy *phy);
@@ -293,10 +318,10 @@ int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev,
bool enable);
int mt7925_mcu_uni_tx_ba(struct mt792x_dev *dev,
struct ieee80211_ampdu_params *params,
- bool enable);
+ struct ieee80211_vif *vif, bool enable);
int mt7925_mcu_uni_rx_ba(struct mt792x_dev *dev,
struct ieee80211_ampdu_params *params,
- bool enable);
+ struct ieee80211_vif *vif, bool enable);
void mt7925_mlo_pm_work(struct work_struct *work);
void mt7925_scan_work(struct work_struct *work);
void mt7925_roc_work(struct work_struct *work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index c4161754c01d..ea64303283ed 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -16,6 +16,12 @@ static const struct pci_device_id mt7925_pci_device_table[] = {
.driver_data = (kernel_ulong_t)MT7925_FIRMWARE_WM },
{ PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0717),
.driver_data = (kernel_ulong_t)MT7925_FIRMWARE_WM },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x7927),
+ .driver_data = (kernel_ulong_t)MT7927_FIRMWARE_WM },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x6639),
+ .driver_data = (kernel_ulong_t)MT7927_FIRMWARE_WM },
+ { PCI_DEVICE(PCI_VENDOR_ID_MEDIATEK, 0x0738),
+ .driver_data = (kernel_ulong_t)MT7927_FIRMWARE_WM },
{ },
};
@@ -210,48 +216,74 @@ static u32 mt7925_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
return dev->bus_ops->rmw(mdev, addr, mask, val);
}
-static int mt7925_dma_init(struct mt792x_dev *dev)
+static const struct mt792x_dma_layout mt7925_dma_layout = {
+ .tx_data0 = mt792x_dma_ring(MT7925_TXQ_BAND0,
+ MT7925_TX_RING_SIZE,
+ MT_TX_RING_BASE),
+ .tx_mcu = mt792x_dma_ring(MT7925_TXQ_MCU_WM,
+ MT7925_TX_MCU_RING_SIZE,
+ MT_TX_RING_BASE),
+ .tx_fwdl = mt792x_dma_ring(MT7925_TXQ_FWDL,
+ MT7925_TX_FWDL_RING_SIZE,
+ MT_TX_RING_BASE),
+ .rx_mcu = mt792x_dma_ring(MT7925_RXQ_MCU_WM,
+ MT7925_RX_MCU_RING_SIZE,
+ MT_RX_EVENT_RING_BASE),
+ .rx_data = mt792x_dma_ring(MT7925_RXQ_BAND0,
+ MT7925_RX_RING_SIZE,
+ MT_RX_DATA_RING_BASE),
+};
+
+static const struct mt792x_dma_layout mt7927_dma_layout = {
+ .tx_data0 = mt792x_dma_ring(MT7927_TXQ_BAND0,
+ MT7925_TX_RING_SIZE,
+ MT_TX_RING_BASE),
+ .tx_mcu = mt792x_dma_ring(MT7927_TXQ_MCU_WM,
+ MT7925_TX_MCU_RING_SIZE,
+ MT_TX_RING_BASE),
+ .tx_fwdl = mt792x_dma_ring(MT7927_TXQ_FWDL,
+ MT7925_TX_FWDL_RING_SIZE,
+ MT_TX_RING_BASE),
+ .rx_mcu = mt792x_dma_ring(MT7927_RXQ_MCU_WM,
+ MT7925_RX_MCU_RING_SIZE,
+ MT_RX_EVENT_RING_BASE),
+ .rx_data = mt792x_dma_ring(MT7927_RXQ_BAND0,
+ MT7925_RX_RING_SIZE,
+ MT_RX_DATA_RING_BASE),
+};
+
+static int mt7927_dma_init(struct mt792x_dev *dev)
{
int ret;
- mt76_dma_attach(&dev->mt76);
-
- ret = mt792x_dma_disable(dev, true);
+ ret = mt792x_dma_alloc_queues(dev, &mt7927_dma_layout);
if (ret)
return ret;
- /* init tx queue */
- ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7925_TXQ_BAND0,
- MT7925_TX_RING_SIZE,
- MT_TX_RING_BASE, NULL, 0);
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
+ MT7927_RXQ_DATA2,
+ MT7925_RX_MCU_RING_SIZE,
+ MT_RX_BUF_SIZE,
+ MT_RX_DATA_RING_BASE);
if (ret)
return ret;
- mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4);
-
- /* command to WM */
- ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM, MT7925_TXQ_MCU_WM,
- MT7925_TX_MCU_RING_SIZE, MT_TX_RING_BASE);
- if (ret)
+ ret = mt76_init_queues(dev, mt792x_poll_rx);
+ if (ret < 0)
return ret;
- /* firmware download */
- ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL, MT7925_TXQ_FWDL,
- MT7925_TX_FWDL_RING_SIZE, MT_TX_RING_BASE);
- if (ret)
- return ret;
+ netif_napi_add_tx(dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
+ mt792x_poll_tx);
+ napi_enable(&dev->mt76.tx_napi);
- /* rx event */
- ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
- MT7925_RXQ_MCU_WM, MT7925_RX_MCU_RING_SIZE,
- MT_RX_BUF_SIZE, MT_RX_EVENT_RING_BASE);
- if (ret)
- return ret;
+ return mt792x_dma_enable(dev);
+}
+
+static int mt7925_dma_init(struct mt792x_dev *dev)
+{
+ int ret;
- /* rx data */
- ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
- MT7925_RXQ_BAND0, MT7925_RX_RING_SIZE,
- MT_RX_BUF_SIZE, MT_RX_DATA_RING_BASE);
+ ret = mt792x_dma_alloc_queues(dev, &mt7925_dma_layout);
if (ret)
return ret;
@@ -266,6 +298,18 @@ static int mt7925_dma_init(struct mt792x_dev *dev)
return mt792x_dma_enable(dev);
}
+static const struct mt792x_irq_map mt7927_irq_map = {
+ .host_irq_enable = MT_WFDMA0_HOST_INT_ENA,
+ .tx = {
+ .all_complete_mask = MT_INT_TX_DONE_ALL,
+ .mcu_complete_mask = MT_INT_TX_DONE_MCU,
+ },
+ .rx = {
+ .data_complete_mask = MT7927_RX_DONE_INT_ENA4,
+ .wm_complete_mask = MT7927_RX_DONE_INT_ENA6,
+ .wm2_complete_mask = MT7927_RX_DONE_INT_ENA7,
+ },
+};
static int mt7925_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@@ -310,6 +354,7 @@ static int mt7925_pci_probe(struct pci_dev *pdev,
struct mt76_bus_ops *bus_ops;
struct mt792x_dev *dev;
struct mt76_dev *mdev;
+ bool is_mt7927_hw;
u8 features;
int ret;
u16 cmd;
@@ -337,7 +382,11 @@ static int mt7925_pci_probe(struct pci_dev *pdev,
if (ret)
goto err_free_pci_vec;
- if (mt7925_disable_aspm)
+ is_mt7927_hw = (pdev->device == 0x6639 || pdev->device == 0x7927 ||
+ pdev->device == 0x0738);
+
+ /* MT7927: ASPM L1 causes unreliable WFDMA register access */
+ if (mt7925_disable_aspm || is_mt7927_hw)
mt76_pci_disable_aspm(pdev);
ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7925_ops,
@@ -358,7 +407,7 @@ static int mt7925_pci_probe(struct pci_dev *pdev,
dev = container_of(mdev, struct mt792x_dev, mt76);
dev->fw_features = features;
dev->hif_ops = &mt7925_pcie_ops;
- dev->irq_map = &irq_map;
+ dev->irq_map = is_mt7927_hw ? &mt7927_irq_map : &irq_map;
mt76_mmio_init(&dev->mt76, pcim_iomap_table(pdev)[0]);
tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev);
@@ -394,6 +443,13 @@ static int mt7925_pci_probe(struct pci_dev *pdev,
dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
+ if (is_mt7927_hw && mt76_chip(mdev) != 0x7927) {
+ dev_info(mdev->dev,
+ "MT7927 raw CHIPID=0x%04x, forcing chip=0x7927\n",
+ mt76_chip(mdev));
+ mdev->rev = (0x7927 << 16) | (mdev->rev & 0xff);
+ }
+
mt76_rmw_field(dev, MT_HW_EMI_CTL, MT_HW_EMI_CTL_SLPPROT_EN, 1);
ret = mt792x_wfsys_reset(dev);
@@ -409,16 +465,24 @@ static int mt7925_pci_probe(struct pci_dev *pdev,
if (ret)
goto err_free_dev;
- ret = mt7925_dma_init(dev);
+ if (is_mt7927(&dev->mt76))
+ ret = mt7927_dma_init(dev);
+ else if (is_mt7925(&dev->mt76))
+ ret = mt7925_dma_init(dev);
+ else
+ ret = -EINVAL;
+
if (ret)
goto err_free_irq;
ret = mt7925_register_device(dev);
if (ret)
- goto err_free_irq;
+ goto err_free_dma;
return 0;
+err_free_dma:
+ mt792x_dma_cleanup(dev);
err_free_irq:
devm_free_irq(&pdev->dev, pdev->irq, dev);
err_free_dev:
@@ -549,7 +613,10 @@ static int _mt7925_pci_resume(struct device *device, bool restore)
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
mt76_connac_irq_enable(&dev->mt76,
dev->irq_map->tx.all_complete_mask |
- MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD);
+ dev->irq_map->rx.data_complete_mask |
+ dev->irq_map->rx.wm_complete_mask |
+ dev->irq_map->rx.wm2_complete_mask |
+ MT_INT_MCU_CMD);
mt76_set(dev, MT_MCU2HOST_SW_INT_ENA, MT_MCU_CMD_WAKE_RX_PCIE);
/* put dma enabled */
@@ -633,6 +700,8 @@ module_pci_driver(mt7925_pci_driver);
MODULE_DEVICE_TABLE(pci, mt7925_pci_device_table);
MODULE_FIRMWARE(MT7925_FIRMWARE_WM);
MODULE_FIRMWARE(MT7925_ROM_PATCH);
+MODULE_FIRMWARE(MT7927_FIRMWARE_WM);
+MODULE_FIRMWARE(MT7927_ROM_PATCH);
MODULE_AUTHOR("Deren Wu <deren.wu@mediatek.com>");
MODULE_AUTHOR("Lorenzo Bianconi <lorenzo@kernel.org>");
MODULE_DESCRIPTION("MediaTek MT7925E (PCIe) wireless driver");
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
index 3072850c2752..97683949a305 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci_mac.c
@@ -3,6 +3,7 @@
#include "mt7925.h"
#include "../dma.h"
+#include "mcu.h"
#include "mac.h"
int mt7925e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
@@ -118,7 +119,10 @@ int mt7925e_mac_reset(struct mt792x_dev *dev)
mt76_wr(dev, dev->irq_map->host_irq_enable,
dev->irq_map->tx.all_complete_mask |
- MT_INT_RX_DONE_ALL | MT_INT_MCU_CMD);
+ dev->irq_map->rx.data_complete_mask |
+ dev->irq_map->rx.wm_complete_mask |
+ dev->irq_map->rx.wm2_complete_mask |
+ MT_INT_MCU_CMD);
mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
err = mt792xe_mcu_fw_pmctrl(dev);
@@ -141,6 +145,12 @@ int mt7925e_mac_reset(struct mt792x_dev *dev)
if (err)
goto out;
+ if (is_mt7927(&dev->mt76)) {
+ err = mt7925_mcu_set_dbdc(&dev->mphy, true);
+ if (err)
+ goto out;
+ }
+
err = __mt7925_start(&dev->phy);
out:
clear_bit(MT76_RESET, &dev->mphy.state);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c b/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c
index 3d40aacfc011..22a8f1ddc321 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/testmode.c
@@ -105,6 +105,11 @@ mt7925_tm_query(struct mt792x_dev *dev, struct mt7925_tm_cmd *req,
if (ret)
goto out;
+ if (skb->len < MT7925_EVT_RSP_LEN + 8) {
+ ret = -EINVAL;
+ goto out;
+ }
+
memcpy((char *)evt_resp, (char *)skb->data + 8, MT7925_EVT_RSP_LEN);
out:
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
index d9968f03856d..e9f58492bf7d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/usb.c
@@ -10,8 +10,13 @@
#include "mac.h"
static const struct usb_device_id mt7925u_device_table[] = {
+ { USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x6639, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },
{ USB_DEVICE_AND_INTERFACE_INFO(0x0e8d, 0x7925, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },
+ /* Netgear, Inc. A8500 */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9050, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },
/* Netgear, Inc. A9000 */
{ USB_DEVICE_AND_INTERFACE_INFO(0x0846, 0x9072, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)MT7925_FIRMWARE_WM },
@@ -120,6 +125,12 @@ static int mt7925u_mac_reset(struct mt792x_dev *dev)
if (err)
goto out;
+ if (is_mt7927(&dev->mt76)) {
+ err = mt7925_mcu_set_dbdc(&dev->mphy, true);
+ if (err)
+ goto out;
+ }
+
err = __mt7925_start(&dev->phy);
out:
clear_bit(MT76_RESET, &dev->mphy.state);
@@ -184,8 +195,8 @@ static int mt7925u_probe(struct usb_interface *usb_intf,
dev = container_of(mdev, struct mt792x_dev, mt76);
dev->fw_features = features;
dev->hif_ops = &hif_ops;
+ mt792xu_reset_work_init(dev);
- udev = usb_get_dev(udev);
usb_reset_device(udev);
usb_set_intfdata(usb_intf, dev);
@@ -198,6 +209,13 @@ static int mt7925u_probe(struct usb_interface *usb_intf,
(mt76_rr(dev, MT_HW_REV) & 0xff);
dev_dbg(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
+ if (mt76_chip(mdev) == 0x6639) {
+ dev_dbg(mdev->dev,
+ "MT7927 raw CHIPID=0x%04x, forcing chip=0x7927\n",
+ mt76_chip(mdev));
+ mdev->rev = (0x7927 << 16) | (mdev->rev & 0xff);
+ }
+
if (mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY)) {
ret = mt792xu_wfsys_reset(dev);
if (ret)
@@ -232,9 +250,9 @@ static int mt7925u_probe(struct usb_interface *usb_intf,
error:
mt76u_queues_deinit(&dev->mt76);
+ mt792xu_reset_work_cleanup(dev);
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
mt76_free_device(&dev->mt76);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index 4ff93f2cd624..70073b43af54 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -46,12 +46,14 @@
#define MT7921_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7961_1.bin"
#define MT7922_FIRMWARE_WM "mediatek/WIFI_RAM_CODE_MT7922_1.bin"
#define MT7925_FIRMWARE_WM "mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin"
+#define MT7927_FIRMWARE_WM "mediatek/mt7927/WIFI_RAM_CODE_MT6639_2_1.bin"
#define MT7902_ROM_PATCH "mediatek/WIFI_MT7902_patch_mcu_1_1_hdr.bin"
#define MT7920_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1a_2_hdr.bin"
#define MT7921_ROM_PATCH "mediatek/WIFI_MT7961_patch_mcu_1_2_hdr.bin"
#define MT7922_ROM_PATCH "mediatek/WIFI_MT7922_patch_mcu_1_1_hdr.bin"
#define MT7925_ROM_PATCH "mediatek/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin"
+#define MT7927_ROM_PATCH "mediatek/mt7927/WIFI_MT6639_PATCH_MCU_2_1_hdr.bin"
#define MT792x_SDIO_HDR_TX_BYTES GENMASK(15, 0)
#define MT792x_SDIO_HDR_PKT_TYPE GENMASK(17, 16)
@@ -204,6 +206,23 @@ struct mt792x_irq_map {
} rx;
};
+struct mt792x_dma_ring {
+ u8 qid;
+ u16 n_desc;
+ u32 ring_base;
+};
+
+struct mt792x_dma_layout {
+ struct mt792x_dma_ring tx_data0;
+ struct mt792x_dma_ring tx_mcu;
+ struct mt792x_dma_ring tx_fwdl;
+ struct mt792x_dma_ring rx_data;
+ struct mt792x_dma_ring rx_mcu;
+};
+
+#define mt792x_dma_ring(_qid, _n_desc, _ring_base) \
+ { .qid = (_qid), .n_desc = (_n_desc), .ring_base = (_ring_base) }
+
#define mt792x_init_reset(dev) ((dev)->hif_ops->init_reset(dev))
#define mt792x_dev_reset(dev) ((dev)->hif_ops->reset(dev))
#define mt792x_mcu_init(dev) ((dev)->hif_ops->mcu_init(dev))
@@ -243,6 +262,8 @@ struct mt792x_dev {
wait_queue_head_t wait;
struct work_struct init_work;
+ struct work_struct usb_reset_work;
+ atomic_t usb_reset_pending;
u8 fw_debug;
u8 fw_features;
@@ -397,6 +418,8 @@ void mt792x_roc_timer(struct timer_list *timer);
void mt792x_csa_timer(struct timer_list *timer);
void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
+int mt792x_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, int *dbm);
int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
@@ -419,6 +442,8 @@ void mt792x_sta_statistics(struct ieee80211_hw *hw,
void mt792x_set_coverage_class(struct ieee80211_hw *hw, int radio_idx,
s16 coverage_class);
void mt792x_dma_cleanup(struct mt792x_dev *dev);
+int mt792x_dma_alloc_queues(struct mt792x_dev *dev,
+ const struct mt792x_dma_layout *layout);
int mt792x_dma_enable(struct mt792x_dev *dev);
int mt792x_wpdma_reset(struct mt792x_dev *dev, bool force);
int mt792x_wpdma_reinit_cond(struct mt792x_dev *dev);
@@ -459,6 +484,8 @@ static inline char *mt792x_ram_name(struct mt792x_dev *dev)
return MT7922_FIRMWARE_WM;
case 0x7925:
return MT7925_FIRMWARE_WM;
+ case 0x7927:
+ return MT7927_FIRMWARE_WM;
default:
return MT7921_FIRMWARE_WM;
}
@@ -475,6 +502,8 @@ static inline char *mt792x_patch_name(struct mt792x_dev *dev)
return MT7922_ROM_PATCH;
case 0x7925:
return MT7925_ROM_PATCH;
+ case 0x7927:
+ return MT7927_ROM_PATCH;
default:
return MT7921_ROM_PATCH;
}
@@ -489,6 +518,10 @@ int mt792xu_dma_init(struct mt792x_dev *dev, bool resume);
int mt792xu_mcu_power_on(struct mt792x_dev *dev);
int mt792xu_wfsys_reset(struct mt792x_dev *dev);
int mt792xu_init_reset(struct mt792x_dev *dev);
+void mt792xu_reset_work_init(struct mt792x_dev *dev);
+void mt792xu_reset_work_cleanup(struct mt792x_dev *dev);
+int mt792xu_check_bus(struct mt792x_dev *dev);
+int mt792xu_reset_on_bus_error(struct mt792x_dev *dev);
u32 mt792xu_rr(struct mt76_dev *dev, u32 addr);
void mt792xu_wr(struct mt76_dev *dev, u32 addr, u32 val);
u32 mt792xu_rmw(struct mt76_dev *dev, u32 addr, u32 mask, u32 val);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_core.c b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
index 152cfcca2f90..b50825eccdaf 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_core.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_core.c
@@ -105,7 +105,8 @@ void mt792x_tx(struct ieee80211_hw *hw, struct ieee80211_tx_control *control,
wcid = &mvif->sta.deflink.wcid;
}
- if (vif && control->sta && ieee80211_vif_is_mld(vif)) {
+ if (vif && control->sta && ieee80211_vif_is_mld(vif) &&
+ !(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_link_sta *link_sta;
struct ieee80211_bss_conf *conf;
@@ -329,6 +330,47 @@ void mt792x_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
EXPORT_SYMBOL_GPL(mt792x_flush);
+int mt792x_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, int *dbm)
+{
+ struct mt76_power_limits limits = {};
+ struct ieee80211_bss_conf *link_conf;
+ struct ieee80211_channel *chan;
+ struct mt792x_bss_conf *mconf;
+ struct mt792x_vif *mvif;
+ struct mt76_phy *phy;
+ s8 max_power;
+
+ if (!vif)
+ return mt76_get_txpower(hw, vif, link_id, dbm);
+
+ mvif = (struct mt792x_vif *)vif->drv_priv;
+ phy = mvif->phy->mt76;
+
+ mt792x_mutex_acquire(mvif->phy->dev);
+
+ link_conf = mt792x_vif_to_bss_conf(vif, link_id);
+ mconf = link_conf ? mt792x_link_conf_to_mconf(link_conf) : NULL;
+ if (mconf && mconf->mt76.ctx && mconf->mt76.ctx->def.chan)
+ chan = mconf->mt76.ctx->def.chan;
+ else
+ /* Fall back to the current PHY chandef if the requested link
+ * does not have a valid channel context.
+ */
+ chan = phy->chandef.chan;
+
+ mt792x_mutex_release(mvif->phy->dev);
+
+ if (!chan)
+ return -EINVAL;
+
+ max_power = mt76_connac_get_rate_power_limit(phy, chan, &limits);
+ *dbm = DIV_ROUND_UP(max_power, 2);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792x_get_txpower);
+
int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
@@ -657,7 +699,6 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO) |
BIT(NL80211_IFTYPE_P2P_DEVICE);
- wiphy->max_remain_on_channel_duration = 5000;
wiphy->max_scan_ie_len = MT76_CONNAC_SCAN_IE_LEN;
wiphy->max_scan_ssids = 4;
wiphy->max_sched_scan_plan_interval =
@@ -759,6 +800,13 @@ out:
return offload_caps;
}
+static bool mt792x_needs_cnm_runtime(const void *drv_data)
+{
+ const char *fw_wm = drv_data;
+
+ return fw_wm && !strcmp(fw_wm, MT7927_FIRMWARE_WM);
+}
+
struct ieee80211_ops *
mt792x_get_mac80211_ops(struct device *dev,
const struct ieee80211_ops *mac80211_ops,
@@ -772,6 +820,10 @@ mt792x_get_mac80211_ops(struct device *dev,
return NULL;
*fw_features = mt792x_get_offload_capability(dev, drv_data);
+
+ if (mt792x_needs_cnm_runtime(drv_data))
+ *fw_features |= MT792x_FW_CAP_CNM;
+
if (!(*fw_features & MT792x_FW_CAP_CNM)) {
ops->remain_on_channel = NULL;
ops->cancel_remain_on_channel = NULL;
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
index 002aece857b2..fc326447c792 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_dma.c
@@ -87,22 +87,122 @@ void mt792x_rx_poll_complete(struct mt76_dev *mdev, enum mt76_rxq_id q)
}
EXPORT_SYMBOL_GPL(mt792x_rx_poll_complete);
+int mt792x_dma_alloc_queues(struct mt792x_dev *dev,
+ const struct mt792x_dma_layout *layout)
+{
+ int ret;
+
+ mt76_dma_attach(&dev->mt76);
+
+ ret = mt792x_dma_disable(dev, true);
+ if (ret)
+ return ret;
+
+ /* init tx queue */
+ ret = mt76_connac_init_tx_queues(dev->phy.mt76, layout->tx_data0.qid,
+ layout->tx_data0.n_desc,
+ layout->tx_data0.ring_base,
+ NULL, 0);
+ if (ret)
+ return ret;
+
+ mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, 0x4);
+
+ /* command to WM */
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_WM,
+ layout->tx_mcu.qid,
+ layout->tx_mcu.n_desc,
+ layout->tx_mcu.ring_base);
+ if (ret)
+ return ret;
+
+ /* firmware download */
+ ret = mt76_init_mcu_queue(&dev->mt76, MT_MCUQ_FWDL,
+ layout->tx_fwdl.qid,
+ layout->tx_fwdl.n_desc,
+ layout->tx_fwdl.ring_base);
+ if (ret)
+ return ret;
+
+ /* rx event */
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU],
+ layout->rx_mcu.qid,
+ layout->rx_mcu.n_desc,
+ MT_RX_BUF_SIZE,
+ layout->rx_mcu.ring_base);
+ if (ret)
+ return ret;
+
+ /* rx data */
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MAIN],
+ layout->rx_data.qid,
+ layout->rx_data.n_desc,
+ MT_RX_BUF_SIZE,
+ layout->rx_data.ring_base);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mt792x_dma_alloc_queues);
+
#define PREFETCH(base, depth) ((base) << 16 | (depth))
+
+static void mt7925_dma_prefetch_setup(struct mt792x_dev *dev)
+{
+ /* rx ring */
+ mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0000, 0x4));
+ mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x0040, 0x4));
+ mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x0080, 0x4));
+ mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x00c0, 0x4));
+
+ /* tx ring */
+ mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x0100, 0x10));
+ mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x0200, 0x10));
+ mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x0300, 0x10));
+ mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0400, 0x10));
+ mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0500, 0x4));
+ mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0540, 0x4));
+}
+
+static void mt7925_wfdma_setup(struct mt792x_dev *dev)
+{
+ mt76_rmw(dev, MT_UWFDMA0_GLO_CFG_EXT1, BIT(28), BIT(28));
+ mt76_set(dev, MT_WFDMA0_INT_RX_PRI, 0x0F00);
+ mt76_set(dev, MT_WFDMA0_INT_TX_PRI, 0x7F00);
+}
+
+static void mt7927_dma_prefetch_setup(struct mt792x_dev *dev)
+{
+ mt76_wr(dev, MT_WFDMA_PREFETCH_CTRL,
+ mt76_rr(dev, MT_WFDMA_PREFETCH_CTRL));
+ mt76_wr(dev, MT_WFDMA_PREFETCH_CFG0, 0x660077);
+ mt76_wr(dev, MT_WFDMA_PREFETCH_CFG1, 0x1100);
+ mt76_wr(dev, MT_WFDMA_PREFETCH_CFG2, 0x30004f);
+ mt76_wr(dev, MT_WFDMA_PREFETCH_CFG3, 0x542200);
+ mt76_wr(dev, MT_WFDMA0_RX_RING4_EXT_CTRL, PREFETCH(0x0000, 0x8));
+ mt76_wr(dev, MT_WFDMA0_RX_RING6_EXT_CTRL, PREFETCH(0x0080, 0x8));
+ mt76_wr(dev, MT_WFDMA0_RX_RING7_EXT_CTRL, PREFETCH(0x0100, 0x4));
+ mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0140, 0x4));
+ mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0180, 0x10));
+ mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x0280, 0x4));
+}
+
+static void mt7927_wfdma_setup(struct mt792x_dev *dev)
+{
+ mt76_set(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_ADDR_EXT_EN |
+ MT_WFDMA0_GLO_CFG_FW_DWLD_BYPASS_DMASHDL);
+ mt76_clear(dev, MT_WFDMA0_GLO_CFG,
+ MT_WFDMA0_GLO_CFG_CSR_LBK_RX_Q_SEL_EN);
+ mt76_rmw(dev, MT_WFDMA0_GLO_CFG_EXT1, BIT(28), BIT(28));
+ mt76_set(dev, MT_WFDMA0_INT_RX_PRI, 0x0F00);
+ mt76_set(dev, MT_WFDMA0_INT_TX_PRI, 0x7F00);
+}
+
static void mt792x_dma_prefetch(struct mt792x_dev *dev)
{
- if (is_mt7925(&dev->mt76)) {
- /* rx ring */
- mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0000, 0x4));
- mt76_wr(dev, MT_WFDMA0_RX_RING1_EXT_CTRL, PREFETCH(0x0040, 0x4));
- mt76_wr(dev, MT_WFDMA0_RX_RING2_EXT_CTRL, PREFETCH(0x0080, 0x4));
- mt76_wr(dev, MT_WFDMA0_RX_RING3_EXT_CTRL, PREFETCH(0x00c0, 0x4));
- /* tx ring */
- mt76_wr(dev, MT_WFDMA0_TX_RING0_EXT_CTRL, PREFETCH(0x0100, 0x10));
- mt76_wr(dev, MT_WFDMA0_TX_RING1_EXT_CTRL, PREFETCH(0x0200, 0x10));
- mt76_wr(dev, MT_WFDMA0_TX_RING2_EXT_CTRL, PREFETCH(0x0300, 0x10));
- mt76_wr(dev, MT_WFDMA0_TX_RING3_EXT_CTRL, PREFETCH(0x0400, 0x10));
- mt76_wr(dev, MT_WFDMA0_TX_RING15_EXT_CTRL, PREFETCH(0x0500, 0x4));
- mt76_wr(dev, MT_WFDMA0_TX_RING16_EXT_CTRL, PREFETCH(0x0540, 0x4));
+ if (is_mt7927(&dev->mt76)) {
+ mt7927_dma_prefetch_setup(dev);
+ } else if (is_mt7925(&dev->mt76)) {
+ mt7925_dma_prefetch_setup(dev);
} else if (is_mt7902(&dev->mt76)) {
/* rx ring */
mt76_wr(dev, MT_WFDMA0_RX_RING0_EXT_CTRL, PREFETCH(0x0000, 0x4));
@@ -166,11 +266,11 @@ int mt792x_dma_enable(struct mt792x_dev *dev)
mt76_set(dev, MT_WFDMA0_GLO_CFG,
MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
- if (is_mt7925(&dev->mt76)) {
- mt76_rmw(dev, MT_UWFDMA0_GLO_CFG_EXT1, BIT(28), BIT(28));
- mt76_set(dev, MT_WFDMA0_INT_RX_PRI, 0x0F00);
- mt76_set(dev, MT_WFDMA0_INT_TX_PRI, 0x7F00);
- }
+ if (is_mt7927(&dev->mt76))
+ mt7927_wfdma_setup(dev);
+ else if (is_mt7925(&dev->mt76))
+ mt7925_wfdma_setup(dev);
+
mt76_set(dev, MT_WFDMA_DUMMY_CR, MT_WFDMA_NEED_REINIT);
/* enable interrupts for TX/RX rings */
@@ -281,6 +381,11 @@ int mt792x_dma_disable(struct mt792x_dev *dev, bool force)
MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 100, 1))
return -ETIMEDOUT;
+ if (is_mt7927(&dev->mt76)) {
+ mt76_wr(dev, MT_WFDMA0_RST_DTX_PTR, ~0);
+ mt76_wr(dev, MT_WFDMA0_RST_DRX_PTR, ~0);
+ }
+
/* disable dmashdl */
mt76_clear(dev, MT_WFDMA0_GLO_CFG_EXT0,
MT_WFDMA0_CSR_TX_DMASHDL_ENABLE);
@@ -370,7 +475,54 @@ int mt792x_poll_rx(struct napi_struct *napi, int budget)
}
EXPORT_SYMBOL_GPL(mt792x_poll_rx);
-int mt792x_wfsys_reset(struct mt792x_dev *dev)
+static void mt7927_sema_status_read(struct mt792x_dev *dev, u32 addr)
+{
+ u32 remap;
+
+ remap = mt76_rr(dev, MT7927_PCIE2AP_REMAP_WF_0_54);
+ mt76_wr(dev, MT7927_PCIE2AP_REMAP_WF_0_54,
+ (remap & ~MT7927_PCIE2AP_REMAP_WF_0_54_MASK) |
+ MT7927_PCIE2AP_REMAP_WF_0_54_VAL);
+ usleep_range(10, 20);
+
+ mt76_rr(dev, addr);
+
+ mt76_wr(dev, MT7927_PCIE2AP_REMAP_WF_0_54, remap);
+ usleep_range(10, 20);
+}
+
+static int mt7927_wfsys_reset(struct mt792x_dev *dev)
+{
+ struct mt76_dev *mdev = &dev->mt76;
+ u32 val;
+
+ mt7927_sema_status_read(dev, MT7927_SEMA_OWN_STA);
+
+ mt76_set(dev, MT7927_CBINFRA_RGU_WF_RST,
+ MT7927_CBINFRA_RGU_WF_RST_WF_SUBSYS);
+ usleep_range(1000, 2000);
+
+ mt76_clear(dev, MT7927_CBINFRA_RGU_WF_RST,
+ MT7927_CBINFRA_RGU_WF_RST_WF_SUBSYS);
+ usleep_range(5000, 10000);
+
+ mt76_wr(dev, MT7927_CBINFRA_MCU_OWN_SET, BIT(0));
+
+ if (!__mt76_poll_msec(mdev, MT7927_ROMCODE_INDEX, 0xffff,
+ MT7927_MCU_IDLE_VALUE, 200)) {
+ val = mt76_rr(dev, MT7927_ROMCODE_INDEX);
+ dev_err(mdev->dev,
+ "MT7927 WFSYS reset timeout (ROMCODE_INDEX=0x%04x)\n",
+ val & 0xffff);
+ return -ETIMEDOUT;
+ }
+
+ mt7927_sema_status_read(dev, MT7927_SEMA_OWN_STA_REP);
+
+ return 0;
+}
+
+static int mt792x_wfsys_reset_default(struct mt792x_dev *dev)
{
u32 addr = is_connac2(&dev->mt76) ? 0x18000140 : 0x7c000140;
@@ -384,5 +536,13 @@ int mt792x_wfsys_reset(struct mt792x_dev *dev)
return 0;
}
+
+int mt792x_wfsys_reset(struct mt792x_dev *dev)
+{
+ if (is_mt7927(&dev->mt76))
+ return mt7927_wfsys_reset(dev);
+
+ return mt792x_wfsys_reset_default(dev);
+}
EXPORT_SYMBOL_GPL(mt792x_wfsys_reset);
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
index d2a8b2b0df32..4cd5b33b640e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_regs.h
@@ -301,7 +301,9 @@
#define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN BIT(12)
#define MT_WFDMA0_GLO_CFG_RX_WB_DDONE BIT(13)
#define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN BIT(15)
+#define MT_WFDMA0_GLO_CFG_CSR_LBK_RX_Q_SEL_EN BIT(20)
#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 BIT(21)
+#define MT_WFDMA0_GLO_CFG_ADDR_EXT_EN BIT(26)
#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO BIT(27)
#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO BIT(28)
#define MT_WFDMA0_GLO_CFG_CLK_GAT_DIS BIT(30)
@@ -310,6 +312,9 @@
#define HOST_RX_DONE_INT_ENA1 BIT(1)
#define HOST_RX_DONE_INT_ENA2 BIT(2)
#define HOST_RX_DONE_INT_ENA3 BIT(3)
+#define MT7927_RX_DONE_INT_ENA4 BIT(12)
+#define MT7927_RX_DONE_INT_ENA6 BIT(14)
+#define MT7927_RX_DONE_INT_ENA7 BIT(15)
#define HOST_TX_DONE_INT_ENA0 BIT(4)
#define HOST_TX_DONE_INT_ENA1 BIT(5)
#define HOST_TX_DONE_INT_ENA2 BIT(6)
@@ -365,6 +370,13 @@
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
#define MT_WFDMA_EXT_CSR_HIF_MISC_BUSY BIT(0)
+#define MT_WFDMA_PREFETCH_CTRL MT_WFDMA_EXT_CSR(0x30)
+#define MT_WFDMA_PREFETCH_CFG0 MT_WFDMA_EXT_CSR(0xf0)
+#define MT_WFDMA_PREFETCH_CFG1 MT_WFDMA_EXT_CSR(0xf4)
+#define MT_WFDMA_PREFETCH_CFG2 MT_WFDMA_EXT_CSR(0xf8)
+#define MT_WFDMA_PREFETCH_CFG3 MT_WFDMA_EXT_CSR(0xfc)
+#define MT_WFDMA0_GLO_CFG_EXT1 MT_WFDMA0(0x2b4)
+
#define MT_SWDEF_BASE 0x41f200
#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs))
#define MT_SWDEF_MODE MT_SWDEF(0x3c)
@@ -490,4 +502,15 @@
#define WFSYS_SW_RST_B BIT(0)
#define WFSYS_SW_INIT_DONE BIT(4)
+/* CBInfra registers - MT7927 combo chip */
+#define MT7927_CBINFRA_RGU_WF_RST 0x1f8600
+#define MT7927_CBINFRA_RGU_WF_RST_WF_SUBSYS BIT(4)
+#define MT7927_CBINFRA_MCU_OWN_SET 0x1f5034
+#define MT7927_ROMCODE_INDEX 0xc1604
+#define MT7927_MCU_IDLE_VALUE 0x1d1e
+#define MT7927_PCIE2AP_REMAP_WF_0_54 0x21008
+#define MT7927_PCIE2AP_REMAP_WF_0_54_MASK GENMASK(15, 0)
+#define MT7927_PCIE2AP_REMAP_WF_0_54_VAL 0x00001807
+#define MT7927_SEMA_OWN_STA 0x40000
+#define MT7927_SEMA_OWN_STA_REP 0x40400
#endif /* __MT792X_REGS_H */
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
index 47827d1c5ccb..910132e94956 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
+++ b/drivers/net/wireless/mediatek/mt76/mt792x_usb.c
@@ -11,6 +11,81 @@
#include "mt792x.h"
#include "mt76_connac2_mac.h"
+static int mt792xu_read32(struct mt76_dev *dev, u32 addr, void *buf)
+{
+ return __mt76u_vendor_request(dev, MT_VEND_READ_EXT,
+ USB_DIR_IN | MT_USB_TYPE_VENDOR,
+ (u16)(addr >> 16), (u16)addr,
+ buf, sizeof(__le32));
+}
+
+static void mt792xu_reset_work(struct work_struct *work)
+{
+ struct mt792x_dev *dev =
+ container_of(work, struct mt792x_dev, usb_reset_work);
+ struct usb_interface *usb_intf = to_usb_interface(dev->mt76.dev);
+
+ if (usb_intf && usb_get_intfdata(usb_intf) == dev)
+ usb_queue_reset_device(usb_intf);
+
+ atomic_set(&dev->usb_reset_pending, 0);
+}
+
+void mt792xu_reset_work_init(struct mt792x_dev *dev)
+{
+ INIT_WORK(&dev->usb_reset_work, mt792xu_reset_work);
+ atomic_set(&dev->usb_reset_pending, 0);
+}
+EXPORT_SYMBOL_GPL(mt792xu_reset_work_init);
+
+void mt792xu_reset_work_cleanup(struct mt792x_dev *dev)
+{
+ cancel_work_sync(&dev->usb_reset_work);
+ atomic_set(&dev->usb_reset_pending, 0);
+}
+EXPORT_SYMBOL_GPL(mt792xu_reset_work_cleanup);
+
+int mt792xu_check_bus(struct mt792x_dev *dev)
+{
+ int ret;
+
+ mutex_lock(&dev->mt76.usb.usb_ctrl_mtx);
+ ret = mt792xu_read32(&dev->mt76, MT_HW_CHIPID, dev->mt76.usb.data);
+ mutex_unlock(&dev->mt76.usb.usb_ctrl_mtx);
+
+ if (ret == sizeof(__le32))
+ return 0;
+
+ return ret < 0 ? ret : -EIO;
+}
+EXPORT_SYMBOL_GPL(mt792xu_check_bus);
+
+int mt792xu_reset_on_bus_error(struct mt792x_dev *dev)
+{
+ int err = 0;
+
+ if (!atomic_read(&dev->mt76.bus_hung))
+ err = mt792xu_check_bus(dev);
+
+ if (err) {
+ atomic_set(&dev->mt76.bus_hung, true);
+
+ if (!atomic_xchg(&dev->usb_reset_pending, 1)) {
+ dev_warn(dev->mt76.dev,
+ "USB transport access failed (%d), queueing device reset\n",
+ err);
+
+ schedule_work(&dev->usb_reset_work);
+ }
+
+ return err;
+ }
+
+ atomic_set(&dev->mt76.bus_hung, false);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(mt792xu_reset_on_bus_error);
+
u32 mt792xu_rr(struct mt76_dev *dev, u32 addr)
{
u32 ret;
@@ -263,7 +338,7 @@ EXPORT_SYMBOL_GPL(mt792xu_dma_init);
int mt792xu_wfsys_reset(struct mt792x_dev *dev)
{
- const struct mt792xu_wfsys_desc *desc = is_mt7925(&dev->mt76) ?
+ const struct mt792xu_wfsys_desc *desc = is_connac3(&dev->mt76) ?
&mt7925_wfsys_desc :
&mt7921_wfsys_desc;
u32 val;
@@ -333,6 +408,7 @@ void mt792xu_disconnect(struct usb_interface *usb_intf)
{
struct mt792x_dev *dev = usb_get_intfdata(usb_intf);
+ mt792xu_reset_work_cleanup(dev);
cancel_work_sync(&dev->init_work);
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
return;
@@ -341,7 +417,6 @@ void mt792xu_disconnect(struct usb_interface *usb_intf)
mt792xu_cleanup(dev);
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
mt76_free_device(&dev->mt76);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
index 34af800964d1..b85c3e549f8b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/debugfs.c
@@ -664,7 +664,7 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
if (!mlink)
continue;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
continue;
@@ -875,8 +875,6 @@ int mt7996_init_debugfs(struct mt7996_dev *dev)
struct dentry *dir;
dir = mt76_register_debugfs_fops(&dev->mphy, NULL);
- if (!dir)
- return -ENOMEM;
debugfs_create_file("hw-queues", 0400, dir, dev,
&mt7996_hw_queues_fops);
@@ -1042,7 +1040,7 @@ static ssize_t mt7996_link_sta_fixed_rate_set(struct file *file,
mutex_lock(&dev->mt76.mutex);
- msta_link = mt76_dereference(msta->link[link_sta->link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_sta->link_id);
if (!msta_link) {
ret = -EINVAL;
goto out;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
index 8f5d297dafce..3d9353811a02 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/dma.c
@@ -683,7 +683,7 @@ int mt7996_dma_init(struct mt7996_dev *dev)
ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(0),
MT7996_NPU_TX_RING_SIZE,
MT_TXQ_RING_BASE(0) + hif1_ofs,
- NULL);
+ wed);
else
ret = mt7996_init_tx_queues(&dev->phy,
MT_TXQ_ID(dev->mphy.band_idx),
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index e2a83da3a09c..0eebc8182ca9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -48,7 +48,7 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
if (mlink->band_idx != band_idx)
continue;
- msta_link = rcu_dereference(msta->link[i]);
+ msta_link = mt7996_sta_link(msta, i);
break;
}
@@ -757,6 +757,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
bool multicast = is_multicast_ether_addr(hdr->addr1);
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
__le16 fc = hdr->frame_control, sc = hdr->seq_ctrl;
+ struct ieee80211_vif *vif = info->control.vif;
u16 seqno = le16_to_cpu(sc);
bool hw_bigtk = false;
u8 fc_type, fc_stype;
@@ -819,7 +820,7 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
txwi[3] |= cpu_to_le32(MT_TXD3_REM_TX_COUNT);
}
- if (multicast && ieee80211_vif_is_mld(info->control.vif)) {
+ if (multicast && vif && ieee80211_vif_is_mld(vif)) {
val = MT_TXD3_SN_VALID |
FIELD_PREP(MT_TXD3_SEQ, IEEE80211_SEQ_TO_SN(seqno));
txwi[3] |= cpu_to_le32(val);
@@ -839,12 +840,12 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
}
- if (ieee80211_vif_is_mld(info->control.vif) &&
+ if (vif && ieee80211_vif_is_mld(vif) &&
(multicast || unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))))
txwi[5] |= cpu_to_le32(MT_TXD5_FL);
if (ieee80211_is_nullfunc(fc) && ieee80211_has_a4(fc) &&
- ieee80211_vif_is_mld(info->control.vif)) {
+ vif && ieee80211_vif_is_mld(vif)) {
txwi[5] |= cpu_to_le32(MT_TXD5_FL);
txwi[6] |= cpu_to_le32(MT_TXD6_DIS_MAT);
}
@@ -856,7 +857,8 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
- enum mt76_txq_id qid, u32 changed)
+ enum mt76_txq_id qid, u32 changed,
+ unsigned int link_id)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
@@ -866,7 +868,6 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
struct mt76_vif_link *mlink = NULL;
struct mt7996_vif *mvif;
- unsigned int link_id;
u16 tx_count = 15;
u32 val;
bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
@@ -874,17 +875,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
bool beacon = !!(changed & (BSS_CHANGED_BEACON |
BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc);
- if (wcid != &dev->mt76.global_wcid)
- link_id = wcid->link_id;
- else
- link_id = u32_get_bits(info->control.flags,
- IEEE80211_TX_CTRL_MLO_LINK);
-
mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
if (mvif) {
if (wcid->offchannel)
mlink = rcu_dereference(mvif->mt76.offchannel_link);
- if (!mlink)
+ if (!mlink && link_id != IEEE80211_LINK_UNSPECIFIED)
mlink = rcu_dereference(mvif->mt76.link[link_id]);
}
@@ -1038,7 +1033,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (link_id != wcid->link_id && link_id != IEEE80211_LINK_UNSPECIFIED) {
if (msta) {
struct mt7996_sta_link *msta_link =
- rcu_dereference(msta->link[link_id]);
+ mt7996_sta_link(msta, link_id);
if (msta_link)
wcid = &msta_link->wcid;
@@ -1067,11 +1062,11 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
link_conf = rcu_dereference(vif->link_conf[wcid->link_id]);
if (!link_conf)
- return -EINVAL;
+ goto error_release_token;
link_sta = rcu_dereference(sta->link[wcid->link_id]);
if (!link_sta)
- return -EINVAL;
+ goto error_release_token;
dma_sync_single_for_cpu(mdev->dma_dev, tx_info->buf[1].addr,
tx_info->buf[1].len, DMA_TO_DEVICE);
@@ -1096,7 +1091,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
/* Transmit non qos data by 802.11 header and need to fill txd by host*/
if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
- pid, qid, 0);
+ pid, qid, 0, link_id);
/* MT7996 and MT7992 require driver to provide the MAC TXP for AddBA
* req
@@ -1176,6 +1171,10 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
tx_info->nbuf = MT_CT_DMA_BUF_NUM;
return 0;
+
+error_release_token:
+ mt76_token_release(mdev, id, NULL);
+ return -EINVAL;
}
u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
@@ -1346,7 +1345,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_sta_link *msta_link;
- msta_link = rcu_dereference(msta->link[id]);
+ msta_link = mt7996_sta_link(msta, id);
if (!msta_link)
continue;
@@ -1360,13 +1359,13 @@ next:
cur_info++;
continue;
} else if (info & MT_TXFREE_INFO_HEADER) {
- u32 tx_retries = 0, tx_failed = 0;
+ u32 tx_retries = 0, tx_failed = 0, count;
if (!wcid)
continue;
- tx_retries =
- FIELD_GET(MT_TXFREE_INFO_COUNT, info) - 1;
+ count = FIELD_GET(MT_TXFREE_INFO_COUNT, info);
+ tx_retries = count ? count - 1 : 0;
tx_failed = tx_retries +
!!FIELD_GET(MT_TXFREE_INFO_STAT, info);
@@ -2059,8 +2058,6 @@ void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
{
s16 coverage_class = phy->coverage_class;
struct mt7996_dev *dev = phy->dev;
- struct mt7996_phy *phy2 = mt7996_phy2(dev);
- struct mt7996_phy *phy3 = mt7996_phy3(dev);
u32 reg_offset;
u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
@@ -2072,14 +2069,6 @@ void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
return;
- if (phy2)
- coverage_class = max_t(s16, dev->phy.coverage_class,
- phy2->coverage_class);
-
- if (phy3)
- coverage_class = max_t(s16, coverage_class,
- phy3->coverage_class);
-
offset = 3 * coverage_class;
reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index a8a6552d49f6..afbcc8c7b18b 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -207,8 +207,7 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct mt7996_sta *msta;
msta = (struct mt7996_sta *)sta->drv_priv;
- msta_link = mt76_dereference(msta->link[link_id],
- &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
return 0;
@@ -1164,6 +1163,9 @@ mt7996_mac_sta_init_link(struct mt7996_dev *dev,
msta_link->wcid.link_valid = !!sta->valid_links;
msta_link->wcid.def_wcid = &msta->deflink.wcid;
+ if (link_sta->sta->tdls)
+ set_bit(MT_WCID_FLAG_TDLS_PEER, &msta_link->wcid.flags);
+
ewma_avg_signal_init(&msta_link->avg_ack_signal);
ewma_signal_init(&msta_link->wcid.rssi);
@@ -1381,7 +1383,7 @@ mt7996_mac_sta_event(struct mt7996_dev *dev, struct ieee80211_vif *vif,
if (!link)
continue;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -1573,7 +1575,7 @@ static void mt7996_tx(struct ieee80211_hw *hw,
if (msta) {
struct mt7996_sta_link *msta_link;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (msta_link)
wcid = &msta_link->wcid;
}
@@ -1944,7 +1946,7 @@ static void mt7996_link_sta_rc_update(struct ieee80211_hw *hw,
rcu_read_lock();
- msta_link = rcu_dereference(msta->link[link_sta->link_id]);
+ msta_link = mt7996_sta_link(msta, link_sta->link_id);
if (msta_link) {
struct mt7996_dev *dev = mt7996_hw_dev(hw);
@@ -1959,9 +1961,13 @@ static void mt7996_sta_rate_ctrl_update(void *data, struct ieee80211_sta *sta)
{
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt7996_sta_link *msta_link;
- u32 *changed = data;
+ struct mt7996_vif *mvif = data;
+ u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
- msta_link = rcu_dereference(msta->link[msta->deflink_id]);
+ if (msta->vif != mvif)
+ return;
+
+ msta_link = mt7996_sta_link(msta, msta->deflink_id);
if (msta_link)
mt7996_link_rate_ctrl_update(&changed, msta_link);
}
@@ -1972,7 +1978,6 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
- u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
mvif->deflink.bitrate_mask = *mask;
@@ -1985,7 +1990,7 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
* then multiple MCS setting (MCS 4,5,6) is not supported.
*/
ieee80211_iterate_stations_atomic(hw, mt7996_sta_rate_ctrl_update,
- &changed);
+ mvif);
ieee80211_queue_work(hw, &dev->rc_work);
return 0;
@@ -2011,7 +2016,7 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw,
if (!link)
continue;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -2049,7 +2054,7 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw,
if (!link)
continue;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -2389,7 +2394,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
if (!link)
return -EIO;
- msta_link = rcu_dereference(msta->link[msta->deflink_id]);
+ msta_link = mt7996_sta_link(msta, msta->deflink_id);
if (!msta_link)
return -EIO;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 16420375112d..f119f023bcd5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -1136,7 +1136,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
struct mt7996_sta_link *msta_link;
int link_id = link_conf->link_id;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (msta_link)
sta_wlan_idx = msta_link->wcid.idx;
}
@@ -1281,6 +1281,10 @@ int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *li
PROT_NONGF_STA = BIT(7),
};
+ /* The current firmware causes TX failure. Need further investigation */
+ if (is_mt7996(&dev->mt76))
+ return 0;
+
skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76,
MT7996_BSS_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
@@ -1429,7 +1433,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
struct mt7996_sta_link *msta_link;
struct mt7996_vif_link *link;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -1463,7 +1467,7 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
struct mt7996_sta_link *msta_link;
struct mt7996_vif_link *link;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -2139,6 +2143,11 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
hdr_trans->from_ds = true;
hdr_trans->mesh = true;
}
+
+ if (test_bit(MT_WCID_FLAG_TDLS_PEER, &wcid->flags)) {
+ hdr_trans->to_ds = false;
+ hdr_trans->from_ds = false;
+ }
}
static enum mcu_mmps_mode
@@ -2200,7 +2209,7 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct mt7996_sta *msta,
if (!mlink)
goto error_unlock;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
goto error_unlock;
@@ -2290,7 +2299,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct mt7996_sta *msta,
if (!link)
goto error_unlock;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
goto error_unlock;
@@ -2508,7 +2517,7 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct mt7996_sta *msta,
if (!link)
goto error_unlock;
- msta_link = rcu_dereference(msta->link[link_id]);
+ msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
goto error_unlock;
@@ -2663,7 +2672,7 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
unsigned int link_id;
struct tlv *tlv;
- msta_link = mt76_dereference(msta->link[msta->deflink_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, msta->deflink_id);
if (!msta_link)
return;
@@ -2677,8 +2686,8 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx);
if (nlinks > 1) {
- msta_link = mt76_dereference(msta->link[msta->seclink_id],
- &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta,
+ msta->seclink_id);
if (!msta_link)
return;
}
@@ -2689,7 +2698,7 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
for_each_sta_active_link(vif, sta, link_sta, link_id) {
struct mt7996_vif_link *link;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
@@ -2837,7 +2846,7 @@ void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta)
if (!link_sta)
return;
- msta_link = mt76_dereference(msta->link[link_id], &dev->mt76);
+ msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
return;
@@ -3098,7 +3107,7 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev,
buf = (u8 *)bcn + sizeof(*bcn);
mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0,
- BSS_CHANGED_BEACON);
+ BSS_CHANGED_BEACON, link_conf->link_id);
memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
}
@@ -3244,7 +3253,8 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
buf = (u8 *)tlv + sizeof(*discov);
- mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0, changed);
+ mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, NULL, 0, 0,
+ changed, link_conf->link_id);
memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index bdcf72457954..0d6488522ba7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -642,6 +642,25 @@ mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif,
link_conf);
}
+static inline struct mt7996_sta_link *
+mt7996_sta_link(struct mt7996_sta *msta, u8 link_id)
+{
+ if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS)
+ return NULL;
+
+ return rcu_dereference(msta->link[link_id]);
+}
+
+static inline struct mt7996_sta_link *
+mt7996_sta_link_protected(struct mt7996_dev *dev, struct mt7996_sta *msta,
+ u8 link_id)
+{
+ if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS)
+ return NULL;
+
+ return mt76_dereference(msta->link[link_id], &dev->mt76);
+}
+
#define mt7996_for_each_phy(dev, phy) \
for (int __i = 0; __i < ARRAY_SIZE((dev)->radio_phy); __i++) \
if (((phy) = (dev)->radio_phy[__i]) != NULL)
@@ -855,7 +874,8 @@ void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key, int pid,
- enum mt76_txq_id qid, u32 changed);
+ enum mt76_txq_id qid, u32 changed,
+ unsigned int link_id);
void mt7996_mac_update_beacons(struct mt7996_phy *phy);
void mt7996_mac_set_coverage_class(struct mt7996_phy *phy);
void mt7996_mac_work(struct work_struct *work);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
index 12523ddba630..b7d9193e042f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/pci.c
@@ -141,7 +141,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
dev->hif2 = hif2;
mt76_npu_init(mdev, pci_resource_start(pdev, 0),
- pdev->bus && pci_domain_nr(pdev->bus) ? 3 : 2);
+ pci_domain_nr(pdev->bus) ? 3 : 2);
ret = mt7996_mmio_wed_init(dev, pdev, false, &irq);
if (ret < 0)
diff --git a/drivers/net/wireless/mediatek/mt76/pci.c b/drivers/net/wireless/mediatek/mt76/pci.c
index 833923ab2483..11fe62aa8113 100644
--- a/drivers/net/wireless/mediatek/mt76/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/pci.c
@@ -30,8 +30,14 @@ void mt76_pci_disable_aspm(struct pci_dev *pdev)
if (IS_ENABLED(CONFIG_PCIEASPM)) {
int err;
+ int state = 0;
- err = pci_disable_link_state(pdev, aspm_conf);
+ if (aspm_conf & PCI_EXP_LNKCTL_ASPM_L0S)
+ state |= PCIE_LINK_STATE_L0S;
+ if (aspm_conf & PCI_EXP_LNKCTL_ASPM_L1)
+ state |= PCIE_LINK_STATE_L1;
+
+ err = pci_disable_link_state(pdev, state);
if (!err)
return;
}
diff --git a/drivers/net/wireless/mediatek/mt76/tx.c b/drivers/net/wireless/mediatek/mt76/tx.c
index 22f9690634c9..f96d9c471853 100644
--- a/drivers/net/wireless/mediatek/mt76/tx.c
+++ b/drivers/net/wireless/mediatek/mt76/tx.c
@@ -933,7 +933,7 @@ mt76_token_release(struct mt76_dev *dev, int token, bool *wake)
#endif
}
- if (dev->token_count < dev->token_size - MT76_TOKEN_FREE_THR &&
+ if (wake && dev->token_count < dev->token_size - MT76_TOKEN_FREE_THR &&
dev->phy.q_tx[0]->blocked)
*wake = true;
diff --git a/drivers/net/wireless/mediatek/mt76/usb.c b/drivers/net/wireless/mediatek/mt76/usb.c
index 632ae755c7a6..d9638a9b749b 100644
--- a/drivers/net/wireless/mediatek/mt76/usb.c
+++ b/drivers/net/wireless/mediatek/mt76/usb.c
@@ -925,6 +925,8 @@ mt76u_ac_to_hwq(struct mt76_dev *dev, struct mt76_queue *q, u8 qid)
q->ep = q->hw_idx + 1;
break;
}
+ case 0x6639:
+ case 0x7902:
case 0x7961:
case 0x7925:
q->hw_idx = mt76_ac_to_hwq(ac);
diff --git a/drivers/net/wireless/mediatek/mt7601u/usb.c b/drivers/net/wireless/mediatek/mt7601u/usb.c
index c41ae251cb95..9306870cbc91 100644
--- a/drivers/net/wireless/mediatek/mt7601u/usb.c
+++ b/drivers/net/wireless/mediatek/mt7601u/usb.c
@@ -274,7 +274,6 @@ static int mt7601u_probe(struct usb_interface *usb_intf,
if (!dev)
return -ENOMEM;
- usb_dev = usb_get_dev(usb_dev);
usb_reset_device(usb_dev);
usb_set_intfdata(usb_intf, dev);
@@ -319,7 +318,6 @@ err_hw:
mt7601u_cleanup(dev);
err:
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
destroy_workqueue(dev->stat_wq);
ieee80211_free_hw(dev->hw);
@@ -334,7 +332,6 @@ static void mt7601u_disconnect(struct usb_interface *usb_intf)
mt7601u_cleanup(dev);
usb_set_intfdata(usb_intf, NULL);
- usb_put_dev(interface_to_usbdev(usb_intf));
destroy_workqueue(dev->stat_wq);
ieee80211_free_hw(dev->hw);