2023-03-29 07:08:19

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 00/34] wifi: iwlwifi: updates intended for v6.4 2023-03-29

From: Gregory Greenman <[email protected]>

Hi,

Here's the next set of iwlwifi patches adding MLO support.
Also, advance FW API version to 75.

Thanks,
Gregory

Avraham Stern (1):
wifi: iwlwifi: mvm: adjust iwl_mvm_scan_respect_p2p_go_iter() for MLO

Benjamin Berg (2):
wifi: iwlwifi: mvm: use appropriate link for rate selection
wifi: iwlwifi: mvm: initialize max_rc_amsdu_len per-link

Gregory Greenman (7):
wifi: iwlwifi: mvm: adjust iwl_mvm_sec_key_remove_ap to MLO
wifi: iwlwifi: mvm: adjust radar detection to MLO
wifi: iwlwifi: mvm: adjust rs init to MLO
wifi: iwlwifi: mvm: update mac config when assigning chanctx
wifi: iwlwifi: mvm: rework active links counting
wifi: iwlwifi: mvm: move max_agg_bufsize into host TLC lq_sta
wifi: iwlwifi: bump FW API to 75 for AX devices

Johannes Berg (19):
wifi: iwlwifi: mvm: make some HW flags conditional
wifi: iwlwifi: mvm: fix narrow RU check for MLO
wifi: iwlwifi: mvm: skip MEI update for MLO
wifi: iwlwifi: mvm: use STA link address
wifi: iwlwifi: mvm: rs-fw: don't crash on missing channel
wifi: iwlwifi: mvm: coex: start handling multiple links
wifi: iwlwifi: mvm: make a few warnings only trigger once
wifi: iwlwifi: mvm: rxmq: report link ID to mac80211
wifi: iwlwifi: mvm: skip inactive links
wifi: iwlwifi: mvm: remove only link-specific AP keys
wifi: iwlwifi: mvm: avoid sending MAC context for idle
wifi: iwlwifi: mvm: remove chanctx WARN_ON
wifi: iwlwifi: mvm: use the new lockdep-checking macros
wifi: iwlwifi: mvm: fix station link data leak
wifi: iwlwifi: mvm: clean up mac_id vs. link_id in MLD sta
wifi: iwlwifi: mvm: send full STA during HW restart
wifi: iwlwifi: mvm: free probe_resp_data later
wifi: iwlwifi: separate AP link management queues
wifi: iwlwifi: mvm: correctly use link in iwl_mvm_sta_del()

Shaul Triebitz (5):
wifi: iwlwifi: mvm: use the link sta address
wifi: iwlwifi: mvm: implement mac80211 callback change_sta_links
wifi: iwlwifi: mvm: translate management frame address
wifi: iwlwifi: mvm: use bcast/mcast link station id
wifi: iwlwifi: mvm: use the correct link queue

.../net/wireless/intel/iwlwifi/cfg/22000.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 89 +++--
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 8 +-
drivers/net/wireless/intel/iwlwifi/mvm/link.c | 33 +-
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 126 +++++--
.../net/wireless/intel/iwlwifi/mvm/mld-key.c | 15 +-
.../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 48 ++-
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 335 ++++++++++++++----
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 11 +-
.../net/wireless/intel/iwlwifi/mvm/power.c | 21 +-
.../net/wireless/intel/iwlwifi/mvm/rs-fw.c | 146 +++++---
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 19 +-
drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 16 +-
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 28 +-
drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 22 +-
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 45 ++-
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 11 +-
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 29 +-
.../net/wireless/intel/iwlwifi/mvm/utils.c | 4 +
19 files changed, 733 insertions(+), 275 deletions(-)

--
2.38.1


2023-03-29 07:08:19

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 03/34] wifi: iwlwifi: mvm: skip MEI update for MLO

From: Johannes Berg <[email protected]>

For now, if using MLO, skip the MEI update. It probably
needs new API for multiple channels.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 9eb95ed48d02..294e1c1de6b6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3464,7 +3464,6 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mei_conn_info conn_info = {
.ssid_len = vif->cfg.ssid_len,
- .channel = vif->bss_conf.chandef.chan->hw_value,
};

if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
@@ -3473,6 +3472,12 @@ static void iwl_mvm_mei_host_associated(struct iwl_mvm *mvm,
if (!mvm->mei_registered)
return;

+ /* FIXME: MEI needs to be updated for MLO */
+ if (!vif->bss_conf.chandef.chan)
+ return;
+
+ conn_info.channel = vif->bss_conf.chandef.chan->hw_value;
+
switch (mvm_sta->pairwise_cipher) {
case WLAN_CIPHER_SUITE_TKIP:
conn_info.pairwise_cipher = IWL_MEI_CIPHER_TKIP;
--
2.38.1

2023-03-29 07:08:19

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 02/34] wifi: iwlwifi: mvm: fix narrow RU check for MLO

From: Johannes Berg <[email protected]>

This needs to apply to the link, not deflink.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 22 +++++++++++++------
1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index c76c6b1f0218..9eb95ed48d02 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3392,20 +3392,27 @@ static void iwl_mvm_check_he_obss_narrow_bw_ru_iter(struct wiphy *wiphy,
rcu_read_unlock();
}

-static void iwl_mvm_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif)
+static void
+iwl_mvm_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ unsigned int link_id,
+ struct ieee80211_bss_conf *link_conf)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_he_obss_narrow_bw_ru_data iter_data = {
.tolerated = true,
};

- if (!(vif->bss_conf.chandef.chan->flags & IEEE80211_CHAN_RADAR)) {
- mvmvif->deflink.he_ru_2mhz_block = false;
+ if (WARN_ON_ONCE(!link_conf->chandef.chan ||
+ !mvmvif->link[link_id]))
+ return;
+
+ if (!(link_conf->chandef.chan->flags & IEEE80211_CHAN_RADAR)) {
+ mvmvif->link[link_id]->he_ru_2mhz_block = false;
return;
}

- cfg80211_bss_iter(hw->wiphy, &vif->bss_conf.chandef,
+ cfg80211_bss_iter(hw->wiphy, &link_conf->chandef,
iwl_mvm_check_he_obss_narrow_bw_ru_iter,
&iter_data);

@@ -3413,7 +3420,7 @@ static void iwl_mvm_check_he_obss_narrow_bw_ru(struct ieee80211_hw *hw,
* If there is at least one AP on radar channel that cannot
* tolerate 26-tone RU UL OFDMA transmissions using HE TB PPDU.
*/
- mvmvif->deflink.he_ru_2mhz_block = !iter_data.tolerated;
+ mvmvif->link[link_id]->he_ru_2mhz_block = !iter_data.tolerated;
}

static void iwl_mvm_reset_cca_40mhz_workaround(struct iwl_mvm *mvm,
@@ -3615,7 +3622,8 @@ static void iwl_mvm_vif_set_he_support(struct ieee80211_hw *hw,
if (is_sta) {
mvmvif->link[i]->he_ru_2mhz_block = false;
if (link_sta->he_cap.has_he)
- iwl_mvm_check_he_obss_narrow_bw_ru(hw, vif);
+ iwl_mvm_check_he_obss_narrow_bw_ru(hw, vif, i,
+ link_conf);
}
}
}
--
2.38.1

2023-03-29 07:08:21

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 01/34] wifi: iwlwifi: mvm: make some HW flags conditional

From: Johannes Berg <[email protected]>

With newer MLD firmware API we no longer need beacon timing
information from the host, so disable TIMING_BEACON_ONLY.

If MLO is enabled (currently only for testing), then we must
not have DEAUTH_NEED_MGD_TX_PREP because mac80211 doesn't
support it yet, we'll have to fix that later.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index c60aff0df801..c76c6b1f0218 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -291,17 +291,28 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
ieee80211_hw_set(hw, SUPPORTS_PS);
ieee80211_hw_set(hw, SUPPORTS_DYNAMIC_PS);
ieee80211_hw_set(hw, AMPDU_AGGREGATION);
- ieee80211_hw_set(hw, TIMING_BEACON_ONLY);
ieee80211_hw_set(hw, CONNECTION_MONITOR);
ieee80211_hw_set(hw, CHANCTX_STA_CSA);
ieee80211_hw_set(hw, SUPPORT_FAST_XMIT);
ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS);
ieee80211_hw_set(hw, SUPPORTS_AMSDU_IN_AMPDU);
ieee80211_hw_set(hw, NEEDS_UNIQUE_STA_ADDR);
- ieee80211_hw_set(hw, DEAUTH_NEED_MGD_TX_PREP);
ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
ieee80211_hw_set(hw, BUFF_MMPDU_TXQ);
ieee80211_hw_set(hw, STA_MMPDU_TXQ);
+
+ /* With MLD FW API, it tracks timing by itself,
+ * no need for any timing from the host
+ */
+ if (!mvm->mld_api_is_used)
+ ieee80211_hw_set(hw, TIMING_BEACON_ONLY);
+
+ /* We should probably have this, but mac80211
+ * currently doesn't support it for MLO.
+ */
+ if (!(hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO))
+ ieee80211_hw_set(hw, DEAUTH_NEED_MGD_TX_PREP);
+
/*
* On older devices, enabling TX A-MSDU occasionally leads to
* something getting messed up, the command read from the FIFO
--
2.38.1

2023-03-29 07:08:26

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 05/34] wifi: iwlwifi: mvm: rs-fw: don't crash on missing channel

From: Johannes Berg <[email protected]>

This is more of a workaround, with MLO we can get here with
the deflink not assigned. It's not critical right now that
we have this right, so WARN_ON_ONCE() and don't crash until
we can fix this area of the code.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index 778c9237fe87..ed4200d9bd04 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -506,6 +506,9 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;

+ if (WARN_ON_ONCE(!mvmsta->vif->bss_conf.chandef.chan))
+ return IEEE80211_MAX_MPDU_LEN_VHT_3895;
+
if (mvmsta->vif->bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) {
switch (le16_get_bits(sta->deflink.he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
--
2.38.1

2023-03-29 07:08:39

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 06/34] wifi: iwlwifi: mvm: coex: start handling multiple links

From: Johannes Berg <[email protected]>

Iterate all the links here and check which ones are active,
then adjust them accordingly.

This is still wrong as far as the RSSI event is concerned
(calling iwl_mvm_bt_coex_enable_rssi_event) since we call
that now multiple times, which could overwrite the data;
we need to either make that per link or call it only once,
but need to sort out first what the firmware will be doing
for beacon filtering/beacon abort in MLO.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/coex.c | 89 +++++++++++++------
.../net/wireless/intel/iwlwifi/mvm/utils.c | 4 +
2 files changed, 64 insertions(+), 29 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
index daaa173aaed6..5a5b1128e75c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/coex.c
@@ -257,33 +257,35 @@ static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm,
swap(data->primary, data->secondary);
}

-/* must be called under rcu_read_lock */
-static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
- struct ieee80211_vif *vif)
+static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct iwl_bt_iterator_data *data,
+ unsigned int link_id)
{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_bt_iterator_data *data = _data;
- struct iwl_mvm *mvm = data->mvm;
- struct ieee80211_chanctx_conf *chanctx_conf;
/* default smps_mode is AUTOMATIC - only used for client modes */
enum ieee80211_smps_mode smps_mode = IEEE80211_SMPS_AUTOMATIC;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 bt_activity_grading, min_ag_for_static_smps;
+ struct ieee80211_chanctx_conf *chanctx_conf;
+ struct iwl_mvm_vif_link_info *link_info;
+ struct ieee80211_bss_conf *link_conf;
int ave_rssi;

lockdep_assert_held(&mvm->mutex);

- switch (vif->type) {
- case NL80211_IFTYPE_STATION:
- break;
- case NL80211_IFTYPE_AP:
- if (!mvmvif->ap_ibss_active)
- return;
- break;
- default:
+ link_info = mvmvif->link[link_id];
+ if (!link_info)
return;
- }

- chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf);
+ link_conf = rcu_dereference(vif->link_conf[link_id]);
+ /* This can happen due to races: if we receive the notification
+ * and have the mutex held, while mac80211 is stuck on our mutex
+ * in the middle of removing the link.
+ */
+ if (!link_conf)
+ return;
+
+ chanctx_conf = rcu_dereference(link_conf->chanctx_conf);

/* If channel context is invalid or not on 2.4GHz .. */
if ((!chanctx_conf ||
@@ -291,10 +293,10 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (vif->type == NL80211_IFTYPE_STATION) {
/* ... relax constraints and disable rssi events */
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
- smps_mode, 0);
- iwl_mvm_bt_coex_reduced_txp(mvm,
- mvmvif->deflink.ap_sta_id,
+ smps_mode, link_id);
+ iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id,
false);
+ /* FIXME: should this be per link? */
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
}
return;
@@ -315,17 +317,18 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (!vif->cfg.assoc)
smps_mode = IEEE80211_SMPS_AUTOMATIC;

- if (mvmvif->deflink.phy_ctxt &&
- (mvm->last_bt_notif.rrc_status & BIT(mvmvif->deflink.phy_ctxt->id)))
+ if (link_info->phy_ctxt &&
+ (mvm->last_bt_notif.rrc_status & BIT(link_info->phy_ctxt->id)))
smps_mode = IEEE80211_SMPS_AUTOMATIC;

IWL_DEBUG_COEX(data->mvm,
- "mac %d: bt_activity_grading %d smps_req %d\n",
- mvmvif->id, bt_activity_grading, smps_mode);
+ "mac %d link %d: bt_activity_grading %d smps_req %d\n",
+ mvmvif->id, link_info->fw_link_id,
+ bt_activity_grading, smps_mode);

