Skip to content

Commit 8c9bef2

Browse files
committed
wifi: iwlwifi: mvm: d3: implement suspend with MLO
When using MLO, we need to have only a single link active when entering suspend and of course most of the code also needs to be adjusted to not use deflink, apart from older code that's not used with MLO-capable firmware. Implement that. Note that the link selection currently prefers the "best" link, which might really not be the best for D3, but that can be fixed later once we agree. Signed-off-by: Johannes Berg <[email protected]> Reviewed-by: Gregory Greenman <[email protected]> Signed-off-by: Miri Korenblit <[email protected]> Link: https://msgid.link/20240131091413.38f0fd4d2db0.I27c7a1d08aecc5da0af2c351212f22e92ed70219@changeid Signed-off-by: Johannes Berg <[email protected]>
1 parent c868a18 commit 8c9bef2

File tree

1 file changed

+54
-25
lines changed
  • drivers/net/wireless/intel/iwlwifi/mvm

1 file changed

+54
-25
lines changed

drivers/net/wireless/intel/iwlwifi/mvm/d3.c

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -450,9 +450,9 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw,
450450
}
451451

452452
static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,
453-
struct ieee80211_vif *vif)
453+
struct ieee80211_vif *vif,
454+
struct iwl_mvm_vif_link_info *mvm_link)
454455
{
455-
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
456456
int ver = iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_TSC_RSC_PARAM,
457457
IWL_FW_CMD_VER_UNKNOWN);
458458
int ret;
@@ -470,7 +470,7 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,
470470
for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++)
471471
data.rsc->mcast_key_id_map[i] =
472472
IWL_MCAST_KEY_MAP_INVALID;
473-
data.rsc->sta_id = cpu_to_le32(mvmvif->deflink.ap_sta_id);
473+
data.rsc->sta_id = cpu_to_le32(mvm_link->ap_sta_id);
474474

475475
ieee80211_iter_keys(mvm->hw, vif,
476476
iwl_mvm_wowlan_get_rsc_v5_data,
@@ -494,7 +494,7 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm,
494494
if (ver == 4) {
495495
size = sizeof(*data.rsc_tsc);
496496
data.rsc_tsc->sta_id =
497-
cpu_to_le32(mvmvif->deflink.ap_sta_id);
497+
cpu_to_le32(mvm_link->ap_sta_id);
498498
} else {
499499
/* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */
500500
size = sizeof(data.rsc_tsc->params);
@@ -668,10 +668,9 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm,
668668
}
669669

670670
static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
671-
struct ieee80211_vif *vif,
671+
struct iwl_mvm_vif_link_info *mvm_link,
672672
struct cfg80211_wowlan *wowlan)
673673
{
674-
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
675674
struct iwl_wowlan_patterns_cmd *pattern_cmd;
676675
struct iwl_host_cmd cmd = {
677676
.id = WOWLAN_PATTERNS,
@@ -693,7 +692,7 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm,
693692

694693
pattern_cmd->n_patterns = wowlan->n_patterns;
695694
if (ver >= 3)
696-
pattern_cmd->sta_id = mvmvif->deflink.ap_sta_id;
695+
pattern_cmd->sta_id = mvm_link->ap_sta_id;
697696

698697
for (i = 0; i < wowlan->n_patterns; i++) {
699698
int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
@@ -730,7 +729,8 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
730729
struct iwl_time_quota_data *quota;
731730
u32 status;
732731

733-
if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm)))
732+
if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm) ||
733+
ieee80211_vif_is_mld(vif)))
734734
return -EINVAL;
735735

736736
/* add back the PHY */
@@ -987,7 +987,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
987987
}
988988

989989
static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
990-
struct ieee80211_vif *vif)
990+
struct ieee80211_vif *vif,
991+
struct iwl_mvm_vif_link_info *mvm_link)
991992
{
992993
bool unified = fw_has_capa(&mvm->fw->ucode_capa,
993994
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
@@ -1016,7 +1017,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
10161017
return -EIO;
10171018
}
10181019

1019-
ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif);
1020+
ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif, mvm_link);
10201021
if (ret)
10211022
return ret;
10221023

@@ -1030,7 +1031,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
10301031
if (ver == 2) {
10311032
size = sizeof(tkip_data.tkip);
10321033
tkip_data.tkip.sta_id =
1033-
cpu_to_le32(mvmvif->deflink.ap_sta_id);
1034+
cpu_to_le32(mvm_link->ap_sta_id);
10341035
} else if (ver == 1 || ver == IWL_FW_CMD_VER_UNKNOWN) {
10351036
size = sizeof(struct iwl_wowlan_tkip_params_cmd_ver_1);
10361037
} else {
@@ -1079,7 +1080,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm,
10791080
kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len);
10801081
kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr;
10811082
kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm);
1082-
kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->deflink.ap_sta_id);
1083+
kek_kck_cmd.sta_id = cpu_to_le32(mvm_link->ap_sta_id);
10831084

