Skip to content

Commit

Permalink
Merge tag 'wireless-2024-10-29' of https://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/wireless/wireless

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]>
  • Loading branch information
kuba-moo committed Oct 30, 2024
2 parents 9ab5cf1 + cf44e74 commit c05c628
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 72 deletions.
96 changes: 58 additions & 38 deletions drivers/net/wireless/intel/iwlwifi/fw/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,38 +429,28 @@ int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk)
return ret;
}

static int iwl_acpi_sar_set_profile(union acpi_object *table,
struct iwl_sar_profile *profile,
bool enabled, u8 num_chains,
u8 num_sub_bands)
static int
iwl_acpi_parse_chains_table(union acpi_object *table,
struct iwl_sar_profile_chain *chains,
u8 num_chains, u8 num_sub_bands)
{
int i, j, idx = 0;

/*
* The table from ACPI is flat, but we store it in a
* structured array.
*/
for (i = 0; i < BIOS_SAR_MAX_CHAINS_PER_PROFILE; i++) {
for (j = 0; j < BIOS_SAR_MAX_SUB_BANDS_NUM; j++) {
for (u8 chain = 0; chain < num_chains; chain++) {
for (u8 subband = 0; subband < BIOS_SAR_MAX_SUB_BANDS_NUM;
subband++) {
/* if we don't have the values, use the default */
if (i >= num_chains || j >= num_sub_bands) {
profile->chains[i].subbands[j] = 0;
if (subband >= num_sub_bands) {
chains[chain].subbands[subband] = 0;
} else if (table->type != ACPI_TYPE_INTEGER ||
table->integer.value > U8_MAX) {
return -EINVAL;
} else {
if (table[idx].type != ACPI_TYPE_INTEGER ||
table[idx].integer.value > U8_MAX)
return -EINVAL;

profile->chains[i].subbands[j] =
table[idx].integer.value;

idx++;
chains[chain].subbands[subband] =
table->integer.value;
table++;
}
}
}

/* Only if all values were valid can the profile be enabled */
profile->enabled = enabled;

return 0;
}

Expand Down Expand Up @@ -543,9 +533,11 @@ int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt)
/* The profile from WRDS is officially profile 1, but goes
* into sar_profiles[0] (because we don't have a profile 0).
*/
ret = iwl_acpi_sar_set_profile(table, &fwrt->sar_profiles[0],
flags & IWL_SAR_ENABLE_MSK,
num_chains, num_sub_bands);
ret = iwl_acpi_parse_chains_table(table, fwrt->sar_profiles[0].chains,
num_chains, num_sub_bands);
if (!ret && flags & IWL_SAR_ENABLE_MSK)
fwrt->sar_profiles[0].enabled = true;

out_free:
kfree(data);
return ret;
Expand All @@ -557,7 +549,7 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
bool enabled;
int i, n_profiles, tbl_rev, pos;
int ret = 0;
u8 num_chains, num_sub_bands;
u8 num_sub_bands;

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

num_chains = ACPI_SAR_NUM_CHAINS_REV2;
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2;

goto read_table;
Expand All @@ -589,7 +580,6 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
goto out_free;
}

num_chains = ACPI_SAR_NUM_CHAINS_REV1;
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1;

goto read_table;
Expand All @@ -605,7 +595,6 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt)
goto out_free;
}

num_chains = ACPI_SAR_NUM_CHAINS_REV0;
num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0;

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

BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0 != ACPI_SAR_NUM_CHAINS_REV1);
BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2 != 2 * ACPI_SAR_NUM_CHAINS_REV0);

/* parse non-cdb chains for all profiles */
for (i = 0; i < n_profiles; i++) {
union acpi_object *table = &wifi_pkg->package.elements[pos];

/* The EWRD profiles officially go from 2 to 4, but we
* save them in sar_profiles[1-3] (because we don't
* have profile 0). So in the array we start from 1.
*/
ret = iwl_acpi_sar_set_profile(table,
&fwrt->sar_profiles[i + 1],
enabled, num_chains,
num_sub_bands);
ret = iwl_acpi_parse_chains_table(table,
fwrt->sar_profiles[i + 1].chains,
ACPI_SAR_NUM_CHAINS_REV0,
num_sub_bands);
if (ret < 0)
break;
goto out_free;

/* go to the next table */
pos += num_chains * num_sub_bands;
pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
}