if (vif->type == NL80211_IFTYPE_STATION)
iwl_mvm_update_smps(mvm, vif, IWL_MVM_SMPS_REQ_BT_COEX,
- smps_mode, 0);
+ smps_mode, link_id);

/* low latency is always primary */
if (iwl_mvm_vif_low_latency(mvmvif)) {
@@ -354,6 +357,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
data->secondary = chanctx_conf;
}

+ /* FIXME: TCM load per interface? or need something per link? */
if (data->primary == chanctx_conf)
data->primary_load = mvm->tcm.result.load[mvmvif->id];
else if (data->secondary == chanctx_conf)
@@ -371,6 +375,7 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
/* if secondary is not NULL, it might be a GO */
data->secondary = chanctx_conf;

+ /* FIXME: TCM load per interface? or need something per link? */
if (data->primary == chanctx_conf)
data->primary_load = mvm->tcm.result.load[mvmvif->id];
else if (data->secondary == chanctx_conf)
@@ -385,8 +390,8 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT ||
mvm->cfg->bt_shared_single_ant || !vif->cfg.assoc ||
le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) {
- iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->deflink.ap_sta_id,
- false);
+ iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id, false);
+ /* FIXME: should this be per link? */
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0);
return;
}
@@ -398,11 +403,11 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
if (!ave_rssi)
ave_rssi = -100;
if (ave_rssi > -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH) {
- if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->deflink.ap_sta_id,
+ if (iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id,
true))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
} else if (ave_rssi < -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH) {
- if (iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->deflink.ap_sta_id,
+ if (iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id,
false))
IWL_ERR(mvm, "Couldn't send BT_CONFIG cmd\n");
}
@@ -411,6 +416,32 @@ static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi);
}

+/* must be called under rcu_read_lock */
+static void iwl_mvm_bt_notif_iterator(void *_data, u8 *mac,
+ struct ieee80211_vif *vif)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_bt_iterator_data *data = _data;
+ struct iwl_mvm *mvm = data->mvm;
+ unsigned int link_id;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_STATION:
+ break;
+ case NL80211_IFTYPE_AP:
+ if (!mvmvif->ap_ibss_active)
+ return;
+ break;
+ default:
+ return;
+ }
+
+ for (link_id = 0; link_id < IEEE80211_MLD_MAX_NUM_LINKS; link_id++)
+ iwl_mvm_bt_notif_per_link(mvm, vif, data, link_id);
+}
+
static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm)
{
struct iwl_bt_iterator_data data = {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
index cf72b9377411..af31b09c3966 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c
@@ -296,6 +296,10 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return;

mvmvif = iwl_mvm_vif_from_mac80211(vif);
+
+ if (WARN_ON_ONCE(!mvmvif->link[link_id]))
+ return;
+
mvmvif->link[link_id]->smps_requests[req_type] = smps_request;
for (i = 0; i < NUM_IWL_MVM_SMPS_REQ; i++) {
if (mvmvif->link[link_id]->smps_requests[i] ==
--
2.38.1

2023-03-29 07:08:41

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 07/34] wifi: iwlwifi: mvm: make a few warnings only trigger once

From: Johannes Berg <[email protected]>

We're hitting these while starting to enable MLO in the
driver, but getting them each and every time isn't very
useful one way or the other. Make these warnings trigger
only once.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 294e1c1de6b6..2b2221d7582b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -5591,7 +5591,7 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
continue;

/* make sure only TDLS peers or the AP are flushed */
- WARN_ON(i != mvmvif->deflink.ap_sta_id && !sta->tdls);
+ WARN_ON_ONCE(i != mvmvif->deflink.ap_sta_id && !sta->tdls);

if (drop) {
if (iwl_mvm_flush_sta(mvm, mvmsta, false))
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
index 154f145396ce..aa8b4fb9c201 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
@@ -213,8 +213,8 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);

- if (WARN_ON(vif->type != NL80211_IFTYPE_STATION ||
- mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA))
+ if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
+ mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA))
return;

if (!sec_key_ver)
--
2.38.1

2023-03-29 07:08:42

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 08/34] wifi: iwlwifi: mvm: adjust iwl_mvm_sec_key_remove_ap to MLO

From: Gregory Greenman <[email protected]>

It has to be done per link. We still don't support keys
configuration for several links, but the single vif link can
still point to a link different from deflink. For now handle
the removal of keys for the default link.

Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 3 ++-
drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 6 +++---
drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 3 +--
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 ++-
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +-
5 files changed, 9 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 2b2221d7582b..44542b00fa14 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2699,7 +2699,8 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status)) {
/* first remove remaining keys */
- iwl_mvm_sec_key_remove_ap(mvm, vif);
+ iwl_mvm_sec_key_remove_ap(mvm, vif,
+ &mvmvif->deflink);

/*
* Remove AP station now that
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
index aa8b4fb9c201..44206e3e1a87 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
@@ -207,14 +207,14 @@ static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
}

void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif)
+ struct ieee80211_vif *vif,
+ struct iwl_mvm_vif_link_info *link)
{
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);

if (WARN_ON_ONCE(vif->type != NL80211_IFTYPE_STATION ||
- mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA))
+ link->ap_sta_id == IWL_MVM_INVALID_STA))
return;

if (!sec_key_ver)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 7463cb8a271a..be9b2efa5ef5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -538,14 +538,13 @@ static void iwl_mvm_mld_vif_delete_all_stas(struct iwl_mvm *mvm,
if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
return;

- iwl_mvm_sec_key_remove_ap(mvm, vif);
-
for_each_mvm_vif_valid_link(mvmvif, i) {
struct iwl_mvm_vif_link_info *link = mvmvif->link[i];

if (!link)
continue;

+ iwl_mvm_sec_key_remove_ap(mvm, vif, link);
ret = iwl_mvm_mld_rm_sta_id(mvm, vif, link->ap_sta_id);
if (ret)
IWL_ERR(mvm, "failed to remove AP station\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index dfe1aff10548..6421edd53404 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -2326,7 +2326,8 @@ int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct ieee80211_key_conf *keyconf);
void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif);
+ struct ieee80211_vif *vif,
+ struct iwl_mvm_vif_link_info *link);

int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm,
struct iwl_rfi_lut_entry *rfi_table);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index eb57acaef96a..f9f512a85ef1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -2022,7 +2022,7 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return true;

/* first remove remaining keys */
- iwl_mvm_sec_key_remove_ap(mvm, vif);
+ iwl_mvm_sec_key_remove_ap(mvm, vif, &mvmvif->deflink);

/* unassoc - go ahead - remove the AP STA now */
mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;
--
2.38.1

2023-03-29 07:08:46

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 09/34] wifi: iwlwifi: mvm: adjust radar detection to MLO

From: Gregory Greenman <[email protected]>

Make the decision about radar detection status depending
on each active MLO link.

Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/power.c | 20 ++++++++++++-------
1 file changed, 13 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
index 45a652cce491..2033d89dc9e5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
@@ -279,18 +279,24 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
{
struct ieee80211_chanctx_conf *chanctx_conf;
- struct ieee80211_channel *chan;
+ struct ieee80211_bss_conf *link_conf;
bool radar_detect = false;
+ unsigned int link_id;

rcu_read_lock();
- chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf);
- WARN_ON(!chanctx_conf);
- if (chanctx_conf) {
- chan = chanctx_conf->def.chan;
- radar_detect = chan->flags & IEEE80211_CHAN_RADAR;
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ chanctx_conf = rcu_dereference(link_conf->chanctx_conf);
+ if (WARN_ON(!chanctx_conf))
+ continue;
+
+ radar_detect = !!(chanctx_conf->def.chan->flags &
+ IEEE80211_CHAN_RADAR);
+ if (radar_detect)
+ goto out;
}
- rcu_read_unlock();

+out:
+ rcu_read_unlock();
return radar_detect;
}

--
2.38.1

2023-03-29 07:08:48

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 10/34] wifi: iwlwifi: mvm: adjust rs init to MLO

From: Gregory Greenman <[email protected]>

Rate scale initialization needs some parameters stored
separately for each link. Pass link_conf and link_sta
pointers and adjust the relevant code accordingly.

Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 36 +++++++++++++------
.../net/wireless/intel/iwlwifi/mvm/rs-fw.c | 36 +++++++++++++------
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 17 ++++++---
drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 10 ++++--
4 files changed, 71 insertions(+), 28 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 44542b00fa14..92567ab34b88 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3557,15 +3557,28 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
* (2) if a link is valid in sta then it's valid in vif (can
* use same index in the link array)
*/
+static void iwl_mvm_rs_rate_init_all_links(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ bool update)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ unsigned int link_id;

-#define iwl_mvm_rs_rate_init_all_links(mvm, mvmvif, sta, update) do { \
- typeof(mvmvif) _mvmvif = mvmvif; \
- unsigned int _i; \
- for_each_mvm_vif_valid_link(_mvmvif, _i) \
- iwl_mvm_rs_rate_init((mvm), (sta), \
- _mvmvif->link[_i]->phy_ctxt->channel->band,\
- (update)); \
-} while (0)
+ for_each_mvm_vif_valid_link(mvmvif, link_id) {
+ struct ieee80211_bss_conf *conf =
+ rcu_dereference_protected(vif->link_conf[link_id], 1);
+ struct ieee80211_link_sta *link_sta =
+ rcu_dereference_protected(sta->link[link_id], 1);
+
+ if (!conf || !link_sta || !mvmvif->link[link_id]->phy_ctxt)
+ continue;
+
+ iwl_mvm_rs_rate_init(mvm, sta, conf, link_sta,
+ mvmvif->link[link_id]->phy_ctxt->channel->band,
+ update);
+ }
+}

#define IWL_MVM_MIN_BEACON_INTERVAL_TU 16

@@ -3729,7 +3742,7 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw,
}

out:
- iwl_mvm_rs_rate_init_all_links(mvm, mvmvif, sta, false);
+ iwl_mvm_rs_rate_init_all_links(mvm, vif, sta, false);

return callbacks->update_sta(mvm, vif, sta);
}
@@ -3762,7 +3775,7 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm,
iwl_mvm_mei_host_associated(mvm, vif, mvm_sta);
}

- iwl_mvm_rs_rate_init_all_links(mvm, mvmvif, sta, true);
+ iwl_mvm_rs_rate_init_all_links(mvm, vif, sta, true);

return 0;
}
@@ -3781,7 +3794,7 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
/* once we move into assoc state, need to update rate scale to
* disable using wide bandwidth
*/
- iwl_mvm_rs_rate_init_all_links(mvm, mvmvif, sta, false);
+ iwl_mvm_rs_rate_init_all_links(mvm, vif, sta, false);

if (!sta->tdls) {
/* Set this but don't call iwl_mvm_mac_ctxt_changed()
@@ -3950,6 +3963,7 @@ void iwl_mvm_sta_rc_update(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
IEEE80211_RC_SUPP_RATES_CHANGED |
IEEE80211_RC_NSS_CHANGED))
iwl_mvm_rs_rate_init(mvm, sta,
+ &vif->bss_conf, &sta->deflink,
mvmvif->deflink.phy_ctxt->channel->band,
true);

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index ed4200d9bd04..d1a308a451cc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -500,16 +500,17 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
rcu_read_unlock();
}

-u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
+u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta)
{
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
- const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
+ const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
+ const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;

- if (WARN_ON_ONCE(!mvmsta->vif->bss_conf.chandef.chan))
+ if (WARN_ON_ONCE(!link_conf->chandef.chan))
return IEEE80211_MAX_MPDU_LEN_VHT_3895;

- if (mvmsta->vif->bss_conf.chandef.chan->band == NL80211_BAND_6GHZ) {
+ if (link_conf->chandef.chan->band == NL80211_BAND_6GHZ) {
switch (le16_get_bits(sta->deflink.he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
@@ -546,16 +547,18 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta)
}

void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta,
enum nl80211_band band, bool update)
{
struct ieee80211_hw *hw = mvm->hw;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_lq_sta_rs_fw *lq_sta = &mvmsta->deflink.lq_sta.rs_fw;
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
struct ieee80211_supported_band *sband = hw->wiphy->bands[band];
- u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta);
+ u16 max_amsdu_len = rs_fw_get_max_amsdu_len(sta, link_conf, link_sta);
+ struct iwl_mvm_link_sta *mvm_link_sta;
+ struct iwl_lq_sta_rs_fw *lq_sta;
struct iwl_tlc_config_cmd_v4 cfg_cmd = {
- .sta_id = mvmsta->deflink.sta_id,
.max_ch_width = update ?
rs_fw_bw_from_sta_bw(sta) : IWL_TLC_MNG_CH_WIDTH_20MHZ,
.flags = cpu_to_le16(rs_fw_get_config_flags(mvm, sta, sband)),
@@ -564,11 +567,24 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
.max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ?
cpu_to_le16(max_amsdu_len) : 0,
};
- int ret;
+ unsigned int link_id = link_conf->link_id;
int cmd_ver;
+ int ret;

+ rcu_read_lock();
+ mvm_link_sta = rcu_dereference(mvmsta->link[link_id]);
+ if (WARN_ON_ONCE(!mvm_link_sta)) {
+ rcu_read_unlock();
+ return;
+ }
+
+ cfg_cmd.sta_id = mvm_link_sta->sta_id;
+
+ lq_sta = &mvm_link_sta->lq_sta.rs_fw;
memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));

+ rcu_read_unlock();
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_mvm_reset_frame_stats(mvm);
#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 1b0e99377156..161a32929848 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -1487,9 +1487,11 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
enum rs_action scale_action)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct ieee80211_bss_conf *bss_conf = &mvmsta->vif->bss_conf;
int i;

- sta->deflink.agg.max_amsdu_len = rs_fw_get_max_amsdu_len(sta);
+ sta->deflink.agg.max_amsdu_len =
+ rs_fw_get_max_amsdu_len(sta, bss_conf, &sta->deflink);

/*
* In case TLC offload is not active amsdu_enabled is either 0xFFFF
@@ -1502,7 +1504,7 @@ static void rs_set_amsdu_len(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
else
mvmsta->amsdu_enabled = 0xFFFF;

- if (mvmsta->vif->bss_conf.he_support &&
+ if (bss_conf->he_support &&
!iwlwifi_mod_params.disable_11ax)
mvmsta->max_amsdu_len = sta->deflink.agg.max_amsdu_len;
else
@@ -3002,17 +3004,20 @@ static void rs_drv_rate_update(void *mvm_r,
void *priv_sta, u32 changed)
{
struct iwl_op_mode *op_mode = mvm_r;
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode);
u8 tid;

- if (!iwl_mvm_sta_from_mac80211(sta)->vif)
+ if (!mvmsta->vif)
return;

/* Stop any ongoing aggregations as rs starts off assuming no agg */
for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++)
ieee80211_stop_tx_ba_session(sta, tid);

