Skip to content

Commit c05c628

Browse files
committed
Johannes Berg says: ==================== wireless fixes for v6.12-rc6 Another set of fixes, mostly iwlwifi: * fix infinite loop in 6 GHz scan if more than 255 colocated APs were reported * revert removal of retry loops for now to work around issues with firmware initialization on some devices/platforms * fix SAR table issues with some BIOSes * fix race in suspend/debug collection * fix memory leak in fw recovery * fix link ID leak in AP mode for older devices * fix sending TX power constraints * fix link handling in FW restart And also the stack: * fix setting TX power from userspace with the new chanctx emulation code for old-style drivers * fix a memory corruption bug due to structure embedding * fix CQM configuration double-free when moving between net namespaces * tag 'wireless-2024-10-29' of https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless: wifi: mac80211: ieee80211_i: Fix memory corruption bug in struct ieee80211_chanctx wifi: iwlwifi: mvm: fix 6 GHz scan construction wifi: cfg80211: clear wdev->cqm_config pointer on free mac80211: fix user-power when emulating chanctx Revert "wifi: iwlwifi: remove retry loops in start" wifi: iwlwifi: mvm: don't add default link in fw restart flow wifi: iwlwifi: mvm: Fix response handling in iwl_mvm_send_recovery_cmd() wifi: iwlwifi: mvm: SAR table alignment wifi: iwlwifi: mvm: Use the sync timepoint API in suspend wifi: iwlwifi: mvm: really send iwl_txpower_constraints_cmd wifi: iwlwifi: mvm: don't leak a link on AP removal ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 9ab5cf1 + cf44e74 commit c05c628

File tree

12 files changed

+131
-72
lines changed

12 files changed

+131
-72
lines changed

drivers/net/wireless/intel/iwlwifi/fw/acpi.c

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -429,38 +429,28 @@ int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)
429429
return ret;
430430
}
431431

432-
static int iwl_acpi_sar_set_profile(union acpi_object *table,
433-
struct iwl_sar_profile *profile,
434-
bool enabled, u8 num_chains,
435-
u8 num_sub_bands)
432+
static int
433+
iwl_acpi_parse_chains_table(union acpi_object *table,
434+
struct iwl_sar_profile_chain *chains,
435+
u8 num_chains, u8 num_sub_bands)
436436
{
437-
int i, j, idx = 0;
438-
439-
/*
440-
* The table from ACPI is flat, but we store it in a
441-
* structured array.
442-
*/
443-
for (i = 0; i < BIOS_SAR_MAX_CHAINS_PER_PROFILE; i++) {
444-
for (j = 0; j < BIOS_SAR_MAX_SUB_BANDS_NUM; j++) {
437+
for (u8 chain = 0; chain < num_chains; chain++) {
438+
for (u8 subband = 0; subband < BIOS_SAR_MAX_SUB_BANDS_NUM;
439+
subband++) {
445440
/* if we don't have the values, use the default */
446-
if (i >= num_chains || j >= num_sub_bands) {
447-
profile->chains[i].subbands[j] = 0;
441+
if (subband >= num_sub_bands) {
442+
chains[chain].subbands[subband] = 0;
443+
} else if (table->type != ACPI_TYPE_INTEGER ||
444+
table->integer.value > U8_MAX) {
445+
return -EINVAL;
448446
} else {
449-
if (table[idx].type != ACPI_TYPE_INTEGER ||
450-
table[idx].integer.value > U8_MAX)
451-
return -EINVAL;
452-
453-
profile->chains[i].subbands[j] =
454-
table[idx].integer.value;
455-
456-
idx++;
447+
chains[chain].subbands[subband] =
448+
table->integer.value;
449+
table++;
457450
}
458451
}
459452
}
460453

461-
/* Only if all values were valid can the profile be enabled */
462-
profile->enabled = enabled;
463-
464454
return 0;
465455
}
466456

@@ -543,9 +533,11 @@ int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt)
543533
/* The profile from WRDS is officially profile 1, but goes
544534
* into sar_profiles[0] (because we don't have a profile 0).
545535
*/
546-
ret = iwl_acpi_sar_set_profile(table, &fwrt->sar_profiles[0],
547-
flags & IWL_SAR_ENABLE_MSK,
548-
num_chains, num_sub_bands);
536+
ret = iwl_acpi_parse_chains_table(table, fwrt->sar_profiles[0].chains,
537+
num_chains, num_sub_bands);
538+
if (!ret && flags & IWL_SAR_ENABLE_MSK)
539+
fwrt->sar_profiles[0].enabled = true;
540+
549541
out_free:
550542
kfree(data);
551543
return ret;
@@ -557,7 +549,7 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
557549
bool enabled;
558550
int i, n_profiles, tbl_rev, pos;
559551
int ret = 0;
560-
u8 num_chains, num_sub_bands;
552+
u8 num_sub_bands;
561553

562554
data = iwl_acpi_get_object(fwrt->dev, ACPI_EWRD_METHOD);
563555
if (IS_ERR(data))
@@ -573,7 +565,6 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
573565
goto out_free;
574566
}
575567

576-
num_chains = ACPI_SAR_NUM_CHAINS_REV2;
577568
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;
578569

579570
goto read_table;
@@ -589,7 +580,6 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
589580
goto out_free;
590581
}
591582