/* non-cdb table revisions */
if (tbl_rev < 2)
goto set_enabled;

/* parse cdb chains for all profiles */
for (i = 0; i < n_profiles; i++) {
struct iwl_sar_profile_chain *chains;
union acpi_object *table;

table = &wifi_pkg->package.elements[pos];
chains = &fwrt->sar_profiles[i + 1].chains[ACPI_SAR_NUM_CHAINS_REV0];
ret = iwl_acpi_parse_chains_table(table,
chains,
ACPI_SAR_NUM_CHAINS_REV0,
num_sub_bands);
if (ret < 0)
goto out_free;

/* go to the next table */
pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands;
}

set_enabled:
for (i = 0; i < n_profiles; i++)
fwrt->sar_profiles[i + 1].enabled = enabled;

out_free:
kfree(data);
return ret;
Expand Down
4 changes: 3 additions & 1 deletion drivers/net/wireless/intel/iwlwifi/fw/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,12 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
}
IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);

/* Assumes the appropriate lock is held by the caller */
void iwl_fw_runtime_suspend(struct iwl_fw_runtime *fwrt)
{
iwl_fw_suspend_timestamp(fwrt);
iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_START, NULL);
iwl_dbg_tlv_time_point_sync(fwrt, IWL_FW_INI_TIME_POINT_HOST_D3_START,
NULL);
}
IWL_EXPORT_SYMBOL(iwl_fw_runtime_suspend);

Expand Down
28 changes: 19 additions & 9 deletions drivers/net/wireless/intel/iwlwifi/iwl-drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1413,25 +1413,35 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)
const struct iwl_op_mode_ops *ops = op->ops;
struct dentry *dbgfs_dir = NULL;
struct iwl_op_mode *op_mode = NULL;
int retry, max_retry = !!iwlwifi_mod_params.fw_restart * IWL_MAX_INIT_RETRY;

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

for (retry = 0; retry <= max_retry; retry++) {

#ifdef CONFIG_IWLWIFI_DEBUGFS
drv->dbgfs_op_mode = debugfs_create_dir(op->name,
drv->dbgfs_drv);
dbgfs_dir = drv->dbgfs_op_mode;
drv->dbgfs_op_mode = debugfs_create_dir(op->name,
drv->dbgfs_drv);
dbgfs_dir = drv->dbgfs_op_mode;
#endif

op_mode = ops->start(drv->trans, drv->trans->cfg,
&drv->fw, dbgfs_dir);
if (op_mode)
return op_mode;
op_mode = ops->start(drv->trans, drv->trans->cfg,
&drv->fw, dbgfs_dir);

if (op_mode)
return op_mode;

if (test_bit(STATUS_TRANS_DEAD, &drv->trans->status))
break;

IWL_ERR(drv, "retry init count %d\n", retry);

#ifdef CONFIG_IWLWIFI_DEBUGFS
debugfs_remove_recursive(drv->dbgfs_op_mode);
drv->dbgfs_op_mode = NULL;
debugfs_remove_recursive(drv->dbgfs_op_mode);
drv->dbgfs_op_mode = NULL;
#endif
}

return NULL;
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/iwl-drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ void iwl_drv_stop(struct iwl_drv *drv);
#define VISIBLE_IF_IWLWIFI_KUNIT static
#endif

/* max retry for init flow */
#define IWL_MAX_INIT_RETRY 2

#define FW_NAME_PRE_BUFSIZE 64
struct iwl_trans;
const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf);
Expand Down
2 changes: 2 additions & 0 deletions drivers/net/wireless/intel/iwlwifi/mvm/d3.c
Original file line number Diff line number Diff line change
Expand Up @@ -1398,7 +1398,9 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)

iwl_mvm_pause_tcm(mvm, true);

mutex_lock(&mvm->mutex);
iwl_fw_runtime_suspend(&mvm->fwrt);
mutex_unlock(&mvm->mutex);