- iwl_mvm_rs_rate_init(mvm, sta, sband->band, true);
+ iwl_mvm_rs_rate_init(mvm, sta,
+ &mvmsta->vif->bss_conf, &sta->deflink,
+ sband->band, true);
}

static void __iwl_mvm_rs_tx_status(struct iwl_mvm *mvm,
@@ -4097,10 +4102,12 @@ static const struct rate_control_ops rs_mvm_ops_drv = {
};

void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta,
enum nl80211_band band, bool update)
{
if (iwl_mvm_has_tlc_offload(mvm)) {
- rs_fw_rate_init(mvm, sta, band, update);
+ rs_fw_rate_init(mvm, sta, link_conf, link_sta, band, update);
} else {
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
index b7bc8c1b2dda..c3145cb8f354 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
@@ -393,7 +393,9 @@ struct iwl_lq_sta {

/* Initialize station's rate scaling information after adding station */
void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
- enum nl80211_band band, bool init);
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta,
+ enum nl80211_band band, bool update);

/* Notify RS about Tx status */
void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
@@ -430,11 +432,15 @@ void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm);

void iwl_mvm_rs_add_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta);
void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta,
enum nl80211_band band, bool update);
int rs_fw_tx_protection(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
bool enable);
void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb);

-u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta);
+u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta,
+ struct ieee80211_bss_conf *link_conf,
+ struct ieee80211_link_sta *link_sta);
#endif /* __rs__ */
--
2.38.1

2023-03-29 07:08:49

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 11/34] wifi: iwlwifi: mvm: use the link sta address

From: Shaul Triebitz <[email protected]>

Replace the deflink.addr with the proper link address
for setting the peer_link_address in the station command.
For a non-MLD station, it will be the deflink.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index da9d2cefa509..c877c94dd1d6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -399,8 +399,7 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
cmd.link_id = cpu_to_le32(link_info->fw_link_id);

memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN);
- /* FIXME: use the correct link */
- memcpy(&cmd.peer_link_address, sta->deflink.addr, ETH_ALEN);
+ memcpy(&cmd.peer_link_address, link_sta->addr, ETH_ALEN);

if (mvm_sta->sta_state >= IEEE80211_STA_ASSOC)
cmd.assoc_id = cpu_to_le32(sta->aid);
--
2.38.1

2023-03-29 07:08:53

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 14/34] wifi: iwlwifi: mvm: use bcast/mcast link station id

From: Shaul Triebitz <[email protected]>

For an MLD AP, use the correct link mcast or bcast station id.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index 61a95ee3ef2d..ca1284f11f8b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -739,10 +739,23 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
if (info.control.vif->type == NL80211_IFTYPE_P2P_DEVICE ||
info.control.vif->type == NL80211_IFTYPE_AP ||
info.control.vif->type == NL80211_IFTYPE_ADHOC) {
+ u32 link_id = u32_get_bits(info.control.flags,
+ IEEE80211_TX_CTRL_MLO_LINK);
+ struct iwl_mvm_vif_link_info *link;
+
+ if (link_id == IEEE80211_LINK_UNSPECIFIED) {
+ if (info.control.vif->active_links)
+ link_id = ffs(info.control.vif->active_links) - 1;
+ else
+ link_id = 0;
+ }
+
+ link = mvmvif->link[link_id];
+
if (!ieee80211_is_data(hdr->frame_control))
- sta_id = mvmvif->deflink.bcast_sta.sta_id;
+ sta_id = link->bcast_sta.sta_id;
else
- sta_id = mvmvif->deflink.mcast_sta.sta_id;
+ sta_id = link->mcast_sta.sta_id;

queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr);
} else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) {
--
2.38.1

2023-03-29 07:08:53

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 12/34] wifi: iwlwifi: mvm: implement mac80211 callback change_sta_links

From: Shaul Triebitz <[email protected]>

Add/removed from iwl driver and firmware station links.
Update the station queues accordingly (which station links
are connected to the station queues).

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 9 +-
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 246 ++++++++++++++++--
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 +
3 files changed, 236 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index be9b2efa5ef5..e475d0daf512 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -953,7 +953,14 @@ iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u16 old_links, u16 new_links)
{
- return 0;
+ struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ int ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links);
+ mutex_unlock(&mvm->mutex);
+
+ return ret;
}

const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index c877c94dd1d6..9be6d858411d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -479,15 +479,53 @@ static void iwl_mvm_mld_sta_rm_all_sta_links(struct iwl_mvm *mvm,
}
}

+static void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
+ struct iwl_mvm_sta *mvm_sta,
+ struct iwl_mvm_link_sta *mvm_sta_link,
+ unsigned int link_id)
+{
+ RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id], NULL);
+ RCU_INIT_POINTER(mvm_sta->link[link_id], NULL);
+
+ if (mvm_sta_link != &mvm_sta->deflink)
+ kfree_rcu(mvm_sta_link, rcu_head);
+}
+
+static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ unsigned int link_id)
+{
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_mvm_link_sta *link;
+ u32 sta_id = iwl_mvm_find_free_sta_id(mvm,
+ ieee80211_vif_type_p2p(vif));
+
+ if (sta_id == IWL_MVM_INVALID_STA)
+ return -ENOSPC;
+
+ if (rcu_access_pointer(sta->link[link_id]) == &sta->deflink) {
+ link = &mvm_sta->deflink;
+ } else {
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (!link)
+ return -ENOMEM;
+ }
+
+ link->sta_id = sta_id;
+ rcu_assign_pointer(mvm_sta->link[link_id], link);
+ rcu_assign_pointer(mvm->fw_id_to_mac_id[link->sta_id], sta);
+
+ return 0;
+}
+
/* allocate all the links of a sta, called when the station is first added */
static int iwl_mvm_mld_alloc_sta_links(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_mvm_link_sta *link;
unsigned int link_id;
- u32 sta_id;
int ret;

lockdep_assert_held(&mvm->mutex);
@@ -497,27 +535,9 @@ static int iwl_mvm_mld_alloc_sta_links(struct iwl_mvm *mvm,
mvm_sta->link[link_id])
continue;

- sta_id = iwl_mvm_find_free_sta_id(mvm,
- ieee80211_vif_type_p2p(vif));
-
- if (sta_id == IWL_MVM_INVALID_STA) {
- ret = -ENOSPC;
+ ret = iwl_mvm_mld_alloc_sta_link(mvm, vif, sta, link_id);
+ if (ret)
goto err;
- }
-
- if (rcu_access_pointer(sta->link[link_id]) == &sta->deflink) {
- link = &mvm_sta->deflink;
- } else {
- link = kzalloc(sizeof(*link), GFP_KERNEL);
- if (!link) {
- ret = -ENOMEM;
- goto err;
- }
- }
-
- link->sta_id = sta_id;
- rcu_assign_pointer(mvm_sta->link[link_id], link);
- rcu_assign_pointer(mvm->fw_id_to_mac_id[link->sta_id], sta);
}

return 0;
@@ -846,3 +866,185 @@ void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm,

rcu_read_unlock();
}
+
+static int iwl_mvm_mld_update_sta_queue(struct iwl_mvm *mvm,
+ struct iwl_mvm_sta *mvm_sta,
+ u32 old_sta_mask,
+ u32 new_sta_mask)
+{
+ struct iwl_scd_queue_cfg_cmd cmd = {
+ .operation = cpu_to_le32(IWL_SCD_QUEUE_MODIFY),
+ .u.modify.old_sta_mask = cpu_to_le32(old_sta_mask),
+ .u.modify.new_sta_mask = cpu_to_le32(new_sta_mask),
+ };
+ struct iwl_host_cmd hcmd = {
+ .id = WIDE_ID(DATA_PATH_GROUP, SCD_QUEUE_CONFIG_CMD),
+ .len[0] = sizeof(cmd),
+ .data[0] = &cmd
+ };
+ int tid;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ for (tid = 0; tid <= IWL_MAX_TID_COUNT; tid++) {
+ struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[tid];
+ int txq_id = tid_data->txq_id;
+
+ if (txq_id == IWL_MVM_INVALID_QUEUE)
+ continue;
+
+ if (tid == IWL_MAX_TID_COUNT)
+ cmd.u.modify.tid = cpu_to_le32(IWL_MGMT_TID);
+ else
+ cmd.u.modify.tid = cpu_to_le32(tid);
+
+ ret = iwl_mvm_send_cmd(mvm, &hcmd);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ u16 old_links, u16 new_links)
+{
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_link_sta *mvm_sta_link;
+ struct iwl_mvm_vif_link_info *mvm_vif_link;
+ unsigned long links_to_add = ~old_links & new_links;
+ unsigned long links_to_rem = old_links & ~new_links;
+ unsigned long old_links_long = old_links;
+ u32 current_sta_mask = 0, sta_mask_added = 0, sta_mask_to_rem = 0;
+ unsigned long link_sta_added_to_fw = 0, link_sta_allocated = 0;
+ unsigned int link_id;
+ int ret;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ for_each_set_bit(link_id, &old_links_long,
+ IEEE80211_MLD_MAX_NUM_LINKS) {
+ mvm_sta_link =
+ rcu_dereference_protected(mvm_sta->link[link_id],
+ lockdep_is_held(&mvm->mutex));
+
+ if (WARN_ON(!mvm_sta_link)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ current_sta_mask |= BIT(mvm_sta_link->sta_id);
+ if (links_to_rem & BIT(link_id))
+ sta_mask_to_rem |= BIT(mvm_sta_link->sta_id);
+ }
+
+ if (sta_mask_to_rem) {
+ ret = iwl_mvm_mld_update_sta_queue(mvm, mvm_sta,
+ current_sta_mask,
+ current_sta_mask & ~sta_mask_to_rem);
+ if (WARN_ON(ret))
+ goto err;
+
+ current_sta_mask &= ~sta_mask_to_rem;
+ }
+
+ for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+ mvm_sta_link =
+ rcu_dereference_protected(mvm_sta->link[link_id],
+ lockdep_is_held(&mvm->mutex));
+ mvm_vif_link = mvm_vif->link[link_id];
+
+ if (WARN_ON(!mvm_sta_link || !mvm_vif_link)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id);
+ if (WARN_ON(ret))
+ goto err;
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ mvm_vif_link->ap_sta_id = IWL_MVM_INVALID_STA;
+
+ iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
+ }
+
+ for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct ieee80211_bss_conf *link_conf =
+ rcu_dereference_protected(vif->link_conf[link_id], 1);
+ struct ieee80211_link_sta *link_sta =
+ rcu_dereference_protected(sta->link[link_id], 1);
+ mvm_vif_link = mvm_vif->link[link_id];
+
+ if (WARN_ON(!mvm_vif_link || !link_conf || !link_sta ||
+ mvm_sta->link[link_id])) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = iwl_mvm_mld_alloc_sta_link(mvm, vif, sta, link_id);
+ if (WARN_ON(ret))
+ goto err;
+
+ mvm_sta_link =
+ rcu_dereference_protected(mvm_sta->link[link_id],
+ lockdep_is_held(&mvm->mutex));
+
+ if (WARN_ON(!mvm_sta_link)) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (vif->type == NL80211_IFTYPE_STATION)
+ iwl_mvm_mld_set_ap_sta_id(sta, mvm_vif_link,
+ mvm_sta_link);
+
+ link_sta_allocated |= BIT(link_id);
+
+ sta_mask_added |= BIT(mvm_sta_link->sta_id);
+
+ ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta, link_conf,
+ mvm_sta_link);
+ if (WARN_ON(ret))
+ goto err;
+
+ link_sta_added_to_fw |= BIT(link_id);
+ }
+
+ if (sta_mask_added) {
+ ret = iwl_mvm_mld_update_sta_queue(mvm, mvm_sta,
+ current_sta_mask,
+ current_sta_mask | sta_mask_added);
+ if (WARN_ON(ret))
+ goto err;
+ }
+
+ return 0;
+
+err:
+ /* remove all already allocated stations in FW */
+ for_each_set_bit(link_id, &link_sta_added_to_fw,
+ IEEE80211_MLD_MAX_NUM_LINKS) {
+ mvm_sta_link =
+ rcu_dereference_protected(mvm_sta->link[link_id],
+ lockdep_is_held(&mvm->mutex));
+
+ iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id);
+ }
+
+ /* remove all already allocated station links in driver */
+ for_each_set_bit(link_id, &link_sta_allocated,
+ IEEE80211_MLD_MAX_NUM_LINKS) {
+ mvm_sta_link =
+ rcu_dereference_protected(mvm_sta->link[link_id],
+ lockdep_is_held(&mvm->mutex));
+
+ iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
+ }
+
+ return ret;
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index 6d4db666368b..2402b41bc0bb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -641,6 +641,10 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
u8 sta_id);
+int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ u16 old_links, u16 new_links);

