mt76 patches for 7.4

- mt7625 NAN fixes
 - mt7996 connection monitor fix
 - offchannel/scan improvements
 - MLO fixes
 - other minor fixes
 -----BEGIN PGP SIGNATURE-----
 Comment: GPGTools - http://gpgtools.org
 
 iF0EABECAB0WIQR10Rp9kadxD0kAQu/XfRQdAqdu9QUCasZRDQAKCRDXfRQdAqdu
 9TzoAKCYRNEOEQ8yxl4Vc06jsVM4CgqTTACgg6Ortv6Y0OxyG9KFF+l8Rwn4LGk=
 =2Vy3
 -----END PGP SIGNATURE-----

Merge tag 'mt76-next-2026-10-07' of https://github.com/nbd168/wireless

Felix Fietkau says:
===================
mt76 patches for 7.4

- mt7625 NAN fixes
- mt7996 connection monitor fix
- offchannel/scan improvements
- MLO fixes
- other minor fixes
===================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2026-10-09 16:06:15 +02:00
commit 45f9960f8c
63 changed files with 2856 additions and 875 deletions

View File

@ -40,6 +40,7 @@ config MT792x_USB
config MT76_NPU
tristate
depends on NET_AIROHA_NPU=y || MT76_CORE=NET_AIROHA_NPU
depends on NET_AIROHA=y || NET_AIROHA=n || MT76_CORE=NET_AIROHA
source "drivers/net/wireless/mediatek/mt76/mt76x0/Kconfig"
source "drivers/net/wireless/mediatek/mt76/mt76x2/Kconfig"

View File

@ -41,7 +41,7 @@ int mt76_add_chanctx(struct ieee80211_hw *hw,
if (WARN_ON_ONCE(!phy))
return ret;
if (dev->scan.phy == phy)
if (mt76_phy_scanning(phy))
mt76_abort_scan(dev);
mutex_lock(&dev->mutex);
@ -66,7 +66,7 @@ void mt76_remove_chanctx(struct ieee80211_hw *hw,
if (WARN_ON_ONCE(!phy))
return;
if (dev->scan.phy == phy)
if (mt76_phy_scanning(phy))
mt76_abort_scan(dev);
mutex_lock(&dev->mutex);
@ -114,7 +114,7 @@ int mt76_assign_vif_chanctx(struct ieee80211_hw *hw,
bool mlink_alloc = false;
int ret = 0;
if (dev->scan.vif == vif)
if (dev->scan.vif == vif && mt76_phy_scanning(phy))
mt76_abort_scan(dev);
mutex_lock(&dev->mutex);
@ -161,7 +161,7 @@ void mt76_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct mt76_phy *phy = ctx->phy;
struct mt76_dev *dev = phy->dev;
if (dev->scan.vif == vif)
if (dev->scan.vif == vif && mt76_phy_scanning(phy))
mt76_abort_scan(dev);
mutex_lock(&dev->mutex);
@ -209,7 +209,7 @@ int mt76_switch_vif_chanctx(struct ieee80211_hw *hw,
continue;
if (phy->chanctx != new_ctx) {
if (dev->scan.phy == phy)
if (mt76_phy_scanning(phy))
mt76_abort_scan(dev);
cancel_delayed_work_sync(&phy->mac_work);
@ -295,7 +295,6 @@ struct mt76_vif_link *mt76_get_vif_phy_link(struct mt76_phy *phy,
kfree(mlink);
return ERR_PTR(ret);
}
rcu_assign_pointer(mvif->offchannel_link, mlink);
return mlink;
}
@ -304,14 +303,10 @@ void mt76_put_vif_phy_link(struct mt76_phy *phy, struct ieee80211_vif *vif,
struct mt76_vif_link *mlink)
{
struct mt76_dev *dev = phy->dev;
struct mt76_vif_data *mvif;
if (IS_ERR_OR_NULL(mlink) || !mlink->offchannel)
return;
mvif = mlink->mvif;
rcu_assign_pointer(mvif->offchannel_link, NULL);
dev->drv->vif_link_remove(phy, vif, &vif->bss_conf, mlink);
kfree_rcu(mlink, rcu_head);
}
@ -330,11 +325,13 @@ void mt76_roc_complete(struct mt76_phy *phy)
!test_bit(MT76_MCU_RESET, &dev->phy.state)) {
__mt76_set_channel(phy, &phy->main_chandef, false);
mt76_offchannel_notify(phy, false);
} else {
phy->offchannel = false;
}
mt76_put_vif_phy_link(phy, phy->roc_vif, phy->roc_link);
phy->roc_vif = NULL;
phy->roc_link = NULL;
if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
if (!test_bit(MT76_RESTART, &dev->phy.state))
ieee80211_remain_on_channel_expired(phy->hw);
}
@ -379,8 +376,9 @@ int mt76_remain_on_channel(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mutex_lock(&dev->mutex);
if (phy->roc_vif || dev->scan.phy == phy ||
test_bit(MT76_MCU_RESET, &dev->phy.state)) {
if (phy->roc_vif || mt76_phy_scanning(phy) ||
test_bit(MT76_MCU_RESET, &dev->phy.state) ||
test_bit(MT76_RESTART, &dev->phy.state)) {
ret = -EBUSY;
goto out;
}
@ -423,7 +421,7 @@ int mt76_cancel_remain_on_channel(struct ieee80211_hw *hw,
struct mt76_vif_data *mvif = mlink->mvif;
struct mt76_phy *phy = mvif->roc_phy;
if (!phy)
if (!phy || phy->roc_vif != vif)
return 0;
mt76_abort_roc(phy);

View File

@ -231,12 +231,14 @@ mt76_find_power_limits_node(struct mt76_dev *dev)
struct property *regd = of_find_property(cur, "regdomain", NULL);
if (!country && !regd) {
fallback = cur;
of_node_put(fallback);
fallback = of_node_get(cur);
continue;
}
if (mt76_string_prop_find(country, dev->alpha2) ||
mt76_string_prop_find(regd, region_name)) {
of_node_put(fallback);
of_node_put(np);
return cur;
}
@ -429,7 +431,7 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
s8 target_power)
{
struct mt76_dev *dev = phy->dev;
struct device_node *np;
struct device_node *np, *band_np;
const s8 *val;
char name[16];
char band;
@ -459,15 +461,18 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
band = '6';
break;
default:
of_node_put(np);
return target_power;
}
snprintf(name, sizeof(name), "txpower-%cg", band);
np = of_get_child_by_name(np, name);
if (!np)
band_np = of_get_child_by_name(np, name);
of_node_put(np);
if (!band_np)
return target_power;
np = mt76_find_channel_node(np, chan);
np = mt76_find_channel_node(band_np, chan);
of_node_put(band_np);
if (!np)
return target_power;
@ -514,6 +519,8 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
ARRAY_SIZE(dest->path.ru_bf), val, len, target_power,
txs_delta, &max_power, n_chains, MT76_SKU_BACKOFF);
of_node_put(np);
return max_power;
}
EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits);

View File

@ -432,6 +432,7 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
INIT_LIST_HEAD(&phy->tx_list);
spin_lock_init(&phy->tx_lock);
INIT_DELAYED_WORK(&phy->roc_work, mt76_roc_complete_work);
INIT_DELAYED_WORK(&phy->scan_work, mt76_scan_work);
if ((void *)phy != hw->priv)
return 0;
@ -729,7 +730,6 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
INIT_LIST_HEAD(&dev->txwi_cache);
INIT_LIST_HEAD(&dev->rxwi_cache);
dev->token_size = dev->drv->token_size;
INIT_DELAYED_WORK(&dev->scan_work, mt76_scan_work);
spin_lock_init(&dev->scan_lock);
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
@ -856,8 +856,8 @@ void mt76_reset_device(struct mt76_dev *dev)
continue;
wcid->sta = 0;
mt76_wcid_cleanup(dev, wcid);
rcu_assign_pointer(dev->wcid[i], NULL);
mt76_wcid_cleanup(dev, wcid);
}
rcu_read_unlock();
@ -1045,6 +1045,20 @@ void mt76_update_survey(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_update_survey);
void mt76_phy_chandef_set(struct mt76_phy *phy,
struct cfg80211_chan_def *chandef)
{
if (!chandef->chan)
return;
mt76_update_survey(phy);
phy->chandef = *chandef;
phy->main_chandef = *chandef;
phy->chan_state = mt76_channel_state(phy, chandef->chan);
}
EXPORT_SYMBOL_GPL(mt76_phy_chandef_set);
int __mt76_set_channel(struct mt76_phy *phy, struct cfg80211_chan_def *chandef,
bool offchannel)
{
@ -1283,7 +1297,6 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
status->rate_idx = mstat.rate_idx;
status->nss = mstat.nss;
status->band = mstat.band;
status->signal = mstat.signal;
status->chains = mstat.chains;
status->ampdu_reference = mstat.ampdu_ref;
status->device_timestamp = mstat.timestamp;
@ -1471,6 +1484,7 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
struct ieee80211_hw *hw;
struct mt76_wcid *wcid = status->wcid;
u8 tidno = status->qos_ctl & IEEE80211_QOS_CTL_TID_MASK;
int signal;
bool ps;
hw = mt76_phy_hw(dev, status->phy_idx);
@ -1488,8 +1502,9 @@ mt76_check_sta(struct mt76_dev *dev, struct sk_buff *skb)
sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
if (status->signal <= 0)
ewma_signal_add(&wcid->rssi, -status->signal);
signal = mt76_rx_signal(status->chains, status->chain_signal);
if (signal <= 0 && signal > -128)
ewma_signal_add(&wcid->rssi, -signal);
wcid->inactive_count = 0;
@ -1747,9 +1762,8 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
mt76_tx_status_lock(dev, &list);
mt76_tx_status_skb_get(dev, wcid, -1, &list);
mt76_tx_status_unlock(dev, &list);
idr_destroy(&wcid->pktid);
mt76_tx_status_unlock(dev, &list);
/* Remove from sta_poll_list to prevent list corruption after reset.
* Without this, mt76_reset_device() reinitializes sta_poll_list but
@ -2110,7 +2124,7 @@ void mt76_vif_cleanup(struct mt76_dev *dev, struct ieee80211_vif *vif)
rcu_assign_pointer(mvif->link[0], NULL);
mt76_abort_scan(dev);
if (mvif->roc_phy)
if (mvif->roc_phy && mvif->roc_phy->roc_vif == vif)
mt76_abort_roc(mvif->roc_phy);
}
EXPORT_SYMBOL_GPL(mt76_vif_cleanup);
@ -2324,7 +2338,7 @@ void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb)
.bssid = hdr->addr3,
};
mt76_scan_rx_beacon(phy->dev, phy->chandef.chan);
mt76_scan_rx_beacon(phy, phy->chandef.chan);
if (!phy->num_sta)
return;

View File

@ -767,7 +767,6 @@ struct mt76_rx_status {
u8 amsdu:1, first_amsdu:1, last_amsdu:1;
u8 rate_idx;
u8 nss:5, band:3;
s8 signal;
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
};
@ -847,7 +846,6 @@ struct mt76_vif_link {
struct mt76_vif_data {
struct mt76_vif_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
struct mt76_vif_link __rcu *offchannel_link;
struct mt76_phy *roc_phy;
u16 valid_links;
@ -879,6 +877,15 @@ struct mt76_phy {
struct ieee80211_vif *roc_vif;
struct mt76_vif_link *roc_link;
struct delayed_work scan_work;
struct {
struct ieee80211_channel *chan;
struct mt76_vif_link *mlink;
int chan_idx;
bool beacon_wait;
bool beacon_received;
} scan;
struct mt76_chanctx *chanctx;
struct mt76_channel_state *chan_state;
@ -1015,17 +1022,12 @@ struct mt76_dev {
u32 rxfilter;
struct delayed_work scan_work;
spinlock_t scan_lock;
struct {
struct cfg80211_scan_request *req;
struct ieee80211_channel *chan;
struct ieee80211_scan_request *req;
struct ieee80211_vif *vif;
struct mt76_vif_link *mlink;
struct mt76_phy *phy;
int chan_idx;
bool beacon_wait;
bool beacon_received;
unsigned long phy_mask;
bool aborted;
} scan;
#ifdef CONFIG_NL80211_TESTMODE
@ -1398,6 +1400,11 @@ mt76_phy_hw(struct mt76_dev *dev, u8 phy_idx)
return mt76_dev_phy(dev, phy_idx)->hw;
}
static inline bool mt76_phy_scanning(struct mt76_phy *phy)
{
return test_bit(phy->band_idx, &phy->dev->scan.phy_mask);
}
static inline u8 *
mt76_get_txwi_ptr(struct mt76_dev *dev, struct mt76_txwi_cache *t)
{
@ -1555,6 +1562,8 @@ void mt76_sta_ps_transition(struct mt76_dev *dev, struct mt76_wcid *wcid,
bool mt76_has_tx_pending(struct mt76_phy *phy);
int mt76_update_channel(struct mt76_phy *phy);
void mt76_update_survey(struct mt76_phy *phy);
void mt76_phy_chandef_set(struct mt76_phy *phy,
struct cfg80211_chan_def *chandef);
void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time);
int mt76_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey);
@ -1623,7 +1632,7 @@ int mt76_get_rate(struct mt76_dev *dev,
int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req);
void mt76_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan);
void mt76_scan_rx_beacon(struct mt76_phy *phy, struct ieee80211_channel *chan);
void mt76_rx_beacon(struct mt76_phy *phy, struct sk_buff *skb);
void mt76_beacon_mon_check(struct mt76_phy *phy);
void mt76_sw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,

View File

@ -34,7 +34,7 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
int idx;
u32 val;
if (skb->len < MT_TXD_SIZE + sizeof(struct ieee80211_hdr))
if (skb->len < MT_TXD_SIZE + 2)
goto free;
val = le32_to_cpu(txd[1]);
@ -52,6 +52,9 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
sta = container_of(priv, struct ieee80211_sta, drv_priv);
hdr = (struct ieee80211_hdr *)&skb->data[MT_TXD_SIZE];
if (skb->len < MT_TXD_SIZE + ieee80211_hdrlen(hdr->frame_control))
goto free;
hwq = wmm_queue_map[IEEE80211_AC_BE];
if (ieee80211_is_data_qos(hdr->frame_control)) {
tid = *ieee80211_get_qos_ctl(hdr) &
@ -62,6 +65,19 @@ mt7603_rx_loopback_skb(struct mt7603_dev *dev, struct sk_buff *skb)
} else if (ieee80211_is_data(hdr->frame_control)) {
skb_set_queue_mapping(skb, IEEE80211_AC_BE);
hwq = wmm_queue_map[IEEE80211_AC_BE];
} else if (ieee80211_is_back_req(hdr->frame_control)) {
struct ieee80211_bar *bar = (struct ieee80211_bar *)hdr;
if (skb->len < MT_TXD_SIZE + sizeof(*bar))
goto free;
tid = (le16_to_cpu(bar->control) &
IEEE80211_BAR_CTRL_TID_INFO_MASK) >>
IEEE80211_BAR_CTRL_TID_INFO_SHIFT;
tid &= IEEE80211_QOS_CTL_TAG1D_MASK;
qid = tid_to_ac[tid];
hwq = wmm_queue_map[qid];
skb_set_queue_mapping(skb, qid);
} else {
skb_pull(skb, MT_TXD_SIZE);
if (!ieee80211_is_bufferable_mmpdu(skb))

View File

@ -54,7 +54,7 @@ static int mt7615_config(void *data, u64 val)
int ret;
mt7615_mutex_acquire(dev);
ret = mt76_connac_mcu_chip_config(&dev->mt76);
ret = mt76_connac_mcu_chip_config(&dev->mt76, "assert");
mt7615_mutex_release(dev);
return ret;

View File

@ -541,8 +541,10 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
mt7615_cap_dbdc_enable(dev);
mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7615_ops, MT_BAND1);
if (!mphy)
return -ENOMEM;
if (!mphy) {
ret = -ENOMEM;
goto error;
}
phy = mphy->priv;
phy->dev = dev;
@ -572,7 +574,7 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
ret = mt76_eeprom_override(mphy);
if (ret)
return ret;
goto error_free_hw;
/* second phy can only handle 5 GHz */
mphy->cap.has_5ghz = true;
@ -590,7 +592,14 @@ int mt7615_register_ext_phy(struct mt7615_dev *dev)
ret = mt76_register_phy(mphy, true, mt76_rates,
ARRAY_SIZE(mt76_rates));
if (ret)
ieee80211_free_hw(mphy->hw);
goto error_free_hw;
return 0;
error_free_hw:
ieee80211_free_hw(mphy->hw);
error:
mt7615_cap_dbdc_disable(dev);
return ret;
}

View File

@ -254,8 +254,10 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
mt7615_mutex_acquire(dev);
mt7615_mcu_add_bss_info(phy, vif, NULL, false);
mt7615_mcu_sta_add(phy, vif, NULL, false);
if (vif->type != NL80211_IFTYPE_MONITOR) {
mt7615_mcu_add_bss_info(phy, vif, NULL, false);
mt7615_mcu_sta_add(phy, vif, NULL, false);
}
mt76_testmode_reset(phy->mt76, true);
if (vif == phy->monitor_vif)

View File

