Commit c05c6285 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge tag 'wireless-2024-10-29' of...

Merge tag 'wireless-2024-10-29' of https://git.kernel.org/pub/scm/linux/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/20241029093926.13750-3-johannes@sipsolutions.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 9ab5cf19 cf44e745
Loading
Loading
Loading
Loading
+58 −38
Original line number Diff line number Diff line
@@ -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;
			} else {
				if (table[idx].type != ACPI_TYPE_INTEGER ||
				    table[idx].integer.value > U8_MAX)
			if (subband >= num_sub_bands) {
				chains[chain].subbands[subband] = 0;
			} else if (table->type != ACPI_TYPE_INTEGER ||
				   table->integer.value > U8_MAX) {
				return -EINVAL;

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

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

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

	return 0;
}

@@ -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,
	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;
@@ -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))
@@ -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;
@@ -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;
@@ -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;
@@ -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,
		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;
+3 −1
Original line number Diff line number Diff line
@@ -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);

+19 −9
Original line number Diff line number Diff line
@@ -1413,10 +1413,13 @@ _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);
@@ -1425,13 +1428,20 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op)

		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;
#endif
	}

	return NULL;
}
+3 −0
Original line number Diff line number Diff line
@@ -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);
+2 −0
Original line number Diff line number Diff line
@@ -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);
}
Loading