/* Queues */
void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
--
2.38.1

2023-03-29 07:08:55

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 15/34] wifi: iwlwifi: mvm: rxmq: report link ID to mac80211

From: Johannes Berg <[email protected]>

Add a fw_id_to_link_sta array in mvm to track the link
STA for each firmware station ID, and then use that to
report the link a frame was received on (since we know
the station ID from firmware).

Notably, this fixes beacon tracking for the correct link
since mac80211 now queues and processes those on the one
link identified by the link ID only.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 8 ++++--
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 ++-
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 8 ++++++
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 1 +
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 28 ++++++++++++++-----
5 files changed, 39 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index d302d98b7631..7fe733dcc748 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1570,8 +1570,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
}

/* init the fw <-> mac80211 STA mapping */
- for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++)
+ for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
+ RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL);
+ }

memset(&mvm->fw_link_ids_map, 0, sizeof(mvm->fw_link_ids_map));

@@ -1757,8 +1759,10 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
goto error;

/* init the fw <-> mac80211 STA mapping */
- for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++)
+ for (i = 0; i < mvm->fw->ucode_capa.num_stations; i++) {
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
+ RCU_INIT_POINTER(mvm->fw_id_to_link_sta[i], NULL);
+ }

if (iwl_fw_lookup_cmd_ver(mvm->fw, ADD_STA, 0) < 12) {
/*
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 4c8ab1db1f19..568f0eaeb0fb 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3319,9 +3319,11 @@ void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
link_sta = rcu_dereference_protected(mvm_sta->link[link_id],
lockdep_is_held(&mvm->mutex));
sta_id = link_sta->sta_id;
- if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[sta_id]))
+ if (sta == rcu_access_pointer(mvm->fw_id_to_mac_id[sta_id])) {
rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id],
ERR_PTR(-ENOENT));
+ RCU_INIT_POINTER(mvm->fw_id_to_link_sta[sta_id], NULL);
+ }
}
mutex_unlock(&mvm->mutex);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 9be6d858411d..a713b8a10781 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -472,6 +472,7 @@ static void iwl_mvm_mld_sta_rm_all_sta_links(struct iwl_mvm *mvm,
continue;

RCU_INIT_POINTER(mvm->fw_id_to_mac_id[link->sta_id], NULL);
+ RCU_INIT_POINTER(mvm->fw_id_to_link_sta[link->sta_id], NULL);
RCU_INIT_POINTER(mvm_sta->link[link_id], NULL);

if (link != &mvm_sta->deflink)
@@ -485,6 +486,7 @@ static void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
unsigned int link_id)
{
RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id], NULL);
+ RCU_INIT_POINTER(mvm->fw_id_to_link_sta[mvm_sta_link->sta_id], NULL);
RCU_INIT_POINTER(mvm_sta->link[link_id], NULL);

if (mvm_sta_link != &mvm_sta->deflink)
@@ -496,6 +498,8 @@ static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
unsigned int link_id)
{
+ struct ieee80211_link_sta *link_sta =
+ rcu_dereference_protected(sta->link[link_id], 1);
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_link_sta *link;
u32 sta_id = iwl_mvm_find_free_sta_id(mvm,
@@ -515,6 +519,8 @@ static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm,
link->sta_id = sta_id;
rcu_assign_pointer(mvm_sta->link[link_id], link);
rcu_assign_pointer(mvm->fw_id_to_mac_id[link->sta_id], sta);
+ rcu_assign_pointer(mvm->fw_id_to_link_sta[link->sta_id],
+ link_sta);

return 0;
}
@@ -604,6 +610,7 @@ static int iwl_mvm_alloc_sta_after_restart(struct iwl_mvm *mvm,
return ret;

rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
+ rcu_assign_pointer(mvm->fw_id_to_link_sta[sta_id], link_sta);
iwl_mvm_realloc_queues_after_restart(mvm, sta);

/* since we need only one station, no need to continue */
@@ -800,6 +807,7 @@ int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex);

RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL);
+ RCU_INIT_POINTER(mvm->fw_id_to_link_sta[sta_id], NULL);
return ret;
}

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 6421edd53404..a7a7018edd2b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -905,6 +905,7 @@ struct iwl_mvm {
/* data related to data path */
struct iwl_rx_phy_info last_phy_info;
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT_MAX];
+ struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_MVM_STATION_COUNT_MAX];
unsigned long fw_link_ids_map;
u8 rx_ba_sessions;

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
index b160ae137c4a..5d803e537b00 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
@@ -253,12 +253,22 @@ static void iwl_mvm_add_rtap_sniffer_config(struct iwl_mvm *mvm,
static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm,
struct napi_struct *napi,
struct sk_buff *skb, int queue,
- struct ieee80211_sta *sta)
+ struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta)
{
- if (iwl_mvm_check_pn(mvm, skb, queue, sta))
+ if (unlikely(iwl_mvm_check_pn(mvm, skb, queue, sta))) {
kfree_skb(skb);
- else
- ieee80211_rx_napi(mvm->hw, sta, skb, napi);
+ return;
+ }
+
+ if (sta && sta->valid_links && link_sta) {
+ struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
+
+ rx_status->link_valid = 1;
+ rx_status->link_id = link_sta->link_id;
+ }
+
+ ieee80211_rx_napi(mvm->hw, sta, skb, napi);
}

static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
@@ -631,7 +641,7 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
while ((skb = __skb_dequeue(skb_list))) {
iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb,
reorder_buf->queue,
- sta);
+ sta, NULL /* FIXME */);
reorder_buf->num_stored--;
}
}
@@ -2298,6 +2308,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
u32 len;
u32 pkt_len = iwl_rx_packet_payload_len(pkt);
struct ieee80211_sta *sta = NULL;
+ struct ieee80211_link_sta *link_sta = NULL;
struct sk_buff *skb;
u8 crypt_len = 0;
size_t desc_size;
@@ -2454,6 +2465,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
sta = rcu_dereference(mvm->fw_id_to_mac_id[id]);
if (IS_ERR(sta))
sta = NULL;
+ link_sta = rcu_dereference(mvm->fw_id_to_link_sta[id]);
}
} else if (!is_multicast_ether_addr(hdr->addr2)) {
/*
@@ -2588,8 +2600,10 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
}

if (!iwl_mvm_reorder(mvm, napi, queue, sta, skb, desc) &&
- (likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr2))))
- iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta);
+ likely(!iwl_mvm_time_sync_frame(mvm, skb, hdr->addr2)))
+ iwl_mvm_pass_packet_to_mac80211(mvm, napi, skb, queue, sta,
+ link_sta);
+
out:
rcu_read_unlock();
}
--
2.38.1

2023-03-29 07:08:56

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 13/34] wifi: iwlwifi: mvm: translate management frame address

From: Shaul Triebitz <[email protected]>

For management frames sent by an AP interface, translate
the MLD addresses to LINK addresses (for an MLD AP).
AP (non-bufferable) management frames are sent via
the broadcast station so the translation cannot be
done by the firmware.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 22 +++++++++++++++++++
1 file changed, 22 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 92567ab34b88..4c8ab1db1f19 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -722,6 +722,9 @@ void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr = (void *)skb->data;
bool offchannel = IEEE80211_SKB_CB(skb)->flags &
IEEE80211_TX_CTL_TX_OFFCHAN;
+ u32 link_id = u32_get_bits(info->control.flags,
+ IEEE80211_TX_CTRL_MLO_LINK);
+ struct ieee80211_sta *tmp_sta = sta;

if (iwl_mvm_is_radio_killed(mvm)) {
IWL_DEBUG_DROP(mvm, "Dropping - RF/CT KILL\n");
@@ -755,6 +758,25 @@ void iwl_mvm_mac_tx(struct ieee80211_hw *hw,
}
}

+ if (tmp_sta && !sta && link_id != IEEE80211_LINK_UNSPECIFIED &&
+ !ieee80211_is_probe_resp(hdr->frame_control)) {
+ /* translate MLD addresses to LINK addresses */
+ struct ieee80211_link_sta *link_sta =
+ rcu_dereference(tmp_sta->link[link_id]);
+ struct ieee80211_bss_conf *link_conf =
+ rcu_dereference(info->control.vif->link_conf[link_id]);
+ struct ieee80211_mgmt *mgmt;
+
+ if (WARN_ON(!link_sta || !link_conf))
+ goto drop;
+
+ /* if sta is NULL, the frame is a management frame */
+ mgmt = (void *)hdr;
+ memcpy(mgmt->da, link_sta->addr, ETH_ALEN);
+ memcpy(mgmt->sa, link_conf->addr, ETH_ALEN);
+ memcpy(mgmt->bssid, link_conf->bssid, ETH_ALEN);
+ }
+
iwl_mvm_tx_skb(mvm, skb, sta);
return;
drop:
--
2.38.1

2023-03-29 07:08:58

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 17/34] wifi: iwlwifi: mvm: skip inactive links

From: Johannes Berg <[email protected]>

When iterating station links, skip the links that are not
yet active by checking for mvmvif->link[] existence.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 568f0eaeb0fb..1fd7e5bf594d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3657,7 +3657,7 @@ static void iwl_mvm_vif_set_he_support(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *link_conf =
rcu_dereference_protected(vif->link_conf[i], 1);

- if (!link_conf || !link_sta)
+ if (!link_conf || !link_sta || !mvmvif->link[i])
continue;

link_conf->he_support = link_sta->he_cap.has_he;
@@ -3757,6 +3757,8 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw,

if (WARN_ON(!link_conf))
return -EINVAL;
+ if (!mvmvif->link[i])
+ continue;

iwl_mvm_link_changed(mvm, vif, link_conf,
LINK_CONTEXT_MODIFY_ALL &
--
2.38.1

2023-03-29 07:08:59

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 16/34] wifi: iwlwifi: mvm: adjust iwl_mvm_scan_respect_p2p_go_iter() for MLO

From: Avraham Stern <[email protected]>

When looking for a GO on for setting the scan parameters, iterate
over all the available links.

Signed-off-by: Avraham Stern <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
index 975edc02e637..07045092c717 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c
@@ -2677,11 +2677,23 @@ static void iwl_mvm_scan_respect_p2p_go_iter(void *_data, u8 *mac,
if (vif == data->current_vif)
return;

- if (vif->type == NL80211_IFTYPE_AP && vif->p2p &&
- mvmvif->deflink.phy_ctxt->id < NUM_PHY_CTX &&
- (data->band == NUM_NL80211_BANDS ||
- mvmvif->deflink.phy_ctxt->channel->band == data->band))
- data->p2p_go = true;
+ if (vif->type == NL80211_IFTYPE_AP && vif->p2p) {
+ u32 link_id;
+
+ for (link_id = 0;
+ link_id < ARRAY_SIZE(mvmvif->link);
+ link_id++) {
+ struct iwl_mvm_vif_link_info *link =
+ mvmvif->link[link_id];
+
+ if (link && link->phy_ctxt->id < NUM_PHY_CTX &&
+ (data->band == NUM_NL80211_BANDS ||
+ link->phy_ctxt->channel->band == data->band)) {
+ data->p2p_go = true;
+ break;
+ }
+ }
+ }
}

static bool _iwl_mvm_get_respect_p2p_go(struct iwl_mvm *mvm,
--
2.38.1

2023-03-29 07:09:00

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 18/34] wifi: iwlwifi: mvm: remove only link-specific AP keys

From: Johannes Berg <[email protected]>

When we remove the AP station, we iterate over the links
and remove all the keys, however, the key iteration will
return all keys for all links, so skip the ones that we
don't need based on the link ID.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 9 +++++++--
drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 ++-
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 2 +-
5 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 1fd7e5bf594d..98c940271648 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2722,7 +2722,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
&mvm->status)) {
/* first remove remaining keys */
iwl_mvm_sec_key_remove_ap(mvm, vif,
- &mvmvif->deflink);
+ &mvmvif->deflink, 0);