@ -145,6 +145,9 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
}
rxd = (struct mt7615_mcu_rxd *)skb->data;
if (skb->len < sizeof(*rxd))
return -EMSGSIZE;
if (seq != rxd->seq)
return -EAGAIN;
@ -152,9 +155,15 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
skb_pull(skb, sizeof(*rxd) - 4);
ret = *skb->data;
} else if (cmd == MCU_EXT_CMD(THERMAL_CTRL)) {
if (skb->len < sizeof(*rxd) + (is_mt7663(mdev) ? 8 : 4))
return -EMSGSIZE;
skb_pull(skb, sizeof(*rxd));
if (is_mt7663(mdev))
skb_pull(skb, 4);
ret = le32_to_cpu(*(__le32 *)skb->data);
} else if (cmd == MCU_EXT_QUERY(RF_REG_ACCESS)) {
if (skb->len < sizeof(*rxd) + 8 + sizeof(__le32))
return -EMSGSIZE;
skb_pull(skb, sizeof(*rxd));
ret = le32_to_cpu(*(__le32 *)&skb->data[8]);
} else if (cmd == MCU_UNI_CMD(DEV_INFO_UPDATE) ||
@ -165,12 +174,16 @@ int mt7615_mcu_parse_response(struct mt76_dev *mdev, int cmd,
cmd == MCU_UNI_CMD(SUSPEND)) {
struct mt76_connac_mcu_uni_event *event;
if (skb->len < sizeof(*rxd) + sizeof(*event))
return -EMSGSIZE;
skb_pull(skb, sizeof(*rxd));
event = (struct mt76_connac_mcu_uni_event *)skb->data;
ret = le32_to_cpu(event->status);
} else if (cmd == MCU_CE_QUERY(REG_READ)) {
struct mt76_connac_mcu_reg_event *event;
if (skb->len < sizeof(*rxd) + sizeof(*event))
return -EMSGSIZE;
skb_pull(skb, sizeof(*rxd));
event = (struct mt76_connac_mcu_reg_event *)skb->data;
ret = (int)le32_to_cpu(event->val);

View File

@ -116,6 +116,7 @@ void mt7615_unregister_device(struct mt7615_dev *dev)
mcu_running = mt7615_wait_for_mcu_init(dev);
mt7615_unregister_ext_phy(dev);
cancel_work_sync(&dev->reset_work);
mt76_unregister_device(&dev->mt76);
if (mcu_running)
mt7615_mcu_exit(dev);

View File

@ -58,15 +58,22 @@ static void mt7663u_copy(struct mt76_dev *dev, u32 offset,
const void *data, int len)
{
struct mt76_usb *usb = &dev->usb;
int ret, i = 0, batch_len;
const u8 *val = data;
int len_aligned;
int batch_len;
int copy_len;
int ret;
int i = 0;
len = round_up(len, 4);
len_aligned = round_up(len, 4);
mutex_lock(&usb->usb_ctrl_mtx);
while (i < len) {
batch_len = min_t(int, usb->data_len, len - i);
memcpy(usb->data, val + i, batch_len);
while (i < len_aligned) {
batch_len = min_t(int, usb->data_len, len_aligned - i);
copy_len = min_t(int, batch_len, len - i);
memcpy(usb->data, val + i, copy_len);
if (copy_len < batch_len)
memset(usb->data + copy_len, 0, batch_len - copy_len);
ret = __mt76u_vendor_request(dev, MT_VEND_WRITE_EXT,
USB_DIR_OUT | USB_TYPE_VENDOR,
(offset + i) >> 16, offset + i,

View File

@ -600,6 +600,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
vif ? &vif->bss_conf : NULL,
beacon, multicast);
u32 val = MT_TXD6_FIXED_BW;
u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
/* hardware won't add HTC for mgmt/ctrl frame */
txwi[2] |= cpu_to_le32(MT_TXD2_HTC_VLD);
@ -608,13 +609,18 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
txwi[6] |= cpu_to_le32(val);
txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
if (!is_connac2(dev)) {
u8 spe_idx = mt76_connac_spe_idx(mphy->antenna_mask);
if (!spe_idx)
spe_idx = 24 + phy_idx;
txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx));
}
/* Fixed-rate frames (all mgmt, so auth/assoc req too) otherwise
* carry spe_idx 0 and TX 1SS 1T on WF0. Fill spe_idx like the
* other connac generations do, but do NOT touch
* MT_TXD6_SPE_ID_IDX: on connac2 setting it points HW at the
* WTBL and the index below is ignored.
*
* spe_idx 0 is also a valid single-path index (WF0), so only
* take the duplicate fallback when a second path exists.
*/
if (!spe_idx && hweight8(mphy->antenna_mask) > 1)
spe_idx = 24 + phy_idx;
txwi[7] |= cpu_to_le32(FIELD_PREP(MT_TXD7_SPE_IDX, spe_idx));
txwi[7] &= ~cpu_to_le32(MT_TXD7_HW_AMSDU);
}

View File

@ -2041,13 +2041,13 @@ int mt76_connac_mcu_sched_scan_enable(struct mt76_phy *phy,
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_sched_scan_enable);
int mt76_connac_mcu_chip_config(struct mt76_dev *dev)
int mt76_connac_mcu_chip_config(struct mt76_dev *dev, const char *cmd)
{
struct mt76_connac_config req = {
.resp_type = 0,
};
strscpy(req.data, "assert");
strscpy(req.data, cmd);
return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG),
&req, sizeof(req), false);
@ -2056,14 +2056,11 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_chip_config);
int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable)
{
struct mt76_connac_config req = {
.resp_type = 0,
};
char cmd[16];
snprintf(req.data, sizeof(req.data), "KeepFullPwr %d", !enable);
snprintf(cmd, sizeof(cmd), "KeepFullPwr %d", !enable);
return mt76_mcu_send_msg(dev, MCU_CE_CMD(CHIP_CONFIG),
&req, sizeof(req), false);
return mt76_connac_mcu_chip_config(dev, cmd);
}
EXPORT_SYMBOL_GPL(mt76_connac_mcu_set_deep_sleep);
@ -2487,9 +2484,7 @@ int mt76_connac_mcu_update_gtk_rekey(struct ieee80211_hw *hw,
gtk_tlv->rekey_mode = 2;
gtk_tlv->option = 1;
rcu_read_lock();
ieee80211_iter_keys_rcu(hw, vif, mt76_connac_mcu_key_iter, gtk_tlv);
rcu_read_unlock();
ieee80211_iter_keys(hw, vif, mt76_connac_mcu_key_iter, gtk_tlv);
memcpy(gtk_tlv->kek, key->kek, NL80211_KEK_LEN);
memcpy(gtk_tlv->kck, key->kck, NL80211_KCK_LEN);
@ -3127,7 +3122,7 @@ mt76_connac_mcu_send_phy_ram_firmware(struct mt76_dev *dev,
err = mt76_connac_mcu_init_download(dev, addr, len, mode);
if (err) {
dev_err(dev->dev,
"The request to dowload PHY firmware failed.\n");
"The request to download PHY firmware failed.\n");
return err;
}

View File

@ -1357,9 +1357,11 @@ enum {
MCU_UNI_CMD_ALL_STA_INFO = 0x6e,
MCU_UNI_CMD_ASSERT_DUMP = 0x6f,
MCU_UNI_CMD_EXT_EEPROM_CTRL = 0x74,
MCU_UNI_CMD_FACT_CAL = 0x7c,
MCU_UNI_CMD_RADIO_STATUS = 0x80,
MCU_UNI_CMD_MLD = 0x82,
MCU_UNI_CMD_SDO = 0x88,
MCU_UNI_CMD_AXIDMA = 0xa2,
};
enum {
@ -2098,7 +2100,7 @@ void mt76_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
int mt76_connac_sta_state_dp(struct mt76_dev *dev,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state);
int mt76_connac_mcu_chip_config(struct mt76_dev *dev);
int mt76_connac_mcu_chip_config(struct mt76_dev *dev, const char *cmd);
int mt76_connac_mcu_set_deep_sleep(struct mt76_dev *dev, bool enable);
void mt76_connac_mcu_coredump_event(struct mt76_dev *dev, struct sk_buff *skb,
struct mt76_connac_coredump *coredump);

View File

@ -302,10 +302,14 @@ mt76x02_mac_process_tx_rate(struct ieee80211_tx_rate *txrate, u16 rate,
txrate->flags |= IEEE80211_TX_RC_GREEN_FIELD;
fallthrough;
case MT_PHY_TYPE_HT:
if (idx > 31)
return -EINVAL;
txrate->flags |= IEEE80211_TX_RC_MCS;
txrate->idx = idx;
break;
case MT_PHY_TYPE_VHT:
if ((idx & 0xf) > 9)
return -EINVAL;
txrate->flags |= IEEE80211_TX_RC_VHT_MCS;
txrate->idx = idx;
break;
@ -493,18 +497,21 @@ mt76x02_mac_fill_tx_status(struct mt76x02_dev *dev, struct mt76x02_sta *msta,
first_rate = st->rate & ~MT_PKTID_RATE;
first_rate |= st->pktid & MT_PKTID_RATE;
mt76x02_mac_process_tx_rate(&rate[0], first_rate,
dev->mphy.chandef.chan->band);
if (mt76x02_mac_process_tx_rate(&rate[0], first_rate,
dev->mphy.chandef.chan->band))
return;
} else if (rate[0].idx < 0) {
if (!msta)
return;
mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info,
dev->mphy.chandef.chan->band);
if (mt76x02_mac_process_tx_rate(&rate[0], msta->wcid.tx_info,
dev->mphy.chandef.chan->band))
return;
}
mt76x02_mac_process_tx_rate(&last_rate, st->rate,
dev->mphy.chandef.chan->band);
if (mt76x02_mac_process_tx_rate(&last_rate, st->rate,
dev->mphy.chandef.chan->band))
return;
for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) {
retry--;
@ -809,9 +816,13 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
len = FIELD_GET(MT_RXWI_CTL_MPDU_LEN, ctl);
pn_len = FIELD_GET(MT_RXINFO_PN_LEN, rxinfo);
if (pn_len) {
int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len;
u8 *data = skb->data + offset;
unsigned int offset = ieee80211_get_hdrlen_from_skb(skb) + pad_len;
u8 *data;
if (offset + 8 > skb->len)
return -EINVAL;
data = skb->data + offset;
status->iv[0] = data[7];
status->iv[1] = data[6];
status->iv[2] = data[5];
@ -831,6 +842,9 @@ int mt76x02_mac_process_rx(struct mt76x02_dev *dev, struct sk_buff *skb,
}
}
if (pad_len + ieee80211_get_hdrlen_from_skb(skb) > skb->len)
return -EINVAL;
mt76x02_remove_hdr_pad(skb, pad_len);
if ((rxinfo & MT_RXINFO_BA) && !(rxinfo & MT_RXINFO_NULL))

View File

@ -90,7 +90,7 @@ __mt76x02u_mcu_send_msg(struct mt76_dev *dev, struct sk_buff *skb,
MT_MCU_MSG_TYPE_CMD;
ret = mt76x02u_skb_dma_info(skb, CPU_TX_PORT, info);
if (ret)
return ret;
goto out;
ret = mt76u_bulk_msg(dev, skb->data, skb->len, NULL, 500,
MT_EP_OUT_INBAND_CMD);

View File

@ -345,11 +345,12 @@ static struct mt7915_coredump *mt7915_coredump_build(struct mt7915_dev *dev)
mt7915_coredump_fw_stack(dev, dump, exception);
/* gather memory content */
dump_mem = (struct mt7915_coredump_mem *)(buf + sofar);
dump_mem->len = crash_data->memdump_buf_len;
if (coredump_memdump && crash_data->memdump_buf_len)
if (coredump_memdump && crash_data->memdump_buf_len) {
dump_mem = (struct mt7915_coredump_mem *)(buf + sofar);
dump_mem->len = crash_data->memdump_buf_len;
memcpy(dump_mem->data, crash_data->memdump_buf,
crash_data->memdump_buf_len);
}
mutex_unlock(&dev->dump_mutex);

View File

@ -111,6 +111,12 @@ mt7915_eeprom_load_default(struct mt7915_dev *dev)
goto out;
}
if (fw->size < mt7915_eeprom_size(dev)) {
dev_err(dev->mt76.dev, "Invalid default bin size\n");
ret = -EINVAL;
goto out;
}
memcpy(eeprom, fw->data, mt7915_eeprom_size(dev));
dev->flash_mode = true;

View File

@ -200,11 +200,17 @@ static void mt7915_unregister_thermal(struct mt7915_phy *phy)
{
struct wiphy *wiphy = phy->mt76->hw->wiphy;
if (phy->tzone) {
devm_thermal_of_zone_unregister(phy->dev->mt76.dev, phy->tzone);
phy->tzone = NULL;
}
if (!phy->cdev)
return;
sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
thermal_cooling_device_unregister(phy->cdev);
phy->cdev = NULL;
}
static int mt7915_thermal_init(struct mt7915_phy *phy)
@ -238,8 +244,8 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
if (IS_ERR(phy->tzone)) {
if (PTR_ERR(phy->tzone) != -ENODEV)
dev_warn(phy->dev->mt76.dev,
"failed to register thermal zone: %ld\n",
PTR_ERR(phy->tzone));
"failed to register thermal zone %d: %ld\n",
phy->mt76->band_idx, PTR_ERR(phy->tzone));
phy->tzone = NULL;
}
@ -248,7 +254,12 @@ static int mt7915_thermal_init(struct mt7915_phy *phy)
hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
mt7915_hwmon_groups);
return PTR_ERR_OR_ZERO(hwmon);
if (IS_ERR(hwmon)) {
mt7915_unregister_thermal(phy);
return PTR_ERR(hwmon);
}
return 0;
}
static void mt7915_led_set_config(struct led_classdev *led_cdev,

View File

@ -273,9 +273,9 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
mt7915_init_bitrate_mask(vif);
memset(&mvif->cap, -1, sizeof(mvif->cap));
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
mt7915_mcu_add_bss_info(phy, vif, true);
mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, true);
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
mutex_unlock(&dev->mt76.mutex);

View File

@ -237,7 +237,7 @@ static int mt7921_chip_reset(void *data, u64 val)
default:
/* Collect the core dump before reset wifisys. */
mt792x_mutex_acquire(dev);
ret = mt76_connac_mcu_chip_config(&dev->mt76);
ret = mt76_connac_mcu_chip_config(&dev->mt76, "assert");
mt792x_mutex_release(dev);
break;
}

View File

@ -188,7 +188,7 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
u16 seq_ctrl = 0;
__le16 fc = 0;
u8 mode = 0;
int i, idx;
int idx;
memset(status, 0, sizeof(*status));
@ -368,15 +368,6 @@ mt7921_mac_fill_rx(struct mt792x_dev *dev, struct sk_buff *skb)
status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1);
status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1);
status->chain_signal[3] = to_rssi(MT_PRXV_RCPI3, v1);
status->signal = -128;
for (i = 0; i < hweight8(mphy->antenna_mask); i++) {
if (!(status->chains & BIT(i)) ||
status->chain_signal[i] >= 0)
continue;
status->signal = max(status->signal,
status->chain_signal[i]);
}
}
amsdu_info = FIELD_GET(MT_RXD4_NORMAL_PAYLOAD_FORMAT, rxd4);
@ -831,11 +822,14 @@ void mt7921_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
u16 idx;
idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
rcu_read_lock();
wcid = __mt76_wcid_ptr(mdev, idx);
sta = wcid_to_sta(wcid);
if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
mt76_connac2_tx_check_aggr(sta, txwi);
rcu_read_unlock();
skb_pull(e->skb, headroom);
mt76_tx_complete_skb(mdev, e->wcid, e->skb);

View File

@ -652,9 +652,9 @@ static int mt7921_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_sniffer_interface_iter, dev);
ieee80211_iterate_active_interfaces_mtx(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_sniffer_interface_iter, dev);
}
out:
@ -668,12 +668,8 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
unsigned int *total_flags,
u64 multicast)
{
#define MT7921_FILTER_FCSFAIL BIT(2)
#define MT7921_FILTER_CONTROL BIT(5)
#define MT7921_FILTER_OTHER_BSS BIT(6)
#define MT7921_FILTER_ENABLE BIT(31)
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_phy *phy = mt792x_hw_phy(hw);
u32 flags = MT7921_FILTER_ENABLE;
#define MT7921_FILTER(_fif, _type) do { \
@ -685,6 +681,8 @@ static void mt7921_configure_filter(struct ieee80211_hw *hw,
MT7921_FILTER(FIF_CONTROL, CONTROL);
MT7921_FILTER(FIF_OTHER_BSS, OTHER_BSS);
phy->rxfilter = flags;
mt792x_mutex_acquire(dev);
mt7921_mcu_set_rxfilter(dev, flags, 0, 0);
mt792x_mutex_release(dev);
@ -865,6 +863,12 @@ int mt7921_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (sta->aid > MT7921_MAX_AID)
return -ENOENT;
if (mvif->roc_join_held && !sta->tdls &&
(ev == MT76_STA_EVENT_AUTHORIZE || ev == MT76_STA_EVENT_DISASSOC)) {
mvif->roc_join_held = false;
mt7921_abort_roc(mvif->phy, mvif);
}
if (ev != MT76_STA_EVENT_ASSOC)
return 0;
@ -906,6 +910,7 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
mvif->wep_sta = NULL;
mvif->roc_join_held = false;
ewma_rssi_init(&mvif->bss_conf.rssi);
if (!sta->tdls)
mt76_connac_mcu_uni_add_bss(&dev->mphy, vif,
@ -1156,10 +1161,10 @@ static int mt7921_suspend(struct ieee80211_hw *hw,
mt792x_mutex_acquire(dev);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_mcu_set_suspend_iter,
&dev->mphy);
ieee80211_iterate_active_interfaces_mtx(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7921_mcu_set_suspend_iter,
&dev->mphy);
mt792x_mutex_release(dev);
@ -1174,10 +1179,10 @@ static int mt7921_resume(struct ieee80211_hw *hw)
mt792x_mutex_acquire(dev);
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt76_connac_mcu_set_suspend_iter,
&dev->mphy);
ieee80211_iterate_active_interfaces_mtx(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt76_connac_mcu_set_suspend_iter,
&dev->mphy);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
MT792x_WATCHDOG_TIME);
@ -1423,6 +1428,7 @@ mt7921_change_chanctx(struct ieee80211_hw *hw,
} else {
mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx);
}
mt76_phy_chandef_set(mvif->phy->mt76, &ctx->def);
mt792x_mutex_release(phy->dev);
}
@ -1447,6 +1453,16 @@ static void mt7921_mgd_complete_tx(struct ieee80211_hw *hw,
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
/* Keep the join ROC until the station is authorized, so that it
* covers the 4-way handshake. mt7921_mac_sta_event() releases it.
*/
if (vif->type == NL80211_IFTYPE_STATION && info->success &&
(info->subtype == IEEE80211_STYPE_ASSOC_REQ ||
info->subtype == IEEE80211_STYPE_REASSOC_REQ)) {
mvif->roc_join_held = true;
return;
}
mt7921_abort_roc(mvif->phy, mvif);
}

View File

@ -3,6 +3,7 @@
#include <linux/fs.h>
#include <linux/firmware.h>
#include <linux/of.h>
#include "mt7921.h"
#include "regd.h"
#include "mcu.h"
@ -676,6 +677,10 @@ int mt7921_run_firmware(struct mt792x_dev *dev)
return err;
set_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
err = mt7921_mcu_set_thermal_protect(dev);
if (err)
return err;
return mt7921_mcu_fw_log_2_host(dev, 1);
}
EXPORT_SYMBOL_GPL(mt7921_run_firmware);
@ -1231,7 +1236,7 @@ int mt7921_mcu_config_sniffer(struct mt792x_vif *vif,
.len = cpu_to_le16(sizeof(req.tlv)),
.control_ch = chandef->chan->hw_value,
.center_ch = ieee80211_frequency_to_channel(freq1),
.drop_err = 1,
.drop_err = !(vif->phy->rxfilter & MT7921_FILTER_FCSFAIL),
},
};
if (chandef->chan->band < ARRAY_SIZE(ch_band))
@ -1359,6 +1364,7 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
.acpi_conf = mt792x_acpi_get_flags(&dev->phy),
.mtcl_conf = mt792x_acpi_get_mtcl_conf(&dev->phy, alpha2),
};
struct device_node *np;
int ret, valid_cnt = 0;
u32 buf_len = 0;
u8 *pos;
@ -1368,8 +1374,11 @@ int __mt7921_mcu_set_clc(struct mt792x_dev *dev, u8 *alpha2,
if (dev->phy.chip_cap & MT792x_CHIP_CAP_CLC_EVT_EN)
req.cap |= CLC_CAP_EVT_EN;
if (mt76_find_power_limits_node(&dev->mt76))
np = mt76_find_power_limits_node(&dev->mt76);
if (np)
req.cap |= CLC_CAP_DTS_EN;
of_node_put(np);
buf_len = le32_to_cpu(clc->len) - sizeof(*clc);
pos = clc->data;
@ -1479,6 +1488,19 @@ int mt7921_mcu_wf_rf_pin_ctrl(struct mt792x_phy *phy, u8 action)
sizeof(req), action ? true : false);
}
#define MT7921_THERMAL_PROT_LOW_TEMP 105
#define MT7921_THERMAL_PROT_HIGH_TEMP 115
int mt7921_mcu_set_thermal_protect(struct mt792x_dev *dev)
{
char cmd[64];
snprintf(cmd, sizeof(cmd), "DowngradeTxStreamTemp %d %d",
MT7921_THERMAL_PROT_LOW_TEMP, MT7921_THERMAL_PROT_HIGH_TEMP);
return mt76_connac_mcu_chip_config(&dev->mt76, cmd);
}
int mt7921_mcu_set_rxfilter(struct mt792x_dev *dev, u32 fif,
u8 bit_op, u32 bit_map)
{

View File

@ -7,6 +7,11 @@
#include "../mt792x.h"
#include "regs.h"
#define MT7921_FILTER_FCSFAIL BIT(2)
#define MT7921_FILTER_CONTROL BIT(5)
#define MT7921_FILTER_OTHER_BSS BIT(6)
#define MT7921_FILTER_ENABLE BIT(31)
#define MT7921_MAX_AID 20
#define MT7921_TX_RING_SIZE 2048
@ -324,6 +329,7 @@ int mt7921_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
int mt7921_mcu_config_sniffer(struct mt792x_vif *vif,
struct ieee80211_chanctx_conf *ctx);
int mt7921_mcu_get_temperature(struct mt792x_phy *phy);
int mt7921_mcu_set_thermal_protect(struct mt792x_dev *dev);
int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
enum mt76_txq_id qid, struct mt76_wcid *wcid,

View File

@ -375,6 +375,7 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
}
map->rx.wm2_complete_mask = 0;
map->rx.all_complete_mask &= ~MT_INT_RX_DONE_WM2;
dev->irq_map = map;
}

View File

@ -57,7 +57,9 @@ int mt7921e_mac_reset(struct mt792x_dev *dev)
{
int i, err;
mt792xe_mcu_drv_pmctrl(dev);
err = mt792xe_mcu_drv_pmctrl(dev);
if (err)
return err;
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);

View File

@ -28,6 +28,21 @@ bool mt7921_regd_clc_supported(struct mt792x_dev *dev)
return true;
}
static bool
mt7921_regd_dt_has_channel(struct device_node *band_np,
struct ieee80211_channel *ch)
{
struct device_node *chan_np;
if (!band_np)
return false;
chan_np = mt76_find_channel_node(band_np, ch);
of_node_put(chan_np);
return !!chan_np;
}
static void
mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
{
@ -43,14 +58,14 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
sband = wiphy->bands[NL80211_BAND_5GHZ];
if (!sband)
return;
goto out;
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))) {
if (np && !mt7921_regd_dt_has_channel(band_np, ch)) {
ch->flags |= IEEE80211_CHAN_DISABLED;
continue;
}
@ -59,17 +74,18 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
if (IS_UNII_INVALID(0, 5845, 5925))
ch->flags |= IEEE80211_CHAN_DISABLED;
}
of_node_put(band_np);
sband = wiphy->bands[NL80211_BAND_6GHZ];
if (!sband)
return;
goto out;
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))) {
if (np && !mt7921_regd_dt_has_channel(band_np, ch)) {
ch->flags |= IEEE80211_CHAN_DISABLED;
continue;
}
@ -81,6 +97,10 @@ mt7921_regd_channel_update(struct wiphy *wiphy, struct mt792x_dev *dev)
IS_UNII_INVALID(4, 6875, 7125))
ch->flags |= IEEE80211_CHAN_DISABLED;
}
of_node_put(band_np);
out:
of_node_put(np);
}
int __mt7921_mcu_regd_update(struct mt792x_dev *dev, u8 *alpha2,

View File

@ -6,5 +6,5 @@ obj-$(CONFIG_MT7925U) += mt7925u.o
mt7925-common-y := mac.o mcu.o regd.o main.o init.o debugfs.o nan.o
mt7925-common-$(CONFIG_NL80211_TESTMODE) += testmode.o
mt7925e-y := pci.o pci_mac.o pci_mcu.o
mt7925e-y := pci.o pci_mac.o pci_mcu.o cached_cal.o
mt7925u-y := usb.o

View File

@ -0,0 +1,298 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/* Copyright (C) 2026 MediaTek Inc. */
#include <linux/dma-mapping.h>
#include "../mt792x.h"
#include "cached_cal.h"
static void mt7925_cal_cache_calc_layout(struct mt7925_cal_cache_layout *l)
{
u32 hdr = sizeof(struct mt7925_fact_cal_buf_info);
l->common_stride = hdr + MT7925_FACT_CAL_LEN_COM;
l->group_stride = hdr + MT7925_FACT_CAL_LEN_GRP;
l->channel_stride = hdr + MT7925_FACT_CAL_LEN_CH;
l->common_off = 0;
l->group_off = l->common_off +
l->common_stride * MT7925_FACT_CAL_COMMON_BAND_NUM;
l->channel_off = l->group_off +
l->group_stride * MT7925_FACT_CAL_GROUP_NUM;
l->mapping_off = l->channel_off +
l->channel_stride * MT7925_FACT_CAL_CH_NUM_ALL;
l->total = l->mapping_off +
sizeof(struct mt7925_fact_cal_mapping_tbl);
}
static u32 mt7925_cal_cache_region_size(void)
{
struct mt7925_cal_cache_layout l;
mt7925_cal_cache_calc_layout(&l);
return l.total;
}
int mt7925_axidma_alloc(struct mt792x_dev *dev)
{
u32 total_size;
dma_addr_t dma_addr;
void *va;
if (dev->cached_cal.va)
return 0;
total_size = mt7925_cal_cache_region_size();
va = dma_alloc_coherent(dev->mt76.dev, total_size, &dma_addr,
GFP_KERNEL);
if (!va)
return -ENOMEM;
dev->cached_cal.va = va;
dev->cached_cal.dma_addr = dma_addr;
dev->cached_cal.size = total_size;
return 0;
}
void mt7925_axidma_free(struct mt792x_dev *dev)
{
if (!dev->cached_cal.va)
return;
dma_free_coherent(dev->mt76.dev, dev->cached_cal.size,
dev->cached_cal.va, dev->cached_cal.dma_addr);
memset(&dev->cached_cal, 0, sizeof(dev->cached_cal));
}
int mt7925_mcu_send_axidma_info(struct mt792x_dev *dev)
{
struct mt7925_axidma_info_req *req;
u32 remap_base, pa_offset;
int ret;
if (!dev->cached_cal.va)
return -EINVAL;
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req)
return -ENOMEM;
remap_base = (u32)(dev->cached_cal.dma_addr >> 16);
pa_offset = (u32)(dev->cached_cal.dma_addr & 0xFFFF);
req->remap.tag = cpu_to_le16(MT7925_AXIDMA_TAG_REMAP);
req->remap.len = cpu_to_le16(sizeof(req->remap));
req->remap.remap_addr = cpu_to_le32(remap_base);
req->fact_cal.tag = cpu_to_le16(MT7925_AXIDMA_TAG_FACT_CAL);
req->fact_cal.len = cpu_to_le16(sizeof(req->fact_cal));
req->fact_cal.host_addr_offset = cpu_to_le32(pa_offset);
req->fact_cal.size = cpu_to_le32(dev->cached_cal.size);
req->fact_cal.bound = cpu_to_le32(pa_offset + dev->cached_cal.size - 1);
ret = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(AXIDMA),
req, sizeof(*req), true);
kfree(req);
if (ret)
dev_err(dev->mt76.dev,
"failed to send AXI DMA info: %d\n", ret);
return ret;
}
static bool mt7925_cal_cache_read_slot(struct mt792x_dev *dev, u32 region_off,
u32 stride, u32 idx,
u32 *cal_param, u32 *total_buf_num)
{
const struct mt7925_fact_cal_buf_info *bi;
u32 off = region_off + stride * idx;
if (!dev->cached_cal.va || off + sizeof(*bi) > dev->cached_cal.size)
return false;
bi = (const struct mt7925_fact_cal_buf_info *)
((const u8 *)dev->cached_cal.va + off);
if (cal_param)
*cal_param = le32_to_cpu(bi->cal_param);
if (total_buf_num)
*total_buf_num = le32_to_cpu(bi->total_buf_num);
return true;
}
static void mt7925_fact_cal_build_mapping_tbl(struct mt792x_dev *dev,
struct mt7925_fact_cal_mapping_tbl *tbl)
{
dma_addr_t common_pa, group_pa, channel_pa, mapping_pa;
u32 hdr = sizeof(struct mt7925_fact_cal_buf_info);
dma_addr_t base = dev->cached_cal.dma_addr;
struct mt7925_cal_cache_layout l;
mt7925_cal_cache_calc_layout(&l);
common_pa = base + l.common_off;
group_pa = base + l.group_off;
channel_pa = base + l.channel_off;
mapping_pa = base + l.mapping_off;
memset(tbl, 0, sizeof(*tbl));
tbl->common.phy_addr_h = cpu_to_le32(upper_32_bits(common_pa));
tbl->common.phy_addr_l = cpu_to_le32(lower_32_bits(common_pa));
tbl->common.offset = cpu_to_le32(l.common_stride);
tbl->group.phy_addr_h = cpu_to_le32(upper_32_bits(group_pa));
tbl->group.phy_addr_l = cpu_to_le32(lower_32_bits(group_pa));
tbl->group.offset = cpu_to_le32(l.group_stride);
tbl->channel.phy_addr_h = cpu_to_le32(upper_32_bits(channel_pa));
tbl->channel.phy_addr_l = cpu_to_le32(lower_32_bits(channel_pa));
tbl->channel.offset = cpu_to_le32(l.channel_stride);
if (dev->cached_cal.reused) {
u32 i, cal_param, total_buf_num;
for (i = 0; i < MT7925_FACT_CAL_COMMON_BAND_NUM; i++)
if (mt7925_cal_cache_read_slot(dev, l.common_off,
l.common_stride, i,
&cal_param, NULL))
tbl->common.band[i] = cal_param & 0xff;
for (i = 0; i < MT7925_FACT_CAL_GROUP_NUM; i++)
if (mt7925_cal_cache_read_slot(dev, l.group_off,
l.group_stride, i,
&cal_param, NULL))
tbl->group.group[i] = cal_param & 0xff;
for (i = 0; i < MT7925_FACT_CAL_CH_NUM_ALL; i++)
if (mt7925_cal_cache_read_slot(dev, l.channel_off,
l.channel_stride, i,
&cal_param,
&total_buf_num)) {
tbl->channel.cal_param[i] =
cpu_to_le32(cal_param);
tbl->channel.total_buf_num[i] =
total_buf_num & 0xff;
}
}
tbl->buf_info_size = cpu_to_le32(hdr);
tbl->phy_addr_h = cpu_to_le32(upper_32_bits(mapping_pa));
tbl->phy_addr_l = cpu_to_le32(lower_32_bits(mapping_pa));
}
static int mt7925_mcu_fact_cal_rapid_set(struct mt792x_dev *dev, u8 cal_type,
u32 seq_num, bool done,
const void *data, u32 data_len)
{
struct mt7925_fact_cal_req *req;
int ret;
if (data_len > MT7925_FACT_CAL_DATA_BUF_LEN)
return -EINVAL;
req = kzalloc(sizeof(*req), GFP_KERNEL);
if (!req)
return -ENOMEM;
req->set.tag = cpu_to_le16(MT7925_FACT_CAL_TAG_RAPID_SET);
req->set.len = cpu_to_le16(sizeof(req->set));
req->set.seq_num = cpu_to_le32(seq_num);
req->set.buf_data_len = cpu_to_le32(data_len);
req->set.cal_type = cal_type;
req->set.done = done;
if (data && data_len)
memcpy(req->set.buf_data, data, data_len);
ret = mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(FACT_CAL),
req, sizeof(*req), true);
kfree(req);
return ret;
}
int mt7925_mcu_send_fact_cal_mapping_tbl(struct mt792x_dev *dev)
{
struct mt7925_fact_cal_mapping_tbl *tbl;
__le32 cfg[MT7925_FACT_CAL_BUF_CFG_LEN / sizeof(__le32)] = {0};
u32 seq = 0, off = 0, left;
int ret;
if (!dev->cached_cal.va)
return -EINVAL;
tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
if (!tbl)
return -ENOMEM;
mt7925_fact_cal_build_mapping_tbl(dev, tbl);
cfg[1] = cpu_to_le32(sizeof(*tbl));
cfg[2] = cpu_to_le32(MT7925_FACT_CAL_DATA_BUF_NUM_MAX);
ret = mt7925_mcu_fact_cal_rapid_set(dev, MT7925_FACT_CAL_TYPE_MAPPING_TBL,
seq, false, cfg, sizeof(cfg));
if (ret) {
dev_err(dev->mt76.dev,
"fact-cal mapping tbl header send failed (seq=%u): %d\n",
seq, ret);
goto out;
}
left = sizeof(*tbl);
while (left) {
u32 chunk = min_t(u32, left, MT7925_FACT_CAL_DATA_BUF_LEN);
ret = mt7925_mcu_fact_cal_rapid_set(dev,
MT7925_FACT_CAL_TYPE_MAPPING_TBL,
++seq, false,
(u8 *)tbl + off, chunk);
if (ret) {
dev_err(dev->mt76.dev,
"fact-cal mapping tbl data send failed (seq=%u, off=%u, chunk=%u): %d\n",
seq, off, chunk, ret);
goto out;
}
off += chunk;
left -= chunk;
}
ret = mt7925_mcu_fact_cal_rapid_set(dev, MT7925_FACT_CAL_TYPE_MAPPING_TBL,
++seq, true, NULL, 0);
if (ret) {
dev_err(dev->mt76.dev,
"fact-cal mapping tbl done send failed (seq=%u): %d\n",
seq, ret);
goto out;
}
out:
kfree(tbl);
return ret;
}
int mt7925_mcu_fact_cal_set_bypass(struct mt792x_dev *dev, bool enable)
{
struct {
u8 _rsv[4];
struct {
__le16 tag;
__le16 len;
__le32 data;
} __packed update_flag;
} req = {
.update_flag = {
.tag = cpu_to_le16(MT7925_FACT_CAL_TAG_UPDATE_FLAG),
.len = cpu_to_le16(sizeof(req.update_flag)),
.data = cpu_to_le32(enable ? 1 : 0),
},
};
return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(FACT_CAL),
&req, sizeof(req), true);
}