592-
num_chains = ACPI_SAR_NUM_CHAINS_REV1;
593583
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;
594584

595585
goto read_table;
@@ -605,7 +595,6 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
605595
goto out_free;
606596
}
607597

608-
num_chains = ACPI_SAR_NUM_CHAINS_REV0;
609598
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;
610599

611600
goto read_table;
@@ -637,23 +626,54 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
637626
/* the tables start at element 3 */
638627
pos = 3;
639628

629+
BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0 != ACPI_SAR_NUM_CHAINS_REV1);
630+
BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2 != 2 * ACPI_SAR_NUM_CHAINS_REV0);
631+
632+
/* parse non-cdb chains for all profiles */
640633
for (i = 0; i < n_profiles; i++) {
641634
union acpi_object *table = &wifi_pkg->package.elements[pos];
635+
642636
/* The EWRD profiles officially go from 2 to 4, but we
643637
* save them in sar_profiles[1-3] (because we don't
644638
* have profile 0). So in the array we start from 1.
645639
*/
646-
ret = iwl_acpi_sar_set_profile(table,
647-
&fwrt->sar_profiles[i + 1],
648-
enabled, num_chains,
649-
num_sub_bands);
640+
ret = iwl_acpi_parse_chains_table(table,
641+
fwrt->sar_profiles[i + 1].chains,
642+
ACPI_SAR_NUM_CHAINS_REV0,
643+
num_sub_bands);
650644
if (ret < 0)
651-
break;
645+
goto out_free;
652646

653647
/* go to the next table */
654-
pos += num_chains * num_sub_bands;
648+
pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
655649
}
656650

651+
/* non-cdb table revisions */
652+
if (tbl_rev < 2)
653+
goto set_enabled;
654+
655+
/* parse cdb chains for all profiles */
656+
for (i = 0; i < n_profiles; i++) {
657+
struct iwl_sar_profile_chain *chains;
658+
union acpi_object *table;
659+
660+
table = &wifi_pkg->package.elements[pos];
661+
chains = &fwrt->sar_profiles[i + 1].chains[ACPI_SAR_NUM_CHAINS_REV0];
662+
ret = iwl_acpi_parse_chains_table(table,
663+
chains,
664+
ACPI_SAR_NUM_CHAINS_REV0,
665+
num_sub_bands);
666+
if (ret < 0)
667+
goto out_free;
668+
669+
/* go to the next table */
670+
pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
671+
}
672+
673+
set_enabled:
674+
for (i = 0; i < n_profiles; i++)
675+
fwrt->sar_profiles[i + 1].enabled = enabled;
676+
657677
out_free:
658678
kfree(data);
659679
return ret;

drivers/net/wireless/intel/iwlwifi/fw/init.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
3939
}
4040
IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);
4141

42+
/* Assumes the appropriate lock is held by the caller */
4243
void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt)
4344
{
4445
iwl_fw_suspend_timestamp(fwrt);
45-
iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_START, NULL);
46+
iwl_dbg_tlv_time_point_sync(fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_START,
47+
NULL);
4648
}
4749
IWL_EXPORT_SYMBOL(iwl_fw_runtime_suspend);
4850

drivers/net/wireless/intel/iwlwifi/iwl-drv.c

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1413,25 +1413,35 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)
14131413
const struct iwl_op_mode_ops *ops = op->ops;
14141414
struct dentry *dbgfs_dir = NULL;
14151415
struct iwl_op_mode *op_mode = NULL;
1416+
int retry, max_retry = !!iwlwifi_mod_params.fw_restart * IWL_MAX_INIT_RETRY;
14161417