/*
* Remove AP station now that
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
index 44206e3e1a87..f4785c0a0b84 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
@@ -195,6 +195,7 @@ static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
void *data)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
+ unsigned int link_id = (uintptr_t)data;

if (key->hw_key_idx == STA_KEY_IDX_INVALID)
return;
@@ -202,13 +203,17 @@ static void iwl_mvm_sec_key_remove_ap_iter(struct ieee80211_hw *hw,
if (sta)
return;

+ if (key->link_id >= 0 && key->link_id != link_id)
+ return;
+
_iwl_mvm_sec_key_del(mvm, vif, NULL, key, CMD_ASYNC);
key->hw_key_idx = STA_KEY_IDX_INVALID;
}

void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- struct iwl_mvm_vif_link_info *link)
+ struct iwl_mvm_vif_link_info *link,
+ unsigned int link_id)
{
u32 sec_key_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
u8 sec_key_ver = iwl_fw_lookup_cmd_ver(mvm->fw, sec_key_id, 0);
@@ -222,5 +227,5 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,

ieee80211_iter_keys_rcu(mvm->hw, vif,
iwl_mvm_sec_key_remove_ap_iter,
- NULL);
+ (void *)(uintptr_t)link_id);
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index e475d0daf512..1a97bf925817 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -544,7 +544,7 @@ static void iwl_mvm_mld_vif_delete_all_stas(struct iwl_mvm *mvm,
if (!link)
continue;

- iwl_mvm_sec_key_remove_ap(mvm, vif, link);
+ iwl_mvm_sec_key_remove_ap(mvm, vif, link, i);
ret = iwl_mvm_mld_rm_sta_id(mvm, vif, link->ap_sta_id);
if (ret)
IWL_ERR(mvm, "failed to remove AP station\n");
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index a7a7018edd2b..23d797247915 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -2328,7 +2328,8 @@ int iwl_mvm_sec_key_del(struct iwl_mvm *mvm,
struct ieee80211_key_conf *keyconf);
void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
- struct iwl_mvm_vif_link_info *link);
+ struct iwl_mvm_vif_link_info *link,
+ unsigned int link_id);

int iwl_rfi_send_config_cmd(struct iwl_mvm *mvm,
struct iwl_rfi_lut_entry *rfi_table);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index f9f512a85ef1..9a3a7eabded8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -2022,7 +2022,7 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return true;

/* first remove remaining keys */
- iwl_mvm_sec_key_remove_ap(mvm, vif, &mvmvif->deflink);
+ iwl_mvm_sec_key_remove_ap(mvm, vif, &mvmvif->deflink, 0);

/* unassoc - go ahead - remove the AP STA now */
mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;
--
2.38.1

2023-03-29 07:09:01

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 20/34] wifi: iwlwifi: mvm: remove chanctx WARN_ON

From: Johannes Berg <[email protected]>

During link switching there might be a link that's marked
active but has no chanctx assigned (so it's not active from
our driver's POV), skip such links in power recalculation
without any warning.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/power.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/power.c b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
index 2033d89dc9e5..ac1dae52556f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/power.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/power.c
@@ -286,7 +286,8 @@ static bool iwl_mvm_power_is_radar(struct ieee80211_vif *vif)
rcu_read_lock();
for_each_vif_active_link(vif, link_conf, link_id) {
chanctx_conf = rcu_dereference(link_conf->chanctx_conf);
- if (WARN_ON(!chanctx_conf))
+ /* this happens on link switching, just ignore inactive ones */
+ if (!chanctx_conf)
continue;

radar_detect = !!(chanctx_conf->def.chan->flags &
--
2.38.1

2023-03-29 07:09:02

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 21/34] wifi: iwlwifi: mvm: use the new lockdep-checking macros

From: Johannes Berg <[email protected]>

Use the new macros from mac80211 that do lockdep checking
on the RCU dereferences, instead of hard-coding 1 as the
argument to rcu_dereference_protected().

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 14 +++++++-------
.../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 4 +---
drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 10 +++++-----
3 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 98c940271648..7fb00220e6cc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -3591,9 +3591,9 @@ static void iwl_mvm_rs_rate_init_all_links(struct iwl_mvm *mvm,

for_each_mvm_vif_valid_link(mvmvif, link_id) {
struct ieee80211_bss_conf *conf =
- rcu_dereference_protected(vif->link_conf[link_id], 1);
+ link_conf_dereference_protected(vif, link_id);
struct ieee80211_link_sta *link_sta =
- rcu_dereference_protected(sta->link[link_id], 1);
+ link_sta_dereference_protected(sta, link_id);

if (!conf || !link_sta || !mvmvif->link[link_id]->phy_ctxt)
continue;
@@ -3622,9 +3622,9 @@ static bool iwl_mvm_vif_conf_from_sta(struct iwl_mvm *mvm,
for_each_set_bit(i, (unsigned long *)&sta->valid_links,
IEEE80211_MLD_MAX_NUM_LINKS) {
struct ieee80211_link_sta *link_sta =
- rcu_dereference_protected(sta->link[i], 1);
+ link_sta_dereference_protected(sta, i);
struct ieee80211_bss_conf *link_conf =
- rcu_dereference_protected(vif->link_conf[i], 1);
+ link_conf_dereference_protected(vif, i);

if (!link_conf || !link_sta)
continue;
@@ -3653,9 +3653,9 @@ static void iwl_mvm_vif_set_he_support(struct ieee80211_hw *hw,
for_each_set_bit(i, (unsigned long *)&sta->valid_links,
IEEE80211_MLD_MAX_NUM_LINKS) {
struct ieee80211_link_sta *link_sta =
- rcu_dereference_protected(sta->link[i], 1);
+ link_sta_dereference_protected(sta, i);
struct ieee80211_bss_conf *link_conf =
- rcu_dereference_protected(vif->link_conf[i], 1);
+ link_conf_dereference_protected(vif, i);

if (!link_conf || !link_sta || !mvmvif->link[i])
continue;
@@ -3753,7 +3753,7 @@ iwl_mvm_sta_state_auth_to_assoc(struct ieee80211_hw *hw,
for_each_set_bit(i, (unsigned long *)&sta->valid_links,
IEEE80211_MLD_MAX_NUM_LINKS) {
struct ieee80211_bss_conf *link_conf =
- rcu_dereference_protected(vif->link_conf[i], 1);
+ link_conf_dereference_protected(vif, i);

if (WARN_ON(!link_conf))
return -EINVAL;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 8ed76fc83702..ddc09012549b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -921,9 +921,7 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
if (added & BIT(i)) {
struct ieee80211_bss_conf *link_conf;

- /* FIXME: allow use of sdata_dereference()? */
- link_conf = rcu_dereference_protected(vif->link_conf[i],
- 1);
+ link_conf = link_conf_dereference_protected(vif, i);
if (WARN_ON(!link_conf))
continue;

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index a713b8a10781..34b85a9a27af 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -499,7 +499,7 @@ static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm,
unsigned int link_id)
{
struct ieee80211_link_sta *link_sta =
- rcu_dereference_protected(sta->link[link_id], 1);
+ link_sta_dereference_protected(sta, link_id);
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_link_sta *link;
u32 sta_id = iwl_mvm_find_free_sta_id(mvm,
@@ -654,7 +654,7 @@ int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,

for_each_sta_active_link(vif, sta, link_sta, link_id) {
struct ieee80211_bss_conf *link_conf =
- rcu_dereference_protected(vif->link_conf[link_id], 1);
+ link_conf_dereference_protected(vif, link_id);
struct iwl_mvm_link_sta *mvm_link_sta =
rcu_dereference_protected(mvm_sta->link[link_id],
lockdep_is_held(&mvm->mutex));
@@ -704,7 +704,7 @@ int iwl_mvm_mld_update_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,

for_each_sta_active_link(vif, sta, link_sta, link_id) {
struct ieee80211_bss_conf *link_conf =
- rcu_dereference_protected(vif->link_conf[link_id], 1);
+ link_conf_dereference_protected(vif, link_id);
struct iwl_mvm_link_sta *mvm_link_sta =
rcu_dereference_protected(mvm_sta->link[link_id],
lockdep_is_held(&mvm->mutex));
@@ -983,9 +983,9 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,

for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
struct ieee80211_bss_conf *link_conf =
- rcu_dereference_protected(vif->link_conf[link_id], 1);
+ link_conf_dereference_protected(vif, link_id);
struct ieee80211_link_sta *link_sta =
- rcu_dereference_protected(sta->link[link_id], 1);
+ link_sta_dereference_protected(sta, link_id);
mvm_vif_link = mvm_vif->link[link_id];

if (WARN_ON(!mvm_vif_link || !link_conf || !link_sta ||
--
2.38.1

2023-03-29 07:09:06

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 23/34] wifi: iwlwifi: mvm: initialize max_rc_amsdu_len per-link

From: Benjamin Berg <[email protected]>

Initialize max_rc_amsdu_len per-link both on state change and when a new
link is added.

Signed-off-by: Benjamin Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 3 +++
1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 34b85a9a27af..5e382981bfa2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -998,6 +998,9 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
if (WARN_ON(ret))
goto err;

+ link_sta->agg.max_rc_amsdu_len = 1;
+ ieee80211_sta_recalc_aggregates(sta);
+
mvm_sta_link =
rcu_dereference_protected(mvm_sta->link[link_id],
lockdep_is_held(&mvm->mutex));
--
2.38.1

2023-03-29 07:09:06

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 24/34] wifi: iwlwifi: mvm: fix station link data leak

From: Johannes Berg <[email protected]>

When we remove the station, we call iwl_mvm_sta_del() which
returns true if we cannot remove it from the firmware yet,
which happens if this is the station ID for the AP station
that's still used because the MAC is still associated.

However, we still must free the link data as the station is
only kept alive in the firmware, in mac80211 and driver the
data structures are destroyed.

To fix that, we need to make iwl_mvm_mld_free_sta_link()
track whether or not the station is still alive in FW, as
otherwise we might reuse the station ID in the meantime and
iwl_mvm_mld_rm_sta_from_fw() would reject the later delete
from the firmware. Add an argument to it for that. Then we
can use the return value of iwl_mvm_sta_del() for that to
fix the issue, and call iwl_mvm_mld_rm_sta_from_fw() only
if we need to not keep the station in FW.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 2 +-
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 59 ++++++++++---------
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 3 +-
3 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index ddc09012549b..beef706d0598 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -545,7 +545,7 @@ static void iwl_mvm_mld_vif_delete_all_stas(struct iwl_mvm *mvm,
continue;

iwl_mvm_sec_key_remove_ap(mvm, vif, link, i);
- ret = iwl_mvm_mld_rm_sta_id(mvm, vif, link->ap_sta_id);
+ ret = iwl_mvm_mld_rm_sta_id(mvm, link->ap_sta_id);
if (ret)
IWL_ERR(mvm, "failed to remove AP station\n");

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 5e382981bfa2..b3377b4d7924 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -458,6 +458,21 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
return iwl_mvm_mld_send_sta_cmd(mvm, &cmd);
}

+static void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
+ struct iwl_mvm_sta *mvm_sta,
+ struct iwl_mvm_link_sta *mvm_sta_link,
+ unsigned int link_id,
+ bool is_in_fw)
+{
+ RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id],
+ is_in_fw ? ERR_PTR(-EINVAL) : NULL);
+ RCU_INIT_POINTER(mvm->fw_id_to_link_sta[mvm_sta_link->sta_id], NULL);
+ RCU_INIT_POINTER(mvm_sta->link[link_id], NULL);
+
+ if (mvm_sta_link != &mvm_sta->deflink)
+ kfree_rcu(mvm_sta_link, rcu_head);
+}
+
static void iwl_mvm_mld_sta_rm_all_sta_links(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta)
{
@@ -471,28 +486,10 @@ static void iwl_mvm_mld_sta_rm_all_sta_links(struct iwl_mvm *mvm,
if (!link)
continue;

- RCU_INIT_POINTER(mvm->fw_id_to_mac_id[link->sta_id], NULL);
- RCU_INIT_POINTER(mvm->fw_id_to_link_sta[link->sta_id], NULL);
- RCU_INIT_POINTER(mvm_sta->link[link_id], NULL);
-
- if (link != &mvm_sta->deflink)
- kfree_rcu(link, rcu_head);
+ iwl_mvm_mld_free_sta_link(mvm, mvm_sta, link, link_id, false);
}
}

-static void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
- struct iwl_mvm_sta *mvm_sta,
- struct iwl_mvm_link_sta *mvm_sta_link,
- unsigned int link_id)
-{
- RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta_link->sta_id], NULL);
- RCU_INIT_POINTER(mvm->fw_id_to_link_sta[mvm_sta_link->sta_id], NULL);
- RCU_INIT_POINTER(mvm_sta->link[link_id], NULL);
-
- if (mvm_sta_link != &mvm_sta->deflink)
- kfree_rcu(mvm_sta_link, rcu_head);
-}
-
static int iwl_mvm_mld_alloc_sta_link(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -787,20 +784,24 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct iwl_mvm_link_sta *mvm_link_sta =
rcu_dereference_protected(mvm_sta->link[link_id],
lockdep_is_held(&mvm->mutex));
+ bool stay_in_fw;

- if (iwl_mvm_sta_del(mvm, vif, sta, mvm_link_sta, &ret))
- return ret;
+ stay_in_fw = iwl_mvm_sta_del(mvm, vif, sta, mvm_link_sta, &ret);
+ if (ret)
+ break;

- ret = iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_link_sta->sta_id);
- }
+ if (!stay_in_fw)
+ ret = iwl_mvm_mld_rm_sta_from_fw(mvm,
+ mvm_link_sta->sta_id);

- iwl_mvm_mld_sta_rm_all_sta_links(mvm, mvm_sta);
+ iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta,
+ link_id, stay_in_fw);
+ }

return ret;
}

-int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- u8 sta_id)
+int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id)
{
int ret = iwl_mvm_mld_rm_sta_from_fw(mvm, sta_id);

@@ -978,7 +979,8 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
if (vif->type == NL80211_IFTYPE_STATION)
mvm_vif_link->ap_sta_id = IWL_MVM_INVALID_STA;

- iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
+ iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id,
+ false);
}

for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
@@ -1054,7 +1056,8 @@ int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
rcu_dereference_protected(mvm_sta->link[link_id],
lockdep_is_held(&mvm->mutex));

- iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
+ iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id,
+ false);
}