View File

@ -0,0 +1,151 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/* Copyright (C) 2026 MediaTek Inc. */
#ifndef __CACHED_CAL_H
#define __CACHED_CAL_H
enum mt7925_axidma_info_tag {
MT7925_AXIDMA_TAG_REMAP = 0,
MT7925_AXIDMA_TAG_FACT_CAL = 1,
MT7925_AXIDMA_TAG_NUM
};
enum mt7925_fact_cal_tag {
MT7925_FACT_CAL_TAG_TRIGGER = 2,
MT7925_FACT_CAL_TAG_UPDATE_FLAG = 3,
MT7925_FACT_CAL_TAG_RAPID_GET = 4,
MT7925_FACT_CAL_TAG_RAPID_SET = 5,
};
enum mt7925_fact_cal_type {
MT7925_FACT_CAL_TYPE_COMMON = 0,
MT7925_FACT_CAL_TYPE_GROUP = 1,
MT7925_FACT_CAL_TYPE_CHANNEL = 2,
MT7925_FACT_CAL_TYPE_MAPPING_TBL = 4,
};
#define MT7925_FACT_CAL_DATA_BUF_LEN 1400
#define MT7925_FACT_CAL_BUF_CFG_LEN 16
#define MT7925_FACT_CAL_DATA_BUF_NUM_MAX 4
#define MT7925_FACT_CAL_BUF_CFG_U32_LEN 4
#define MT7925_FACT_CAL_DATA_MAX_BUF_LEN \
(MT7925_FACT_CAL_DATA_BUF_NUM_MAX * MT7925_FACT_CAL_BUF_CFG_U32_LEN)
#define MT7925_FACT_CAL_COMMON_BAND_NUM 2
#define MT7925_FACT_CAL_GROUP_NUM 35
#define MT7925_FACT_CAL_CH_NUM_2G 14
#define MT7925_FACT_CAL_CH_NUM_5G 68
#define MT7925_FACT_CAL_CH_NUM_6G 109
#define MT7925_FACT_CAL_CH_NUM_ALL \
(MT7925_FACT_CAL_CH_NUM_2G + MT7925_FACT_CAL_CH_NUM_5G + \
MT7925_FACT_CAL_CH_NUM_6G)
#define MT7925_FACT_CAL_LEN_COM 600
#define MT7925_FACT_CAL_LEN_GRP 4500
#define MT7925_FACT_CAL_LEN_CH 2800
struct mt7925_fact_cal_buf_info {
__le32 cal_type;
__le32 cal_param;
__le32 buf_seq_num;
__le32 total_buf_num;
__le32 buf_data_len;
u8 valid;
u8 done;
u8 rsv[2];
__le32 buf_cfg_info[MT7925_FACT_CAL_DATA_MAX_BUF_LEN];
} __packed;
static_assert(sizeof(struct mt7925_fact_cal_buf_info) == 88,
"buf_info must match the MT7928 FW (88 bytes) or it rejects the mapping table");
struct mt7925_fact_cal_common_map {
__le32 phy_addr_h;
__le32 phy_addr_l;
__le32 offset;
u8 band[MT7925_FACT_CAL_COMMON_BAND_NUM];
u8 rsv[2];
} __packed;
struct mt7925_fact_cal_group_map {
__le32 phy_addr_h;
__le32 phy_addr_l;
__le32 offset;
u8 group[MT7925_FACT_CAL_GROUP_NUM];
u8 rsv;
} __packed;
struct mt7925_fact_cal_channel_map {
__le32 phy_addr_h;
__le32 phy_addr_l;
__le32 offset;
__le32 cal_param[MT7925_FACT_CAL_CH_NUM_ALL];
u8 total_buf_num[MT7925_FACT_CAL_CH_NUM_ALL];
u8 rsv;
} __packed;
struct mt7925_fact_cal_mapping_tbl {
struct mt7925_fact_cal_common_map common;
struct mt7925_fact_cal_group_map group;
struct mt7925_fact_cal_channel_map channel;
__le32 buf_info_size;
__le32 phy_addr_h;
__le32 phy_addr_l;
} __packed;
static_assert(sizeof(struct mt7925_fact_cal_mapping_tbl) == 1044,
"mapping table must match the MT7928 FW (1044 bytes) or the FW parse corrupts");
struct mt7925_cal_cache_layout {
u32 common_off, group_off, channel_off, mapping_off;
u32 common_stride, group_stride, channel_stride;
u32 total;
};
struct mt7925_axidma_info_req {
u8 _rsv[4];
struct {
__le16 tag;
__le16 len;
__le32 remap_addr;
__le32 reserved;
} __packed remap;
struct {
__le16 tag;
__le16 len;
__le32 host_addr_offset;
__le32 size;
__le32 bound;
__le32 reserved;
} __packed fact_cal;
} __packed;
struct mt7925_fact_cal_req {
u8 _rsv[4];
struct {
__le16 tag;
__le16 len;
__le32 data;
__le32 seq_num;
__le32 buf_data_len;
u8 cal_type;
u8 done;
u8 rsv[2];
u8 buf_data[MT7925_FACT_CAL_DATA_BUF_LEN];
} __packed set;
} __packed;
int mt7925_axidma_alloc(struct mt792x_dev *dev);
void mt7925_axidma_free(struct mt792x_dev *dev);
int mt7925_mcu_send_axidma_info(struct mt792x_dev *dev);
int mt7925_mcu_send_fact_cal_mapping_tbl(struct mt792x_dev *dev);
int mt7925_mcu_fact_cal_set_bypass(struct mt792x_dev *dev, bool enable);
#endif /* __CACHED_CAL_H */

View File

@ -270,6 +270,8 @@ int mt7925_register_device(struct mt792x_dev *dev)
INIT_WORK(&dev->reset_work, mt7925_mac_reset_work);
INIT_WORK(&dev->init_work, mt7925_init_work);
INIT_WORK(&dev->nan_deferred_work, mt7925_nan_deferred_work);
spin_lock_init(&dev->nan_deferred_lock);
INIT_WORK(&dev->phy.roc_work, mt7925_roc_work);
timer_setup(&dev->phy.roc_timer, mt792x_roc_timer, 0);

View File

@ -1503,7 +1503,7 @@ mt7925_vif_connect_iter(void *priv, u8 *mac,
true, NULL);
mt7925_mcu_sta_update(dev, NULL, vif,
&mvif->sta.deflink, true,
MT76_STA_INFO_STATE_NONE);
MT76_STA_INFO_STATE_NONE, NULL);
mt7925_mcu_uni_add_beacon_offload(dev, hw, vif, true);
}
}
@ -1688,11 +1688,14 @@ void mt7925_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
u16 idx;
idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
rcu_read_lock();
wcid = __mt76_wcid_ptr(mdev, idx);
sta = wcid_to_sta(wcid);
if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
mt7925_tx_check_aggr(sta, e->skb, wcid);
rcu_read_unlock();
skb_pull(e->skb, headroom);
mt76_tx_complete_skb(mdev, e->wcid, e->skb);

View File

