mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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:
commit
45f9960f8c
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
298
drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.c
Normal file
298
drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.c
Normal 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);
|
||||
}
|
||||
151
drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.h
Normal file
151
drivers/net/wireless/mediatek/mt76/mt7925/cached_cal.h
Normal 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 */
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 *
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user