14171418
/* also protects start/stop from racing against each other */
14181419
lockdep_assert_held(&iwlwifi_opmode_table_mtx);
14191420

1421+
for (retry = 0; retry <= max_retry; retry++) {
1422+
14201423
#ifdef CONFIG_IWLWIFI_DEBUGFS
1421-
drv->dbgfs_op_mode = debugfs_create_dir(op->name,
1422-
drv->dbgfs_drv);
1423-
dbgfs_dir = drv->dbgfs_op_mode;
1424+
drv->dbgfs_op_mode = debugfs_create_dir(op->name,
1425+
drv->dbgfs_drv);
1426+
dbgfs_dir = drv->dbgfs_op_mode;
14241427
#endif
14251428

1426-
op_mode = ops->start(drv->trans, drv->trans->cfg,
1427-
&drv->fw, dbgfs_dir);
1428-
if (op_mode)
1429-
return op_mode;
1429+
op_mode = ops->start(drv->trans, drv->trans->cfg,
1430+
&drv->fw, dbgfs_dir);
1431+
1432+
if (op_mode)
1433+
return op_mode;
1434+
1435+
if (test_bit(STATUS_TRANS_DEAD, &drv->trans->status))
1436+
break;
1437+
1438+
IWL_ERR(drv, "retry init count %d\n", retry);
14301439

14311440
#ifdef CONFIG_IWLWIFI_DEBUGFS
1432-
debugfs_remove_recursive(drv->dbgfs_op_mode);
1433-
drv->dbgfs_op_mode = NULL;
1441+
debugfs_remove_recursive(drv->dbgfs_op_mode);
1442+
drv->dbgfs_op_mode = NULL;
14341443
#endif
1444+
}
14351445

14361446
return NULL;
14371447
}

drivers/net/wireless/intel/iwlwifi/iwl-drv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ void iwl_drv_stop(struct iwl_drv *drv);
9898
#define VISIBLE_IF_IWLWIFI_KUNIT static
9999
#endif
100100

101+
/* max retry for init flow */
102+
#define IWL_MAX_INIT_RETRY 2
103+
101104
#define FW_NAME_PRE_BUFSIZE 64
102105
struct iwl_trans;
103106
const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf);

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,7 +1398,9 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
13981398

13991399
iwl_mvm_pause_tcm(mvm, true);
14001400

1401+
mutex_lock(&mvm->mutex);
14011402
iwl_fw_runtime_suspend(&mvm->fwrt);
1403+
mutex_unlock(&mvm->mutex);
14021404

14031405
return __iwl_mvm_suspend(hw, wowlan, false);
14041406
}

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

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1307,16 +1307,15 @@ static void iwl_mvm_disconnect_iterator(void *data, u8 *mac,
13071307
void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
13081308
{
13091309
u32 error_log_size = mvm->fw->ucode_capa.error_log_size;
1310+
u32 status = 0;
13101311
int ret;
1311-
u32 resp;
13121312

13131313
struct iwl_fw_error_recovery_cmd recovery_cmd = {
13141314
.flags = cpu_to_le32(flags),
13151315
.buf_size = 0,
13161316
};
13171317
struct iwl_host_cmd host_cmd = {
13181318
.id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD),
1319-
.flags = CMD_WANT_SKB,
13201319
.data = {&recovery_cmd, },
13211320
.len = {sizeof(recovery_cmd), },
13221321
};
@@ -1336,7 +1335,7 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
13361335
recovery_cmd.buf_size = cpu_to_le32(error_log_size);
13371336
}
13381337

1339-
ret = iwl_mvm_send_cmd(mvm, &host_cmd);
1338+
ret = iwl_mvm_send_cmd_status(mvm, &host_cmd, &status);
13401339
kfree(mvm->error_recovery_buf);
13411340
mvm->error_recovery_buf = NULL;
13421341

@@ -1347,11 +1346,10 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
13471346