return ret;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index 2402b41bc0bb..824d12047019 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -639,8 +639,7 @@ int iwl_mvm_mld_update_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
-int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
- u8 sta_id);
+int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id);
int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
--
2.38.1

2023-03-29 07:09:07

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 25/34] wifi: iwlwifi: mvm: clean up mac_id vs. link_id in MLD sta

From: Johannes Berg <[email protected]>

Here we always have a link ID, not MAC ID, so clean up the
naming.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index b3377b4d7924..4d713c78b508 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -21,8 +21,7 @@ static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm,
*/
static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm,
struct iwl_mvm_int_sta *sta,
- const u8 *addr,
- u16 mac_id)
+ const u8 *addr, int link_id)
{
struct iwl_mvm_sta_cfg_cmd cmd;

@@ -31,7 +30,7 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm,
memset(&cmd, 0, sizeof(cmd));
cmd.sta_id = cpu_to_le32((u8)sta->sta_id);

- cmd.link_id = cpu_to_le32(mac_id);
+ cmd.link_id = cpu_to_le32(link_id);

cmd.station_type = cpu_to_le32(sta->type);

@@ -94,7 +93,7 @@ static int iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm *mvm,
*/
static int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
struct iwl_mvm_int_sta *sta,
- const u8 *addr, int mac_id,
+ const u8 *addr, int link_id,
u16 *queue, u8 tid,
unsigned int *_wdg_timeout)
{
@@ -106,9 +105,9 @@ static int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
return -ENOSPC;

if (sta->type == STATION_TYPE_AUX)
- ret = iwl_mvm_add_aux_sta_to_fw(mvm, sta, mac_id);
+ ret = iwl_mvm_add_aux_sta_to_fw(mvm, sta, link_id);
else
- ret = iwl_mvm_mld_add_int_sta_to_fw(mvm, sta, addr, mac_id);
+ ret = iwl_mvm_mld_add_int_sta_to_fw(mvm, sta, addr, link_id);
if (ret)
return ret;

@@ -135,7 +134,7 @@ static int iwl_mvm_mld_add_int_sta(struct iwl_mvm *mvm,
struct iwl_mvm_int_sta *int_sta, u16 *queue,
enum nl80211_iftype iftype,
enum iwl_fw_sta_type sta_type,
- int mac_id, const u8 *addr, u8 tid,
+ int link_id, const u8 *addr, u8 tid,
unsigned int *wdg_timeout)
{
int ret;
@@ -148,7 +147,7 @@ static int iwl_mvm_mld_add_int_sta(struct iwl_mvm *mvm,
if (ret)
return ret;

- ret = iwl_mvm_mld_add_int_sta_with_queue(mvm, int_sta, addr, mac_id,
+ ret = iwl_mvm_mld_add_int_sta_with_queue(mvm, int_sta, addr, link_id,
queue, tid, wdg_timeout);
if (ret) {
iwl_mvm_dealloc_int_sta(mvm, int_sta);
@@ -254,8 +253,8 @@ int iwl_mvm_mld_add_aux_sta(struct iwl_mvm *mvm, u32 lmac_id)
{
lockdep_assert_held(&mvm->mutex);

- /* In CDB NICs we need to specify which lmac to use for aux activity
- * using the mac_id argument place to send lmac_id to the function
+ /* In CDB NICs we need to specify which lmac to use for aux activity;
+ * use the link_id argument place to send lmac_id to the function.
*/
return iwl_mvm_mld_add_int_sta(mvm, &mvm->aux_sta, &mvm->aux_queue,
NL80211_IFTYPE_UNSPECIFIED,
--
2.38.1

2023-03-29 07:09:08

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 26/34] wifi: iwlwifi: mvm: use the correct link queue

From: Shaul Triebitz <[email protected]>

For bcase/mcast tx frames use the link queue.

Signed-off-by: Shaul Triebitz <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index ca1284f11f8b..f5b92d99f39d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -604,11 +604,10 @@ static void iwl_mvm_skb_prepare_status(struct sk_buff *skb,
}

static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
+ struct iwl_mvm_vif_link_info *link,
struct ieee80211_tx_info *info,
struct ieee80211_hdr *hdr)
{
- struct iwl_mvm_vif *mvmvif =
- iwl_mvm_vif_from_mac80211(info->control.vif);
__le16 fc = hdr->frame_control;

switch (info->control.vif->type) {
@@ -631,7 +630,7 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,

if (!ieee80211_has_order(fc) && !ieee80211_is_probe_req(fc) &&
is_multicast_ether_addr(hdr->addr1))
- return mvmvif->deflink.cab_queue;
+ return link->cab_queue;

WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC,
"fc=0x%02x", le16_to_cpu(fc));
@@ -757,7 +756,8 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
else
sta_id = link->mcast_sta.sta_id;

- queue = iwl_mvm_get_ctrl_vif_queue(mvm, &info, hdr);
+ queue = iwl_mvm_get_ctrl_vif_queue(mvm, link, &info,
+ hdr);
} else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) {
queue = mvm->snif_queue;
sta_id = mvm->snif_sta.sta_id;
--
2.38.1

2023-03-29 07:09:10

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 22/34] wifi: iwlwifi: mvm: use appropriate link for rate selection

From: Benjamin Berg <[email protected]>

We were still using the deflink in most cases, update the code to use
the appropriate link.

Signed-off-by: Benjamin Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/rs-fw.c | 109 ++++++++++--------
1 file changed, 61 insertions(+), 48 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
index d1a308a451cc..c8ba2fe3e4a2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
@@ -9,9 +9,9 @@
#include "iwl-op-mode.h"
#include "mvm.h"

-static u8 rs_fw_bw_from_sta_bw(const struct ieee80211_sta *sta)
+static u8 rs_fw_bw_from_sta_bw(const struct ieee80211_link_sta *link_sta)
{
- switch (sta->deflink.bandwidth) {
+ switch (link_sta->bandwidth) {
case IEEE80211_STA_RX_BW_320:
return IWL_TLC_MNG_CH_WIDTH_320MHZ;
case IEEE80211_STA_RX_BW_160:
@@ -38,11 +38,11 @@ static u8 rs_fw_set_active_chains(u8 chains)
return fw_chains;
}

-static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
+static u8 rs_fw_sgi_cw_support(struct ieee80211_link_sta *link_sta)
{
- struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
- struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
- struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
+ struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
+ struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
+ struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
u8 supp = 0;

if (he_cap->has_he)
@@ -61,12 +61,12 @@ static u8 rs_fw_sgi_cw_support(struct ieee80211_sta *sta)
}

static u16 rs_fw_get_config_flags(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta,
+ struct ieee80211_link_sta *link_sta,
struct ieee80211_supported_band *sband)
{
- struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
- struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
- struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
+ struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
+ struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
+ struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
bool vht_ena = vht_cap->vht_supported;
u16 flags = 0;

@@ -132,20 +132,20 @@ int rs_fw_vht_highest_rx_mcs_index(const struct ieee80211_sta_vht_cap *vht_cap,
}

static void
-rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
+rs_fw_vht_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
const struct ieee80211_sta_vht_cap *vht_cap,
struct iwl_tlc_config_cmd_v4 *cmd)
{
u16 supp;
int i, highest_mcs;
- u8 max_nss = sta->deflink.rx_nss;
+ u8 max_nss = link_sta->rx_nss;
struct ieee80211_vht_cap ieee_vht_cap = {
.vht_cap_info = cpu_to_le32(vht_cap->cap),
.supp_mcs = vht_cap->vht_mcs,
};

/* the station support only a single receive chain */
- if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC)
+ if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
max_nss = 1;

for (i = 0; i < max_nss && i < IWL_TLC_NSS_MAX; i++) {
@@ -156,7 +156,7 @@ rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
continue;

supp = BIT(highest_mcs + 1) - 1;
- if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_20)
+ if (link_sta->bandwidth == IEEE80211_STA_RX_BW_20)
supp &= ~BIT(IWL_TLC_MNG_HT_RATE_MCS9);

cmd->ht_rates[i][IWL_TLC_MCS_PER_BW_80] = cpu_to_le16(supp);
@@ -165,7 +165,7 @@ rs_fw_vht_set_enabled_rates(const struct ieee80211_sta *sta,
* configuration is supported - only for MCS 0 since we already
* decoded the MCS bits anyway ourselves.
*/
- if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160 &&
+ if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160 &&
ieee80211_get_vht_max_nss(&ieee_vht_cap,
IEEE80211_VHT_CHANWIDTH_160MHZ,
0, true, nss) >= nss)
@@ -192,11 +192,11 @@ static u16 rs_fw_he_ieee80211_mcs_to_rs_mcs(u16 mcs)
}

static void
-rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta,
+rs_fw_he_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
struct ieee80211_supported_band *sband,
struct iwl_tlc_config_cmd_v4 *cmd)
{
- const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
+ const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;
u16 mcs_160 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_160);
u16 mcs_80 = le16_to_cpu(he_cap->he_mcs_nss_supp.rx_mcs_80);
u16 tx_mcs_80 =
@@ -204,10 +204,10 @@ rs_fw_he_set_enabled_rates(const struct ieee80211_sta *sta,
u16 tx_mcs_160 =
le16_to_cpu(sband->iftype_data->he_cap.he_mcs_nss_supp.tx_mcs_160);
int i;
- u8 nss = sta->deflink.rx_nss;
+ u8 nss = link_sta->rx_nss;

/* the station support only a single receive chain */
- if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC)
+ if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
nss = 1;

for (i = 0; i < nss && i < IWL_TLC_NSS_MAX; i++) {
@@ -282,13 +282,14 @@ rs_fw_rs_mcs2eht_mcs(enum IWL_TLC_MCS_PER_BW bw,
}
}

-static void rs_fw_eht_set_enabled_rates(const struct ieee80211_sta *sta,
- struct ieee80211_supported_band *sband,
- struct iwl_tlc_config_cmd_v4 *cmd)
+static void
+rs_fw_eht_set_enabled_rates(const struct ieee80211_link_sta *link_sta,
+ struct ieee80211_supported_band *sband,
+ struct iwl_tlc_config_cmd_v4 *cmd)
{
/* peer RX mcs capa */
const struct ieee80211_eht_mcs_nss_supp *eht_rx_mcs =
- &sta->deflink.eht_cap.eht_mcs_nss_supp;
+ &link_sta->eht_cap.eht_mcs_nss_supp;
/* our TX mcs capa */
const struct ieee80211_eht_mcs_nss_supp *eht_tx_mcs =
&sband->iftype_data->eht_cap.eht_mcs_nss_supp;
@@ -298,7 +299,7 @@ static void rs_fw_eht_set_enabled_rates(const struct ieee80211_sta *sta,
struct ieee80211_eht_mcs_nss_supp_20mhz_only mcs_tx_20;

/* peer is 20Mhz only */
- if (!(sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] &
+ if (!(link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_MASK_ALL)) {
mcs_rx_20 = eht_rx_mcs->only_20mhz;
} else {
@@ -354,25 +355,25 @@ static void rs_fw_eht_set_enabled_rates(const struct ieee80211_sta *sta,
}

/* the station support only a single receive chain */
- if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC ||
- sta->deflink.rx_nss < 2)
+ if (link_sta->smps_mode == IEEE80211_SMPS_STATIC ||
+ link_sta->rx_nss < 2)
memset(cmd->ht_rates[IWL_TLC_NSS_2], 0,
sizeof(cmd->ht_rates[IWL_TLC_NSS_2]));
}

-static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
+static void rs_fw_set_supp_rates(struct ieee80211_link_sta *link_sta,
struct ieee80211_supported_band *sband,
struct iwl_tlc_config_cmd_v4 *cmd)
{
int i;
u16 supp = 0;
unsigned long tmp; /* must be unsigned long for for_each_set_bit */
- const struct ieee80211_sta_ht_cap *ht_cap = &sta->deflink.ht_cap;
- const struct ieee80211_sta_vht_cap *vht_cap = &sta->deflink.vht_cap;
- const struct ieee80211_sta_he_cap *he_cap = &sta->deflink.he_cap;
+ const struct ieee80211_sta_ht_cap *ht_cap = &link_sta->ht_cap;
+ const struct ieee80211_sta_vht_cap *vht_cap = &link_sta->vht_cap;
+ const struct ieee80211_sta_he_cap *he_cap = &link_sta->he_cap;

/* non HT rates */
- tmp = sta->deflink.supp_rates[sband->band];
+ tmp = link_sta->supp_rates[sband->band];
for_each_set_bit(i, &tmp, BITS_PER_LONG)
supp |= BIT(sband->bitrates[i].hw_value);

@@ -380,22 +381,22 @@ static void rs_fw_set_supp_rates(struct ieee80211_sta *sta,
cmd->mode = IWL_TLC_MNG_MODE_NON_HT;

/* HT/VHT rates */
- if (sta->deflink.eht_cap.has_eht) {
+ if (link_sta->eht_cap.has_eht) {
cmd->mode = IWL_TLC_MNG_MODE_EHT;
- rs_fw_eht_set_enabled_rates(sta, sband, cmd);
+ rs_fw_eht_set_enabled_rates(link_sta, sband, cmd);
} else if (he_cap->has_he) {
cmd->mode = IWL_TLC_MNG_MODE_HE;
- rs_fw_he_set_enabled_rates(sta, sband, cmd);
+ rs_fw_he_set_enabled_rates(link_sta, sband, cmd);
} else if (vht_cap->vht_supported) {
cmd->mode = IWL_TLC_MNG_MODE_VHT;
- rs_fw_vht_set_enabled_rates(sta, vht_cap, cmd);
+ rs_fw_vht_set_enabled_rates(link_sta, vht_cap, cmd);
} else if (ht_cap->ht_supported) {
cmd->mode = IWL_TLC_MNG_MODE_HT;
cmd->ht_rates[IWL_TLC_NSS_1][IWL_TLC_MCS_PER_BW_80] =
cpu_to_le16(ht_cap->mcs.rx_mask[0]);

/* the station support only a single receive chain */
- if (sta->deflink.smps_mode == IEEE80211_SMPS_STATIC)
+ if (link_sta->smps_mode == IEEE80211_SMPS_STATIC)
cmd->ht_rates[IWL_TLC_NSS_2][IWL_TLC_MCS_PER_BW_80] =
0;
else
@@ -410,15 +411,18 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_tlc_update_notif *notif;
struct ieee80211_sta *sta;
+ struct ieee80211_link_sta *link_sta;
struct iwl_mvm_sta *mvmsta;
+ struct iwl_mvm_link_sta *mvm_link_sta;
struct iwl_lq_sta_rs_fw *lq_sta;
u32 flags;

rcu_read_lock();

notif = (void *)pkt->data;
+ link_sta = rcu_dereference(mvm->fw_id_to_link_sta[notif->sta_id]);
sta = rcu_dereference(mvm->fw_id_to_mac_id[notif->sta_id]);
- if (IS_ERR_OR_NULL(sta)) {
+ if (IS_ERR_OR_NULL(sta) || !link_sta) {
/* can happen in remove station flow where mvm removed internally
* the station before removing from FW
*/
@@ -438,7 +442,14 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,

flags = le32_to_cpu(notif->flags);

- lq_sta = &mvmsta->deflink.lq_sta.rs_fw;
+ mvm_link_sta = rcu_dereference(mvmsta->link[link_sta->link_id]);
+ if (!mvm_link_sta) {
+ IWL_DEBUG_RATE(mvm,
+ "Invalid mvmsta RCU pointer for link (%d) of sta id (%d) in TLC notification\n",
+ link_sta->link_id, notif->sta_id);
+ goto out;
+ }
+ lq_sta = &mvm_link_sta->lq_sta.rs_fw;

if (flags & IWL_TLC_NOTIF_FLAG_RATE) {
char pretty_rate[100];
@@ -465,9 +476,9 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,
u16 size = le32_to_cpu(notif->amsdu_size);
int i;

- if (sta->deflink.agg.max_amsdu_len < size) {
+ if (link_sta->agg.max_amsdu_len < size) {
/*
- * In debug sta->deflink.agg.max_amsdu_len < size
+ * In debug link_sta->agg.max_amsdu_len < size
* so also check with orig_amsdu_len which holds the
* original data before debugfs changed the value
*/
@@ -477,18 +488,18 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,

mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled);
mvmsta->max_amsdu_len = size;
- sta->deflink.agg.max_rc_amsdu_len = mvmsta->max_amsdu_len;
+ link_sta->agg.max_rc_amsdu_len = mvmsta->max_amsdu_len;

for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
if (mvmsta->amsdu_enabled & BIT(i))
- sta->deflink.agg.max_tid_amsdu_len[i] =
+ link_sta->agg.max_tid_amsdu_len[i] =
iwl_mvm_max_amsdu_size(mvm, sta, i);
else
/*
* Not so elegant, but this will effectively
* prevent AMSDU on this TID
*/
- sta->deflink.agg.max_tid_amsdu_len[i] = 1;
+ link_sta->agg.max_tid_amsdu_len[i] = 1;
}

IWL_DEBUG_RATE(mvm,
@@ -511,7 +522,7 @@ u16 rs_fw_get_max_amsdu_len(struct ieee80211_sta *sta,
return IEEE80211_MAX_MPDU_LEN_VHT_3895;

if (link_conf->chandef.chan->band == NL80211_BAND_6GHZ) {
- switch (le16_get_bits(sta->deflink.he_6ghz_capa.capa,
+ switch (le16_get_bits(link_sta->he_6ghz_capa.capa,
IEEE80211_HE_6GHZ_CAP_MAX_MPDU_LEN)) {
case IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454:
return IEEE80211_MAX_MPDU_LEN_VHT_11454;
@@ -560,10 +571,12 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_lq_sta_rs_fw *lq_sta;
struct iwl_tlc_config_cmd_v4 cfg_cmd = {
.max_ch_width = update ?
- rs_fw_bw_from_sta_bw(sta) : IWL_TLC_MNG_CH_WIDTH_20MHZ,
- .flags = cpu_to_le16(rs_fw_get_config_flags(mvm, sta, sband)),
+ rs_fw_bw_from_sta_bw(link_sta) :
+ IWL_TLC_MNG_CH_WIDTH_20MHZ,
+ .flags = cpu_to_le16(rs_fw_get_config_flags(mvm, link_sta,
+ sband)),
.chains = rs_fw_set_active_chains(iwl_mvm_get_valid_tx_ant(mvm)),
- .sgi_ch_width_supp = rs_fw_sgi_cw_support(sta),
+ .sgi_ch_width_supp = rs_fw_sgi_cw_support(link_sta),
.max_mpdu_len = iwl_mvm_is_csum_supported(mvm) ?
cpu_to_le16(max_amsdu_len) : 0,
};
@@ -588,7 +601,7 @@ void rs_fw_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
#ifdef CONFIG_IWLWIFI_DEBUGFS
iwl_mvm_reset_frame_stats(mvm);
#endif
- rs_fw_set_supp_rates(sta, sband, &cfg_cmd);
+ rs_fw_set_supp_rates(link_sta, sband, &cfg_cmd);

/*
* since TLC offload works with one mode we can assume
--
2.38.1

2023-03-29 07:09:13

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 19/34] wifi: iwlwifi: mvm: avoid sending MAC context for idle

From: Johannes Berg <[email protected]>

If we change only idle, avoid sending the MAC context
command since it doesn't depend on idle state. This
also fixes an issue with the firmware because without
this we send the command during link switching, as we
just deactivated the first link, and we cannot send
this command when there's no active link.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 1a97bf925817..8ed76fc83702 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -563,6 +563,12 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,
unsigned int i;
int ret;

+ /* This might get called without active links during the
+ * chanctx switch, but we don't care about it anyway.
+ */
+ if (changes == BSS_CHANGED_IDLE)
+ return;
+
ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);
if (ret)
IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
--
2.38.1

2023-03-29 07:09:13

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 27/34] wifi: iwlwifi: mvm: update mac config when assigning chanctx

From: Gregory Greenman <[email protected]>

Some mac parameters, such as HE support, can change at this stage.
Update mac config before updating links.

Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index beef706d0598..4d56b2fc5f33 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -231,6 +231,18 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
if (WARN_ON_ONCE(!mvmvif->link[link_id]))
return -EINVAL;

+ /* mac parameters such as HE support can change at this stage
+ * For sta, need first to configure correct state from drv_sta_state
+ * and only after that update mac config.
+ */
+ if (vif->type == NL80211_IFTYPE_AP) {
+ ret = iwl_mvm_mld_mac_ctxt_changed(mvm, vif, false);
+ if (ret) {
+ IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
+ return -EINVAL;
+ }
+ }
+
mvmvif->link[link_id]->phy_ctxt = phy_ctxt;

if (switching_chanctx) {
--
2.38.1

2023-03-29 07:09:17

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 28/34] wifi: iwlwifi: mvm: rework active links counting

From: Gregory Greenman <[email protected]>

Remove fw_active_links_num counter since we now have a bitmap of
active links in vif. Also, update link activation status only when
LINK_CONTEXT_MODIFY_ACTIVE bit set in changes parameter.

Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/link.c | 33 ++++++++++---------
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 1 -
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 --
3 files changed, 17 insertions(+), 20 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/link.c b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
index 0cd40672fade..eb828de40a3c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/link.c
@@ -104,11 +104,6 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID))
return -EINVAL;

- /* cannot activate third link */
- if (!link_info->active && active &&
- mvmvif->fw_active_links_num >= IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM)
- return -EINVAL;
-
if (changes & LINK_CONTEXT_MODIFY_ACTIVE) {
/* When activating a link, phy context should be valid;
* when deactivating a link, it also should be valid since
@@ -119,6 +114,22 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
if (!link_info->phy_ctxt)
return 0;

+ /* check there aren't too many active links */
+ if (!link_info->active && active) {
+ int i, count = 0;
+
+ /* link with phy_ctxt is active in FW */
+ for_each_mvm_vif_valid_link(mvmvif, i)
+ if (mvmvif->link[i]->phy_ctxt)
+ count++;
+
+ /* FIXME: IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM should be
+ * defined per HW
+ */
+ if (count >= IWL_MVM_FW_MAX_ACTIVE_LINKS_NUM)
+ return -EINVAL;
+ }
+
/* Catch early if driver tries to activate or deactivate a link
* twice.
*/
@@ -230,18 +241,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
cmd.flags_mask = cpu_to_le32(flags_mask);

ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY);
- if (!ret) {
- /* the FW is updated, so now it's possible to update the
- * activation status. If activating a link, it was already
- * checked above that we didn't reach the FW limit.
- */
- if (link_info->active && !active)
- mvmvif->fw_active_links_num--;
- else if (!link_info->active && active)
- mvmvif->fw_active_links_num++;
-
+ if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE))
link_info->active = active;
- }

return ret;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 7fb00220e6cc..ff03c8d52277 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -1027,7 +1027,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,

memset(&mvmvif->bf_data, 0, sizeof(mvmvif->bf_data));

- mvmvif->fw_active_links_num = 0;
for_each_mvm_vif_valid_link(mvmvif, link_id) {
mvmvif->link[link_id]->ap_sta_id = IWL_MVM_INVALID_STA;
mvmvif->link[link_id]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 23d797247915..022f7bd64a5d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -355,7 +355,6 @@ struct iwl_mvm_vif_link_info {
* @csa_failed: CSA failed to schedule time event, report an error later
* @csa_bcn_pending: indicates that we are waiting for a beacon on a new channel
* @features: hw features active for this vif
- * @fw_active_links_num: the number of activated links
*/
struct iwl_mvm_vif {
struct iwl_mvm *mvm;
@@ -439,8 +438,6 @@ struct iwl_mvm_vif {
struct ieee80211_key_conf __rcu *keys[2];
} bcn_prot;

- u32 fw_active_links_num;
-
struct iwl_mvm_vif_link_info deflink;
struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS];
};
--
2.38.1

2023-03-29 07:10:03

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 29/34] wifi: iwlwifi: mvm: send full STA during HW restart

From: Johannes Berg <[email protected]>

By using the internal station add the station is installed in
firmware with zeroed MAC addresses, which is wrong. Use the
full installation function instead, to fill all data.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 23 ++++++++-----------
1 file changed, 9 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 4d713c78b508..26686cc7ff4c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -572,10 +572,9 @@ static int iwl_mvm_alloc_sta_after_restart(struct iwl_mvm *mvm,
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct ieee80211_link_sta *link_sta;
unsigned int link_id;
- struct iwl_mvm_int_sta tmp_sta = {
- .type = mvm_sta->sta_type,
- };
- int sta_id, ret;
+ /* no active link found */
+ int ret = -EINVAL;
+ int sta_id;

/* First add an empty station since allocating a queue requires
* a valid station. Since we need a link_id to allocate a station,
@@ -598,23 +597,19 @@ static int iwl_mvm_alloc_sta_after_restart(struct iwl_mvm *mvm,
continue;

sta_id = mvm_link_sta->sta_id;
- tmp_sta.sta_id = sta_id;
- ret = iwl_mvm_mld_add_int_sta_to_fw(mvm, &tmp_sta,
- vif->bss_conf.bssid,
- mvm_link->fw_link_id);
+ ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta,
+ link_conf, mvm_link_sta);
if (ret)
return ret;

rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
rcu_assign_pointer(mvm->fw_id_to_link_sta[sta_id], link_sta);
- iwl_mvm_realloc_queues_after_restart(mvm, sta);
-
- /* since we need only one station, no need to continue */
- return 0;
+ ret = 0;
}

- /* no active link found */
- return -EINVAL;
+ iwl_mvm_realloc_queues_after_restart(mvm, sta);
+
+ return ret;
}

int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
--
2.38.1

2023-03-29 07:10:08

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 30/34] wifi: iwlwifi: mvm: move max_agg_bufsize into host TLC lq_sta

From: Gregory Greenman <[email protected]>

This field is used only for host TLC, so it can reside inside
the corresponding lq_sta struct. Also, TLC lq_sta is cleared
in iwl_mvm_rs_rate_init() upon association, but max_agg_bufsize
is set earlier in iwl_mvm_sta_init(). Thus, place this field
in the persistent part of lq_sta to retain its value.

Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/rs.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/rs.h | 6 ++++--
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 11 ++++++-----
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 --
4 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
index 161a32929848..ab82965bc0f4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
@@ -3607,7 +3607,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
num_of_ant(initial_rate->ant) == 1)
lq_cmd->single_stream_ant_msk = initial_rate->ant;

- lq_cmd->agg_frame_cnt_limit = mvmsta->max_agg_bufsize;
+ lq_cmd->agg_frame_cnt_limit = lq_sta->pers.max_agg_bufsize;

/*
* In case of low latency, tell the firmware to leave a frame in the
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
index c3145cb8f354..f99603b0f693 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.h
@@ -1,10 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/******************************************************************************
*
- * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Mobile Communications GmbH
* Copyright(c) 2017 Intel Deutschland GmbH
- * Copyright(c) 2018 - 2019 Intel Corporation
+ * Copyright (C) 2003 - 2014, 2018 - 2022 Intel Corporation
*****************************************************************************/

#ifndef __rs_h__
@@ -204,6 +203,7 @@ struct rs_rate {
/**
* struct iwl_lq_sta_rs_fw - rate and related statistics for RS in FW
* @last_rate_n_flags: last rate reported by FW
+ * @max_agg_bufsize: the maximal size of the AGG buffer for this station
* @sta_id: the id of the station
#ifdef CONFIG_MAC80211_DEBUGFS
* @dbg_fixed_rate: for debug, use fixed rate if not 0
@@ -353,6 +353,7 @@ struct iwl_lq_sta {

/* last tx rate_n_flags */
u32 last_rate_n_flags;
+
/* packets destined for this STA are aggregated */
u8 is_agg;

@@ -371,6 +372,7 @@ struct iwl_lq_sta {
u8 chains;
s8 chain_signal[IEEE80211_MAX_CHAINS];
s8 last_rssi;
+ u16 max_agg_bufsize;
struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT];
struct iwl_mvm *drv;
spinlock_t lock; /* for races in reinit/update table */
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 9a3a7eabded8..db6a3419bd31 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1719,10 +1719,10 @@ int iwl_mvm_sta_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
rcu_assign_pointer(mvm_sta->link[0], &mvm_sta->deflink);

if (!mvm->trans->trans_cfg->gen2)
- mvm_sta->max_agg_bufsize =
+ mvm_sta->deflink.lq_sta.rs_drv.pers.max_agg_bufsize =
LINK_QUAL_AGG_FRAME_LIMIT_DEF;
else
- mvm_sta->max_agg_bufsize =
+ mvm_sta->deflink.lq_sta.rs_drv.pers.max_agg_bufsize =
LINK_QUAL_AGG_FRAME_LIMIT_GEN2_DEF;
}

@@ -3258,10 +3258,11 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
* for each station. Therefore, use the minimum of all the
* aggregation sessions and our default value.
*/
- mvmsta->max_agg_bufsize =
- min(mvmsta->max_agg_bufsize, buf_size);
+ mvmsta->deflink.lq_sta.rs_drv.pers.max_agg_bufsize =
+ min(mvmsta->deflink.lq_sta.rs_drv.pers.max_agg_bufsize,
+ buf_size);
mvmsta->deflink.lq_sta.rs_drv.lq.agg_frame_cnt_limit =
- mvmsta->max_agg_bufsize;
+ mvmsta->deflink.lq_sta.rs_drv.pers.max_agg_bufsize;

IWL_DEBUG_HT(mvm, "Tx aggregation enabled on ra = %pM tid = %d\n",
sta->addr, tid);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index 824d12047019..625e1dfd47a2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -355,7 +355,6 @@ struct iwl_mvm_link_sta {
* @mac_id_n_color: the MAC context this station is linked to
* @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
* tid.
- * @max_agg_bufsize: the maximal size of the AGG buffer for this station
* @sta_type: station type
* @sta_state: station state according to enum %ieee80211_sta_state
* @bt_reduced_txpower: is reduced tx power enabled for this station
@@ -406,7 +405,6 @@ struct iwl_mvm_sta {
u32 tfd_queue_msk;
u32 mac_id_n_color;
u16 tid_disable_agg;
- u16 max_agg_bufsize;
u8 sta_type;
enum ieee80211_sta_state sta_state;
bool bt_reduced_txpower;
--
2.38.1

2023-03-29 07:10:22

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 04/34] wifi: iwlwifi: mvm: use STA link address

From: Johannes Berg <[email protected]>

For now we only support a single link, so just use the
deflink's address for the link address, instead of the
STA's (MLD) address, but use the link address anyway
in order to facilitate MLO connections.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 7a01295949fa..da9d2cefa509 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -398,9 +398,9 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,

cmd.link_id = cpu_to_le32(link_info->fw_link_id);

- /* For now the link addr is the same as the mld addr */
memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN);
- memcpy(&cmd.peer_link_address, sta->addr, ETH_ALEN);
+ /* FIXME: use the correct link */
+ memcpy(&cmd.peer_link_address, sta->deflink.addr, ETH_ALEN);

if (mvm_sta->sta_state >= IEEE80211_STA_ASSOC)
cmd.assoc_id = cpu_to_le32(sta->aid);
--
2.38.1

2023-03-29 07:10:22

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 34/34] wifi: iwlwifi: mvm: correctly use link in iwl_mvm_sta_del()

From: Johannes Berg <[email protected]>

This function can be invoked for both MLO and non-MLO, so
it must deal with multi-link correctly. Notable, on auth
timeout, we'd otherwise get a warning due to the erroneous
deflink usage in MLO cases.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 18 +++++++++++++-----
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 +-
3 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index ca788a427fa6..78d4f186cd99 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -780,7 +780,7 @@ int iwl_mvm_mld_rm_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_is_held(&mvm->mutex));
bool stay_in_fw;

- stay_in_fw = iwl_mvm_sta_del(mvm, vif, sta, mvm_link_sta, &ret);
+ stay_in_fw = iwl_mvm_sta_del(mvm, vif, sta, link_sta, &ret);
if (ret)
break;

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index a57de37f6e02..8489554e58b1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1986,14 +1986,22 @@ int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm,
*/
bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct iwl_mvm_link_sta *mvm_link_sta, int *ret)
+ struct ieee80211_link_sta *link_sta, int *ret)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm_vif_link_info *mvm_link =
+ mvmvif->link[link_sta->link_id];
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
- u8 sta_id = mvm_link_sta->sta_id;
+ struct iwl_mvm_link_sta *mvm_link_sta;
+ u8 sta_id;

lockdep_assert_held(&mvm->mutex);

+ mvm_link_sta =
+ rcu_dereference_protected(mvm_sta->link[link_sta->link_id],
+ lockdep_is_held(&mvm->mutex));
+ sta_id = mvm_link_sta->sta_id;
+
/* If there is a TXQ still marked as reserved - free it */
if (mvm_sta->reserved_queue != IEEE80211_INVAL_HW_QUEUE) {
u8 reserved_txq = mvm_sta->reserved_queue;
@@ -2022,10 +2030,10 @@ bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return true;

/* first remove remaining keys */
- iwl_mvm_sec_key_remove_ap(mvm, vif, &mvmvif->deflink, 0);
+ iwl_mvm_sec_key_remove_ap(mvm, vif, mvm_link, 0);

/* unassoc - go ahead - remove the AP STA now */
- mvmvif->deflink.ap_sta_id = IWL_MVM_INVALID_STA;
+ mvm_link->ap_sta_id = IWL_MVM_INVALID_STA;
}

/*
@@ -2082,7 +2090,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,

iwl_mvm_disable_sta_queues(mvm, vif, sta);

- if (iwl_mvm_sta_del(mvm, vif, sta, &mvm_sta->deflink, &ret))
+ if (iwl_mvm_sta_del(mvm, vif, sta, &sta->deflink, &ret))
return ret;

ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->deflink.sta_id);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index 625e1dfd47a2..7b9e91935aa0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -489,7 +489,7 @@ int iwl_mvm_wait_sta_queues_empty(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvm_sta);
bool iwl_mvm_sta_del(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
- struct iwl_mvm_link_sta *mvm_link_sta, int *ret);
+ struct ieee80211_link_sta *link_sta, int *ret);
int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
--
2.38.1

2023-03-29 07:10:10

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 31/34] wifi: iwlwifi: bump FW API to 75 for AX devices

From: Gregory Greenman <[email protected]>

Start supporting API version 75 for AX devices.

Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index e649daaf842c..0b10b34a77a8 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -10,7 +10,7 @@
#include "fw/api/txq.h"

/* Highest firmware API version supported */
-#define IWL_22000_UCODE_API_MAX 74
+#define IWL_22000_UCODE_API_MAX 75

/* Lowest firmware API version supported */
#define IWL_22000_UCODE_API_MIN 39
--
2.38.1

2023-03-29 07:11:15

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 32/34] wifi: iwlwifi: mvm: free probe_resp_data later

From: Johannes Berg <[email protected]>

In the MLD code, we free probe_resp_data before we remove
the MAC from the firmware, so we might receive another one
from the device after freeing, and thus might leak it. Fix
that by moving the free later.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
.../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 4d56b2fc5f33..203f2513e7ea 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -159,12 +159,6 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,
mvm->csme_vif = NULL;
}

- probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data,
- lockdep_is_held(&mvm->mutex));
- RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);
- if (probe_data)
- kfree_rcu(probe_data, rcu_head);
-
if (mvm->bf_allowed_vif == mvmvif) {
mvm->bf_allowed_vif = NULL;
vif->driver_flags &= ~(IEEE80211_VIF_BEACON_FILTER |
@@ -207,6 +201,12 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,

RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL);

+ probe_data = rcu_dereference_protected(mvmvif->deflink.probe_resp_data,
+ lockdep_is_held(&mvm->mutex));
+ RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);
+ if (probe_data)
+ kfree_rcu(probe_data, rcu_head);
+
if (vif->type == NL80211_IFTYPE_MONITOR) {
mvm->monitor_on = false;
__clear_bit(IEEE80211_HW_RX_INCLUDES_FCS, mvm->hw->flags);
--
2.38.1

2023-03-29 07:11:15

by Greenman, Gregory

[permalink] [raw]
Subject: [PATCH 33/34] wifi: iwlwifi: separate AP link management queues

From: Johannes Berg <[email protected]>

The link management queues associated with the broadcast stations
were forgotten and so the same queue was used with both broadcast
stations. This leads to lost frames and warnings on cleanup and
HW restart.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: Gregory Greenman <[email protected]>
---
drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 4 ++--
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 3 +++
drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 16 ++++++++++++++--
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 4 ++--
4 files changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 26686cc7ff4c..ca788a427fa6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -181,7 +181,7 @@ int iwl_mvm_mld_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,

if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC) {
- queue = &mvm->probe_queue;
+ queue = &mvm_link->mgmt_queue;
} else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
queue = &mvm->p2p_dev_queue;
} else {
@@ -327,7 +327,7 @@ int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
switch (vif->type) {
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
- queueptr = &mvm->probe_queue;
+ queueptr = &link->mgmt_queue;
break;
case NL80211_IFTYPE_P2P_DEVICE:
queueptr = &mvm->p2p_dev_queue;
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 022f7bd64a5d..707c930a278f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -299,6 +299,7 @@ struct iwl_probe_resp_data {
* data to be inserted into probe response.
* @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked
* @queue_params: QoS params for this MAC
+ * @mgmt_queue: queue number for unbufferable management frames
*/
struct iwl_mvm_vif_link_info {
u8 bssid[ETH_ALEN];
@@ -329,6 +330,8 @@ struct iwl_mvm_vif_link_info {
* to have the data for the MAC context
*/
struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+
+ u16 mgmt_queue;
};

/**
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index db6a3419bd31..a57de37f6e02 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -2348,10 +2348,18 @@ int iwl_mvm_send_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
}

if (vif->type == NL80211_IFTYPE_AP ||
- vif->type == NL80211_IFTYPE_ADHOC)
+ vif->type == NL80211_IFTYPE_ADHOC) {
+ /* for queue management */
mvm->probe_queue = queue;
- else if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
+ /* for use in TX */
+ mvmvif->deflink.mgmt_queue = queue;
+ } else if (vif->type == NL80211_IFTYPE_P2P_DEVICE) {
mvm->p2p_dev_queue = queue;
+ }
+ } else if (vif->type == NL80211_IFTYPE_AP ||
+ vif->type == NL80211_IFTYPE_ADHOC) {
+ /* set it for use in TX */
+ mvmvif->deflink.mgmt_queue = mvm->probe_queue;
}

return 0;
@@ -2384,6 +2392,10 @@ void iwl_mvm_free_bcast_sta_queues(struct iwl_mvm *mvm,
queue = *queueptr;
iwl_mvm_disable_txq(mvm, NULL, mvmvif->deflink.bcast_sta.sta_id,
queueptr, IWL_MAX_TID_COUNT);
+
+ if (vif->type == NL80211_IFTYPE_AP || vif->type == NL80211_IFTYPE_ADHOC)
+ mvmvif->deflink.mgmt_queue = mvm->probe_queue;
+
if (iwl_mvm_has_new_tx_api(mvm))
return;

diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index f5b92d99f39d..2c842938656d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -626,7 +626,7 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,
if (ieee80211_is_mgmt(fc) &&
(!ieee80211_is_bufferable_mmpdu(fc) ||
ieee80211_is_deauth(fc) || ieee80211_is_disassoc(fc)))
- return mvm->probe_queue;
+ return link->mgmt_queue;

if (!ieee80211_has_order(fc) && !ieee80211_is_probe_req(fc) &&
is_multicast_ether_addr(hdr->addr1))
@@ -634,7 +634,7 @@ static int iwl_mvm_get_ctrl_vif_queue(struct iwl_mvm *mvm,

WARN_ONCE(info->control.vif->type != NL80211_IFTYPE_ADHOC,
"fc=0x%02x", le16_to_cpu(fc));
- return mvm->probe_queue;
+ return link->mgmt_queue;
case NL80211_IFTYPE_P2P_DEVICE:
if (ieee80211_is_mgmt(fc))
return mvm->p2p_dev_queue;
--
2.38.1