10841085
if (cmd_ver == 4) {
10851086
cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4);
@@ -1112,6 +1113,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
11121113
struct cfg80211_wowlan *wowlan,
11131114
struct iwl_wowlan_config_cmd *wowlan_config_cmd,
11141115
struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif,
1116+
struct iwl_mvm_vif_link_info *mvm_link,
11151117
struct ieee80211_sta *ap_sta)
11161118
{
11171119
int ret;
@@ -1130,7 +1132,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
11301132
return ret;
11311133
}
11321134

1133-
ret = iwl_mvm_wowlan_config_key_params(mvm, vif);
1135+
ret = iwl_mvm_wowlan_config_key_params(mvm, vif, mvm_link);
11341136
if (ret)
11351137
return ret;
11361138

@@ -1142,7 +1144,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
11421144

11431145
if (fw_has_api(&mvm->fw->ucode_capa,
11441146
IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE))
1145-
ret = iwl_mvm_send_patterns(mvm, vif, wowlan);
1147+
ret = iwl_mvm_send_patterns(mvm, mvm_link, wowlan);
11461148
else
11471149
ret = iwl_mvm_send_patterns_v1(mvm, wowlan);
11481150
if (ret)
@@ -1223,6 +1225,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
12231225
struct ieee80211_vif *vif = NULL;
12241226
struct iwl_mvm_vif *mvmvif = NULL;
12251227
struct ieee80211_sta *ap_sta = NULL;
1228+
struct iwl_mvm_vif_link_info *mvm_link;
12261229
struct iwl_d3_manager_config d3_cfg_cmd_data = {
12271230
/*
12281231
* Program the minimum sleep time to 10 seconds, as many
@@ -1237,7 +1240,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
12371240
.data[0] = &d3_cfg_cmd_data,
12381241
.len[0] = sizeof(d3_cfg_cmd_data),
12391242
};
1240-
int ret;
1243+
int ret, primary_link;
12411244
int len __maybe_unused;
12421245
bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
12431246
IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
@@ -1251,21 +1254,44 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
12511254
return -EINVAL;
12521255
}
12531256

1257+
vif = iwl_mvm_get_bss_vif(mvm);
1258+
if (IS_ERR_OR_NULL(vif))
1259+
return 1;
1260+
1261+
if (ieee80211_vif_is_mld(vif) && vif->cfg.assoc) {
1262+
/*
1263+
* Select the 'best' link. May need to revisit, it seems
1264+
* better to not optimize for throughput but rather range,
1265+
* reliability and power here - and select 2.4 GHz ...
1266+
*/
1267+
primary_link =
1268+
iwl_mvm_mld_get_primary_link(mvm, vif,
1269+
vif->active_links);
1270+
1271+
if (WARN_ONCE(primary_link < 0, "no primary link in 0x%x\n",
1272+
vif->active_links))
1273+
primary_link = __ffs(vif->active_links);
1274+
1275+
ret = ieee80211_set_active_links(vif, BIT(primary_link));
1276+
if (ret)
1277+
return ret;
1278+
} else {
1279+
primary_link = 0;
1280+
}
1281+
12541282
mutex_lock(&mvm->mutex);
12551283

12561284
set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status);
12571285

12581286
synchronize_net();
12591287

1260-
vif = iwl_mvm_get_bss_vif(mvm);
1261-
if (IS_ERR_OR_NULL(vif)) {
1262-
ret = 1;
1263-
goto out_noreset;
1264-
}
1265-
12661288
mvmvif = iwl_mvm_vif_from_mac80211(vif);
12671289

1268-
if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA) {
1290+
mvm_link = mvmvif->link[primary_link];
1291+
if (WARN_ON_ONCE(!mvm_link))
1292+
return -EINVAL;
1293+
1294+
if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) {
12691295
/* if we're not associated, this must be netdetect */
12701296
if (!wowlan->nd_config) {
12711297
ret = 1;
@@ -1281,10 +1307,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
12811307
} else {
12821308
struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
12831309

1284-
wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id;
1310+
wowlan_config_cmd.sta_id = mvm_link->ap_sta_id;
12851311

12861312
ap_sta = rcu_dereference_protected(
1287-
mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id],
1313+
mvm->fw_id_to_mac_id[mvm_link->ap_sta_id],
12881314
lockdep_is_held(&mvm->mutex));
12891315
if (IS_ERR_OR_NULL(ap_sta)) {
12901316
ret = -EINVAL;
@@ -1296,7 +1322,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
12961322
if (ret)
12971323
goto out_noreset;
12981324
ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
1299-
vif, mvmvif, ap_sta);
1325+
vif, mvmvif, mvm_link, ap_sta);
13001326
if (ret)
13011327
goto out;
13021328

@@ -2846,6 +2872,9 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm,
28462872
u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA :
28472873
mvmvif->deflink.ap_sta_id;
28482874

2875+
/* bug - FW with MLO has status notification */
2876+
WARN_ON(ieee80211_vif_is_mld(vif));
2877+
28492878
d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id);
28502879
}
28512880

0 commit comments

Comments
 (0)