13481347
/* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */
13491348
if (flags & ERROR_RECOVERY_UPDATE_DB) {
1350-
resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data);
1351-
if (resp) {
1349+
if (status) {
13521350
IWL_ERR(mvm,
13531351
"Failed to send recovery cmd blob was invalid %d\n",
1354-
resp);
1352+
status);
13551353

13561354
ieee80211_iterate_interfaces(mvm->hw, 0,
13571355
iwl_mvm_disconnect_iterator,

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,20 +1293,28 @@ int iwl_mvm_mac_start(struct ieee80211_hw *hw)
12931293
{
12941294
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
12951295
int ret;
1296+
int retry, max_retry = 0;
12961297

12971298
mutex_lock(&mvm->mutex);
12981299

12991300
/* we are starting the mac not in error flow, and restart is enabled */
13001301
if (!test_bit(IWL_MVM_STATUS_HW_RESTART_REQUESTED, &mvm->status) &&
13011302
iwlwifi_mod_params.fw_restart) {
1303+
max_retry = IWL_MAX_INIT_RETRY;
13021304
/*
13031305
* This will prevent mac80211 recovery flows to trigger during
13041306
* init failures
13051307
*/
13061308
set_bit(IWL_MVM_STATUS_STARTING, &mvm->status);
13071309
}
13081310

1309-
ret = __iwl_mvm_mac_start(mvm);
1311+
for (retry = 0; retry <= max_retry; retry++) {
1312+
ret = __iwl_mvm_mac_start(mvm);
1313+
if (!ret)
1314+
break;
1315+
1316+
IWL_ERR(mvm, "mac start retry %d\n", retry);
1317+
}
13101318
clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status);
13111319

13121320
mutex_unlock(&mvm->mutex);
@@ -1970,7 +1978,6 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
19701978
mvm->p2p_device_vif = NULL;
19711979
}
19721980

1973-
iwl_mvm_unset_link_mapping(mvm, vif, &vif->bss_conf);
19741981
iwl_mvm_mac_ctxt_remove(mvm, vif);
19751982

19761983
RCU_INIT_POINTER(mvm->vif_id_to_mac[mvmvif->id], NULL);
@@ -1979,6 +1986,7 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
19791986
mvm->monitor_on = false;
19801987

19811988
out:
1989+
iwl_mvm_unset_link_mapping(mvm, vif, &vif->bss_conf);
19821990
if (vif->type == NL80211_IFTYPE_AP ||
19831991
vif->type == NL80211_IFTYPE_ADHOC) {
19841992
iwl_mvm_dealloc_int_sta(mvm, &mvmvif->deflink.mcast_sta);

drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
4141
/* reset deflink MLO parameters */
4242
mvmvif->deflink.fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
4343
mvmvif->deflink.active = 0;
44-
/* the first link always points to the default one */
45-
mvmvif->link[0] = &mvmvif->deflink;
4644

4745
ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif);
4846
if (ret)
@@ -60,9 +58,19 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
6058
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
6159
}
6260

63-
ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
64-
if (ret)
65-
goto out_free_bf;
61+
/* We want link[0] to point to the default link, unless we have MLO and
62+
* in this case this will be modified later by .change_vif_links()
63+
* If we are in the restart flow with an MLD connection, we will wait
64+
* to .change_vif_links() to setup the links.
65+
*/
66+
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
67+
!ieee80211_vif_is_mld(vif)) {
68+
mvmvif->link[0] = &mvmvif->deflink;
69+
70+
ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
71+
if (ret)
72+
goto out_free_bf;
73+
}
6674

6775
/* Save a pointer to p2p device vif, so it can later be used to
6876
* update the p2p device MAC when a GO is started/stopped
@@ -350,11 +358,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
350358
rcu_read_unlock();
351359
}
352360

353-
if (vif->type == NL80211_IFTYPE_STATION)
354-
iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
355-
link_conf,
356-
false);
357-
358361
/* then activate */
359362
ret = iwl_mvm_link_changed(mvm, vif, link_conf,
360363
LINK_CONTEXT_MODIFY_ACTIVE |
@@ -363,6 +366,11 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
363366
if (ret)
364367
goto out;
365368

369+
if (vif->type == NL80211_IFTYPE_STATION)
370+
iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
371+
link_conf,
372+
false);
373+
366374
/*
367375
* Power state must be updated before quotas,
368376
* otherwise fw will complain.
@@ -1194,7 +1202,11 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
11941202

11951203
mutex_lock(&mvm->mutex);
11961204

1197-
if (old_links == 0) {
1205+
/* If we're in RESTART flow, the default link wasn't added in
1206+
* drv_add_interface(), and link[0] doesn't point to it.
1207+
*/
1208+
if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
1209+
&mvm->status)) {
11981210
err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
11991211
if (err)
12001212
goto out_err;

0 commit comments

Comments
 (0)