@ -840,9 +840,9 @@ static int mt7925_config(struct ieee80211_hw *hw, int radio_idx, u32 changed)
}
if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_sniffer_interface_iter, dev);
ieee80211_iterate_active_interfaces_mtx(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_sniffer_interface_iter, dev);
}
out:
@ -856,11 +856,8 @@ static void mt7925_configure_filter(struct ieee80211_hw *hw,
unsigned int *total_flags,
u64 multicast)
{
#define MT7925_FILTER_FCSFAIL BIT(2)
#define MT7925_FILTER_CONTROL BIT(5)
#define MT7925_FILTER_OTHER_BSS BIT(6)
#define MT7925_FILTER_ENABLE BIT(31)
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_phy *phy = mt792x_hw_phy(hw);
u32 flags = MT7925_FILTER_ENABLE;
#define MT7925_FILTER(_fif, _type) do { \
@ -872,6 +869,8 @@ static void mt7925_configure_filter(struct ieee80211_hw *hw,
MT7925_FILTER(FIF_CONTROL, CONTROL);
MT7925_FILTER(FIF_OTHER_BSS, OTHER_BSS);
phy->rxfilter = flags;
mt792x_mutex_acquire(dev);
mt7925_mcu_set_rxfilter(dev, flags, 0, 0);
mt792x_mutex_release(dev);
@ -964,6 +963,21 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
/* NAN_DATA (NDI) peers skip association - fill link_sta caps
* from sband and push BSS_INFO with correct phymode + RLM.
*/
if (vif->type == NL80211_IFTYPE_NAN_DATA) {
struct ieee80211_chanctx_conf *nan_ctx;
nan_ctx = mt7925_nan_seed_link_sta(dev, link_sta);
mconf->mt76.ctx = nan_ctx;
ret = mt7925_mcu_add_bss_info(&dev->phy, nan_ctx,
link_conf, link_sta, true);
if (ret)
goto out_pm;
}
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
struct mt792x_link_sta *mlink_bc;
@ -991,7 +1005,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
link_sta == mlink->pri_link) {
ret = mt7925_mcu_sta_update(dev, link_sta, vif,
mlink, true,
MT76_STA_INFO_STATE_NONE);
MT76_STA_INFO_STATE_NONE, NULL);
if (ret)
goto out_pm;
} else if (ieee80211_vif_is_mld(vif) &&
@ -1013,19 +1027,19 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
pri_mlink, true,
MT76_STA_INFO_STATE_ASSOC);
MT76_STA_INFO_STATE_ASSOC, mlink);
if (ret)
goto out_pm;
ret = mt7925_mcu_sta_update(dev, link_sta, vif,
mlink, true,
MT76_STA_INFO_STATE_ASSOC);
MT76_STA_INFO_STATE_ASSOC, mlink);
if (ret)
goto out_pm;
} else {
ret = mt7925_mcu_sta_update(dev, link_sta, vif,
mlink, true,
MT76_STA_INFO_STATE_NONE);
MT76_STA_INFO_STATE_NONE, NULL);
if (ret)
goto out_pm;
}
@ -1233,7 +1247,7 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
memset(mlink->airtime_ac, 0, sizeof(mlink->airtime_ac));
mt7925_mcu_sta_update(dev, link_sta, vif, mlink, true,
MT76_STA_INFO_STATE_ASSOC);
MT76_STA_INFO_STATE_ASSOC, NULL);
mt792x_mutex_release(dev);
}
@ -1243,6 +1257,13 @@ int mt7925_mac_sta_event(struct mt76_dev *mdev, struct ieee80211_vif *vif,
{
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct ieee80211_link_sta *link_sta = &sta->deflink;
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
if (mvif->roc_join_held && !sta->tdls &&
(ev == MT76_STA_EVENT_AUTHORIZE || ev == MT76_STA_EVENT_DISASSOC)) {
mvif->roc_join_held = false;
mt7925_abort_roc(mvif->phy, &mvif->bss_conf);
}
switch (ev) {
case MT76_STA_EVENT_ASSOC:
@ -1293,7 +1314,7 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
mt76_connac_pm_wake(&dev->mphy, &dev->pm);
mt7925_mcu_sta_update(dev, link_sta, vif, mlink, false,
MT76_STA_INFO_STATE_NONE);
MT76_STA_INFO_STATE_NONE, NULL);
mt7925_mac_wtbl_update(dev, mlink->wcid.idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
@ -1438,6 +1459,7 @@ void mt7925_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (vif->type == NL80211_IFTYPE_STATION) {
mvif->wep_sta = NULL;
mvif->roc_join_held = false;
ewma_rssi_init(&mvif->bss_conf.rssi);
}
@ -1717,10 +1739,10 @@ static int mt7925_suspend(struct ieee80211_hw *hw,
mt792x_mutex_acquire(dev);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_mcu_set_suspend_iter,
&dev->mphy);
ieee80211_iterate_active_interfaces_mtx(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_mcu_set_suspend_iter,
&dev->mphy);
mt792x_mutex_release(dev);
@ -1735,10 +1757,10 @@ static int mt7925_resume(struct ieee80211_hw *hw)
mt792x_mutex_acquire(dev);
set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
ieee80211_iterate_active_interfaces(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_mcu_set_suspend_iter,
&dev->mphy);
ieee80211_iterate_active_interfaces_mtx(hw,
IEEE80211_IFACE_ITER_RESUME_ALL,
mt7925_mcu_set_suspend_iter,
&dev->mphy);
ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
MT792x_WATCHDOG_TIME);
@ -1964,7 +1986,7 @@ mt7925_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
err = mt7925_mcu_sta_update(dev, NULL, vif,
&mvif->sta.deflink, true,
MT76_STA_INFO_STATE_NONE);
MT76_STA_INFO_STATE_NONE, NULL);
out:
mt792x_mutex_release(dev);
@ -2063,6 +2085,7 @@ mt7925_change_chanctx(struct ieee80211_hw *hw,
link_conf, ctx);
}
}
mt76_phy_chandef_set(mvif->phy->mt76, &ctx->def);
mt792x_mutex_release(phy->dev);
}
@ -2089,6 +2112,19 @@ static void mt7925_mgd_complete_tx(struct ieee80211_hw *hw,
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
/* Keep the join ROC until the station is authorized, so that it
* covers the 4-way handshake. mt7925_mac_sta_event() releases it.
* On MLD, the active ROC is the MLO ROC, which must be released
* before the link activation work sets its own.
*/
if (vif->type == NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) &&
info->success &&
(info->subtype == IEEE80211_STYPE_ASSOC_REQ ||
info->subtype == IEEE80211_STYPE_REASSOC_REQ)) {
mvif->roc_join_held = true;
return;
}
mt7925_abort_roc(mvif->phy, &mvif->bss_conf);
}
@ -2108,7 +2144,7 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ASSOC) {
mt7925_mcu_sta_update(dev, NULL, vif,
&mvif->sta.deflink, true,
MT76_STA_INFO_STATE_ASSOC);
MT76_STA_INFO_STATE_ASSOC, NULL);
mt7925_mcu_set_beacon_filter(dev, vif, vif->cfg.assoc);
if (ieee80211_vif_is_mld(vif))
@ -2411,6 +2447,7 @@ static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw,
mconf->mt76.ctx = ctx;
mctx->bss_conf = mconf;
mt76_phy_chandef_set(mvif->phy->mt76, &ctx->def);
mutex_unlock(&dev->mt76.mutex);
return 0;
@ -2599,26 +2636,18 @@ static int mt7925_start_nan(struct ieee80211_hw *hw,
cfg80211_chandef_create(&link_conf->chanreq.oper, chan,
NL80211_CHAN_NO_HT);
err = mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf,
NULL, true);
err = mt7925_mcu_add_bss_info(&dev->phy, NULL,
link_conf, NULL, true);
if (err < 0)
goto out;
dev->nan_vif = vif;
err = mt7925_nan_set_nmi_addr(dev, vif->addr);
if (err)
goto rollback_bss;
err = mt7925_nan_enable(vif, dev, conf);
if (err)
goto rollback_bss;
if (err) {
mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false);
goto out;
}
goto out;
rollback_bss:
dev->nan_vif = NULL;
mt7925_mcu_add_bss_info(&dev->phy, NULL, link_conf, NULL, false);
err = mt7925_nan_update_phy_setting(dev);
out:
mt792x_mutex_release(dev);
@ -2633,6 +2662,13 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,
struct mt792x_dev *dev = mt792x_hw_dev(hw);
int err, ret;
/* Drop a deferred event queued just before stop so a stale cluster_id
* cannot leak into a restart; the work re-checks liveness anyway.
*/
spin_lock_bh(&dev->nan_deferred_lock);
dev->nan_deferred_pending = 0;
spin_unlock_bh(&dev->nan_deferred_lock);
mt792x_mutex_acquire(dev);
err = mt7925_nan_disable(vif, dev);
@ -2642,9 +2678,6 @@ static int mt7925_stop_nan(struct ieee80211_hw *hw,
if (!err)
err = ret;
if (dev->nan_vif == vif)
dev->nan_vif = NULL;
mt792x_mutex_release(dev);
return err;

View File

@ -1914,11 +1914,9 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb,
phy = (struct sta_rec_phy *)tlv;
if (mt7925_vif_is_nan(vif)) {
enum nl80211_band band = chandef->chan ? chandef->chan->band
: NL80211_BAND_2GHZ;
phy->phy_type = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_ERP;
phy->phy_type |= mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif,
band,
NL80211_BAND_5GHZ,
link_sta);
} else {
phy->phy_type = mt76_connac_get_phy_mode_v2(mvif->phy->mt76, vif,
@ -2003,7 +2001,11 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb,
ra_info = (struct sta_rec_ra_info *)tlv;
if (mt7925_vif_is_nan(vif))
band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ;
/* NAN is OFDM-only per spec; borrow the 5 GHz band lookup to
* avoid PHY_TYPE_BIT_HR_DSSS/CCK bits being added to phy_type.
* NAN interfaces have no chanctx, so chandef->chan is always NULL.
*/
band = NL80211_BAND_5GHZ;
else
band = chandef->chan->band;
@ -2063,14 +2065,18 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct mt792x_bss_conf *mconf,
struct mt792x_link_sta *mlink)
struct mt792x_link_sta *mlink,
struct mt792x_link_sta *pending)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_sta *msta = (struct mt792x_sta *)sta->drv_priv;
struct mt792x_dev *dev = mvif->phy->dev;
unsigned long valid = msta->valid_links;
struct mt792x_bss_conf *mconf_pri;
struct sta_rec_mld *mld;
unsigned int link_id;
struct tlv *tlv;
u8 max_links;
u8 cnt = 0;
/* Primary link always uses driver's deflink WCID. */
@ -2099,11 +2105,38 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
mld->link[cnt].wlan_id = cpu_to_le16(msta->deflink.wcid.idx);
mld->link[cnt++].bss_idx = mconf_pri->mt76.idx;
/* Optionally encode the currently-updated secondary link. */
if (mlink && mlink != &msta->deflink && mconf) {
mld->secondary_id = cpu_to_le16(mlink->wcid.idx);
mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx);
mld->link[cnt++].bss_idx = mconf->mt76.idx;
max_links = ARRAY_SIZE(mld->link);
/* A link being added is not set in msta->valid_links yet */
if (pending && pending != &msta->deflink)
valid |= BIT(pending->wcid.link_id);
for_each_set_bit(link_id, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt792x_link_sta *mlink_sec;
struct mt792x_bss_conf *mconf_sec;
if (cnt == max_links)
break;
if (link_id == msta->deflink_id)
continue;
mlink_sec = mt792x_sta_to_link(msta, link_id);
if (!mlink_sec && pending && link_id == pending->wcid.link_id)
mlink_sec = pending;
if (!mlink_sec || mlink_sec == &msta->deflink)
continue;
mconf_sec = rcu_dereference_protected(mvif->link_conf[link_id],
lockdep_is_held(&dev->mt76.mutex));
if (!mconf_sec)
continue;
if (cnt == 1)
mld->secondary_id = cpu_to_le16(mlink_sec->wcid.idx);
mld->link[cnt].wlan_id = cpu_to_le16(mlink_sec->wcid.idx);
mld->link[cnt++].bss_idx = mconf_sec->mt76.idx;
}
mld->link_num = cnt;
@ -2122,7 +2155,8 @@ mt7925_mcu_sta_remove_tlv(struct sk_buff *skb)
static int
mt7925_mcu_sta_cmd(struct mt76_phy *phy,
struct mt76_sta_cmd_info *info)
struct mt76_sta_cmd_info *info,
struct mt792x_link_sta *pending)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)info->vif->drv_priv;
struct mt76_dev *dev = phy->dev;
@ -2163,7 +2197,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
if (info->state != MT76_STA_INFO_STATE_NONE) {
mt7925_mcu_sta_mld_tlv(skb, info->vif,
info->link_sta->sta,
mconf, mlink);
mconf, mlink, pending);
mt7925_mcu_sta_eht_mld_tlv(skb, info->vif, info->link_sta->sta);
}
@ -2188,7 +2222,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
struct mt792x_link_sta *mlink,
bool enable,
enum mt76_sta_info_state state)
enum mt76_sta_info_state state,
struct mt792x_link_sta *pending)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
int rssi = -ewma_rssi_read(&mvif->bss_conf.rssi);
@ -2206,7 +2241,7 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
info.wcid = &mlink->wcid;
info.newly = state != MT76_STA_INFO_STATE_ASSOC;
return mt7925_mcu_sta_cmd(&dev->mphy, &info);
return mt7925_mcu_sta_cmd(&dev->mphy, &info, pending);
}
int mt7925_mcu_set_beacon_filter(struct mt792x_dev *dev,
@ -2354,7 +2389,7 @@ int mt7925_mcu_config_sniffer(struct mt792x_vif *vif,
.len = cpu_to_le16(sizeof(req.tlv)),
.control_ch = chandef->chan->hw_value,
.center_ch = ieee80211_frequency_to_channel(freq1),
.drop_err = 1,
.drop_err = !(vif->phy->rxfilter & MT7925_FILTER_FCSFAIL),
},
};
@ -2392,10 +2427,13 @@ mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev,
u8 pad[3];
} __packed hdr;
struct bcn_content_tlv {
/* DW 0 */
__le16 tag;
__le16 len;
/* DW 1 */
__le16 tim_ie_pos;
__le16 csa_ie_pos;
/* DW 2 */
__le16 bcc_ie_pos;
/* 0: disable beacon offload
* 1: enable beacon offload
@ -2406,8 +2444,9 @@ mt7925_mcu_uni_add_beacon_offload(struct mt792x_dev *dev,
* 1: only cap field IE
*/
u8 type;
/* DW 3~130 */
__le16 pkt_len;
u8 pkt[512];
u8 pkt[510];
} __packed beacon_tlv;
} req = {
.hdr = {
@ -2847,7 +2886,7 @@ mt7925_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt792x_phy *phy,
bmc = (struct bss_rate_tlv *)tlv;
if (mt7925_vif_is_nan(vif))
band = chandef->chan ? chandef->chan->band : NL80211_BAND_2GHZ;
band = NL80211_BAND_5GHZ;
else
band = chandef->chan->band;

View File

@ -7,6 +7,11 @@
#include "../mt792x.h"
#include "regs.h"
#define MT7925_FILTER_FCSFAIL BIT(2)
#define MT7925_FILTER_CONTROL BIT(5)
#define MT7925_FILTER_OTHER_BSS BIT(6)
#define MT7925_FILTER_ENABLE BIT(31)
#define MT7925_BEACON_RATES_TBL 25
#define MT7925_TX_RING_SIZE 2048
@ -286,7 +291,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
struct ieee80211_vif *vif,
struct mt792x_link_sta *mlink,
bool enable,
enum mt76_sta_info_state state);
enum mt76_sta_info_state state,
struct mt792x_link_sta *pending);
int mt7925_mcu_set_chan_info(struct mt792x_phy *phy, u16 tag);
int mt7925_mcu_set_tx(struct mt792x_dev *dev, struct ieee80211_bss_conf *bss_conf);
int mt7925_mcu_set_eeprom(struct mt792x_dev *dev);
@ -353,6 +359,7 @@ int mt7925_mcu_parse_response(struct mt76_dev *mdev, int cmd,
int mt7925e_mac_reset(struct mt792x_dev *dev);
int mt7925e_mcu_init(struct mt792x_dev *dev);
void mt7925e_axidma_cal_cache_init(struct mt792x_dev *dev);
void mt7925_mac_add_txs(struct mt792x_dev *dev, void *data);
void mt7928_mac_add_txs_msg(struct mt792x_dev *dev, void *evt);
void mt7925_set_runtime_pm(struct mt792x_dev *dev);
@ -361,6 +368,7 @@ void mt7925_mcu_set_suspend_iter(void *priv, u8 *mac,
void mt7925_connac_mcu_set_suspend_iter(void *priv, u8 *mac,
struct ieee80211_vif *vif);
void mt7925_set_ipv6_ns_work(struct work_struct *work);
void mt7925_nan_deferred_work(struct work_struct *work);
int mt7925_mcu_set_sniffer(struct mt792x_dev *dev, struct ieee80211_vif *vif,
bool enable);

View File

@ -32,8 +32,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,
if (!mt7925_regd_is_valid_channel(dev, NL80211_BAND_5GHZ, chan))
return;
req->config_support_5g = 1;
req->support_5g_val = 1;
req->config_5g_channel = 1;
if (chan->hw_value == NAN_5G_LOW_DISC_CHANNEL)
@ -44,73 +42,6 @@ static void mt7925_nan_set_5g_channel(struct mt792x_dev *dev,
req->channel_5g_val = cpu_to_le32(ch5g);
}
static void mt7925_nan_set_2g_support(struct mt7925_nan_enable_req_tlv *req,
struct cfg80211_nan_conf *conf)
{
if (!conf->band_cfgs[NL80211_BAND_2GHZ].chan)
return;
req->config_2dot4g_support = 1;
req->support_2dot4g_val = 1;
}
static void mt7925_nan_set_cluster_id(struct mt7925_nan_enable_req_tlv *req,
const u8 *cluster_id)
{
if (!cluster_id)
return;
req->cluster_high = cpu_to_le16(cluster_id[4] | cluster_id[5] << 8);
req->cluster_low = cpu_to_le16((u16)cluster_id[3]);
}
static void mt7925_nan_set_dw_interval(struct mt7925_nan_enable_req_tlv *req,
struct cfg80211_nan_conf *conf)
{
if (conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval > 0) {
req->config_dw.config_2dot4g_dw_band = 1;
req->config_dw.dw_2dot4g_interval_val =
cpu_to_le32(conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval);
}
if (conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval > 0) {
req->config_dw.config_5g_dw_band = 1;
req->config_dw.dw_5g_interval_val =
cpu_to_le32(conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval);
}
}
static void mt7925_nan_set_disc_beacon(struct mt7925_nan_enable_req_tlv *req,
struct cfg80211_nan_conf *conf)
{
if (conf->discovery_beacon_interval > 0) {
req->config_2dot4g_beacons = true;
req->beacon_2dot4g_val = conf->discovery_beacon_interval;
}
}
static void mt7925_nan_set_rssi_thresholds(struct mt7925_nan_enable_req_tlv *req,
struct cfg80211_nan_conf *conf)
{
if (conf->band_cfgs[NL80211_BAND_2GHZ].chan) {
req->config_2dot4g_rssi_close = 1;
req->rssi_close_2dot4g_val =
abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close);
req->config_2dot4g_rssi_middle = 1;
req->rssi_middle_2dot4g_val =
abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle);
}
if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) {
req->config_5g_rssi_close = 1;
req->rssi_close_5g_val =
abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close);
req->config_5g_rssi_middle = 1;
req->rssi_middle_5g_val =
abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle);
}
}
static void mt7925_nan_set_scan_params(struct mt7925_nan_enable_req_tlv *req,
struct cfg80211_nan_conf *conf)
{
@ -144,101 +75,6 @@ mt7925_nan_update_conf(struct mt792x_vif *mvif,
memcpy(mvif->nan.conf.cluster_id, conf->cluster_id, ETH_ALEN);
}
int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr)
{
struct mt76_dev *mdev;
struct {
u8 rsv[4];
struct mt7925_nan_nmi_addr_tlv nmi_addr_tlv;
} nmi_cmd = {
.rsv = { 0 },
.nmi_addr_tlv = {
.tag = cpu_to_le16(NAN_UNI_CMD_CHANGE_NMI_ADDRESS),
.len = cpu_to_le16(sizeof(struct mt7925_nan_nmi_addr_tlv)),
},
};
int ret;
if (!dev || !addr)
return -EINVAL;
if (is_zero_ether_addr(addr) || is_multicast_ether_addr(addr)) {
dev_err(dev->mt76.dev, "NAN: invalid NMI address %pM\n", addr);
return -EINVAL;
}
mdev = &dev->mt76;
memcpy(nmi_cmd.nmi_addr_tlv.nmi_addr, addr, ETH_ALEN);
ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nmi_cmd,
sizeof(nmi_cmd), true);
return ret;
}
int mt7925_nan_enable(struct ieee80211_vif *vif,
struct mt792x_dev *dev,
struct cfg80211_nan_conf *conf)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt76_dev *mdev = &dev->mt76;
struct {
u8 rsv[4];
struct mt7925_nan_enable_req_tlv nan_req_tlv;
} nan_cmd = {
.rsv = { 0 },
.nan_req_tlv = {
.tag = cpu_to_le16(NAN_UNI_CMD_ENABLE_REQUEST),
.len = cpu_to_le16(sizeof(struct mt7925_nan_enable_req_tlv)),
.config_random_factor_force = 0,
.random_factor_force_val = 0,
.config_hop_count_force = 0,
.hop_count_force_val = 0,
},
};
struct mt7925_nan_enable_req_tlv *p_nan_req_tlv = &nan_cmd.nan_req_tlv;
int ret;
if (!vif || !dev || !conf)
return -EINVAL;
p_nan_req_tlv->master_pref = conf->master_pref;
mt7925_nan_set_2g_support(p_nan_req_tlv, conf);
mt7925_nan_set_5g_channel(dev, p_nan_req_tlv, conf);
mt7925_nan_set_cluster_id(p_nan_req_tlv, conf->cluster_id);
mt7925_nan_set_dw_interval(p_nan_req_tlv, conf);
mt7925_nan_set_disc_beacon(p_nan_req_tlv, conf);
mt7925_nan_set_rssi_thresholds(p_nan_req_tlv, conf);
mt7925_nan_set_scan_params(p_nan_req_tlv, conf);
mt7925_nan_update_conf(mvif, conf);
ret = mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
return ret;
}
int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
struct {
u8 rsv[4];
struct tlv nan_dis_tlv;
} nan_cmd = {
.rsv = { 0 },
.nan_dis_tlv = {
.tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),
.len = cpu_to_le16(sizeof(struct tlv)),
},
};
if (!dev)
return -EINVAL;
return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
}
static int
mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref)
{
@ -255,9 +91,6 @@ mt7925_nan_mp_tlv(struct sk_buff *skb, u8 master_pref)
mp_tlv = (struct mt7925_nan_master_preference_tlv *)tlv;
if (master_pref > NAN_MAX_MASTER_PREFERENCE)
return 0;
mp_tlv->master_preference = master_pref;
return 0;
@ -357,6 +190,213 @@ mt7925_nan_sync_rssi_tlv(struct sk_buff *skb, struct cfg80211_nan_conf *conf)
return 0;
}
/* FW rate set bit definitions (matches FW wlan_def_cmm.h) */
#define NAN_RATE_SET_BIT_1M BIT(0)
#define NAN_RATE_SET_BIT_2M BIT(1)
#define NAN_RATE_SET_BIT_5_5M BIT(2)
#define NAN_RATE_SET_BIT_11M BIT(3)
#define NAN_RATE_SET_BIT_6M BIT(6)
#define NAN_RATE_SET_BIT_9M BIT(7)
#define NAN_RATE_SET_BIT_12M BIT(8)
#define NAN_RATE_SET_BIT_18M BIT(9)
#define NAN_RATE_SET_BIT_24M BIT(10)
#define NAN_RATE_SET_BIT_36M BIT(11)
#define NAN_RATE_SET_BIT_48M BIT(12)
#define NAN_RATE_SET_BIT_54M BIT(13)
#define NAN_RATE_SET_ALL_A (NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_9M | \
NAN_RATE_SET_BIT_12M | NAN_RATE_SET_BIT_18M | \
NAN_RATE_SET_BIT_24M | NAN_RATE_SET_BIT_36M | \
NAN_RATE_SET_BIT_48M | NAN_RATE_SET_BIT_54M)
/* 5G basic: 6M+12M+24M (OFDM) */
#define NAN_BASIC_RATE_SET_5G (NAN_RATE_SET_BIT_6M | NAN_RATE_SET_BIT_12M | \
NAN_RATE_SET_BIT_24M)
/* GF_MODE_DISALLOWED = 2, RIFS_MODE_DISALLOWED = 1 */
#define NAN_GF_MODE_DISALLOWED 2
#define NAN_RIFS_MODE_DISALLOWED 1
int mt7925_nan_update_phy_setting(struct mt792x_dev *dev)
{
struct mt76_phy *mphy = &dev->mphy;
struct ieee80211_supported_band *sband_5g;
struct mt7925_nan_phy_setting *phy;
struct {
u8 rsv[4];
struct mt7925_nan_update_phy_setting_tlv tlv;
} req = {};
sband_5g = mphy->hw->wiphy->bands[NL80211_BAND_5GHZ];
req.tlv.tag = cpu_to_le16(NAN_UNI_CMD_UPDATE_PHY_SETTING);
req.tlv.len = cpu_to_le16(sizeof(req.tlv));
/* 2G: ERP + HT (no CCK/HR_DSSS - NAN uses OFDM only) */
phy = &req.tlv.phy_2g;
phy->phy_type_set = PHY_TYPE_BIT_ERP | PHY_TYPE_BIT_HT;
phy->non_ht_basic_phy_type = PHY_TYPE_ERP_INDEX;
phy->use_short_preamble = 1;
phy->use_short_slot_time = 1;
phy->operational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A);
phy->bss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G);
phy->gf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED);
phy->rifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED);
/* 5G: OFDM + HT + VHT (NAN_MODE_11A) */
phy = &req.tlv.phy_5g;
phy->phy_type_set = PHY_TYPE_BIT_OFDM | PHY_TYPE_BIT_HT |
PHY_TYPE_BIT_VHT;
phy->non_ht_basic_phy_type = PHY_TYPE_OFDM_INDEX;
phy->use_short_preamble = 1;
phy->use_short_slot_time = 1;
phy->operational_rate_set = cpu_to_le16(NAN_RATE_SET_ALL_A);
phy->bss_basic_rate_set = cpu_to_le16(NAN_BASIC_RATE_SET_5G);
phy->gf_operation_mode = cpu_to_le32(NAN_GF_MODE_DISALLOWED);
phy->rifs_operation_mode = cpu_to_le32(NAN_RIFS_MODE_DISALLOWED);
/* VHT basic MCS set from sband capability */
if (sband_5g && sband_5g->vht_cap.vht_supported)
phy->vht_basic_mcs_set =
sband_5g->vht_cap.vht_mcs.rx_mcs_map;
return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(NAN),
&req, sizeof(req), true);
}
struct ieee80211_chanctx_conf *
mt7925_nan_seed_link_sta(struct mt792x_dev *dev,
struct ieee80211_link_sta *link_sta)
{
struct ieee80211_supported_band *sband_2g, *sband_5g;
struct ieee80211_chanctx_conf *nan_ctx = NULL;
struct ieee80211_vif *nan_vif = dev->nan_vif;
/* Fill HT cap from 2G sband */
sband_2g = dev->mphy.hw->wiphy->bands[NL80211_BAND_2GHZ];
sband_5g = dev->mphy.hw->wiphy->bands[NL80211_BAND_5GHZ];
if (sband_2g)
link_sta->ht_cap = sband_2g->ht_cap;
link_sta->sta->wme = true;
link_sta->rx_nss = hweight8(dev->mphy.antenna_mask);
/* Get chanctx from NAN schedule.
* Prefer 5G committed slot for wider BW (VHT), fallback
* to first valid slot if no 5G data slot is scheduled.
*/
if (nan_vif) {
struct ieee80211_nan_channel **slots =
nan_vif->cfg.nan_sched.schedule;
int i;
for (i = 0; i < CFG80211_NAN_SCHED_NUM_TIME_SLOTS; i++) {
struct ieee80211_chanctx_conf *ctx;
if (!slots[i] || IS_ERR(slots[i]) ||
!slots[i]->chanctx_conf)
continue;
ctx = slots[i]->chanctx_conf;
if (!nan_ctx)
nan_ctx = ctx;
if (ctx->def.chan->band == NL80211_BAND_5GHZ) {
nan_ctx = ctx;
break;
}
}
}
/* Capability describes what the device can do and must not be
* filtered by the current schedule - firmware gates the VHT rate
* mode per the data schedule and re-derives it on schedule
* change, which only works if the caps are present up front.
*/
if (sband_5g)
link_sta->vht_cap = sband_5g->vht_cap;
/* Bandwidth here is the capability ceiling, not the operating
* width - the per-slot operating bandwidth follows the current
* slot channel via the firmware RLM sync, so deriving it from
* the schedule at STA-add time would cap a later 5 GHz schedule
* at the bring-up width.
*/
link_sta->bandwidth = IEEE80211_STA_RX_BW_80;
return nan_ctx;
}
int mt7925_nan_enable(struct ieee80211_vif *vif,
struct mt792x_dev *dev,
struct cfg80211_nan_conf *conf)
{
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt76_dev *mdev = &dev->mt76;
struct mt7925_nan_common_hdr *hdr;
struct mt7925_nan_enable_req_tlv *req;
struct sk_buff *skb;
if (!vif || !dev || !conf)
return -EINVAL;
skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_ENABLE_MAX_SIZE);
if (!skb)
return -ENOMEM;
hdr = (struct mt7925_nan_common_hdr *)skb_put(skb, sizeof(*hdr));
memset(hdr, 0, sizeof(*hdr));
/* Set cluster id before joining cluster */
if (mt7925_nan_cluster_id_tlv(skb, conf->cluster_id)) {
dev_kfree_skb(skb);
return -ENOMEM;
}
/* NAN enable request tlv */
req = (struct mt7925_nan_enable_req_tlv *)
mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_ENABLE_REQUEST,
sizeof(*req));
if (!req) {
dev_kfree_skb(skb);
return -ENOMEM;
}
req->master_pref = conf->master_pref;
mt7925_nan_set_5g_channel(dev, req, conf);
mt7925_nan_set_scan_params(req, conf);
if (mt7925_nan_dw_tlv(skb, conf) ||
mt7925_nan_sync_rssi_tlv(skb, conf)) {
dev_kfree_skb(skb);
return -ENOMEM;
}
mt7925_nan_update_conf(mvif, conf);
return mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
}
int mt7925_nan_disable(struct ieee80211_vif *vif, struct mt792x_dev *dev)
{
struct mt76_dev *mdev = &dev->mt76;
struct {
u8 rsv[4];
struct tlv nan_dis_tlv;
} nan_cmd = {
.rsv = { 0 },
.nan_dis_tlv = {
.tag = cpu_to_le16(NAN_UNI_CMD_DISABLE_REQUEST),
.len = cpu_to_le16(sizeof(struct tlv)),
},
};
if (!dev)
return -EINVAL;
return mt76_mcu_send_msg(mdev, MCU_UNI_CMD(NAN), &nan_cmd, sizeof(nan_cmd), true);
}
int mt7925_nan_change_configure(struct ieee80211_vif *vif,
struct mt792x_dev *dev,
struct cfg80211_nan_conf *conf)
@ -473,9 +513,27 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
dev_dbg(dev->mt76.dev, "nan: evt=%u cluster=%pM\n",
de_evt->event_type, de_evt->cluster_id);
if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER)
if (de_evt->event_type != NAN_EVENT_ID_JOINED_CLUSTER &&
de_evt->event_type != NAN_EVENT_ID_STARTED_CLUSTER)
return;
/* STARTED_CLUSTER fires during NAN_START, before nan.started is set and
* before the supplicant subscribes - defer past NAN_START via the work
* so ieee80211_nan_cluster_joined() actually reaches userspace.
*/
if (de_evt->event_type == NAN_EVENT_ID_STARTED_CLUSTER) {
dev_dbg(dev->mt76.dev,
"nan: deferring STARTED_CLUSTER cluster=%pM\n",
cluster_id);
spin_lock_bh(&dev->nan_deferred_lock);
memcpy(dev->nan_started_cluster_id, cluster_id, ETH_ALEN);
set_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER,
&dev->nan_deferred_pending);
spin_unlock_bh(&dev->nan_deferred_lock);
ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work);
return;
}
if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif)) {
dev_warn(dev->mt76.dev, "nan: joined-cluster event but NAN not started\n");
return;
@ -487,7 +545,110 @@ mt7925_nan_mcu_handle_de_event(struct mt792x_dev *dev, struct tlv *tlv)
dev_dbg(dev->mt76.dev, "nan: own_nmi=%pM master_nmi=%pM\n",
de_evt->own_nmi, de_evt->master_nmi);
ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, true, GFP_KERNEL);
/* joined an existing cluster, not a self-anchored new one */
ieee80211_nan_cluster_joined(dev->nan_vif, cluster_id, false, GFP_KERNEL);
}
/* Runs the deferred NAN MCU events in process context; takes wiphy_lock
* before nan_vif, which the NAN stop path frees under that mutex.
*/
void
mt7925_nan_deferred_work(struct work_struct *work)
{
struct mt792x_dev *dev = container_of(work, struct mt792x_dev,
nan_deferred_work);
struct ieee80211_vif *vif;
unsigned long pending;
u8 cluster_id[ETH_ALEN];
spin_lock_bh(&dev->nan_deferred_lock);
pending = dev->nan_deferred_pending;
dev->nan_deferred_pending = 0;
memcpy(cluster_id, dev->nan_started_cluster_id, ETH_ALEN);
spin_unlock_bh(&dev->nan_deferred_lock);
if (!pending)
return;
wiphy_lock(dev->mt76.hw->wiphy);
vif = dev->nan_vif;
if (!vif || !ieee80211_vif_nan_started(vif))
goto out;
if (test_bit(MT7925_NAN_DEFERRED_STARTED_CLUSTER, &pending))
ieee80211_nan_cluster_joined(vif, cluster_id, true, GFP_KERNEL);
if (test_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &pending))
ieee80211_nan_sched_update_done(vif);
out:
wiphy_unlock(dev->mt76.hw->wiphy);
}
static void
mt7925_nan_handle_ulw_update(struct mt792x_dev *dev, struct tlv *tlv)
{
struct mt7925_nan_ulw_event *evt;
struct mt7925_nan_ulw_attr attr;
struct wireless_dev *wdev;
u16 len;
if (!dev || !tlv)
return;
if (!dev->nan_vif || !ieee80211_vif_nan_started(dev->nan_vif))
return;
len = le16_to_cpu(tlv->len);
if (len < sizeof(*tlv) + sizeof(*evt)) {
dev_warn(dev->mt76.dev,
"nan: short ulw event tlv len=%u\n", len);
return;
}
evt = (struct mt7925_nan_ulw_event *)tlv->data;
wdev = ieee80211_vif_to_wdev(dev->nan_vif);
if (!wdev)
return;
dev_dbg(dev->mt76.dev,
"nan: ulw_update wdev=%p owner_nlportid=%u sched_id=%u seq=%u dur=%u\n",
wdev, wdev->owner_nlportid,
evt->sched_id, evt->seq_id, le32_to_cpu(evt->duration));
/* Reorder the FW fields into NAN spec Table 109 attribute layout */
attr.attr_id = NAN_ULW_ATTR_ID;
attr.length = cpu_to_le16(NAN_ULW_FIXED_PAYLOAD);
attr.sched_id = evt->sched_id;
attr.seq_id = evt->seq_id;
attr.start_time = evt->start_time;
attr.duration = evt->duration;
attr.period = evt->period;
attr.count_down = evt->count_down;
attr.ulw_overwrite = evt->ulw_overwrite;
cfg80211_nan_ulw_update(wdev, (const u8 *)&attr, sizeof(attr),
GFP_KERNEL);
}
static void
mt7925_nan_handle_sched_update_done(struct mt792x_dev *dev, struct tlv *tlv)
{
struct ieee80211_vif *vif;
if (!dev || !tlv)
return;
vif = dev->nan_vif;
if (!vif || !ieee80211_vif_nan_started(vif))
return;
/* Runs in the BH-disabled MCU-event RX path; the mac80211 helper needs
* the wiphy mutex and may sleep, so hand it to the work instead.
*/
spin_lock_bh(&dev->nan_deferred_lock);
set_bit(MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE, &dev->nan_deferred_pending);
spin_unlock_bh(&dev->nan_deferred_lock);
ieee80211_queue_work(dev->mt76.hw, &dev->nan_deferred_work);
}
void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
@ -515,9 +676,15 @@ void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb)
case NAN_UNI_EVENT_ID_DE_EVENT_IND:
mt7925_nan_mcu_handle_de_event(dev, tlv);
break;
case NAN_UNI_EVENT_REPORT_DW_END:
case NAN_UNI_EVENT_REPORT_DW_START:
mt7925_nan_handle_dw_ind(dev, tlv);
break;
case NAN_UNI_EVENT_ID_ULW_UPDATE:
mt7925_nan_handle_ulw_update(dev, tlv);
break;
case NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE:
mt7925_nan_handle_sched_update_done(dev, tlv);
break;
default:
break;
}
@ -555,6 +722,7 @@ static int mt7925_nan_avail_ctrl_tlv(struct sk_buff *skb,
avail_ctrl_tlv->avail_ctrl =
cpu_to_le16(ctrl & NAN_AVAIL_CTRL_CHECK_FOR_CHANGED);
avail_ctrl_tlv->seq_id = seq_id;
avail_ctrl_tlv->is_deferred = sched->deferred ? 1 : 0;
return 0;
}
@ -584,9 +752,14 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,
if (FIELD_GET(NAN_CH_CTRL_PRIMARY_CH, raw) ==
slot_chan->chan->hw_value) {
u32 map = le32_to_cpu(ch_list[j].avail_map[0]);
u32 dw;
ch_list[j].avail_map[0] = cpu_to_le32(map | BIT(i));
for (dw = 0; dw < NAN_TOTAL_DW; dw++) {
u32 map = le32_to_cpu(ch_list[j].avail_map[dw]);
ch_list[j].avail_map[dw] =
cpu_to_le32(map | BIT(i));
}
le32_add_cpu(&ch_list[j].num, 1);
is_found = true;
break;
@ -594,12 +767,18 @@ static u32 mt7925_nan_slot_to_bitmap(struct ieee80211_vif *vif,
}
if (!is_found && num_channels < NAN_TIMELINE_MGMT_CHNL_LIST_NUM) {
u32 dw;
ch_list[num_channels].ch_info =
cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_OP_CLASS,
cpu_to_le32(FIELD_PREP(NAN_CH_CTRL_CH_TYPE,
NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL) |
FIELD_PREP(NAN_CH_CTRL_OP_CLASS,
slot->channel_entry[0]) |
FIELD_PREP(NAN_CH_CTRL_PRIMARY_CH,
slot_chan->chan->hw_value));
ch_list[num_channels].avail_map[0] = cpu_to_le32(BIT(i));
for (dw = 0; dw < NAN_TOTAL_DW; dw++)
ch_list[num_channels].avail_map[dw] =
cpu_to_le32(BIT(i));
le32_add_cpu(&ch_list[num_channels].num, 1);
ch_list[num_channels].is_valid++;
num_channels++;
@ -647,15 +826,12 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
{
struct mt7925_nan_common_hdr *hdr;
struct mt76_dev *mdev;
bool deferred;
struct sk_buff *skb;
int ret = -ENOMEM;
if (!dev || !vif)
return;
mdev = &dev->mt76;
deferred = vif->cfg.nan_sched.deferred;
mt792x_mutex_acquire(dev);
@ -672,19 +848,9 @@ void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
goto out;
}
ret = mt76_mcu_skb_send_msg(mdev, skb,
MCU_UNI_CMD(NAN), true);
mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), false);
out:
mt792x_mutex_release(dev);
if (deferred) {
if (ret)
dev_err(mdev->dev,
"NAN: local schedule update failed: %d\n",
ret);
ieee80211_nan_sched_update_done(vif);
}
}
static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,
@ -712,23 +878,6 @@ static int mt7925_nan_peer_rec_tlv(struct sk_buff *skb,
return 0;
}
static u8 mt7925_nan_get_supported_bands(struct mt792x_vif *mvif)
{
struct wiphy *wiphy;
u8 bands = 0;
if (!mvif || !mvif->phy)
return BIT(NAN_SUPPORTED_BAND_ID_2P4G);
wiphy = mvif->phy->mt76->hw->wiphy;
if (wiphy->nan_supported_bands & BIT(NL80211_BAND_2GHZ))
bands |= BIT(NAN_SUPPORTED_BAND_ID_2P4G);
if (wiphy->nan_supported_bands & BIT(NL80211_BAND_5GHZ))
bands |= BIT(NAN_SUPPORTED_BAND_ID_5G);
return bands ?: BIT(NAN_SUPPORTED_BAND_ID_2P4G);
}
static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
struct ieee80211_sta *sta,
struct mt792x_sta *msta)
@ -755,8 +904,7 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
peer_cap_tlv = (struct mt7925_nan_sched_update_peer_cap_tlv *)tlv;
peer_cap_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx);
peer_cap_tlv->supported_bands =
mt7925_nan_get_supported_bands(msta->vif);
peer_cap_tlv->supported_bands = BIT(NAN_SUPPORTED_BAND_ID_2P4G);
peer_cap_tlv->max_chnl_switch_time = cpu_to_le16(sched->max_chan_switch);
for (i = 0; i < sched->n_channels; i++) {
@ -785,52 +933,40 @@ static int mt7925_nan_peer_cap_tlv(struct sk_buff *skb,
static void
mt7925_nan_fill_crb_committed(struct mt7925_nan_sched_update_crb_tlv *crb_tlv,
struct ieee80211_vif *vif,
struct ieee80211_nan_peer_sched *sched)
{
struct ieee80211_nan_sched_cfg *local_sched;
u8 local_map_id;
u32 m, slot;
if (!vif || !sched)
if (!sched)
return;
local_sched = &vif->cfg.nan_sched;
local_map_id = mt7925_nan_avail_attr_ctrl(local_sched) &
NAN_AVAIL_CTRL_MAPID;
for (m = 0; m < CFG80211_NAN_MAX_PEER_MAPS &&
m < NAN_TIMELINE_MGMT_SIZE; m++) {
struct ieee80211_nan_peer_map *map = &sched->maps[m];
struct mt7925_nan_sched_timeline *tl =
&crb_tlv->comm_faw_timeline[m];
struct ieee80211_nan_peer_map *map = &sched->maps[m];
u32 avail_map = 0;
if (map->map_id == CFG80211_NAN_INVALID_MAP_ID)
continue;
tl->map_id = map->map_id;
tl->local_map_id = local_map_id;
/*
* Convert peer schedule slots to FW avail_map bitmap.
* Each bit represents one time slot where the peer has
* committed availability. Fill all DW intervals the same.
*/
for (slot = 0; slot < CFG80211_NAN_SCHED_NUM_TIME_SLOTS;
slot++) {
struct ieee80211_nan_channel *local_ch;
struct ieee80211_nan_channel *peer_ch;
struct ieee80211_nan_channel *ch = map->slots[slot];
u32 dw;
local_ch = local_sched->schedule[slot];
peer_ch = map->slots[slot];
if (!local_ch || !local_ch->chanctx_conf ||
!peer_ch || !peer_ch->chanctx_conf)
if (!ch || !ch->chanctx_conf)
continue;
if (local_ch->chanctx_conf != peer_ch->chanctx_conf)
continue;
avail_map |= BIT(slot);
for (dw = 0; dw < NAN_TOTAL_DW; dw++)
tl->avail_map[dw] |= cpu_to_le32(BIT(slot));
}
tl->avail_map[0] = cpu_to_le32(avail_map);
}
}
@ -856,8 +992,38 @@ static int mt7925_nan_update_crb_tlv(struct sk_buff *skb,
crb_tlv->is_use_ranging = false;
crb_tlv->comm_ndc_ctrl.is_valid = false;
mt7925_nan_fill_crb_committed(crb_tlv, msta->vif->phy->dev->nan_vif,
sta->nan_sched);
mt7925_nan_fill_crb_committed(crb_tlv, sta->nan_sched);
return 0;
}
static int
mt7925_nan_peer_ulw_tlv(struct sk_buff *skb,
struct ieee80211_sta *sta,
struct mt792x_sta *msta)
{
struct mt7925_nan_update_ulw_tlv *ulw_tlv = NULL;
struct ieee80211_nan_peer_sched *sched = NULL;
struct tlv *tlv = NULL;
if (!skb || !sta || !msta)
return -EINVAL;
sched = sta->nan_sched;
if (!sched || !sched->init_ulw || !sched->ulw_size)
return 0; /* No ULW to send, not an error */
if (sched->ulw_size > NAN_ULW_MAX_SIZE)
return -EINVAL;
tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_ULW,
sizeof(struct mt7925_nan_update_ulw_tlv));
if (!tlv)
return -ENOMEM;
ulw_tlv = (struct mt7925_nan_update_ulw_tlv *)tlv;
ether_addr_copy(ulw_tlv->nmi_addr, sta->addr);
memcpy(ulw_tlv->ulw_attr, sched->init_ulw, sched->ulw_size);
return 0;
}
@ -914,6 +1080,10 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
goto free_skb;
}
ret = mt7925_nan_peer_ulw_tlv(skb, sta, msta);
if (ret)
goto free_skb;
ret = mt76_mcu_skb_send_msg(mdev, skb, MCU_UNI_CMD(NAN), true);
if (ret && idx_allocated)
goto clear_idx;
@ -935,18 +1105,18 @@ int mt792x_nan_set_peer_schedule(struct mt792x_dev *dev,
int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,
struct ieee80211_sta *sta)
{
struct mt7925_nan_sched_update_crb_tlv *crb_tlv;
struct mt7925_nan_common_hdr *hdr;
struct mt792x_sta *msta;
struct mt792x_nan *nan;
struct sk_buff *skb;
struct tlv *tlv;
int ret;
if (!mdev || !sta)
return -EINVAL;
skb = mt76_mcu_msg_alloc(mdev, NULL,
sizeof(struct mt7925_nan_common_hdr) +
sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv));
skb = mt76_mcu_msg_alloc(mdev, NULL, MT7925_NAN_PEER_MAX_SIZE);
if (!skb)
return -ENOMEM;
@ -961,6 +1131,25 @@ int mt792x_nan_set_peer_rec(struct mt76_dev *mdev,
return 0;
}
/* Send a zero-avail_map CRB TLV before deactivating the peer record so
* firmware clears the committed schedule slots for this peer. Without
* this, stale CRB entries linger and cause scheduling conflicts for
* subsequent NDP connections that reuse the same sch_idx.
*/
tlv = mt76_connac_mcu_add_tlv(skb, NAN_UNI_CMD_UPDATE_CRB,
sizeof(struct mt7925_nan_sched_update_crb_tlv));
if (!tlv) {
dev_kfree_skb(skb);
return -ENOMEM;
}
crb_tlv = (struct mt7925_nan_sched_update_crb_tlv *)tlv;
crb_tlv->sch_idx = cpu_to_le32(msta->nan_sched.sch_idx);
crb_tlv->flags = NAN_CRB_USE_DATA_PATH;
crb_tlv->is_use_ranging = false;
crb_tlv->comm_ndc_ctrl.is_valid = false;
/* avail_map is zero-initialised by mt76_connac_mcu_add_tlv */
/* Deactivate peer record and release connection index */
if (mt7925_nan_peer_rec_tlv(skb, sta, msta, false)) {
dev_kfree_skb(skb);
return -ENOMEM;
@ -984,21 +1173,17 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
struct mt7925_nan_common_hdr *hdr;
struct ieee80211_sta *nmi_sta;
struct mt792x_sta *nmi_msta;
struct mt792x_vif *mvif;
struct mt792x_sta *msta;
u8 nmi_addr[ETH_ALEN];
struct sk_buff *skb;
int ndp_ctx_id = 0;
int ret = -ENOMEM;
struct mt792x_dev *dev;
struct tlv *tlv;
if (!mdev || !vif || !sta)
return -EINVAL;
dev = container_of(mdev, struct mt792x_dev, mt76);
msta = (struct mt792x_sta *)sta->drv_priv;
mvif = (struct mt792x_vif *)vif->drv_priv;
rcu_read_lock();
nmi_sta = rcu_dereference(sta->nmi);
@ -1012,33 +1197,6 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
memcpy(nmi_addr, nmi_sta->addr, ETH_ALEN);
nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
if (!nmi_msta->nan_sched.idx_assigned) {
if (!nmi_sta->nan_sched) {
rcu_read_unlock();
dev_err(mdev->dev,
"NAN: peer schedule missing for NDI sta %pM\n",
sta->addr);
return -EAGAIN;
}
rcu_read_unlock();
ret = mt792x_nan_set_peer_schedule(dev, nmi_sta);
if (ret)
return ret;
rcu_read_lock();
nmi_sta = rcu_dereference(sta->nmi);
if (!nmi_sta) {
rcu_read_unlock();
dev_err(mdev->dev,
"NAN: NMI sta not found for NDI sta %pM\n",
sta->addr);
return -EINVAL;
}
nmi_msta = (struct mt792x_sta *)nmi_sta->drv_priv;
}
ndp_ctx_id = find_first_zero_bit(&nmi_msta->nan_sched.ndp_ctx_bitmap,
NAN_MAX_NDP_CXT);
if (ndp_ctx_id >= NAN_MAX_NDP_CXT) {
@ -1073,7 +1231,7 @@ int mt792x_nan_map_sta_rec(struct mt76_dev *mdev,
memcpy(map_tlv->nmi_addr, nmi_addr, ETH_ALEN);
map_tlv->sta_rec_idx = msta->deflink.wcid.idx;
map_tlv->ndp_ctx_id = ndp_ctx_id;
map_tlv->role_idx = cpu_to_le32(mvif->bss_conf.mt76.idx);
map_tlv->role_idx = cpu_to_le32(NAN_BSS_INDEX_BAND0);
memcpy(map_tlv->ndi_addr, vif->addr, ETH_ALEN);
ret = mt76_mcu_skb_send_msg(mdev, skb,

View File

@ -28,6 +28,13 @@
#define NAN_MAX_CONN_CFG 8
#define NAN_MAX_NDP_CXT 4
#define MT7925_NAN_ENABLE_MAX_SIZE \
(sizeof(struct mt7925_nan_common_hdr) + \
sizeof(struct mt7925_nan_enable_req_tlv) + \
sizeof(struct mt7925_nan_dw_interval_tlv) + \
sizeof(struct mt7925_nan_cluster_id_tlv) + \
sizeof(struct mt7925_nan_sync_rssi_tlv))
#define MT7925_NAN_CONF_MAX_SIZE \
(sizeof(struct mt7925_nan_common_hdr) + \
sizeof(struct mt7925_nan_master_preference_tlv) + \
@ -44,7 +51,8 @@
(sizeof(struct mt7925_nan_common_hdr) + \
sizeof(struct mt7925_nan_sched_manage_peer_rec_tlv) + \
sizeof(struct mt7925_nan_sched_update_peer_cap_tlv) + \
sizeof(struct mt7925_nan_sched_update_crb_tlv))
sizeof(struct mt7925_nan_sched_update_crb_tlv) + \
sizeof(struct mt7925_nan_update_ulw_tlv))
/* NAN Availability Attribute */
#define NAN_AVAIL_ATTR_ID_OFFSET 0
@ -65,6 +73,8 @@
#define UNII3_LOWER_BOUND 149
#define UNII3_UPPER_BOUND 165
#define NAN_BSS_INDEX_BAND0 0
enum nan_uni_cmd_tag {
NAN_UNI_CMD_SET_MASTER_PREFERENCE = 0,
NAN_UNI_CMD_ENABLE_REQUEST = 7,
@ -73,6 +83,8 @@ enum nan_uni_cmd_tag {
NAN_UNI_CMD_UPDATE_CRB = 10,
NAN_UNI_CMD_MANAGE_PEER_SCH_RECORD = 12,
NAN_UNI_CMD_MAP_STA_RECORD = 13,
NAN_UNI_CMD_UPDATE_ULW = 16,
NAN_UNI_CMD_UPDATE_PHY_SETTING = 18,
NAN_UNI_CMD_UPDATE_AVAILABILITY_CTRL = 20,
NAN_UNI_CMD_UPDATE_PEER_CAPABILITY = 21,
NAN_UNI_CMD_CHANGE_NMI_ADDRESS = 24,
@ -84,14 +96,26 @@ enum nan_uni_cmd_tag {
enum nan_uni_event_tag {
NAN_UNI_EVENT_ID_DE_EVENT_IND = 19,
NAN_UNI_EVENT_ID_ULW_UPDATE = 39,
NAN_UNI_EVENT_ID_SCHED_UPDATE_DONE = 43,
NAN_UNI_EVENT_REPORT_DW_START = 59,
NAN_UNI_EVENT_REPORT_DW_END = 60,
};
enum nan_disc_event_type {
NAN_EVENT_ID_DISC_MAC_ADDR = 0,
NAN_EVENT_ID_STARTED_CLUSTER = 1,
NAN_EVENT_ID_JOINED_CLUSTER = 2,
};
/* bit indices into mt792x_dev->nan_deferred_pending, set from the atomic
* MCU-event RX path and consumed by mt7925_nan_deferred_work()
*/
enum mt7925_nan_deferred_event {
MT7925_NAN_DEFERRED_STARTED_CLUSTER,
MT7925_NAN_DEFERRED_SCHED_UPDATE_DONE,
};
/* NAN 4.0 Table 79. Device Capability attribute format, Supported Bands */
enum nan_supported_bands {
NAN_SUPPORTED_BAND_ID_2P4G = 2,
@ -108,12 +132,15 @@ enum nan_peer_supported_bands {
NAN_SUPPORTED_BN_NUM
};
#define NAN_CH_CTRL_CH_TYPE BIT(0)
#define NAN_CH_CTRL_OP_CLASS GENMASK(15, 8)
#define NAN_CH_CTRL_PRIMARY_CH GENMASK(23, 16)
#define NAN_CRB_USE_DATA_PATH BIT(0)
#define NAN_CRB_AVAIL_6G_FORMAT GENMASK(2, 1)
#define NAN_BAND_CHANNEL_ENTRY_LIST_TYPE_CHANNEL 1
struct mt7925_nan_social_ch_scan_params {
u8 dwell_time[NAN_MAX_SOCIAL_CHANNELS];
__le16 scan_period[NAN_MAX_SOCIAL_CHANNELS];
@ -153,6 +180,32 @@ struct nan_rpt_dw_evt {
__le16 dw_num;
};
#define NAN_ULW_ATTR_ID 0x17
#define NAN_ULW_FIXED_PAYLOAD 16 /* Table 109 fixed fields */
struct mt7925_nan_ulw_event {
u8 sched_id;
u8 seq_id;
u8 count_down;
u8 ulw_overwrite;
__le32 start_time;
__le32 duration;
__le32 period;
} __packed;
/* ULW attribute laid out in NAN spec Table 109 field order */
struct mt7925_nan_ulw_attr {
u8 attr_id;
__le16 length;
u8 sched_id;
u8 seq_id;
__le32 start_time;
__le32 duration;
__le32 period;
u8 count_down;
u8 ulw_overwrite;
} __packed;
struct mt7925_nan_conf_dw {
u8 config_2dot4g_dw_band;
__le32 dw_2dot4g_interval_val;
@ -302,7 +355,7 @@ struct mt7925_nan_avail_ctrl_tlv {
__le16 len;
__le16 avail_ctrl;
u8 seq_id;
u8 reserved[1];
u8 is_deferred;
} __packed __aligned(4);
struct mt7925_nan_ch_timeline {
@ -346,8 +399,7 @@ struct mt7925_nan_sched_update_peer_cap_tlv {
struct mt7925_nan_sched_timeline {
u8 map_id;
u8 local_map_id;
u8 reserved[2];
u8 reserved[3];
union {
__le32 avail_map[NAN_TOTAL_DW];
u8 avail_block[NAN_TOTAL_DW * 4];
@ -378,6 +430,15 @@ struct mt7925_nan_sched_update_crb_tlv {
struct mt7925_nan_sched_faw_ndc_timeline faw_ndc_timeline[NAN_TIMELINE_MGMT_SIZE];
} __packed __aligned(4);
#define NAN_ULW_MAX_SIZE 256
struct mt7925_nan_update_ulw_tlv {
__le16 tag;
__le16 len;
u8 nmi_addr[ETH_ALEN];
u8 ulw_attr[NAN_ULW_MAX_SIZE];
} __packed __aligned(4);
struct mt7925_nan_sched_map_sta_rec_tlv {
__le16 tag;
__le16 len;
@ -390,6 +451,38 @@ struct mt7925_nan_sched_map_sta_rec_tlv {
u8 reserved[2];
} __packed __aligned(4);
/* Matches FW NAN_PHY_SETTING_T (enum fields are 4 bytes on ARM) */
struct mt7925_nan_phy_setting {
u8 phy_type_set;
u8 non_ht_basic_phy_type;
u8 use_short_preamble;
u8 use_short_slot_time;
__le16 operational_rate_set;
__le16 bss_basic_rate_set;
__le16 vht_basic_mcs_set;
u8 erp_protect_mode;
u8 ht_op_info1;
__le16 ht_op_info2;
__le16 ht_op_info3;
__le32 ht_protect_mode;
__le32 gf_operation_mode;
__le32 rifs_operation_mode;
} __packed;
/* Matches FW NAN_SCHED_CMD_UPDATE_PHY_PARAM_T */
struct mt7925_nan_update_phy_setting_tlv {
__le16 tag;
__le16 len;
struct mt7925_nan_phy_setting phy_2g;
struct mt7925_nan_phy_setting phy_5g;
} __packed __aligned(4);
int mt7925_nan_update_phy_setting(struct mt792x_dev *dev);
struct ieee80211_chanctx_conf *
mt7925_nan_seed_link_sta(struct mt792x_dev *dev,
struct ieee80211_link_sta *link_sta);
int mt7925_nan_enable(struct ieee80211_vif *vif,
struct mt792x_dev *dev,
struct cfg80211_nan_conf *conf);
@ -403,8 +496,6 @@ int mt7925_nan_change_configure(struct ieee80211_vif *vif,
void mt7925_nan_mcu_event(struct mt792x_dev *dev, struct sk_buff *skb);
int mt7925_nan_set_nmi_addr(struct mt792x_dev *dev, const u8 *addr);
void mt7925_nan_local_sched_changed(struct mt792x_dev *dev,
struct ieee80211_vif *vif);

View File

@ -9,6 +9,7 @@
#include "mac.h"
#include "mcu.h"
#include "regd.h"
#include "cached_cal.h"
#include "../dma.h"
static const struct pci_device_id mt7925_pci_device_table[] = {
@ -38,6 +39,62 @@ static int mt7925e_init_reset(struct mt792x_dev *dev)
return mt792x_wpdma_reset(dev, true);
}
/* Set up the factory-calibration cache in host memory. PCIe only: the FW
* reaches the buffer through AXI DMA, so it has no meaning on other buses.
* Every failure just leaves the cache off, which is not fatal.
*/
void mt7925e_axidma_cal_cache_init(struct mt792x_dev *dev)
{
if (!(dev->phy.chip_cap & MT792x_CHIP_CAP_AXIDMA_EN))
return;
if (dev->cached_cal.va) {
/* Carried-over buffer still holds FW-written cal data. */
dev->cached_cal.reused = true;
} else {
if (mt7925_axidma_alloc(dev)) {
dev_warn(dev->mt76.dev,
"AXI DMA cal cache disabled: buffer alloc failed\n");
return;
}
/* Freshly allocated buffer is zeroed: no cal data yet. */
dev->cached_cal.reused = false;
}
if (mt7925_mcu_send_axidma_info(dev)) {
dev_warn(dev->mt76.dev,
"AXI DMA cal cache disabled: info cmd to FW failed\n");
return;
}
/* Enable the bypass-cal flow so the FW reuses cached cal data
* (common / power-on group) instead of running a full calibration;
* must be set before the mapping table is sent.
*/
if (mt7925_mcu_fact_cal_set_bypass(dev, true)) {
dev_warn(dev->mt76.dev,
"AXI DMA cal cache disabled: bypass flag set failed\n");
return;
}
if (mt7925_mcu_send_fact_cal_mapping_tbl(dev)) {
dev_warn(dev->mt76.dev,
"AXI DMA cal cache disabled: mapping tbl send failed\n");
return;
}
if (mt7925_mcu_fact_cal_set_bypass(dev, false)) {
dev_warn(dev->mt76.dev,
"AXI DMA cal cache disabled: bypass flag set failed\n");
return;
}
dev_info(dev->mt76.dev,
"AXI DMA cal cache enabled (DMA=%pad, size=%u, reused=%d)\n",
&dev->cached_cal.dma_addr, dev->cached_cal.size,
dev->cached_cal.reused);
}
static void mt7925e_unregister_device(struct mt792x_dev *dev)
{
int i;
@ -47,19 +104,22 @@ static void mt7925e_unregister_device(struct mt792x_dev *dev)
if (dev->phy.chip_cap & MT792x_CHIP_CAP_WF_RF_PIN_CTRL_EVT_EN)
wiphy_rfkill_stop_polling(hw->wiphy);
cancel_work_sync(&dev->reset_work);
cancel_work_sync(&dev->init_work);
mt76_unregister_device(&dev->mt76);
set_bit(MT76_REMOVED, &dev->mphy.state);
cancel_work_sync(&dev->reset_work);
mt76_for_each_q_rx(&dev->mt76, i)
napi_disable(&dev->mt76.napi[i]);
cancel_delayed_work_sync(&pm->ps_work);
cancel_delayed_work_sync(&dev->mlo_pm_work);
cancel_work_sync(&pm->wake_work);
cancel_work_sync(&dev->nan_deferred_work);
mt7925_tx_token_put(dev);
__mt792x_mcu_drv_pmctrl(dev);
mt792x_dma_cleanup(dev);
mt792x_wfsys_reset(dev);
mt7925_axidma_free(dev);
skb_queue_purge(&dev->mt76.mcu.res_q);
tasklet_disable(&dev->mt76.irq_tasklet);
@ -493,7 +553,6 @@ static const struct mt792x_irq_map mt7925_irq_map = {
.all_complete_mask = MT7925_INT_RX_DONE_ALL,
.data_complete_mask = MT7925_INT_RX_DONE_DATA,
.wm_complete_mask = MT7925_INT_RX_DONE_WM,
.wm2_complete_mask = MT_INT_RX_DONE_WM2,
},
};
@ -587,7 +646,7 @@ static int mt7925_pci_probe(struct pci_dev *pdev,
is_mt7928_hw = (pdev->device == 0x7928 || pdev->device == 0x7935);
if (is_mt7928_hw)
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(34));
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(34));
else
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
@ -725,7 +784,6 @@ static void mt7925_pci_remove(struct pci_dev *pdev)
struct mt76_dev *mdev = pci_get_drvdata(pdev);
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
set_bit(MT76_REMOVED, &mdev->phy.state);
mt7925e_unregister_device(dev);
devm_free_irq(&pdev->dev, pdev->irq, dev);
mt76_free_device(&dev->mt76);

View File

@ -73,7 +73,9 @@ int mt7925e_mac_reset(struct mt792x_dev *dev)
const struct mt792x_irq_map *irq_map = dev->irq_map;
int i, err;
mt792xe_mcu_drv_pmctrl(dev);
err = mt792xe_mcu_drv_pmctrl(dev);
if (err)
return err;
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
@ -125,7 +127,7 @@ int mt7925e_mac_reset(struct mt792x_dev *dev)
err = mt792xe_mcu_fw_pmctrl(dev);
if (err)
return err;
goto out;
err = __mt792xe_mcu_drv_pmctrl(dev);
if (err)
@ -135,6 +137,8 @@ int mt7925e_mac_reset(struct mt792x_dev *dev)
if (err)
goto out;
mt7925e_axidma_cal_cache_init(dev);
err = mt7925_mcu_set_eeprom(dev);
if (err)
goto out;

View File

@ -46,6 +46,8 @@ int mt7925e_mcu_init(struct mt792x_dev *dev)
mt76_rmw_field(dev, dev->pcie_reg->pm, MT_PCIE_MAC_PM_L0S_DIS, 1);
err = mt7925_run_firmware(dev);
if (!err)
mt7925e_axidma_cal_cache_init(dev);
mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[MT_MCUQ_FWDL], false);

View File

@ -48,8 +48,7 @@
#define MT7925_INT_RX_DONE_DATA HOST_RX_DONE_INT_ENA2
#define MT7925_INT_RX_DONE_WM HOST_RX_DONE_INT_ENA0
#define MT7925_INT_RX_DONE_ALL (MT7925_INT_RX_DONE_DATA | \
MT7925_INT_RX_DONE_WM | \
MT_INT_RX_DONE_WM2)
MT7925_INT_RX_DONE_WM)
#define MT7927_INT_RX_DONE_DATA MT7927_RX_DONE_INT_ENA4
#define MT7927_INT_RX_DONE_WM MT7927_RX_DONE_INT_ENA6

View File

@ -147,6 +147,15 @@ static int mt7925u_mac_reset(struct mt792x_dev *dev)
return err;
}
static void mt7925u_stop(struct ieee80211_hw *hw, bool suspend)
{
struct mt792x_dev *dev = mt792x_hw_dev(hw);
cancel_delayed_work_sync(&dev->mlo_pm_work);
mt792xu_stop(hw, suspend);
}
static int mt7925u_probe(struct usb_interface *usb_intf,
const struct usb_device_id *id)
{
@ -193,7 +202,7 @@ static int mt7925u_probe(struct usb_interface *usb_intf,
if (!ops)
return -ENOMEM;
ops->stop = mt792xu_stop;
ops->stop = mt7925u_stop;
mdev = mt76_alloc_device(&usb_intf->dev, sizeof(*dev), ops, &drv_ops);
if (!mdev)
@ -348,6 +357,19 @@ static int mt7925u_resume(struct usb_interface *intf)
}
#endif /* CONFIG_PM */
static void mt7925u_disconnect(struct usb_interface *usb_intf)
{
struct mt792x_dev *dev = usb_get_intfdata(usb_intf);
/* mt792xu_disconnect() ends in mt76_free_device(), so the work has to
* go before it rather than after mt76_unregister_device() as on PCI.
*/
if (dev)
cancel_work_sync(&dev->nan_deferred_work);
mt792xu_disconnect(usb_intf);
}
MODULE_DEVICE_TABLE(usb, mt7925u_device_table);
MODULE_FIRMWARE(MT7925_FIRMWARE_WM);
MODULE_FIRMWARE(MT7925_ROM_PATCH);
@ -356,7 +378,7 @@ static struct usb_driver mt7925u_driver = {
.name = KBUILD_MODNAME,
.id_table = mt7925u_device_table,
.probe = mt7925u_probe,
.disconnect = mt792xu_disconnect,
.disconnect = mt7925u_disconnect,
#ifdef CONFIG_PM
.suspend = mt7925u_suspend,
.resume = mt7925u_resume,

View File

@ -33,6 +33,7 @@
#define MT792x_CHIP_CAP_REGD_EN BIT(5)
#define MT792x_CHIP_CAP_MLO_EN BIT(8)
#define MT792x_CHIP_CAP_MLO_EML_EN BIT(9)
#define MT792x_CHIP_CAP_AXIDMA_EN BIT(16)
/* NOTE: used to map mt76_rates. idx may change if firmware expands table */
#define MT792x_BASIC_RATES_TBL 14
@ -191,6 +192,7 @@ struct mt792x_vif {
struct mt792x_sta *wep_sta;
struct mt792x_phy *phy;
bool roc_join_held; /* join ROC kept until the STA is authorized */
u16 valid_links;
u8 deflink_id;
enum mt792x_mlo_pm_state mlo_pm_state;
@ -214,6 +216,7 @@ struct mt792x_phy {
s16 coverage_class;
u8 slottime;
u32 rxfilter;
u32 rx_ampdu_ts;
u32 ampdu_ref;
@ -342,6 +345,21 @@ struct mt792x_dev {
struct ieee80211_vif *nan_vif;
const struct ieee80211_iface_combination *iface_combinations;
int n_iface_combinations;
/* deferred NAN MCU events run out of the atomic RX path on one shared
* work; see mt7925_nan_deferred_work() and enum mt7925_nan_deferred_event
*/
struct work_struct nan_deferred_work;
/* protects @nan_deferred_pending */
spinlock_t nan_deferred_lock;
unsigned long nan_deferred_pending;
u8 nan_started_cluster_id[ETH_ALEN];
struct {
void *va;
dma_addr_t dma_addr;
u32 size;
bool reused;
} cached_cal;
};
static inline struct mt792x_bss_conf *

View File

@ -472,6 +472,7 @@ int mt792x_assign_vif_chanctx(struct ieee80211_hw *hw,
mutex_lock(&dev->mt76.mutex);
mvif->bss_conf.mt76.ctx = ctx;
mctx->bss_conf = &mvif->bss_conf;
mt76_phy_chandef_set(&dev->mphy, &ctx->def);
mutex_unlock(&dev->mt76.mutex);
return 0;
@ -857,7 +858,7 @@ int mt792x_init_wiphy(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL_GPL(mt792x_init_wiphy);
static u8
static int
mt792x_get_offload_capability(struct device *dev, const char *fw_wm)
{
const struct mt76_connac2_fw_trailer *hdr;
@ -926,13 +927,20 @@ mt792x_get_mac80211_ops(struct device *dev,
void *drv_data, u8 *fw_features)
{
struct ieee80211_ops *ops;
int ret;
ops = devm_kmemdup(dev, mac80211_ops, sizeof(struct ieee80211_ops),
GFP_KERNEL);
if (!ops)
return NULL;
*fw_features = mt792x_get_offload_capability(dev, drv_data);
ret = mt792x_get_offload_capability(dev, drv_data);
if (ret < 0) {
dev_warn(dev, "failed to read firmware offload caps: %d\n", ret);
*fw_features = 0;
} else {
*fw_features = ret;
}
if (mt792x_needs_cnm_runtime(drv_data))
*fw_features |= MT792x_FW_CAP_CNM;

View File

@ -165,14 +165,16 @@ mt792x_mac_rssi_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
int signal;
if (status->signal > 0)
signal = mt76_rx_signal(status->chains, status->chain_signal);
if (signal > 0 || signal <= -128)
return;
if (!ether_addr_equal(vif->addr, hdr->addr1))
return;
ewma_rssi_add(&mvif->bss_conf.rssi, -status->signal);
ewma_rssi_add(&mvif->bss_conf.rssi, -signal);
}
void mt792x_mac_assoc_rssi(struct mt792x_dev *dev, struct sk_buff *skb)
@ -278,6 +280,9 @@ void mt792x_reset(struct mt76_dev *mdev)
if (pm->suspended)
return;
if (test_bit(MT76_REMOVED, &mdev->phy.state))
return;
queue_work(dev->mt76.wq, &dev->reset_work);
}
EXPORT_SYMBOL_GPL(mt792x_reset);

View File

@ -502,21 +502,26 @@ void mt792xu_disconnect(struct usb_interface *usb_intf)
return;
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
clear_bit(MT76_STATE_RUNNING, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
cancel_work_sync(&dev->reset_work);
cancel_work_sync(&dev->init_work);
mt76_worker_disable(&dev->mt76.tx_worker);
mt792xu_reset_work_cleanup(dev);
if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state)) {
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
cancel_work_sync(&dev->reset_work);
set_bit(MT76_REMOVED, &dev->mphy.state);
return;
}
mt76_unregister_device(&dev->mt76);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
skb_queue_purge(&dev->mt76.mcu.res_q);
cancel_work_sync(&dev->reset_work);
mt792xu_cleanup(dev);
set_bit(MT76_REMOVED, &dev->mphy.state);

View File

@ -17,5 +17,6 @@ config MT7996_NPU
bool "MT7996 (PCIe) NPU support"
depends on MT7996E
depends on NET_AIROHA_NPU=y || MT76_CORE=NET_AIROHA_NPU
depends on NET_AIROHA=y || NET_AIROHA=n || MT76_CORE=NET_AIROHA
select MT76_NPU
default n

View File

@ -202,11 +202,12 @@ static struct mt7996_coredump *mt7996_coredump_build(struct mt7996_dev *dev)
mt7996_coredump_fw_stack(dev, dump, exception);
/* gather memory content */
dump_mem = (struct mt7996_coredump_mem *)(buf + sofar);
dump_mem->len = crash_data->memdump_buf_len;
if (coredump_memdump && crash_data->memdump_buf_len)
if (coredump_memdump && crash_data->memdump_buf_len) {
dump_mem = (struct mt7996_coredump_mem *)(buf + sofar);
dump_mem->len = crash_data->memdump_buf_len;
memcpy(dump_mem->data, crash_data->memdump_buf,
crash_data->memdump_buf_len);
}
mutex_unlock(&dev->dump_mutex);

View File

@ -13,13 +13,6 @@
/** global debugfs **/
struct hw_queue_map {
const char *name;
u8 index;
u8 pid;
u8 qid;
};
static int
mt7996_implicit_txbf_set(void *data, u64 val)
{
@ -604,87 +597,230 @@ mt7996_tx_stats_show(struct seq_file *file, void *data)
DEFINE_SHOW_ATTRIBUTE(mt7996_tx_stats);
enum {
MT_QUEUE_PORT_HIF,
MT_QUEUE_PORT_CPU,
MT_QUEUE_PORT_LMAC,
MT_QUEUE_PORT_PLE_CTRL,
};
struct mt7996_hw_queue {
const char *name;
u8 pid;
u8 qid;
u8 tgid;
};
#define MT7996_HW_QUEUE(_name, _pid, _qid, _tgid) \
{ .name = _name, .pid = MT_QUEUE_PORT_##_pid, .qid = _qid, .tgid = _tgid }
static const struct mt7996_hw_queue mt7996_ple_queues[32] = {
[0] = MT7996_HW_QUEUE("CPU Q0", CPU, 0, 0),
[1] = MT7996_HW_QUEUE("CPU Q1", CPU, 1, 0),
[2] = MT7996_HW_QUEUE("CPU Q2", CPU, 2, 0),
[3] = MT7996_HW_QUEUE("CPU Q3", CPU, 3, 0),
[4] = MT7996_HW_QUEUE("ALTX Q0", LMAC, 0x10, 0),
[5] = MT7996_HW_QUEUE("BMC Q0", LMAC, 0x11, 0),
[6] = MT7996_HW_QUEUE("BCN Q0", LMAC, 0x12, 0),
[7] = MT7996_HW_QUEUE("PSMP Q0", LMAC, 0x13, 0),
[8] = MT7996_HW_QUEUE("ALTX Q1", LMAC, 0x10, 1),
[9] = MT7996_HW_QUEUE("BMC Q1", LMAC, 0x11, 1),
[10] = MT7996_HW_QUEUE("BCN Q1", LMAC, 0x12, 1),
[11] = MT7996_HW_QUEUE("PSMP Q1", LMAC, 0x13, 1),
[12] = MT7996_HW_QUEUE("ALTX Q2", LMAC, 0x1c, 2),
[13] = MT7996_HW_QUEUE("BMC Q2", LMAC, 0x1d, 2),
[14] = MT7996_HW_QUEUE("BCN Q2", LMAC, 0x1e, 2),
[15] = MT7996_HW_QUEUE("PSMP Q2", LMAC, 0x1f, 2),
[16] = MT7996_HW_QUEUE("NAF Q", LMAC, 0x18, 0),
[17] = MT7996_HW_QUEUE("NBCN Q", LMAC, 0x19, 0),
[20] = MT7996_HW_QUEUE("FIXFID Q", LMAC, 0x1a, 0),
[28] = MT7996_HW_QUEUE("RLS4 Q", PLE_CTRL, 0x7c, 0),
[29] = MT7996_HW_QUEUE("RLS3 Q", PLE_CTRL, 0x7d, 0),
[30] = MT7996_HW_QUEUE("RLS2 Q", PLE_CTRL, 0x7e, 0),
[31] = MT7996_HW_QUEUE("RLS Q", PLE_CTRL, 0x7f, 0),
};
static const struct mt7996_hw_queue mt7996_pse_queues[32] = {
[0] = MT7996_HW_QUEUE("CPU Q0", CPU, 0, 0),
[1] = MT7996_HW_QUEUE("CPU Q1", CPU, 1, 0),
[2] = MT7996_HW_QUEUE("CPU Q2", CPU, 2, 0),
[3] = MT7996_HW_QUEUE("CPU Q3", CPU, 3, 0),
[16] = MT7996_HW_QUEUE("LMAC Q", LMAC, 0, 0),
[17] = MT7996_HW_QUEUE("MDP TX Q0", LMAC, 1, 0),
[18] = MT7996_HW_QUEUE("MDP RX Q", LMAC, 2, 0),
[19] = MT7996_HW_QUEUE("SEC TX Q0", LMAC, 3, 0),
[20] = MT7996_HW_QUEUE("SEC RX Q", LMAC, 4, 0),
[21] = MT7996_HW_QUEUE("SFD PARK Q", LMAC, 5, 0),
[22] = MT7996_HW_QUEUE("MDP TXIOC Q0", LMAC, 6, 0),
[23] = MT7996_HW_QUEUE("MDP RXIOC Q0", LMAC, 7, 0),
[24] = MT7996_HW_QUEUE("MDP TX Q1", LMAC, 0x11, 0),
[25] = MT7996_HW_QUEUE("SEC TX Q1", LMAC, 0x13, 0),
[26] = MT7996_HW_QUEUE("MDP TXIOC Q1", LMAC, 0x16, 0),
[27] = MT7996_HW_QUEUE("MDP RXIOC Q1", LMAC, 0x17, 0),
[28] = MT7996_HW_QUEUE("CPU Q4", CPU, 4, 0),
[31] = MT7996_HW_QUEUE("RLS Q", PLE_CTRL, 0x1f, 0),
};
static const struct mt7996_hw_queue mt7996_pse_queues_1[32] = {
[0] = MT7996_HW_QUEUE("MDP TDPIOC Q0", LMAC, 0x08, 0),
[1] = MT7996_HW_QUEUE("MDP RDPIOC Q0", LMAC, 0x09, 0),
[2] = MT7996_HW_QUEUE("MDP TDPIOC Q1", LMAC, 0x18, 0),
[3] = MT7996_HW_QUEUE("MDP RDPIOC Q1", LMAC, 0x19, 0),
[4] = MT7996_HW_QUEUE("MDP TDPIOC Q2", LMAC, 0x28, 0),
[5] = MT7996_HW_QUEUE("MDP RDPIOC Q2", LMAC, 0x29, 0),
[7] = MT7996_HW_QUEUE("MDP RDPIOC Q3", LMAC, 0x39, 0),
[8] = MT7996_HW_QUEUE("MDP TX Q2", LMAC, 0x21, 0),
[9] = MT7996_HW_QUEUE("SEC TX Q2", LMAC, 0x23, 0),
[10] = MT7996_HW_QUEUE("MDP TXIOC Q2", LMAC, 0x26, 0),
[11] = MT7996_HW_QUEUE("MDP RXIOC Q2", LMAC, 0x27, 0),
[15] = MT7996_HW_QUEUE("MDP RXIOC Q3", LMAC, 0x37, 0),
[16] = MT7996_HW_QUEUE("HIF Q0", HIF, 0, 0),
[17] = MT7996_HW_QUEUE("HIF Q1", HIF, 1, 0),
[18] = MT7996_HW_QUEUE("HIF Q2", HIF, 2, 0),
[19] = MT7996_HW_QUEUE("HIF Q3", HIF, 3, 0),
[20] = MT7996_HW_QUEUE("HIF Q4", HIF, 4, 0),
[21] = MT7996_HW_QUEUE("HIF Q5", HIF, 5, 0),
[22] = MT7996_HW_QUEUE("HIF Q6", HIF, 6, 0),
[23] = MT7996_HW_QUEUE("HIF Q7", HIF, 7, 0),
[24] = MT7996_HW_QUEUE("HIF Q8", HIF, 8, 0),
[25] = MT7996_HW_QUEUE("HIF Q9", HIF, 9, 0),
[26] = MT7996_HW_QUEUE("HIF Q10", HIF, 10, 0),
[27] = MT7996_HW_QUEUE("HIF Q11", HIF, 11, 0),
[28] = MT7996_HW_QUEUE("HIF Q12", HIF, 12, 0),
[29] = MT7996_HW_QUEUE("HIF Q13", HIF, 13, 0),
};
static void
mt7996_hw_queue_read(struct seq_file *s, u32 size,
const struct hw_queue_map *map)
mt7996_fl_queue_show(struct seq_file *s, struct mt7996_dev *dev, bool pse,
const struct mt7996_hw_queue *q, u16 wlan_idx)
{
struct mt7996_phy *phy = s->private;
struct mt7996_dev *dev = phy->dev;
u32 i, val;
static DEFINE_SPINLOCK(lock);
u32 val, fid, num;
val = mt76_rr(dev, MT_FL_Q_EMPTY);
for (i = 0; i < size; i++) {
u32 ctrl, head, tail, queued;
val = MT_FL_Q0_CTRL_EXECUTE |
u32_encode_bits(q->qid, MT_FL_Q0_CTRL_QID) |
u32_encode_bits(q->tgid, MT_FL_Q0_CTRL_TGID) |
u32_encode_bits(q->pid, MT_FL_Q0_CTRL_PID) |
u32_encode_bits(wlan_idx, MT_FL_Q0_CTRL_WLAN_IDX);
if (val & BIT(map[i].index))
spin_lock(&lock);
mt76_wr(dev, pse ? MT_PSE_FL_Q0_CTRL : MT_FL_Q0_CTRL, val);
fid = mt76_rr(dev, pse ? MT_PSE_FL_Q2_CTRL : MT_FL_Q2_CTRL);
num = mt76_rr(dev, pse ? MT_PSE_FL_Q3_CTRL : MT_FL_Q3_CTRL);
spin_unlock(&lock);
seq_printf(s, "tail/head fid 0x%04x/0x%04x, packets %u",
u32_get_bits(fid, MT_FL_Q2_CTRL_TAIL_FID),
u32_get_bits(fid, MT_FL_Q2_CTRL_HEAD_FID),
u32_get_bits(num, MT_FL_Q3_CTRL_PKT_NUM));
}
static void
mt7996_fl_queues_show(struct seq_file *s, struct mt7996_dev *dev, bool pse,
const struct mt7996_hw_queue *queues, unsigned long empty)
{
unsigned int i;
for_each_clear_bit(i, &empty, 32) {
if (!queues[i].name)
continue;
ctrl = BIT(31) | (map[i].pid << 10) | ((u32)map[i].qid << 24);
mt76_wr(dev, MT_FL_Q0_CTRL, ctrl);
head = mt76_get_field(dev, MT_FL_Q2_CTRL,
GENMASK(11, 0));
tail = mt76_get_field(dev, MT_FL_Q2_CTRL,
GENMASK(27, 16));
queued = mt76_get_field(dev, MT_FL_Q3_CTRL,
GENMASK(11, 0));
seq_printf(s, "\t%s: ", map[i].name);
seq_printf(s, "queued:0x%03x head:0x%03x tail:0x%03x\n",
queued, head, tail);
seq_printf(s, "\t%s: ", queues[i].name);
mt7996_fl_queue_show(s, dev, pse, &queues[i], 0);
seq_puts(s, "\n");
}
}
static void
mt7996_freepg_show(struct seq_file *s, u32 cnt, u32 head_tail)
{
seq_printf(s, "\tfree pages 0x%04x, free for all 0x%04x, head/tail 0x%04x/0x%04x\n",
u32_get_bits(cnt, MT_FREEPG_CNT_FREE),
u32_get_bits(cnt, MT_FREEPG_CNT_FFA),
u32_get_bits(head_tail, MT_FREEPG_HEAD_TAIL_HEAD),
u32_get_bits(head_tail, MT_FREEPG_HEAD_TAIL_TAIL));
}
static void
mt7996_pg_group_show(struct seq_file *s, const char *name, u32 group, u32 info)
{
seq_printf(s, "\t%s group: max/min quota 0x%04x/0x%04x, used/reserved 0x%04x/0x%04x\n",
name, u32_get_bits(group, MT_PG_GROUP_MAX_QUOTA),
u32_get_bits(group, MT_PG_GROUP_MIN_QUOTA),
u32_get_bits(info, MT_PG_INFO_SRC_CNT),
u32_get_bits(info, MT_PG_INFO_RSV_CNT));
}
static unsigned int
mt7996_ple_sta_cr_num(struct mt7996_dev *dev)
{
return is_mt7996(&dev->mt76) ? 34 : 17;
}
static unsigned int
mt7996_ple_sta_cr(struct mt7996_dev *dev, unsigned int n)
{
/* MT7992 and MT7990 keep the last station group in the
* extension register that follows the first 32 groups
*/
if (!is_mt7996(&dev->mt76) && n == mt7996_ple_sta_cr_num(dev) - 1)
return 32;
return n;
}
static void
mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
{
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct mt7996_vif *mvif = msta->vif;
struct mt7996_phy *phy = mt7996_vif_link_phy(&mvif->deflink);
struct ieee80211_link_sta *link_sta;
struct seq_file *s = data;
struct ieee80211_vif *vif;
struct mt7996_dev *dev;
unsigned int link_id;
if (!phy)
return;
vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
dev = phy->dev;
rcu_read_lock();
for_each_sta_active_link(vif, sta, link_sta, link_id) {
struct mt7996_sta_link *msta_link;
struct mt76_vif_link *mlink;
struct mt7996_phy *phy;
unsigned int cr;
u16 wlan_idx;
u8 ac;
mlink = rcu_dereference(mvif->mt76.link[link_id]);
if (!mlink)
continue;
phy = mt7996_vif_link_phy(container_of(mlink,
struct mt7996_vif_link,
mt76));
if (!phy)
continue;
msta_link = mt7996_sta_link(msta, link_id);
if (!msta_link)
continue;
for (ac = 0; ac < 4; ac++) {
u32 idx = msta_link->wcid.idx >> 5, qlen, ctrl, val;
u8 offs = msta_link->wcid.idx & GENMASK(4, 0);
wlan_idx = msta_link->wcid.idx;
cr = mt7996_ple_sta_cr(phy->dev, wlan_idx / 32);
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
struct mt7996_hw_queue q = {
.pid = MT_QUEUE_PORT_LMAC,
.qid = ac,
};
ctrl = BIT(31) | BIT(11) | (ac << 24);
val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));
if (val & BIT(offs))
if (mt76_rr(phy->dev, MT_PLE_AC_QEMPTY(ac, cr)) &
BIT(wlan_idx % 32))
continue;
mt76_wr(dev,
MT_FL_Q0_CTRL, ctrl | msta_link->wcid.idx);
qlen = mt76_get_field(dev, MT_FL_Q3_CTRL,
GENMASK(11, 0));
seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
sta->addr, msta_link->wcid.idx,
mlink->wmm_idx, ac, qlen);
seq_printf(s, "\tSTA %pM wcid %u AC%u%u: ", sta->addr,
wlan_idx, mlink->wmm_idx, ac);
mt7996_fl_queue_show(s, phy->dev, false, &q, wlan_idx);
seq_puts(s, "\n");
}
}
@ -692,78 +828,27 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
}
static int
mt7996_hw_queues_show(struct seq_file *file, void *data)
mt7996_hw_queues_show(struct seq_file *s, void *data)
{
struct mt7996_dev *dev = file->private;
struct mt7996_phy *phy = &dev->phy;
static const struct hw_queue_map ple_queue_map[] = {
{ "CPU_Q0", 0, 1, MT_CTX0 },
{ "CPU_Q1", 1, 1, MT_CTX0 + 1 },
{ "CPU_Q2", 2, 1, MT_CTX0 + 2 },
{ "CPU_Q3", 3, 1, MT_CTX0 + 3 },
{ "ALTX_Q0", 8, 2, MT_LMAC_ALTX0 },
{ "BMC_Q0", 9, 2, MT_LMAC_BMC0 },
{ "BCN_Q0", 10, 2, MT_LMAC_BCN0 },
{ "PSMP_Q0", 11, 2, MT_LMAC_PSMP0 },
{ "ALTX_Q1", 12, 2, MT_LMAC_ALTX0 + 4 },
{ "BMC_Q1", 13, 2, MT_LMAC_BMC0 + 4 },
{ "BCN_Q1", 14, 2, MT_LMAC_BCN0 + 4 },
{ "PSMP_Q1", 15, 2, MT_LMAC_PSMP0 + 4 },
};
static const struct hw_queue_map pse_queue_map[] = {
{ "CPU Q0", 0, 1, MT_CTX0 },
{ "CPU Q1", 1, 1, MT_CTX0 + 1 },
{ "CPU Q2", 2, 1, MT_CTX0 + 2 },
{ "CPU Q3", 3, 1, MT_CTX0 + 3 },
{ "HIF_Q0", 8, 0, MT_HIF0 },
{ "HIF_Q1", 9, 0, MT_HIF0 + 1 },
{ "HIF_Q2", 10, 0, MT_HIF0 + 2 },
{ "HIF_Q3", 11, 0, MT_HIF0 + 3 },
{ "HIF_Q4", 12, 0, MT_HIF0 + 4 },
{ "HIF_Q5", 13, 0, MT_HIF0 + 5 },
{ "LMAC_Q", 16, 2, 0 },
{ "MDP_TXQ", 17, 2, 1 },
{ "MDP_RXQ", 18, 2, 2 },
{ "SEC_TXQ", 19, 2, 3 },
{ "SEC_RXQ", 20, 2, 4 },
};
u32 val, head, tail;
struct mt7996_dev *dev = s->private;
/* ple queue */
val = mt76_rr(dev, MT_PLE_FREEPG_CNT);
head = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(11, 0));
tail = mt76_get_field(dev, MT_PLE_FREEPG_HEAD_TAIL, GENMASK(27, 16));
seq_puts(file, "PLE page info:\n");
seq_printf(file,
"\tTotal free page: 0x%08x head: 0x%03x tail: 0x%03x\n",
val, head, tail);
seq_puts(s, "PLE page info:\n");
mt7996_freepg_show(s, mt76_rr(dev, MT_PLE_FREEPG_CNT),
mt76_rr(dev, MT_PLE_FREEPG_HEAD_TAIL));
mt7996_pg_group_show(s, "HIF", mt76_rr(dev, MT_PLE_PG_HIF_GROUP),
mt76_rr(dev, MT_PLE_HIF_PG_INFO));
val = mt76_rr(dev, MT_PLE_PG_HIF_GROUP);
head = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(11, 0));
tail = mt76_get_field(dev, MT_PLE_HIF_PG_INFO, GENMASK(27, 16));
seq_printf(file, "\tHIF free page: 0x%03x res: 0x%03x used: 0x%03x\n",
val, head, tail);
seq_puts(s, "PLE non-empty queue info:\n");
mt7996_fl_queues_show(s, dev, false, mt7996_ple_queues,
mt76_rr(dev, MT_FL_Q_EMPTY));
ieee80211_iterate_stations_atomic(dev->mphy.hw,
mt7996_sta_hw_queue_read, s);
seq_puts(file, "PLE non-empty queue info:\n");
mt7996_hw_queue_read(file, ARRAY_SIZE(ple_queue_map),
&ple_queue_map[0]);
/* iterate per-sta ple queue */
ieee80211_iterate_stations_atomic(phy->mt76->hw,
mt7996_sta_hw_queue_read, file);
phy = mt7996_phy2(dev);
if (phy)
ieee80211_iterate_stations_atomic(phy->mt76->hw,
mt7996_sta_hw_queue_read, file);
phy = mt7996_phy3(dev);
if (phy)
ieee80211_iterate_stations_atomic(phy->mt76->hw,
mt7996_sta_hw_queue_read, file);
/* pse queue */
seq_puts(file, "PSE non-empty queue info:\n");
mt7996_hw_queue_read(file, ARRAY_SIZE(pse_queue_map),
&pse_queue_map[0]);
seq_puts(s, "PSE non-empty queue info:\n");
mt7996_fl_queues_show(s, dev, true, mt7996_pse_queues,
mt76_rr(dev, MT_PSE_QUEUE_EMPTY));
mt7996_fl_queues_show(s, dev, true, mt7996_pse_queues_1,
mt76_rr(dev, MT_PSE_QUEUE_EMPTY_1));
return 0;
}

View File

@ -541,6 +541,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
ieee80211_hw_set(hw, CONNECTION_MONITOR);
ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
hw->max_tx_fragments = 4;
wiphy->txq_memory_limit = 32 << 20; /* 32 MiB */
@ -1810,6 +1811,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
void mt7996_unregister_device(struct mt7996_dev *dev)
{
int i;
cancel_work_sync(&dev->dump_work);
cancel_work_sync(&dev->wed_rro.work);
cancel_work_sync(&dev->reset_work);
@ -1820,6 +1823,10 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
mt7996_coredump_unregister(dev);
mt76_unregister_device(&dev->mt76);
mt7996_wed_rro_free(dev);
for (i = 0; i < ARRAY_SIZE(dev->mt76.napi); i++) {
if (dev->mt76.napi[i].dev)
napi_disable(&dev->mt76.napi[i]);
}
mt7996_mcu_exit(dev);
mt7996_tx_token_put(dev);
mt7996_dma_cleanup(dev);

View File

@ -915,7 +915,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
if (mvif) {
if (wcid->offchannel)
mlink = rcu_dereference(mvif->mt76.offchannel_link);
mlink = mt7996_offchannel_link(wcid);
if (!mlink && link_id != IEEE80211_LINK_UNSPECIFIED)
mlink = rcu_dereference(mvif->mt76.link[link_id]);
}
@ -1057,7 +1057,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (!wcid)
wcid = &dev->mt76.global_wcid;
if ((is_8023 || ieee80211_is_data_qos(hdr->frame_control)) && sta->mlo &&
if (sta && (is_8023 || ieee80211_is_data_qos(hdr->frame_control)) && sta->mlo &&
likely(tx_info->skb->protocol != cpu_to_be16(ETH_P_PAE))) {
u8 tid = tx_info->skb->priority & IEEE80211_QOS_CTL_TID_MASK;
@ -1097,7 +1097,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
* compatible with 802.11 EAPOL frame, we do the translation by
* software
*/
if (tx_info->skb->protocol == cpu_to_be16(ETH_P_PAE) && sta->mlo) {
if (sta && tx_info->skb->protocol == cpu_to_be16(ETH_P_PAE) && sta->mlo) {
struct ieee80211_hdr *hdr = (void *)tx_info->skb->data;
struct ieee80211_bss_conf *link_conf;
struct ieee80211_link_sta *link_sta;
@ -1196,7 +1196,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
if (mvif) {
if (wcid->offchannel)
mlink = rcu_dereference(mvif->mt76.offchannel_link);
mlink = mt7996_offchannel_link(wcid);
if (!mlink)
mlink = rcu_dereference(mvif->mt76.link[wcid->link_id]);
@ -1503,7 +1503,8 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
}
}
if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wcid->sta) {
if ((mtk_wed_device_active(&dev->mt76.mmio.wed) ||
mt76_npu_device_active(&dev->mt76)) && wcid->sta) {
struct ieee80211_sta *sta;
u8 tid;
@ -1936,6 +1937,9 @@ void mt7996_rro_rx_process(struct mt76_dev *mdev, void *data)
struct mt7996_msdu_page *p = NULL;
int i, seq_num = 0;
if (seq_id > MT7996_RRO_MAX_SESSION)
return;
for (i = 0; i < ind_count; i++) {
struct mt7996_wed_rro_addr *e;
struct mt76_rx_status *status;
@ -2463,6 +2467,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
dev->recovery.hw_full_reset = true;
set_bit(MT76_RESTART, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
ieee80211_stop_queues(hw);
@ -2944,6 +2949,10 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
changed = msta_link->changed;
msta_link->changed = 0;
if (!msta_link->connected)
continue;
mvif = msta_link->sta->vif;
vif = container_of((void *)mvif, struct ieee80211_vif,
drv_priv);
@ -3285,8 +3294,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
flow->tsf = le64_to_cpu(twt_agrt->twt);
if (mt7996_mcu_twt_agrt_update(dev, &msta->vif->deflink, flow,
MCU_TWT_AGRT_ADD))
MCU_TWT_AGRT_ADD)) {
list_del(&flow->list);
goto unlock;
}
setup_cmd = TWT_SETUP_CMD_ACCEPT;
dev->twt.table_mask |= BIT(table_id);

File diff suppressed because it is too large Load Diff

View File

@ -488,6 +488,9 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
struct mt7996_mcu_countdown_notify *event;
struct mt7996_mcu_countdown_data cdata;
if (skb->len < sizeof(*rxd) + sizeof(*hdr))
return;
if (hdr->band >= ARRAY_SIZE(dev->mt76.phys))
return;
@ -497,9 +500,14 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
tail = skb->data + skb->len;
data += sizeof(*hdr);
while (data + sizeof(*tlv) < tail && le16_to_cpu(tlv->len)) {
event = (struct mt7996_mcu_countdown_notify *)tlv->data;
while (data + sizeof(*tlv) <= tail) {
u16 tag_len = le16_to_cpu(tlv->len);
if (tag_len < sizeof(*tlv) + sizeof(*event) ||
data + tag_len > tail)
break;
event = (struct mt7996_mcu_countdown_notify *)tlv->data;
cdata.omac_idx = event->omac_idx;
switch (le16_to_cpu(tlv->tag)) {
@ -517,7 +525,7 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
break;
}
data += le16_to_cpu(tlv->len);
data += tag_len;
tlv = (struct tlv *)data;
}
}
@ -572,21 +580,32 @@ mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb)
{
#define UNI_EVENT_FW_LOG_FORMAT 0
struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
const char *data = (char *)&rxd[1] + 4, *type;
struct tlv *tlv = (struct tlv *)data;
const char *data, *type;
struct tlv *tlv;
int len;
if (skb->len < sizeof(*rxd))
return;
if (!(rxd->option & MCU_UNI_CMD_EVENT)) {
len = skb->len - sizeof(*rxd);
data = (char *)&rxd[1];
len = skb->len - sizeof(*rxd);
goto out;
}
if (skb->len < sizeof(*rxd) + 4 + sizeof(*tlv))
return;
tlv = (struct tlv *)((char *)&rxd[1] + 4);
if (le16_to_cpu(tlv->tag) != UNI_EVENT_FW_LOG_FORMAT)
return;
data += sizeof(*tlv) + 4;
if (le16_to_cpu(tlv->len) < sizeof(*tlv) + 4)
return;
data = (char *)tlv + sizeof(*tlv) + 4;
len = le16_to_cpu(tlv->len) - sizeof(*tlv) - 4;
len = min_t(int, len, skb->len - (int)(data - (char *)skb->data));
out:
switch (rxd->s2d_index) {
@ -648,13 +667,38 @@ static void
mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
struct mt7996_mcu_all_sta_info_event *res;
u32 elem_size;
u16 sta_num;
u16 i;
if (skb->len < sizeof(struct mt7996_mcu_rxd))
return;
skb_pull(skb, sizeof(struct mt7996_mcu_rxd));
res = (struct mt7996_mcu_all_sta_info_event *)skb->data;
if (skb->len < sizeof(*res))
return;
for (i = 0; i < le16_to_cpu(res->sta_num); i++) {
sta_num = le16_to_cpu(res->sta_num);
switch (le16_to_cpu(res->tag)) {
case UNI_ALL_STA_TXRX_RATE:
elem_size = sizeof(res->rate[0]);
break;
case UNI_ALL_STA_TXRX_ADM_STAT:
elem_size = sizeof(res->adm_stat[0]);
break;
case UNI_ALL_STA_TXRX_MSDU_COUNT:
elem_size = sizeof(res->msdu_cnt[0]);
break;
default:
return;
}
if (sta_num > (skb->len - sizeof(*res)) / elem_size)
sta_num = (skb->len - sizeof(*res)) / elem_size;
for (i = 0; i < sta_num; i++) {
u8 ac;
u16 wlan_idx;
struct mt76_wcid *wcid;
@ -1467,15 +1511,15 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif_link *mvif,
/** starec & wtbl **/
int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
struct ieee80211_ampdu_params *params,
struct ieee80211_vif *vif, bool enable)
struct ieee80211_vif *vif, unsigned long links,
bool enable)
{
struct ieee80211_sta *sta = params->sta;
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct ieee80211_link_sta *link_sta;
unsigned int link_id;
int ret = 0;
for_each_sta_active_link(vif, sta, link_sta, link_id) {
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_sta_link *msta_link;
struct mt7996_vif_link *link;
@ -1501,15 +1545,15 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
struct ieee80211_ampdu_params *params,
struct ieee80211_vif *vif, bool enable)
struct ieee80211_vif *vif, unsigned long links,
bool enable)
{
struct ieee80211_sta *sta = params->sta;
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
struct ieee80211_link_sta *link_sta;
unsigned int link_id;
int ret = 0;
for_each_sta_active_link(vif, sta, link_sta, link_id) {
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_sta_link *msta_link;
struct mt7996_vif_link *link;
@ -2715,18 +2759,20 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
struct ieee80211_sta *sta)
{
struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
unsigned int nlinks = hweight16(sta->valid_links);
unsigned long links = mt7996_mac_sta_links(dev, vif, sta);
unsigned int nlinks = hweight16(links);
struct mld_setup_link *mld_setup_link;
struct ieee80211_link_sta *link_sta;
struct sta_rec_mld_setup *mld_setup;
struct mt7996_sta_link *msta_link;
u8 seclink_id = msta->deflink_id;
unsigned int link_id;
struct tlv *tlv;
msta_link = mt7996_sta_link_protected(dev, msta, msta->deflink_id);
if (!msta_link)
if (!(links & BIT(msta->deflink_id)))
return;
msta_link = mt7996_sta_link_protected(dev, msta, msta->deflink_id);
tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD,
sizeof(struct sta_rec_mld_setup) +
sizeof(struct mld_setup_link) * nlinks);
@ -2736,26 +2782,18 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
mld_setup->setup_wcid = cpu_to_le16(msta_link->wcid.idx);
mld_setup->primary_id = cpu_to_le16(msta_link->wcid.idx);
if (nlinks > 1) {
msta_link = mt7996_sta_link_protected(dev, msta,
msta->seclink_id);
if (!msta_link)
return;
}
if (links & BIT(msta->seclink_id))
seclink_id = msta->seclink_id;
msta_link = mt7996_sta_link_protected(dev, msta, seclink_id);
mld_setup->seconed_id = cpu_to_le16(msta_link->wcid.idx);
mld_setup->link_num = nlinks;
mld_setup_link = (struct mld_setup_link *)mld_setup->link_info;
for_each_sta_active_link(vif, sta, link_sta, link_id) {
for_each_set_bit(link_id, &links, IEEE80211_MLD_MAX_NUM_LINKS) {
struct mt7996_vif_link *link;
msta_link = mt7996_sta_link_protected(dev, msta, link_id);
if (!msta_link)
continue;
link = mt7996_vif_link(dev, vif, link_id);
if (!link)
continue;
mld_setup_link->wcid = cpu_to_le16(msta_link->wcid.idx);
mld_setup_link->bss_idx = link->mt76.idx;
@ -2872,6 +2910,27 @@ int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
int mt7996_mcu_update_mld_sta(struct mt7996_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct mt7996_vif_link *link,
struct mt7996_sta_link *msta_link)
{
struct sk_buff *skb;
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &link->mt76,
&msta_link->wcid,
MT7996_STA_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
return PTR_ERR(skb);
mt7996_mcu_sta_mld_setup_tlv(dev, skb, vif, sta);
mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta);
return mt76_mcu_skb_send_msg(&dev->mt76, skb,
MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
}
void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta)
{
struct mt7996_vif_link *link = (struct mt7996_vif_link *)data;
@ -5444,6 +5503,40 @@ int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled)
sizeof(req), true);
}
int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data)
{
struct mt7996_dev *dev = phy->dev;
struct tx_power_ctrl req = {
.tag = cpu_to_le16(power_ctrl_id),
.len = cpu_to_le16(sizeof(req) - 4),
.power_ctrl_id = power_ctrl_id,
.band_idx = phy->mt76->band_idx,
};
switch (power_ctrl_id) {
case UNI_TXPOWER_SKU_POWER_LIMIT_CTRL:
req.sku_enable = !!data;
break;
case UNI_TXPOWER_PERCENTAGE_CTRL:
req.percentage_ctrl_enable = !!data;
break;
case UNI_TXPOWER_PERCENTAGE_DROP_CTRL:
req.power_drop_level = data;
break;
case UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL:
req.bf_backoff_enable = !!data;
break;
case UNI_TXPOWER_ATE_MODE_CTRL:
req.ate_mode_enable = !!data;
break;
default:
return -EINVAL;
}
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TXPOWER),
&req, sizeof(req), false);
}
int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
{
#define TX_POWER_LIMIT_TABLE_RATE 0

View File

@ -1039,8 +1039,31 @@ enum {
UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
};
struct tx_power_ctrl {
u8 _rsv[4];
__le16 tag;
__le16 len;
u8 power_ctrl_id;
union {
bool sku_enable;
bool ate_mode_enable;
bool percentage_ctrl_enable;
bool bf_backoff_enable;
u8 power_drop_level;
};
u8 band_idx;
u8 rsv[1];
} __packed;
enum {
UNI_TXPOWER_SKU_POWER_LIMIT_CTRL = 0,
UNI_TXPOWER_PERCENTAGE_CTRL = 1,
UNI_TXPOWER_PERCENTAGE_DROP_CTRL = 2,
UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3,
UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
UNI_TXPOWER_ATE_MODE_CTRL = 6,
};
enum {

View File

@ -244,6 +244,7 @@ struct mt7996_sta_link {
struct mt76_wcid wcid; /* must be first */
struct mt7996_sta *sta;
bool connected;
struct list_head rc_list;
u32 airtime_ac[8];
@ -263,11 +264,25 @@ struct mt7996_sta_link {
struct rcu_head rcu_head;
};
struct mt7996_sta_ba {
u16 ssn;
u16 buf_size;
bool amsdu;
};
struct mt7996_sta {
struct mt7996_sta_link deflink; /* must be first */
struct mt7996_sta_link __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
u8 deflink_id;
u8 seclink_id;
u8 conn_state;
unsigned long wcid_flags;
u16 ba_tx_mask;
u16 ba_rx_mask;
struct mt7996_sta_ba ba_tx[IEEE80211_NUM_TIDS];
struct mt7996_sta_ba ba_rx[IEEE80211_NUM_TIDS];
struct mt7996_vif *vif;
};
@ -279,6 +294,7 @@ struct mt7996_vif_link {
struct cfg80211_bitrate_mask bitrate_mask;
u8 mld_idx;
u8 bmc_bssid[ETH_ALEN];
};
struct mt7996_vif_link_info {
@ -643,6 +659,18 @@ mt7996_vif_conf_link(struct mt7996_dev *dev, struct ieee80211_vif *vif,
link_conf);
}
static inline struct mt76_vif_link *
mt7996_offchannel_link(struct mt76_wcid *wcid)
{
struct mt7996_sta_link *msta_link;
struct mt7996_vif_link *link;
msta_link = container_of(wcid, struct mt7996_sta_link, wcid);
link = container_of(msta_link, struct mt7996_vif_link, msta_link);
return &link->mt76;
}
static inline struct mt7996_sta_link *
mt7996_sta_link(struct mt7996_sta *msta, u8 link_id)
{
@ -725,13 +753,20 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev,
int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
struct mt7996_vif_link *link,
struct mt7996_sta_link *msta_link);
int mt7996_mcu_update_mld_sta(struct mt7996_dev *dev,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct mt7996_vif_link *link,
struct mt7996_sta_link *msta_link);
void mt7996_mcu_update_sta_rec_bw(void *data, struct ieee80211_sta *sta);
int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
struct ieee80211_ampdu_params *params,
struct ieee80211_vif *vif, bool enable);
struct ieee80211_vif *vif, unsigned long links,
bool enable);
int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
struct ieee80211_ampdu_params *params,
struct ieee80211_vif *vif, bool enable);
struct ieee80211_vif *vif, unsigned long links,
bool enable);
int mt7996_mcu_update_bss_color(struct mt7996_dev *dev,
struct mt76_vif_link *mlink,
struct cfg80211_he_bss_color *he_bss_color);
@ -778,6 +813,7 @@ int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy);
int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data);
int mt7996_mcu_rdd_resume_tx(struct mt7996_phy *phy);
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 rdd_idx, u8 val);
int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
@ -893,6 +929,8 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
void mt7996_mac_sta_remove_link(struct mt7996_dev *dev,
struct ieee80211_sta *sta,
unsigned int link_id, bool flush);
u16 mt7996_mac_sta_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
struct ieee80211_twt_setup *twt);

View File

@ -283,7 +283,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan rx ring0 addr\n");
"failed retrieving NPU wlan rx ring0 addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND0].regs->desc_base);
@ -292,7 +292,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan rx ring2 addr\n");
"failed retrieving NPU wlan rx ring2 addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_BAND2].regs->desc_base);
@ -302,7 +302,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan msdu pg ring addr\n");
"failed retrieving NPU wlan msdu pg ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND0].regs->desc_base);
@ -311,7 +311,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan msdu pg ring addr\n");
"failed retrieving NPU wlan msdu pg ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND1].regs->desc_base);
@ -320,7 +320,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan msdu pg ring addr\n");
"failed retrieving NPU wlan msdu pg ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_MSDU_PAGE_BAND2].regs->desc_base);
@ -330,7 +330,7 @@ static int mt7996_npu_rxd_init(struct mt7996_dev *dev, struct airoha_npu *npu)
&val, GFP_KERNEL);
if (err) {
dev_warn(dev->mt76.dev,
"failed retriving NPU wlan ind_cmd ring addr\n");
"failed retrieving NPU wlan ind_cmd ring addr\n");
return err;
}
writel(val, &dev->mt76.q_rx[MT_RXQ_RRO_IND].regs->desc_base);

View File

@ -63,12 +63,18 @@ static void mt7996_put_hif2(struct mt7996_hif *hif)
static struct mt7996_hif *mt7996_pci_init_hif2(struct pci_dev *pdev)
{
struct pci_dev *tmp_pdev;
hif_idx++;
if (!pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2, NULL) &&
!pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL) &&
!pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID_2, NULL))
tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7996_DEVICE_ID_2, NULL);
if (!tmp_pdev)
tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7992_DEVICE_ID_2, NULL);
if (!tmp_pdev)
tmp_pdev = pci_get_device(PCI_VENDOR_ID_MEDIATEK, MT7990_DEVICE_ID_2, NULL);
if (!tmp_pdev)
return NULL;
pci_dev_put(tmp_pdev);
writel(hif_idx | MT_PCIE_RECOG_ID_SEM,
pcim_iomap_table(pdev)[0] + MT_PCIE_RECOG_ID);

View File

@ -155,14 +155,42 @@ enum offs_rev {
#define MT_FL_Q2_CTRL MT_PLE(0x3e8)
#define MT_FL_Q3_CTRL MT_PLE(0x3ec)
#define MT_PLE_FREEPG_CNT MT_PLE(0x380)
#define MT_PLE_FREEPG_HEAD_TAIL MT_PLE(0x384)
#define MT_PLE_PG_HIF_GROUP MT_PLE(0x00c)
#define MT_PLE_HIF_PG_INFO MT_PLE(0x388)
#define MT_FL_Q0_CTRL_EXECUTE BIT(31)
#define MT_FL_Q0_CTRL_QID GENMASK(30, 24)
#define MT_FL_Q0_CTRL_TGID GENMASK(21, 20)
#define MT_FL_Q0_CTRL_PID GENMASK(17, 16)
#define MT_FL_Q0_CTRL_WLAN_IDX GENMASK(11, 0)
#define MT_FL_Q2_CTRL_TAIL_FID GENMASK(28, 16)
#define MT_FL_Q2_CTRL_HEAD_FID GENMASK(12, 0)
#define MT_FL_Q3_CTRL_PKT_NUM GENMASK(12, 0)
#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x600 + 0x80 * (ac) + ((n) << 2))
#define MT_PLE_FREEPG_CNT MT_PLE(0x3a0)
#define MT_PLE_FREEPG_HEAD_TAIL MT_PLE(0x3a4)
#define MT_PLE_PG_HIF_GROUP MT_PLE(0x00c)
#define MT_PLE_HIF_PG_INFO MT_PLE(0x3a8)
#define MT_PLE_AC_QEMPTY(ac, n) MT_PLE(0x600 + 0x100 * (ac) + ((n) << 2))
#define MT_PLE_AMSDU_PACK_MSDU_CNT(n) MT_PLE(0x10e0 + ((n) << 2))
#define MT_FREEPG_CNT_FFA GENMASK(28, 16)
#define MT_FREEPG_CNT_FREE GENMASK(12, 0)
#define MT_FREEPG_HEAD_TAIL_TAIL GENMASK(28, 16)
#define MT_FREEPG_HEAD_TAIL_HEAD GENMASK(12, 0)
#define MT_PG_GROUP_MAX_QUOTA GENMASK(28, 16)
#define MT_PG_GROUP_MIN_QUOTA GENMASK(12, 0)
#define MT_PG_INFO_SRC_CNT GENMASK(28, 16)
#define MT_PG_INFO_RSV_CNT GENMASK(12, 0)
/* PSE */
#define MT_PSE_BASE 0x820c8000
#define MT_PSE(ofs) (MT_PSE_BASE + (ofs))
#define MT_PSE_QUEUE_EMPTY MT_PSE(0x0b0)
#define MT_PSE_QUEUE_EMPTY_1 MT_PSE(0x0bc)
#define MT_PSE_FL_Q0_CTRL MT_PSE(0x1b0)
#define MT_PSE_FL_Q2_CTRL MT_PSE(0x1b8)
#define MT_PSE_FL_Q3_CTRL MT_PSE(0x1bc)
/* WF MDP TOP */
#define MT_MDP_BASE 0x820cc000
#define MT_MDP(ofs) (MT_MDP_BASE + (ofs))

View File

@ -4,16 +4,26 @@
*/
#include "mt76.h"
static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
static struct mt76_phy *
mt76_scan_chan_phy(struct ieee80211_hw *hw, struct ieee80211_channel *chan)
{
struct mt76_phy *phy = dev->scan.phy;
struct cfg80211_scan_info info = {
.aborted = abort,
};
struct mt76_phy *phy = hw->priv;
if (hw->wiphy->n_radio > 1)
return phy->dev->band_phys[chan->band];
return phy;
}
static void mt76_scan_phy_complete(struct mt76_phy *phy, bool abort)
{
struct mt76_dev *dev = phy->dev;
struct cfg80211_scan_info info = {};
struct ieee80211_hw *hw = phy->hw;
lockdep_assert_held(&dev->mutex);
if (!phy)
if (!mt76_phy_scanning(phy))
return;
clear_bit(MT76_SCANNING, &phy->state);
@ -29,41 +39,75 @@ static void mt76_scan_complete(struct mt76_dev *dev, bool abort)
__mt76_set_channel(phy, &phy->main_chandef, false);
if (offchannel)
mt76_offchannel_notify(phy, false);
} else {
/* A phy that has no operating channel has nothing to restore,
* but the flag also gates the TX queues of every station whose
* wcid points at this band, so leaving it set stalls them until
* something else happens to set a channel.
*/
phy->offchannel = false;
}
mt76_put_vif_phy_link(phy, dev->scan.vif, dev->scan.mlink);
mt76_put_vif_phy_link(phy, dev->scan.vif, phy->scan.mlink);
memset(&phy->scan, 0, sizeof(phy->scan));
clear_bit(phy->band_idx, &dev->scan.phy_mask);
if (abort)
dev->scan.aborted = true;
if (dev->scan.phy_mask)
return;
info.aborted = dev->scan.aborted;
memset(&dev->scan, 0, sizeof(dev->scan));
if (!test_bit(MT76_MCU_RESET, &dev->phy.state))
ieee80211_scan_completed(phy->hw, &info);
ieee80211_scan_completed(hw, &info);
}
void mt76_abort_scan(struct mt76_dev *dev)
{
spin_lock_bh(&dev->scan_lock);
dev->scan.beacon_wait = false;
spin_unlock_bh(&dev->scan_lock);
struct mt76_phy *phy;
int i;
cancel_delayed_work_sync(&dev->scan_work);
for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {
phy = dev->phys[i];
if (!phy)
continue;
spin_lock_bh(&dev->scan_lock);
phy->scan.beacon_wait = false;
spin_unlock_bh(&dev->scan_lock);
disable_delayed_work_sync(&phy->scan_work);
}
mutex_lock(&dev->mutex);
mt76_scan_complete(dev, true);
for (i = 0; i < ARRAY_SIZE(dev->phys); i++) {
phy = dev->phys[i];
if (!phy)
continue;
mt76_scan_phy_complete(phy, true);
enable_delayed_work(&phy->scan_work);
}
mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL_GPL(mt76_abort_scan);
static void
mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
mt76_scan_send_probe(struct mt76_phy *phy, struct cfg80211_ssid *ssid)
{
struct cfg80211_scan_request *req = dev->scan.req;
struct mt76_dev *dev = phy->dev;
struct cfg80211_scan_request *req = &dev->scan.req->req;
struct ieee80211_scan_ies *ies = &dev->scan.req->ies;
struct ieee80211_vif *vif = dev->scan.vif;
struct mt76_vif_link *mvif = dev->scan.mlink;
enum nl80211_band band = dev->scan.chan->band;
struct mt76_phy *phy = dev->scan.phy;
struct mt76_vif_link *mvif = phy->scan.mlink;
enum nl80211_band band = phy->scan.chan->band;
struct ieee80211_tx_info *info;
struct sk_buff *skb;
u8 link_id;
skb = ieee80211_probereq_get(phy->hw, vif->addr, ssid->ssid,
ssid->ssid_len, req->ie_len);
ssid->ssid_len,
ies->len[band] + ies->common_ie_len);
if (!skb)
return;
@ -74,8 +118,10 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
ether_addr_copy(hdr->addr3, req->bssid);
}
if (req->ie_len)
skb_put_data(skb, req->ie, req->ie_len);
if (ies->len[band])
skb_put_data(skb, ies->ies[band], ies->len[band]);
if (ies->common_ie_len)
skb_put_data(skb, ies->common_ies, ies->common_ie_len);
skb->priority = 7;
skb_set_queue_mapping(skb, IEEE80211_AC_VO);
@ -100,65 +146,77 @@ mt76_scan_send_probe(struct mt76_dev *dev, struct cfg80211_ssid *ssid)
rcu_read_unlock();
}
void mt76_scan_rx_beacon(struct mt76_dev *dev, struct ieee80211_channel *chan)
void mt76_scan_rx_beacon(struct mt76_phy *phy, struct ieee80211_channel *chan)
{
struct mt76_phy *phy;
struct mt76_dev *dev = phy->dev;
spin_lock(&dev->scan_lock);
if (!dev->scan.beacon_wait || dev->scan.beacon_received ||
dev->scan.chan != chan)
if (!phy->scan.beacon_wait || phy->scan.beacon_received ||
phy->scan.chan != chan)
goto out;
phy = dev->scan.phy;
if (!phy)
goto out;
dev->scan.beacon_received = true;
ieee80211_queue_delayed_work(phy->hw, &dev->scan_work, 0);
phy->scan.beacon_received = true;
ieee80211_queue_delayed_work(phy->hw, &phy->scan_work, 0);
out:
spin_unlock(&dev->scan_lock);
}
void mt76_scan_work(struct work_struct *work)
static int mt76_scan_next_chan_idx(struct mt76_phy *phy)
{
struct mt76_dev *dev = container_of(work, struct mt76_dev,
scan_work.work);
struct cfg80211_scan_request *req = dev->scan.req;
struct cfg80211_chan_def chandef = {};
struct mt76_phy *phy = dev->scan.phy;
int duration = HZ / 9; /* ~110 ms */
bool beacon_rx, offchannel = true;
struct cfg80211_scan_request *req = &phy->dev->scan.req->req;
int i;
if (!phy || !req)
for (i = phy->scan.chan_idx; i < req->n_channels; i++)
if (mt76_scan_chan_phy(phy->hw, req->channels[i]) == phy)
return i;
return -1;
}
void mt76_scan_work(struct work_struct *work)
{
struct mt76_phy *phy = container_of(work, struct mt76_phy,
scan_work.work);
struct mt76_dev *dev = phy->dev;
struct cfg80211_scan_request *req;
struct cfg80211_chan_def chandef = {};
int duration = HZ / 9; /* ~110 ms */
bool beacon_rx, offchannel = true;
int i, idx;
if (!dev->scan.req || !mt76_phy_scanning(phy))
return;
req = &dev->scan.req->req;
spin_lock_bh(&dev->scan_lock);
beacon_rx = dev->scan.beacon_wait && dev->scan.beacon_received;
dev->scan.beacon_wait = false;
beacon_rx = phy->scan.beacon_wait && phy->scan.beacon_received;
phy->scan.beacon_wait = false;
spin_unlock_bh(&dev->scan_lock);
if (beacon_rx)
goto probe;
if (dev->scan.chan_idx >= req->n_channels) {
idx = mt76_scan_next_chan_idx(phy);
if (idx < 0) {
mutex_lock(&dev->mutex);
mt76_scan_complete(dev, false);
mt76_scan_phy_complete(phy, false);
mutex_unlock(&dev->mutex);
return;
}
if (dev->scan.chan && phy->num_sta && phy->offchannel) {
dev->scan.chan = NULL;
if (phy->scan.chan && phy->num_sta && phy->offchannel) {
phy->scan.chan = NULL;
mt76_set_channel(phy, &phy->main_chandef, false);
mt76_offchannel_notify(phy, false);
goto out;
}
dev->scan.chan = req->channels[dev->scan.chan_idx++];
offchannel = mt76_offchannel_chandef(phy, dev->scan.chan, &chandef);
phy->scan.chan = req->channels[idx];
phy->scan.chan_idx = idx + 1;
offchannel = mt76_offchannel_chandef(phy, phy->scan.chan, &chandef);
if (offchannel)
mt76_offchannel_notify(phy, true);
@ -169,8 +227,8 @@ void mt76_scan_work(struct work_struct *work)
if (chandef.chan->flags & (IEEE80211_CHAN_NO_IR | IEEE80211_CHAN_RADAR)) {
spin_lock_bh(&dev->scan_lock);
dev->scan.beacon_received = false;
dev->scan.beacon_wait = true;
phy->scan.beacon_received = false;
phy->scan.beacon_wait = true;
spin_unlock_bh(&dev->scan_lock);
goto out;
}
@ -180,16 +238,16 @@ void mt76_scan_work(struct work_struct *work)
duration = HZ / 16; /* ~60 ms */
local_bh_disable();
for (i = 0; i < req->n_ssids; i++)
mt76_scan_send_probe(dev, &req->ssids[i]);
mt76_scan_send_probe(phy, &req->ssids[i]);
local_bh_enable();
out:
if (dev->scan.chan && phy->offchannel)
if (phy->scan.chan && phy->offchannel)
duration = max_t(int, duration,
msecs_to_jiffies(req->duration +
(req->duration >> 5)));
ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, duration);
ieee80211_queue_delayed_work(phy->hw, &phy->scan_work, duration);
}
int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@ -197,36 +255,67 @@ int mt76_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
{
struct mt76_phy *phy = hw->priv;
struct mt76_dev *dev = phy->dev;
unsigned long phy_mask = 0;
struct mt76_vif_link *mlink;
int ret = 0;
int i, ret = 0;
if (hw->wiphy->n_radio > 1) {
phy = dev->band_phys[req->req.channels[0]->band];
for (i = 0; i < req->req.n_channels; i++) {
phy = mt76_scan_chan_phy(hw, req->req.channels[i]);
if (!phy)
return -EINVAL;
phy_mask |= BIT(phy->band_idx);
}
mutex_lock(&dev->mutex);
if (dev->scan.req || phy->roc_vif ||
test_bit(MT76_MCU_RESET, &dev->phy.state)) {
if (dev->scan.req || test_bit(MT76_MCU_RESET, &dev->phy.state) ||
test_bit(MT76_RESTART, &dev->phy.state)) {
ret = -EBUSY;
goto out;
}
mlink = mt76_get_vif_phy_link(phy, vif);
if (IS_ERR(mlink)) {
ret = PTR_ERR(mlink);
goto out;
for_each_set_bit(i, &phy_mask, ARRAY_SIZE(dev->phys)) {
if (dev->phys[i]->roc_vif) {
ret = -EBUSY;
goto out;
}
}
memset(&dev->scan, 0, sizeof(dev->scan));
dev->scan.req = &req->req;
for_each_set_bit(i, &phy_mask, ARRAY_SIZE(dev->phys)) {
phy = dev->phys[i];
mlink = mt76_get_vif_phy_link(phy, vif);
if (IS_ERR(mlink)) {
ret = PTR_ERR(mlink);
goto put_links;
}
memset(&phy->scan, 0, sizeof(phy->scan));
phy->scan.mlink = mlink;
}
dev->scan.req = req;
dev->scan.vif = vif;
dev->scan.phy = phy;
dev->scan.mlink = mlink;
set_bit(MT76_SCANNING, &phy->state);
ieee80211_queue_delayed_work(dev->phy.hw, &dev->scan_work, 0);
dev->scan.phy_mask = phy_mask;
dev->scan.aborted = false;
for_each_set_bit(i, &phy_mask, ARRAY_SIZE(dev->phys)) {
phy = dev->phys[i];
set_bit(MT76_SCANNING, &phy->state);
ieee80211_queue_delayed_work(phy->hw, &phy->scan_work, 0);
}
goto out;
put_links:
for_each_set_bit(i, &phy_mask, ARRAY_SIZE(dev->phys)) {
phy = dev->phys[i];
if (!phy->scan.mlink)
break;
mt76_put_vif_phy_link(phy, vif, phy->scan.mlink);
phy->scan.mlink = NULL;
}
out:
mutex_unlock(&dev->mutex);

View File

@ -129,7 +129,7 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
memset(cb, 0, sizeof(*cb));
if (!wcid || !rcu_access_pointer(dev->wcid[wcid->idx]))
if (!wcid)
return MT_PACKET_ID_NO_ACK;
if (info->flags & IEEE80211_TX_CTL_NO_ACK)
@ -147,6 +147,11 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
spin_lock_bh(&dev->status_lock);
if (rcu_access_pointer(dev->wcid[wcid->idx]) != wcid) {
pid = MT_PACKET_ID_NO_ACK;
goto out;
}
pid = idr_alloc(&wcid->pktid, skb, MT_PACKET_ID_FIRST,
MT_PACKET_ID_MASK, GFP_ATOMIC);
if (pid < 0) {
@ -885,7 +890,7 @@ int mt76_skb_adjust_pad(struct sk_buff *skb, int pad)
}
}
if (skb_pad(last, pad))
if (__skb_pad(last, pad, false))
return -ENOMEM;
__skb_put(last, pad);

View File

@ -171,8 +171,10 @@ static void mt76u_copy(struct mt76_dev *dev, u32 offset,
{
struct mt76_usb *usb = &dev->usb;
const u8 *val = data;
int ret;
int current_batch_size;
int len_aligned;
int copy_len;
int ret;
int i = 0;
/* Assure that always a multiple of 4 bytes are copied,
@ -180,12 +182,16 @@ static void mt76u_copy(struct mt76_dev *dev, u32 offset,
* See: "mt76: round up length on mt76_wr_copy"
* Commit 850e8f6fbd5d0003b0
*/
len = round_up(len, 4);
len_aligned = round_up(len, 4);
mutex_lock(&usb->usb_ctrl_mtx);
while (i < len) {
current_batch_size = min_t(int, usb->data_len, len - i);
memcpy(usb->data, val + i, current_batch_size);
while (i < len_aligned) {
current_batch_size = min_t(int, usb->data_len, len_aligned - i);
copy_len = min_t(int, current_batch_size, len - i);
memcpy(usb->data, val + i, copy_len);
if (copy_len < current_batch_size)
memset(usb->data + copy_len, 0,
current_batch_size - copy_len);
ret = __mt76u_vendor_request(dev, MT_VEND_MULTI_WRITE,
USB_DIR_OUT | USB_TYPE_VENDOR,
0, offset + i, usb->data,
@ -893,6 +899,9 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
enum mt76_txq_id qid, struct sk_buff *skb,
struct mt76_wcid *wcid, struct ieee80211_sta *sta)
{
struct ieee80211_tx_status status = {
.sta = sta,
};
struct mt76_tx_info tx_info = {
.skb = skb,
};
@ -900,17 +909,27 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
u16 idx = q->head;
int err;
if (q->queued == q->ndesc)
return -ENOSPC;
if (q->queued == q->ndesc) {
err = -ENOSPC;
goto err_free_skb;
}
skb->prev = skb->next = NULL;
err = dev->drv->tx_prepare_skb(dev, NULL, qid, wcid, sta, &tx_info);
if (err < 0)
return err;
goto err_free_skb;
err = mt76u_tx_setup_buffers(dev, tx_info.skb, q->entry[idx].urb);
if (err < 0)
return err;
if (err < 0) {
/*
* mt76_tx_status_skb_get() walks the idr and dereferences
* a freed skb. This SKB is not counted in non-AQL counter
* due to error return, so using 0xffff as wcid to keep
* balanced.
*/
mt76_tx_complete_skb(dev, 0xffff, tx_info.skb);
goto err_ret;
}
mt76u_fill_bulk_urb(dev, USB_DIR_OUT, q->ep, q->entry[idx].urb,
mt76u_complete_tx, &q->entry[idx]);
@ -921,6 +940,14 @@ mt76u_tx_queue_skb(struct mt76_phy *phy, struct mt76_queue *q,
q->queued++;
return idx;
err_free_skb:
status.skb = tx_info.skb;
spin_lock_bh(&dev->rx_lock);
ieee80211_tx_status_ext(dev->hw, &status);
spin_unlock_bh(&dev->rx_lock);
err_ret:
return err;
}
static void mt76u_tx_kick(struct mt76_dev *dev, struct mt76_queue *q)