return __iwl_mvm_suspend(hw, wowlan, false);
}
Expand Down
10 changes: 4 additions & 6 deletions drivers/net/wireless/intel/iwlwifi/mvm/fw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1307,16 +1307,15 @@ static void iwl_mvm_disconnect_iterator(void *data, u8 *mac,
void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
{
u32 error_log_size = mvm->fw->ucode_capa.error_log_size;
u32 status = 0;
int ret;
u32 resp;

struct iwl_fw_error_recovery_cmd recovery_cmd = {
.flags = cpu_to_le32(flags),
.buf_size = 0,
};
struct iwl_host_cmd host_cmd = {
.id = WIDE_ID(SYSTEM_GROUP, FW_ERROR_RECOVERY_CMD),
.flags = CMD_WANT_SKB,
.data = {&recovery_cmd, },
.len = {sizeof(recovery_cmd), },
};
Expand All @@ -1336,7 +1335,7 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags)
recovery_cmd.buf_size = cpu_to_le32(error_log_size);
}

ret = iwl_mvm_send_cmd(mvm, &host_cmd);
ret = iwl_mvm_send_cmd_status(mvm, &host_cmd, &status);
kfree(mvm->error_recovery_buf);
mvm->error_recovery_buf = NULL;

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

/* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */
if (flags & ERROR_RECOVERY_UPDATE_DB) {
resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data);
if (resp) {
if (status) {
IWL_ERR(mvm,
"Failed to send recovery cmd blob was invalid %d\n",
resp);
status);

ieee80211_iterate_interfaces(mvm->hw, 0,
iwl_mvm_disconnect_iterator,
Expand Down
12 changes: 10 additions & 2 deletions drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -1293,20 +1293,28 @@ int iwl_mvm_mac_start(struct ieee80211_hw *hw)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
int retry, max_retry = 0;

mutex_lock(&mvm->mutex);

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

ret = __iwl_mvm_mac_start(mvm);
for (retry = 0; retry <= max_retry; retry++) {
ret = __iwl_mvm_mac_start(mvm);
if (!ret)
break;

IWL_ERR(mvm, "mac start retry %d\n", retry);
}
clear_bit(IWL_MVM_STATUS_STARTING, &mvm->status);

mutex_unlock(&mvm->mutex);
Expand Down Expand Up @@ -1970,7 +1978,6 @@ static void iwl_mvm_mac_remove_interface(struct ieee80211_hw *hw,
mvm->p2p_device_vif = NULL;
}

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

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

out:
iwl_mvm_unset_link_mapping(mvm, vif, &vif->bss_conf);
if (vif->type == NL80211_IFTYPE_AP ||
vif->type == NL80211_IFTYPE_ADHOC) {
iwl_mvm_dealloc_int_sta(mvm, &mvmvif->deflink.mcast_sta);
Expand Down
34 changes: 23 additions & 11 deletions drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
/* reset deflink MLO parameters */
mvmvif->deflink.fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
mvmvif->deflink.active = 0;
/* the first link always points to the default one */
mvmvif->link[0] = &mvmvif->deflink;

ret = iwl_mvm_mld_mac_ctxt_add(mvm, vif);
if (ret)
Expand All @@ -60,9 +58,19 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
}

ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
if (ret)
goto out_free_bf;
/* We want link[0] to point to the default link, unless we have MLO and
* in this case this will be modified later by .change_vif_links()
* If we are in the restart flow with an MLD connection, we will wait
* to .change_vif_links() to setup the links.
*/
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) ||
!ieee80211_vif_is_mld(vif)) {
mvmvif->link[0] = &mvmvif->deflink;

ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
if (ret)
goto out_free_bf;
}

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

if (vif->type == NL80211_IFTYPE_STATION)
iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
link_conf,
false);

/* then activate */
ret = iwl_mvm_link_changed(mvm, vif, link_conf,
LINK_CONTEXT_MODIFY_ACTIVE |
Expand All @@ -363,6 +366,11 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
if (ret)
goto out;

if (vif->type == NL80211_IFTYPE_STATION)
iwl_mvm_send_ap_tx_power_constraint_cmd(mvm, vif,
link_conf,
false);

/*
* Power state must be updated before quotas,
* otherwise fw will complain.
Expand Down Expand Up @@ -1194,7 +1202,11 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,

mutex_lock(&mvm->mutex);

if (old_links == 0) {
/* If we're in RESTART flow, the default link wasn't added in
* drv_add_interface(), and link[0] doesn't point to it.
*/
if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
&mvm->status)) {
err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
if (err)
goto out_err;
Expand Down
Loading

0 comments on commit c05c628

Please sign in to comment.