mirror of
https://github.com/torvalds/linux.git
synced 2026-05-25 15:41:52 +02:00
iwlwifi features. Notably:
- Partial NAN support - without DATA - Initial UHR support - UNII-9 support - EHT code cleanup in iwlmvm -----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQQM3A3Pv7vbm9vtjWbacY7uyt+OfQUCaXDIsAAKCRDacY7uyt+O fQWjAQCjlDYAmOr6TbN8ZnQBNJncRPyl393KbIgqxL2McGdYJAEAo9JXnMjpI+z5 ezVGNSJRhEXDP/2MEwR5IzNCb2cvyAw= =Ctdt -----END PGP SIGNATURE----- Merge tag 'iwlwifi-next-2026-01-21' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next Miri Korenblit says: ==================== iwlwifi features. Notably: - Partial NAN support - without DATA - Initial UHR support - UNII-9 support - EHT code cleanup in iwlmvm ==================== Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
commit
c30e188bd2
|
|
@ -19,12 +19,6 @@
|
|||
#define IWL_BZ_SMEM_OFFSET 0x400000
|
||||
#define IWL_BZ_SMEM_LEN 0xD0000
|
||||
|
||||
#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0"
|
||||
#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0"
|
||||
#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0"
|
||||
#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0"
|
||||
#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0"
|
||||
|
||||
static const struct iwl_family_base_params iwl_bz_base = {
|
||||
.num_of_queues = 512,
|
||||
.max_tfd_queue_size = 65536,
|
||||
|
|
@ -100,9 +94,3 @@ const struct iwl_mac_cfg iwl_gl_mac_cfg = {
|
|||
.xtal_latency = 12000,
|
||||
.low_latency_xtal = true,
|
||||
};
|
||||
|
||||
IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,12 @@
|
|||
*/
|
||||
#include "iwl-config.h"
|
||||
|
||||
#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0"
|
||||
#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0"
|
||||
#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0"
|
||||
#define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0"
|
||||
#define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0"
|
||||
|
||||
/* NVM versions */
|
||||
#define IWL_FM_NVM_VERSION 0x0a1d
|
||||
|
||||
|
|
@ -50,3 +56,9 @@ const char iwl_be201_name[] = "Intel(R) Wi-Fi 7 BE201 320MHz";
|
|||
const char iwl_be200_name[] = "Intel(R) Wi-Fi 7 BE200 320MHz";
|
||||
const char iwl_be202_name[] = "Intel(R) Wi-Fi 7 BE202 160MHz";
|
||||
const char iwl_be401_name[] = "Intel(R) Wi-Fi 7 BE401 320MHz";
|
||||
|
||||
IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX);
|
||||
|
|
|
|||
|
|
@ -13,5 +13,4 @@ const char iwl_killer_bn1850i_name[] =
|
|||
|
||||
const char iwl_bn201_name[] = "Intel(R) Wi-Fi 8 BN201";
|
||||
const char iwl_bn203_name[] = "Intel(R) Wi-Fi 8 BN203";
|
||||
const char iwl_be221_name[] = "Intel(R) Wi-Fi 7 BE221";
|
||||
const char iwl_be223_name[] = "Intel(R) Wi-Fi 7 BE223";
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = {
|
|||
[DSM_FUNC_ENERGY_DETECTION_THRESHOLD] = sizeof(u32),
|
||||
[DSM_FUNC_RFI_CONFIG] = sizeof(u32),
|
||||
[DSM_FUNC_ENABLE_11BE] = sizeof(u32),
|
||||
[DSM_FUNC_ENABLE_UNII_9] = sizeof(u32),
|
||||
[DSM_FUNC_ENABLE_11BN] = sizeof(u32),
|
||||
};
|
||||
|
||||
static int iwl_acpi_get_handle(struct device *dev, acpi_string method,
|
||||
|
|
@ -155,6 +157,70 @@ static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function loads all the DSM functions, it checks the size and populates
|
||||
* the cache with the values in a 32-bit field.
|
||||
* In case the expected size is smaller than 32-bit, padding will be added.
|
||||
*/
|
||||
static int iwl_acpi_load_dsm_values(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
u64 query_func_val;
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS);
|
||||
|
||||
ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV,
|
||||
DSM_FUNC_QUERY,
|
||||
&iwl_guid, &query_func_val,
|
||||
acpi_dsm_size[DSM_FUNC_QUERY]);
|
||||
|
||||
if (ret) {
|
||||
IWL_DEBUG_RADIO(fwrt, "ACPI QUERY FUNC not valid: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fwrt->dsm_revision = ACPI_DSM_REV;
|
||||
fwrt->dsm_source = BIOS_SOURCE_ACPI;
|
||||
|
||||
IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n",
|
||||
(u32)query_func_val);
|
||||
|
||||
/* DSM_FUNC_QUERY is 0, start from 1 */
|
||||
for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
|
||||
size_t expected_size = acpi_dsm_size[func];
|
||||
u64 tmp;
|
||||
|
||||
if (!(query_func_val & BIT(func))) {
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"ACPI DSM %d not indicated as valid\n",
|
||||
func);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This is an invalid function (5 for example) */
|
||||
if (!expected_size)
|
||||
continue;
|
||||
|
||||
/* Currently all ACPI DSMs are either 8-bit or 32-bit */
|
||||
if (expected_size != sizeof(u8) && expected_size != sizeof(u32))
|
||||
continue;
|
||||
|
||||
ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func,
|
||||
&iwl_guid, &tmp, expected_size);
|
||||
if (ret)
|
||||
continue;
|
||||
|
||||
if ((expected_size == sizeof(u8) && tmp != (u8)tmp) ||
|
||||
(expected_size == sizeof(u32) && tmp != (u32)tmp))
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"DSM value overflows the expected size, truncating\n");
|
||||
fwrt->dsm_values[func] = (u32)tmp;
|
||||
fwrt->dsm_funcs_valid |= BIT(func);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function receives a DSM function number, calculates its expected size
|
||||
* according to Intel BIOS spec, and fills in the value in a 32-bit field.
|
||||
|
|
@ -163,54 +229,33 @@ static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func,
|
|||
int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt,
|
||||
enum iwl_dsm_funcs func, u32 *value)
|
||||
{
|
||||
size_t expected_size;
|
||||
u64 tmp;
|
||||
int ret;
|
||||
if (!fwrt->dsm_funcs_valid) {
|
||||
int ret = iwl_acpi_load_dsm_values(fwrt);
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS);
|
||||
/*
|
||||
* Always set the valid bit for DSM_FUNC_QUERY so that even if
|
||||
* DSM_FUNC_QUERY returns 0 (no DSM function is valid), we will
|
||||
* still consider the cache as valid.
|
||||
*/
|
||||
fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY);
|
||||
|
||||
if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size) || !func))
|
||||
return -EINVAL;
|
||||
|
||||
expected_size = acpi_dsm_size[func];
|
||||
|
||||
/* Currently all ACPI DSMs are either 8-bit or 32-bit */
|
||||
if (expected_size != sizeof(u8) && expected_size != sizeof(u32))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!fwrt->acpi_dsm_funcs_valid) {
|
||||
ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV,
|
||||
DSM_FUNC_QUERY,
|
||||
&iwl_guid, &tmp,
|
||||
acpi_dsm_size[DSM_FUNC_QUERY]);
|
||||
if (ret) {
|
||||
/* always indicate BIT(0) to avoid re-reading */
|
||||
fwrt->acpi_dsm_funcs_valid = BIT(0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
IWL_DEBUG_RADIO(fwrt, "ACPI DSM validity bitmap 0x%x\n",
|
||||
(u32)tmp);
|
||||
/* always indicate BIT(0) to avoid re-reading */
|
||||
fwrt->acpi_dsm_funcs_valid = tmp | BIT(0);
|
||||
}
|
||||
|
||||
if (!(fwrt->acpi_dsm_funcs_valid & BIT(func))) {
|
||||
BUILD_BUG_ON(ARRAY_SIZE(fwrt->dsm_values) != DSM_FUNC_NUM_FUNCS);
|
||||
BUILD_BUG_ON(BITS_PER_TYPE(fwrt->dsm_funcs_valid) < DSM_FUNC_NUM_FUNCS);
|
||||
|
||||
if (WARN_ON(func >= ARRAY_SIZE(fwrt->dsm_values) || !func))
|
||||
return -EINVAL;
|
||||
|
||||
if (!(fwrt->dsm_funcs_valid & BIT(func))) {
|
||||
IWL_DEBUG_RADIO(fwrt, "ACPI DSM %d not indicated as valid\n",
|
||||
func);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func,
|
||||
&iwl_guid, &tmp, expected_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((expected_size == sizeof(u8) && tmp != (u8)tmp) ||
|
||||
(expected_size == sizeof(u32) && tmp != (u32)tmp))
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"DSM value overflows the expected size, truncating\n");
|
||||
*value = (u32)tmp;
|
||||
*value = fwrt->dsm_values[func];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,18 @@ enum iwl_mac_conf_subcmd_ids {
|
|||
* @TWT_OPERATION_CMD: &struct iwl_twt_operation_cmd
|
||||
*/
|
||||
TWT_OPERATION_CMD = 0x10,
|
||||
/**
|
||||
* @NAN_CFG_CMD: &struct iwl_nan_config_cmd
|
||||
*/
|
||||
NAN_CFG_CMD = 0x12,
|
||||
/**
|
||||
* @NAN_DW_END_NOTIF: &struct iwl_nan_dw_end_notif
|
||||
*/
|
||||
NAN_DW_END_NOTIF = 0xf4,
|
||||
/**
|
||||
* @NAN_JOINED_CLUSTER_NOTIF: &struct iwl_nan_cluster_notif
|
||||
*/
|
||||
NAN_JOINED_CLUSTER_NOTIF = 0xf5,
|
||||
/**
|
||||
* @MISSED_BEACONS_NOTIF: &struct iwl_missed_beacons_notif
|
||||
*/
|
||||
|
|
@ -491,23 +503,37 @@ enum iwl_link_modify_bandwidth {
|
|||
IWL_LINK_MODIFY_BW_320,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_npca_flags - NPCA flags
|
||||
* @IWL_NPCA_FLAG_MAC_HDR_BASED: MAC header based NPCA operation
|
||||
* permitted in the BSS (MOPLEN)
|
||||
*/
|
||||
enum iwl_npca_flags {
|
||||
IWL_NPCA_FLAG_MAC_HDR_BASED = BIT(0),
|
||||
}; /* NPCA_FLAG_E */
|
||||
|
||||
/**
|
||||
* struct iwl_npca_params - NPCA parameters (non-primary channel access)
|
||||
*
|
||||
* @dis_subch_bmap: disabled subchannel bitmap for NPCA
|
||||
* @switch_delay: after switch, delay TX according to destination AP
|
||||
* @switch_back_delay: switch back to control channel before OBSS frame end
|
||||
* @initial_qsrc: Indicates the value that is used to initialize the
|
||||
* EDCAF QSRC[AC] variables
|
||||
* @min_dur_threshold: minimum PPDU time to switch to the non-primary
|
||||
* NPCA channel
|
||||
* @flags: NPCA flags - bit 0: puncturing allowed, bit 1: new TX allowed
|
||||
* NPCA channel (usec)
|
||||
* @flags: NPCA flags, see &enum iwl_npca_flags
|
||||
* @reserved: reserved for alignment purposes
|
||||
*/
|
||||
struct iwl_npca_params {
|
||||
__le16 dis_subch_bmap;
|
||||
u8 switch_delay;
|
||||
u8 switch_back_delay;
|
||||
__le16 min_dur_threshold;
|
||||
__le16 flags;
|
||||
__le16 reserved;
|
||||
} __packed; /* NPCA_PARAM_API_S_VER_1 */
|
||||
u8 initial_qsrc;
|
||||
u8 min_dur_threshold;
|
||||
u8 flags;
|
||||
u8 reserved;
|
||||
} __packed; /* NPCA_PARAM_API_S_VER_2 */
|
||||
|
||||
/**
|
||||
* struct iwl_link_config_cmd - command structure to configure the LINK context
|
||||
|
|
@ -618,7 +644,8 @@ struct iwl_link_config_cmd {
|
|||
struct iwl_npca_params npca_params; /* since _VER_7 */
|
||||
struct iwl_ac_qos prio_edca_params; /* since _VER_7 */
|
||||
__le32 reserved3[4];
|
||||
} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, _VER_5, _VER_6, _VER_7 */
|
||||
} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4,
|
||||
* _VER_5, _VER_6, _VER_7, _VER_8 */
|
||||
|
||||
/* Currently FW supports link ids in the range 0-3 and can have
|
||||
* at most two active links for each vif.
|
||||
|
|
@ -990,4 +1017,122 @@ struct iwl_twt_operation_cmd {
|
|||
u8 ul_tid_bitmap;
|
||||
} __packed; /* TWT_OPERATION_API_S_VER_1 */
|
||||
|
||||
enum iwl_nan_band {
|
||||
IWL_NAN_BAND_5GHZ = 0,
|
||||
IWL_NAN_BAND_2GHZ = 1,
|
||||
IWL_NUM_NAN_BANDS,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_nan_band_config - NAN band configuration
|
||||
*
|
||||
* @rssi_close: RSSI threshold for close proximity in dBm
|
||||
* @rssi_middle: RSSI threshold for middle proximity in dBm
|
||||
* @dw_interval: Discovery Window (DW) interval for synchronization beacons and
|
||||
* SDFs. Valid values of DW interval are: 1, 2, 3, 4 and 5 corresponding to
|
||||
* 1, 2, 4, 8, and 16 DWs.
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct iwl_nan_band_config {
|
||||
u8 rssi_close;
|
||||
u8 rssi_middle;
|
||||
u8 dw_interval;
|
||||
u8 reserved;
|
||||
}; /* NAN_BAND_SPECIFIC_CONFIG_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* enum iwl_nan_flags - flags for NAN configuration
|
||||
*
|
||||
* @IWL_NAN_FLAG_DW_END_NOTIF_ENABLED: indicates that the host wants to receive
|
||||
* notifications when a DW ends.
|
||||
*/
|
||||
enum iwl_nan_flags {
|
||||
IWL_NAN_FLAG_DW_END_NOTIF_ENABLED = BIT(0),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_nan_config_cmd - NAN configuration command
|
||||
*
|
||||
* @action: action to perform, see &enum iwl_ctxt_action
|
||||
* @nmi_addr: NAN Management Interface (NMI) address
|
||||
* @reserved_for_nmi_addr: reserved
|
||||
* @discovery_beacon_interval: discovery beacon interval in TUs
|
||||
* @cluster_id: lower last two bytes of the cluster ID, in case the local
|
||||
* device starts a cluster
|
||||
* @sta_id: station ID of the NAN station
|
||||
* @hb_channel: channel for 5 GHz if the device supports operation on 5 GHz.
|
||||
* Valid values are 44 and 149, which correspond to the 5 GHz channel, and
|
||||
* 0 which means that NAN operation on the 5 GHz band is disabled.
|
||||
* @master_pref: master preference
|
||||
* @dwell_time: dwell time on the discovery channel during scan (milliseconds).
|
||||
* If set to 0, the dwell time is determined by the firmware.
|
||||
* @scan_period: scan period in seconds. If set to 0, the scan period is
|
||||
* determined by the firmware.
|
||||
* @flags: flags for NAN configuration, see &enum iwl_nan_flags
|
||||
* @band_config: band configuration for NAN, one for each band
|
||||
* @nan_attr_len: length of the NAN attributes to be added to the beacon (bytes)
|
||||
* @nan_vendor_elems_len: length of the NAN vendor elements to be added to the
|
||||
* beacon (bytes)
|
||||
* @beacon_data: variable length data that contains the NAN attributes
|
||||
* (&nan_attr_len) followed by the NAN vendor elements
|
||||
* (&nan_vendor_elems_len).
|
||||
*/
|
||||
struct iwl_nan_config_cmd {
|
||||
__le32 action;
|
||||
u8 nmi_addr[6];
|
||||
__le16 reserved_for_nmi_addr;
|
||||
__le32 discovery_beacon_interval;
|
||||
|
||||
u8 cluster_id[2];
|
||||
u8 sta_id;
|
||||
u8 hb_channel;
|
||||
|
||||
u8 master_pref;
|
||||
u8 dwell_time;
|
||||
u8 scan_period;
|
||||
u8 flags;
|
||||
|
||||
struct iwl_nan_band_config band_config[IWL_NUM_NAN_BANDS];
|
||||
|
||||
__le32 nan_attr_len;
|
||||
__le32 nan_vendor_elems_len;
|
||||
u8 beacon_data[];
|
||||
} __packed; /* NAN_CONFIG_CMD_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* enum iwl_nan_cluster_notif_flags - flags for the cluster notification
|
||||
*
|
||||
* @IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER: indicates that the device has
|
||||
* started a new cluster. If not set, the device has joined an existing
|
||||
* cluster.
|
||||
*/
|
||||
enum iwl_nan_cluster_notif_flags {
|
||||
IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER = BIT(0),
|
||||
}; /* NAN_JOINED_CLUSTER_FLAG_E_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_nan_cluster_notif - event sent when the device starts or joins a
|
||||
* NAN cluster.
|
||||
*
|
||||
* @cluster_id: the last two bytes of the cluster ID
|
||||
* @flags: combination of &enum iwl_nan_cluster_notif_flags
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct iwl_nan_cluster_notif {
|
||||
u8 cluster_id[2];
|
||||
u8 flags;
|
||||
u8 reserved;
|
||||
}; /* NAN_JOINED_CLUSTER_NTF_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_nan_dw_end_notif - sent to notify the host the end of a DW.
|
||||
*
|
||||
* @band: band on which the DW ended. See &enum iwl_nan_band.
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct iwl_nan_dw_end_notif {
|
||||
u8 band;
|
||||
u8 reserved[3];
|
||||
} __packed; /* NAN_DW_END_NTF_API_S_VER_1 */
|
||||
|
||||
#endif /* __iwl_fw_api_mac_cfg_h__ */
|
||||
|
|
|
|||
|
|
@ -503,18 +503,26 @@ enum bios_source {
|
|||
};
|
||||
|
||||
/**
|
||||
* struct bios_value_u32 - BIOS configuration.
|
||||
* struct iwl_bios_config_hdr - BIOS configuration header
|
||||
* @table_source: see &enum bios_source
|
||||
* @table_revision: table revision.
|
||||
* @reserved: reserved
|
||||
* @value: value in bios.
|
||||
*/
|
||||
struct bios_value_u32 {
|
||||
struct iwl_bios_config_hdr {
|
||||
u8 table_source;
|
||||
u8 table_revision;
|
||||
u8 reserved[2];
|
||||
} __packed; /* BIOS_CONFIG_HDR_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct bios_value_u32 - BIOS configuration.
|
||||
* @hdr: bios config header
|
||||
* @value: value in bios.
|
||||
*/
|
||||
struct bios_value_u32 {
|
||||
struct iwl_bios_config_hdr hdr;
|
||||
__le32 value;
|
||||
} __packed; /* BIOS_TABLE_SOURCE_U32_S_VER_1 */
|
||||
} __packed; /* BIOS_CONFIG_DATA_U32_API_S_VER_1 */
|
||||
|
||||
/**
|
||||
* struct iwl_tas_config_cmd - configures the TAS.
|
||||
|
|
@ -650,6 +658,10 @@ struct iwl_lari_config_change_cmd_v8 {
|
|||
* bit0: enable 11be in China(CB/CN).
|
||||
* bit1: enable 11be in South Korea.
|
||||
* bit 2 - 31: reserved.
|
||||
* @oem_11bn_allow_bitmap: Bitmap of 11bn allowed MCCs. The firmware expects to
|
||||
* get the data from the BIOS.
|
||||
* @oem_unii9_enable: UNII-9 enablement as read from the BIOS
|
||||
* @bios_hdr: bios config header
|
||||
*/
|
||||
struct iwl_lari_config_change_cmd {
|
||||
__le32 config_bitmap;
|
||||
|
|
@ -661,8 +673,16 @@ struct iwl_lari_config_change_cmd {
|
|||
__le32 edt_bitmap;
|
||||
__le32 oem_320mhz_allow_bitmap;
|
||||
__le32 oem_11be_allow_bitmap;
|
||||
/* since version 13 */
|
||||
__le32 oem_11bn_allow_bitmap;
|
||||
/* since version 13 */
|
||||
__le32 oem_unii9_enable;
|
||||
/* since version 13 */
|
||||
struct iwl_bios_config_hdr bios_hdr;
|
||||
} __packed;
|
||||
/* LARI_CHANGE_CONF_CMD_S_VER_12 */
|
||||
/* LARI_CHANGE_CONF_CMD_S_VER_12
|
||||
* LARI_CHANGE_CONF_CMD_S_VER_13
|
||||
*/
|
||||
|
||||
/* Activate UNII-1 (5.2GHz) for World Wide */
|
||||
#define ACTIVATE_5G2_IN_WW_MASK BIT(4)
|
||||
|
|
@ -682,11 +702,11 @@ struct iwl_pnvm_init_complete_ntfy {
|
|||
|
||||
/**
|
||||
* struct iwl_mcc_allowed_ap_type_cmd - struct for MCC_ALLOWED_AP_TYPE_CMD
|
||||
* @offset_map: mapping a mcc to UHB AP type support (UATS) allowed
|
||||
* @mcc_to_ap_type_map: mapping an MCC to 6 GHz AP type support (UATS)
|
||||
* @reserved: reserved
|
||||
*/
|
||||
struct iwl_mcc_allowed_ap_type_cmd {
|
||||
u8 offset_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE];
|
||||
u8 mcc_to_ap_type_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE];
|
||||
__le16 reserved;
|
||||
} __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_1 */
|
||||
|
||||
|
|
|
|||
|
|
@ -766,7 +766,7 @@ enum iwl_6ghz_ap_type {
|
|||
* AP_TX_POWER_CONSTRAINTS_CMD
|
||||
* Used for VLP/LPI/AFC Access Point power constraints for 6GHz channels
|
||||
* @link_id: linkId
|
||||
* @ap_type: see &enum iwl_ap_type
|
||||
* @ap_type: see &enum iwl_6ghz_ap_type
|
||||
* @eirp_pwr: 8-bit 2s complement signed integer in the range
|
||||
* -64 dBm to 63 dBm with a 0.5 dB step
|
||||
* default &DEFAULT_TPE_TX_POWER (no maximum limit)
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ enum iwl_tlc_mng_cfg_chains {
|
|||
* @IWL_TLC_MNG_MODE_VHT: enable VHT
|
||||
* @IWL_TLC_MNG_MODE_HE: enable HE
|
||||
* @IWL_TLC_MNG_MODE_EHT: enable EHT
|
||||
* @IWL_TLC_MNG_MODE_UHR: enable UHR
|
||||
*/
|
||||
enum iwl_tlc_mng_cfg_mode {
|
||||
IWL_TLC_MNG_MODE_CCK = 0,
|
||||
|
|
@ -82,6 +83,7 @@ enum iwl_tlc_mng_cfg_mode {
|
|||
IWL_TLC_MNG_MODE_VHT,
|
||||
IWL_TLC_MNG_MODE_HE,
|
||||
IWL_TLC_MNG_MODE_EHT,
|
||||
IWL_TLC_MNG_MODE_UHR,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -205,7 +207,7 @@ struct iwl_tlc_config_cmd_v4 {
|
|||
} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_4 */
|
||||
|
||||
/**
|
||||
* struct iwl_tlc_config_cmd - TLC configuration
|
||||
* struct iwl_tlc_config_cmd_v5 - TLC configuration
|
||||
* @sta_id: station id
|
||||
* @reserved1: reserved
|
||||
* @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw
|
||||
|
|
@ -221,7 +223,7 @@ struct iwl_tlc_config_cmd_v4 {
|
|||
* @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI),
|
||||
* set zero for no limit.
|
||||
*/
|
||||
struct iwl_tlc_config_cmd {
|
||||
struct iwl_tlc_config_cmd_v5 {
|
||||
u8 sta_id;
|
||||
u8 reserved1[3];
|
||||
u8 max_ch_width;
|
||||
|
|
@ -235,6 +237,38 @@ struct iwl_tlc_config_cmd {
|
|||
__le16 max_tx_op;
|
||||
} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_5 */
|
||||
|
||||
/**
|
||||
* struct iwl_tlc_config_cmd - TLC configuration
|
||||
* @sta_mask: station mask (in NAN we can have multiple logical stations of
|
||||
* the same peer (with the same TLC configuration)).
|
||||
* @phy_id: the phy id to used for this TLC configuration
|
||||
* @max_ch_width: max supported channel width from &enum iwl_tlc_mng_cfg_cw
|
||||
* @mode: &enum iwl_tlc_mng_cfg_mode
|
||||
* @chains: bitmask of &enum iwl_tlc_mng_cfg_chains
|
||||
* @sgi_ch_width_supp: bitmap of SGI support per channel width
|
||||
* use BIT(&enum iwl_tlc_mng_cfg_cw)
|
||||
* @flags: bitmask of &enum iwl_tlc_mng_cfg_flags
|
||||
* @non_ht_rates: bitmap of supported legacy rates
|
||||
* @ht_rates: bitmap of &enum iwl_tlc_mng_ht_rates, per <nss, channel-width>
|
||||
* pair (0 - 80mhz width and below, 1 - 160mhz, 2 - 320mhz).
|
||||
* @max_mpdu_len: max MPDU length, in bytes
|
||||
* @max_tx_op: max TXOP in uSecs for all AC (BK, BE, VO, VI),
|
||||
* set zero for no limit.
|
||||
*/
|
||||
struct iwl_tlc_config_cmd {
|
||||
__le32 sta_mask;
|
||||
__le32 phy_id;
|
||||
u8 max_ch_width;
|
||||
u8 mode;
|
||||
u8 chains;
|
||||
u8 sgi_ch_width_supp;
|
||||
__le16 flags;
|
||||
__le16 non_ht_rates;
|
||||
__le32 ht_rates[IWL_TLC_NSS_MAX][IWL_TLC_MCS_PER_BW_NUM_V4];
|
||||
__le16 max_mpdu_len;
|
||||
__le16 max_tx_op;
|
||||
} __packed; /* TLC_MNG_CONFIG_CMD_API_S_VER_6 */
|
||||
|
||||
/**
|
||||
* enum iwl_tlc_update_flags - updated fields
|
||||
* @IWL_TLC_NOTIF_FLAG_RATE: last initial rate update
|
||||
|
|
@ -706,10 +740,11 @@ enum {
|
|||
#define RATE_MCS_HE_SU_4_LTF 3
|
||||
#define RATE_MCS_HE_SU_4_LTF_08_GI 4
|
||||
|
||||
/* Bit 24-23: HE type. (0) SU, (1) SU_EXT, (2) MU, (3) trigger based */
|
||||
/* Bit 24-23: HE type. (0) SU, (1) HE SU_EXT/UHR ELR, (2) MU, (3) trigger based */
|
||||
#define RATE_MCS_HE_TYPE_POS 23
|
||||
#define RATE_MCS_HE_TYPE_SU (0 << RATE_MCS_HE_TYPE_POS)
|
||||
#define RATE_MCS_HE_TYPE_EXT_SU (1 << RATE_MCS_HE_TYPE_POS)
|
||||
#define RATE_MCS_HE_TYPE_UHR_ELR (1 << RATE_MCS_HE_TYPE_POS)
|
||||
#define RATE_MCS_HE_TYPE_MU (2 << RATE_MCS_HE_TYPE_POS)
|
||||
#define RATE_MCS_HE_TYPE_TRIG (3 << RATE_MCS_HE_TYPE_POS)
|
||||
#define RATE_MCS_HE_TYPE_MSK (3 << RATE_MCS_HE_TYPE_POS)
|
||||
|
|
|
|||
|
|
@ -1062,13 +1062,37 @@ struct iwl_vht_sigs {
|
|||
#define OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM 0x000007ff
|
||||
#define OFDM_RX_FRAME_VHT_NUM_OF_DATA_SYM_VALID 0x80000000
|
||||
__le32 a0;
|
||||
__le32 a1, a2;
|
||||
#define OFDM_RX_FRAME_VHT_BANDWIDTH 0x00000003
|
||||
#define OFDM_RX_FRAME_VHT_STBC 0x00000008
|
||||
#define OFDM_RX_FRAME_VHT_GRP_ID 0x000003f0
|
||||
#define OFDM_RX_FRAME_VHT_STS_USER0 0x00001c00
|
||||
#define OFDM_RX_FRAME_VHT_MU_STS_USER1 0x0000e000
|
||||
#define OFDM_RX_FRAME_VHT_MU_STS_USER2 0x00070000
|
||||
#define OFDM_RX_FRAME_VHT_MU_STS_USER3 0x00380000
|
||||
#define OFDM_RX_FRAME_VHT_PARTIAL_AID_OR_MU_STS 0x003fe000
|
||||
#define OFDM_RX_FRAME_VHT_MU_MIMO_USER_POSITION 0x03000000
|
||||
#define OFDM_RX_FRAME_VHT_NO_STREAMS 0x04000000
|
||||
#define OFDM_RX_FRAME_VHT_STS 0x38000000
|
||||
__le32 a1;
|
||||
#define OFDM_RX_FRAME_VHT_SHORT_GI 0x00000001
|
||||
#define OFDM_RX_FRAME_VHT_SHORT_GI_AMBIG 0x00000002
|
||||
#define OFDM_RX_FRAME_VHT_CODING 0x00000004
|
||||
#define OFDM_RX_FRAME_VHT_CODING_EXTRA_SYM 0x00000008
|
||||
#define OFDM_RX_FRAME_VHT_MCS_OR_MU_CODING 0x000000f0
|
||||
#define OFDM_RX_FRAME_VHT_BF_OR_MU_RESERVED 0x00000100
|
||||
#define OFDM_RX_FRAME_VHT_CRC 0x0003fc00
|
||||
#define OFDM_RX_FRAME_VHT_CRC_OK_BIT 0x00040000
|
||||
#define OFDM_RX_FRAME_VHT_CUR_USER_CODING 0x00080000
|
||||
#define OFDM_RX_FRAME_VHT_CUR_USER_STS 0x00700000
|
||||
__le32 a2;
|
||||
};
|
||||
|
||||
struct iwl_he_sigs {
|
||||
#define OFDM_RX_FRAME_HE_BEAM_CHANGE 0x00000001
|
||||
#define OFDM_RX_FRAME_HE_UL_FLAG 0x00000002
|
||||
/* SU/ER-SU: MCS, MU: SIG-B MCS */
|
||||
#define OFDM_RX_FRAME_HE_MCS 0x0000003c
|
||||
/* SU/ER-SU: DCM, MU: SIG-B DCM */
|
||||
#define OFDM_RX_FRAME_HE_DCM 0x00000040
|
||||
#define OFDM_RX_FRAME_HE_BSS_COLOR 0x00001f80
|
||||
#define OFDM_RX_FRAME_HE_SPATIAL_REUSE 0x0001e000
|
||||
|
|
@ -1247,19 +1271,82 @@ struct iwl_eht_tb_sigs {
|
|||
};
|
||||
|
||||
struct iwl_uhr_sigs {
|
||||
__le32 usig_a1, usig_a1_uhr, usig_a2_uhr, b1, b2;
|
||||
/* same as EHT above */
|
||||
__le32 usig_a1;
|
||||
#define OFDM_RX_FRAME_UHR_BSS_COLOR2 0x0000003f
|
||||
__le32 usig_a1_uhr;
|
||||
#define OFDM_RX_FRAME_UHR_PPDU_TYPE 0x00000003
|
||||
#define OFDM_RX_FRAME_UHR_COBF_CSR_DISABLE 0x00000004
|
||||
#define OFDM_RX_FRAME_UHR_PUNC_CHANNEL 0x000000f8
|
||||
#define OFDM_RX_FRAME_UHR_USIG2_VALIDATE_B8 0x00000100
|
||||
#define OFDM_RX_FRAME_UHR_SIG_MCS 0x00000600
|
||||
#define OFDM_RX_FRAME_UHR_SIG_SYM_NUM 0x0000f800
|
||||
#define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_1 0x000f0000
|
||||
#define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_2 0x00f00000
|
||||
#define OFDM_RX_FRAME_UHR_TRIG_USIG2_DISREGARD 0x1f000000
|
||||
__le32 usig_a2_uhr;
|
||||
#define OFDM_RX_FRAME_UHR_SPATIAL_REUSE 0x0000000f
|
||||
#define OFDM_RX_FRAME_UHR_GI_LTF_TYPE 0x00000030
|
||||
#define OFDM_RX_FRAME_UHR_NUM_OF_LTF_SYM 0x000001c0
|
||||
#define OFDM_RX_FRAME_UHR_CODING_EXTRA_SYM 0x00000200
|
||||
#define OFDM_RX_FRAME_UHR_PE_A_FACTOR 0x00000c00
|
||||
#define OFDM_RX_FRAME_UHR_PE_DISAMBIGUITY 0x00001000
|
||||
#define OFDM_RX_FRAME_UHR_IM_DISABLE 0x00002000
|
||||
#define OFDM_RX_FRAME_UHR_USIG_OVF_DISREGARD 0x0000c000
|
||||
#define OFDM_RX_FRAME_UHR_NUM_OF_USERS 0x00070000
|
||||
#define OFDM_RX_FRAME_UHR_NSTS 0x00f00000
|
||||
#define OFDM_RX_FRAME_UHR_BF 0x01000000
|
||||
#define OFDM_RX_FRAME_UHR_USIG_OVF_NDP_DISREGARD 0x06000000
|
||||
#define OFDM_RX_FRAME_UHR_COMM_CC1_CRC_OK 0x08000000
|
||||
#define OFDM_RX_FRAME_UHR_COMM_CC2_CRC_OK 0x10000000
|
||||
#define OFDM_RX_FRAME_UHR_NON_VALID_RU_ALLOC 0x20000000
|
||||
__le32 b1;
|
||||
#define OFDM_RX_FRAME_UHR_MCS 0x000001f0
|
||||
#define OFDM_RX_FRAME_UHR_CODING 0x00000200
|
||||
#define OFDM_RX_FRAME_UHR_SPATIAL_CONFIG 0x00003c00
|
||||
#define OFDM_RX_FRAME_UHR_STA_RU 0x003fc000
|
||||
#define OFDM_RX_FRAME_UHR_STA_RU_PS160 0x00400000
|
||||
#define OFDM_RX_FRAME_UHR_UEQM 0x00800000
|
||||
#define OFDM_RX_FRAME_UHR_2XLDPC 0x01000000
|
||||
#define OFDM_RX_FRAME_UHR_UEQM_PATTERN 0x06000000
|
||||
#define OFDM_RX_FRAME_UHR_IS_MU_MIMO_USER_FIELD 0x08000000
|
||||
#define OFDM_RX_FRAME_UHR_USER_FIELD_CRC_OK 0x40000000
|
||||
__le32 b2;
|
||||
#define OFDM_RX_UHR_NUM_OF_DATA_SYM 0x000007ff
|
||||
#define OFDM_RX_UHR_PE_DURATION 0x00003800
|
||||
__le32 sig2;
|
||||
/* same as EHT above: OFDM_RX_FRAME_EHT_RU_ALLOC_* */
|
||||
__le32 cmn[6];
|
||||
#define OFDM_RX_FRAME_UHR_USER_FIELD_ID 0x000007ff
|
||||
__le32 user_id;
|
||||
};
|
||||
|
||||
struct iwl_uhr_tb_sigs {
|
||||
__le32 usig_a1, usig_a2_uhr, tb_rx0, tb_rx1;
|
||||
/* same as UHR above */
|
||||
__le32 usig_a1, usig_a2_uhr;
|
||||
/* same as HE above */
|
||||
__le32 tb_rx0, tb_rx1;
|
||||
};
|
||||
|
||||
struct iwl_uhr_elr_sigs {
|
||||
/* same as UHR above */
|
||||
__le32 usig_a1, usig_a2_uhr;
|
||||
__le32 uhr_sig_elr1, uhr_sig_elr2;
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_VER_ID 0x00000007
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_UPLINK_FLAG 0x00000008
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_MCS 0x00000010
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_CODING 0x00000020
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_LENGTH_IN_SYM 0x00007fc0
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_CODING_EXTRA_SYM 0x00008000
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_SIG1_CRC_OK 0x00010000
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_STA_ID 0x0ffe0000
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_DISREGARD 0x70000000
|
||||
__le32 uhr_sig_elr1;
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_MARK_BSS_COLOR 0x0000003f
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_SIG_ID_INDX 0x00000e00
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_STA_RU 0x000ff000
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_STA_RU_PS160 0x00100000
|
||||
#define OFDM_RX_VECTOR_UHR_ELR_SIG2_CRC_OK 0x00200000
|
||||
__le32 uhr_sig_elr2;
|
||||
};
|
||||
|
||||
union iwl_sigs {
|
||||
|
|
|
|||
|
|
@ -447,6 +447,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t;
|
|||
* during assert handling even if the dump isn't split
|
||||
* @IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE: Firmware has capability of
|
||||
* handling raw DSM table data.
|
||||
* @IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT: Supports NAN synchronization
|
||||
*
|
||||
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
|
||||
*/
|
||||
|
|
@ -550,6 +551,7 @@ enum iwl_ucode_tlv_capa {
|
|||
|
||||
IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0),
|
||||
IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 1),
|
||||
IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 2),
|
||||
NUM_IWL_UCODE_TLV_CAPA
|
||||
/*
|
||||
* This construction make both sparse (which cannot increment the previous
|
||||
|
|
|
|||
|
|
@ -376,8 +376,10 @@ int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
|
|||
num_sub_bands = IWL_NUM_SUB_BANDS_V2;
|
||||
gain = cmd->v7.gain[0];
|
||||
*cmd_size = sizeof(cmd->v7);
|
||||
cmd->v7.ppag_config_info.table_source = fwrt->ppag_bios_source;
|
||||
cmd->v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev;
|
||||
cmd->v7.ppag_config_info.hdr.table_source =
|
||||
fwrt->ppag_bios_source;
|
||||
cmd->v7.ppag_config_info.hdr.table_revision =
|
||||
fwrt->ppag_bios_rev;
|
||||
cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);
|
||||
} else {
|
||||
IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
|
||||
|
|
@ -488,206 +490,6 @@ bool iwl_add_mcc_to_tas_block_list(u16 *list, u8 *size, u16 mcc)
|
|||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_add_mcc_to_tas_block_list);
|
||||
|
||||
__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
__le32 config_bitmap = 0;
|
||||
|
||||
switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) {
|
||||
case IWL_CFG_RF_TYPE_HR1:
|
||||
case IWL_CFG_RF_TYPE_HR2:
|
||||
case IWL_CFG_RF_TYPE_JF1:
|
||||
case IWL_CFG_RF_TYPE_JF2:
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2,
|
||||
&val);
|
||||
|
||||
if (!ret && val == DSM_VALUE_INDONESIA_ENABLE)
|
||||
config_bitmap |=
|
||||
cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val);
|
||||
if (!ret) {
|
||||
if (val == DSM_VALUE_SRD_PASSIVE)
|
||||
config_bitmap |=
|
||||
cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
|
||||
else if (val == DSM_VALUE_SRD_DISABLE)
|
||||
config_bitmap |=
|
||||
cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
|
||||
}
|
||||
|
||||
if (fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) {
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG,
|
||||
&val);
|
||||
/*
|
||||
* China 2022 enable if the BIOS object does not exist or
|
||||
* if it is enabled in BIOS.
|
||||
*/
|
||||
if (ret < 0 || val & DSM_MASK_CHINA_22_REG)
|
||||
config_bitmap |=
|
||||
cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK);
|
||||
}
|
||||
|
||||
return config_bitmap;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_get_lari_config_bitmap);
|
||||
|
||||
static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver)
|
||||
{
|
||||
size_t cmd_size;
|
||||
|
||||
switch (cmd_ver) {
|
||||
case 12:
|
||||
cmd_size = sizeof(struct iwl_lari_config_change_cmd);
|
||||
break;
|
||||
case 8:
|
||||
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8);
|
||||
break;
|
||||
case 6:
|
||||
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6);
|
||||
break;
|
||||
default:
|
||||
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1);
|
||||
break;
|
||||
}
|
||||
return cmd_size;
|
||||
}
|
||||
|
||||
int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_lari_config_change_cmd *cmd,
|
||||
size_t *cmd_size)
|
||||
{
|
||||
int ret;
|
||||
u32 value;
|
||||
bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
|
||||
u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE), 1);
|
||||
|
||||
if (WARN_ONCE(cmd_ver > 12,
|
||||
"Don't add newer versions to this function\n"))
|
||||
return -EINVAL;
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
*cmd_size = iwl_get_lari_config_cmd_size(cmd_ver);
|
||||
|
||||
cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= DSM_11AX_ALLOW_BITMAP;
|
||||
cmd->oem_11ax_allow_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= DSM_UNII4_ALLOW_BITMAP;
|
||||
|
||||
/* Since version 12, bits 4 and 5 are supported
|
||||
* regardless of this capability, By pass this masking
|
||||
* if firmware has capability of accepting raw DSM table.
|
||||
*/
|
||||
if (!has_raw_dsm_capa && cmd_ver < 12 &&
|
||||
!fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA))
|
||||
value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK |
|
||||
DSM_VALUE_UNII4_CANADA_EN_MSK);
|
||||
|
||||
cmd->oem_unii4_allow_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12;
|
||||
|
||||
if (!has_raw_dsm_capa && cmd_ver < 8)
|
||||
value &= ~ACTIVATE_5G2_IN_WW_MASK;
|
||||
|
||||
/* Since version 12, bits 5 and 6 are supported
|
||||
* regardless of this capability, By pass this masking
|
||||
* if firmware has capability of accepting raw DSM table.
|
||||
*/
|
||||
if (!has_raw_dsm_capa && cmd_ver < 12 &&
|
||||
!fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA))
|
||||
value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V8;
|
||||
|
||||
cmd->chan_state_active_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value);
|
||||
if (!ret)
|
||||
cmd->oem_uhb_allow_bitmap = cpu_to_le32(value);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP;
|
||||
cmd->force_disable_channels_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD,
|
||||
&value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= DSM_EDT_ALLOWED_BITMAP;
|
||||
cmd->edt_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_wbem(fwrt, &value);
|
||||
if (!ret)
|
||||
cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);
|
||||
if (!ret)
|
||||
cmd->oem_11be_allow_bitmap = cpu_to_le32(value);
|
||||
|
||||
if (cmd->config_bitmap ||
|
||||
cmd->oem_uhb_allow_bitmap ||
|
||||
cmd->oem_11ax_allow_bitmap ||
|
||||
cmd->oem_unii4_allow_bitmap ||
|
||||
cmd->chan_state_active_bitmap ||
|
||||
cmd->force_disable_channels_bitmap ||
|
||||
cmd->edt_bitmap ||
|
||||
cmd->oem_320mhz_allow_bitmap ||
|
||||
cmd->oem_11be_allow_bitmap) {
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd->config_bitmap),
|
||||
le32_to_cpu(cmd->oem_11ax_allow_bitmap));
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n",
|
||||
le32_to_cpu(cmd->oem_unii4_allow_bitmap),
|
||||
le32_to_cpu(cmd->chan_state_active_bitmap),
|
||||
cmd_ver);
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd->oem_uhb_allow_bitmap),
|
||||
le32_to_cpu(cmd->force_disable_channels_bitmap));
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd->edt_bitmap),
|
||||
le32_to_cpu(cmd->oem_320mhz_allow_bitmap));
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd->oem_11be_allow_bitmap));
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fill_lari_config);
|
||||
|
||||
int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
|
||||
u32 *value)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -125,7 +125,9 @@ enum iwl_dsm_funcs {
|
|||
DSM_FUNC_ENERGY_DETECTION_THRESHOLD = 10,
|
||||
DSM_FUNC_RFI_CONFIG = 11,
|
||||
DSM_FUNC_ENABLE_11BE = 12,
|
||||
DSM_FUNC_NUM_FUNCS = 13,
|
||||
DSM_FUNC_ENABLE_11BN = 13,
|
||||
DSM_FUNC_ENABLE_UNII_9 = 14,
|
||||
DSM_FUNC_NUM_FUNCS,
|
||||
};
|
||||
|
||||
enum iwl_dsm_values_srd {
|
||||
|
|
@ -218,11 +220,6 @@ int iwl_bios_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc);
|
|||
int iwl_bios_get_eckv(struct iwl_fw_runtime *fwrt, u32 *ext_clk);
|
||||
int iwl_bios_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value);
|
||||
|
||||
__le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt);
|
||||
int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_lari_config_change_cmd *cmd,
|
||||
size_t *cmd_size);
|
||||
|
||||
int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
|
||||
u32 *value);
|
||||
|
||||
|
|
|
|||
|
|
@ -116,10 +116,14 @@ struct iwl_txf_iter_data {
|
|||
* @phy_filters: specific phy filters as read from WPFC BIOS table
|
||||
* @ppag_bios_rev: PPAG BIOS revision
|
||||
* @ppag_bios_source: see &enum bios_source
|
||||
* @acpi_dsm_funcs_valid: bitmap indicating which DSM values are valid,
|
||||
* @dsm_funcs_valid: bitmap indicating which DSM values are valid,
|
||||
* zero (default initialization) means it hasn't been read yet,
|
||||
* and BIT(0) is set when it has since function 0 also has this
|
||||
* bitmap and is always supported
|
||||
* bitmap and is always supported.
|
||||
* If the bit is set for a specific function, then the corresponding
|
||||
* entry in &dsm_values is valid.
|
||||
* @dsm_values: cache of the DSM values. The validity of each entry is
|
||||
* determined by &dsm_funcs_valid.
|
||||
* @geo_enabled: WGDS table is present
|
||||
* @geo_num_profiles: number of geo profiles
|
||||
* @geo_rev: geo profiles table revision
|
||||
|
|
@ -137,6 +141,8 @@ struct iwl_txf_iter_data {
|
|||
* @timestamp.seq: timestamp marking sequence
|
||||
* @timestamp.delay: timestamp marking worker delay
|
||||
* @tpc_enabled: TPC enabled
|
||||
* @dsm_source: one of &enum bios_source. UEFI, ACPI or NONE
|
||||
* @dsm_revision: the revision of the DSM table
|
||||
*/
|
||||
struct iwl_fw_runtime {
|
||||
struct iwl_trans *trans;
|
||||
|
|
@ -211,9 +217,12 @@ struct iwl_fw_runtime {
|
|||
bool uats_valid;
|
||||
u8 uefi_tables_lock_status;
|
||||
struct iwl_phy_specific_cfg phy_filters;
|
||||
enum bios_source dsm_source;
|
||||
u8 dsm_revision;
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
u32 acpi_dsm_funcs_valid;
|
||||
#if defined(CONFIG_ACPI) || defined(CONFIG_EFI)
|
||||
u32 dsm_funcs_valid;
|
||||
u32 dsm_values[DSM_FUNC_NUM_FUNCS];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
#include "iwl-drv.h"
|
||||
#include "runtime.h"
|
||||
#include "dbg.h"
|
||||
#include "fw/api/commands.h"
|
||||
|
||||
static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
|
||||
|
|
@ -17,7 +18,9 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
|
|||
u8 api_ver = iwl_fw_lookup_notif_ver(fwrt->fw, SYSTEM_GROUP,
|
||||
SHARED_MEM_CFG_CMD, 0);
|
||||
|
||||
if (WARN_ON(lmac_num > ARRAY_SIZE(mem_cfg->lmac_smem)))
|
||||
/* Note: notification has 3 entries, but we only expect 2 */
|
||||
if (IWL_FW_CHECK(fwrt, lmac_num > ARRAY_SIZE(fwrt->smem_cfg.lmac),
|
||||
"FW advertises %d LMACs\n", lmac_num))
|
||||
return;
|
||||
|
||||
fwrt->smem_cfg.num_lmacs = lmac_num;
|
||||
|
|
@ -26,7 +29,8 @@ static void iwl_parse_shared_mem_22000(struct iwl_fw_runtime *fwrt,
|
|||
fwrt->smem_cfg.rxfifo2_size = le32_to_cpu(mem_cfg->rxfifo2_size);
|
||||
|
||||
if (api_ver >= 4 &&
|
||||
!WARN_ON_ONCE(iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg))) {
|
||||
!IWL_FW_CHECK(fwrt, iwl_rx_packet_payload_len(pkt) < sizeof(*mem_cfg),
|
||||
"bad shared mem notification size\n")) {
|
||||
fwrt->smem_cfg.rxfifo2_control_size =
|
||||
le32_to_cpu(mem_cfg->rxfifo2_control_size);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -402,8 +402,9 @@ static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data,
|
|||
if (uats_data->revision != 1)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(fwrt->uats_table.offset_map, uats_data->offset_map,
|
||||
sizeof(fwrt->uats_table.offset_map));
|
||||
memcpy(fwrt->uats_table.mcc_to_ap_type_map,
|
||||
uats_data->mcc_to_ap_type_map,
|
||||
sizeof(fwrt->uats_table.mcc_to_ap_type_map));
|
||||
|
||||
fwrt->uats_valid = true;
|
||||
|
||||
|
|
@ -721,17 +722,12 @@ int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
|
||||
u32 *value)
|
||||
static int iwl_uefi_load_dsm_values(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
struct uefi_cnv_var_general_cfg *data;
|
||||
int ret = -EINVAL;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(data->functions) < DSM_FUNC_NUM_FUNCS);
|
||||
|
||||
/* Not supported function index */
|
||||
if (func >= DSM_FUNC_NUM_FUNCS || func == 5)
|
||||
return -EOPNOTSUPP;
|
||||
BUILD_BUG_ON(ARRAY_SIZE(data->functions) < ARRAY_SIZE(fwrt->dsm_values));
|
||||
|
||||
data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME,
|
||||
"DSM", sizeof(*data), NULL);
|
||||
|
|
@ -743,22 +739,64 @@ int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
|
|||
data->revision);
|
||||
goto out;
|
||||
}
|
||||
fwrt->dsm_revision = data->revision;
|
||||
fwrt->dsm_source = BIOS_SOURCE_UEFI;
|
||||
|
||||
if (!(data->functions[DSM_FUNC_QUERY] & BIT(func))) {
|
||||
IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n",
|
||||
func, data->functions[DSM_FUNC_QUERY]);
|
||||
goto out;
|
||||
fwrt->dsm_funcs_valid = data->functions[DSM_FUNC_QUERY];
|
||||
|
||||
/*
|
||||
* Make sure we don't load the DSM values twice. Set this only after we
|
||||
* validated the DSM table so that if the table in UEFI is not valid,
|
||||
* we will fallback to ACPI.
|
||||
*/
|
||||
fwrt->dsm_funcs_valid |= BIT(DSM_FUNC_QUERY);
|
||||
|
||||
for (int func = 1; func < ARRAY_SIZE(fwrt->dsm_values); func++) {
|
||||
if (!(fwrt->dsm_funcs_valid & BIT(func))) {
|
||||
IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n",
|
||||
func, fwrt->dsm_funcs_valid);
|
||||
continue;
|
||||
}
|
||||
|
||||
fwrt->dsm_values[func] = data->functions[func];
|
||||
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"UEFI: DSM func=%d: value=%d\n", func,
|
||||
fwrt->dsm_values[func]);
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
|
||||
u32 *value)
|
||||
{
|
||||
/* Not supported function index */
|
||||
if (func >= DSM_FUNC_NUM_FUNCS || func == 5)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!fwrt->dsm_funcs_valid) {
|
||||
int ret = iwl_uefi_load_dsm_values(fwrt);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
*value = data->functions[func];
|
||||
if (!(fwrt->dsm_funcs_valid & BIT(func))) {
|
||||
IWL_DEBUG_RADIO(fwrt, "DSM func %d not in 0x%x\n",
|
||||
func, fwrt->dsm_funcs_valid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*value = fwrt->dsm_values[func];
|
||||
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"UEFI: DSM func=%d: value=%d\n", func, *value);
|
||||
|
||||
ret = 0;
|
||||
out:
|
||||
kfree(data);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt)
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ struct uefi_cnv_wlan_sgom_data {
|
|||
|
||||
struct uefi_cnv_wlan_uats_data {
|
||||
u8 revision;
|
||||
u8 offset_map[IWL_UATS_MAP_SIZE - 1];
|
||||
u8 mcc_to_ap_type_map[IWL_UATS_MAP_SIZE - 1];
|
||||
} __packed;
|
||||
|
||||
struct uefi_cnv_common_step_data {
|
||||
|
|
|
|||
|
|
@ -687,7 +687,6 @@ extern const char iwl_killer_bn1850w2_name[];
|
|||
extern const char iwl_killer_bn1850i_name[];
|
||||
extern const char iwl_bn201_name[];
|
||||
extern const char iwl_bn203_name[];
|
||||
extern const char iwl_be221_name[];
|
||||
extern const char iwl_be223_name[];
|
||||
extern const char iwl_ax221_name[];
|
||||
#if IS_ENABLED(CONFIG_IWLDVM)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += tests/
|
|||
|
||||
iwlmld-y += mld.o notif.o mac80211.o fw.o power.o iface.o link.o rx.o mcc.o session-protect.o phy.o
|
||||
iwlmld-y += scan.o sta.o tx.o coex.o tlc.o agg.o key.o regulatory.o ap.o thermal.o roc.o stats.o
|
||||
iwlmld-y += low_latency.o mlo.o ptp.o time_sync.o ftm-initiator.o
|
||||
iwlmld-y += low_latency.o mlo.o ptp.o time_sync.o ftm-initiator.o nan.o
|
||||
iwlmld-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
|
||||
iwlmld-$(CONFIG_IWLWIFI_LEDS) += led.o
|
||||
iwlmld-$(CONFIG_PM_SLEEP) += d3.o
|
||||
|
|
|
|||
|
|
@ -996,8 +996,6 @@ static void iwl_mld_mlo_rekey(struct iwl_mld *mld,
|
|||
struct iwl_mld_wowlan_status *wowlan_status,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mld_old_mlo_keys *old_keys __free(kfree) = NULL;
|
||||
|
||||
IWL_DEBUG_WOWLAN(mld, "Num of MLO Keys: %d\n", wowlan_status->num_mlo_keys);
|
||||
|
||||
if (!wowlan_status->num_mlo_keys)
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ static size_t iwl_mld_dump_tas_resp(struct iwl_dhc_tas_status_resp *resp,
|
|||
}
|
||||
|
||||
pos += scnprintf(buf + pos, count - pos, "TAS Report\n");
|
||||
switch (resp->tas_config_info.table_source) {
|
||||
switch (resp->tas_config_info.hdr.table_source) {
|
||||
case BIOS_SOURCE_NONE:
|
||||
pos += scnprintf(buf + pos, count - pos,
|
||||
"BIOS SOURCE NONE ");
|
||||
|
|
@ -260,13 +260,13 @@ static size_t iwl_mld_dump_tas_resp(struct iwl_dhc_tas_status_resp *resp,
|
|||
default:
|
||||
pos += scnprintf(buf + pos, count - pos,
|
||||
"BIOS SOURCE UNKNOWN (%d) ",
|
||||
resp->tas_config_info.table_source);
|
||||
resp->tas_config_info.hdr.table_source);
|
||||
break;
|
||||
}
|
||||
|
||||
pos += scnprintf(buf + pos, count - pos,
|
||||
"revision is: %d data is: 0x%08x\n",
|
||||
resp->tas_config_info.table_revision,
|
||||
resp->tas_config_info.hdr.table_revision,
|
||||
resp->tas_config_info.value);
|
||||
pos += scnprintf(buf + pos, count - pos, "Current MCC: 0x%x\n",
|
||||
le16_to_cpu(resp->curr_mcc));
|
||||
|
|
|
|||
|
|
@ -339,6 +339,10 @@ int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
|||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
/* NAN interface type is not known to FW */
|
||||
if (vif->type == NL80211_IFTYPE_NAN)
|
||||
return 0;
|
||||
|
||||
if (action == FW_CTXT_ACTION_REMOVE)
|
||||
return iwl_mld_rm_mac_from_fw(mld, vif);
|
||||
|
||||
|
|
@ -387,21 +391,16 @@ static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy,
|
|||
IWL_MLD_ALLOC_FN(vif, vif)
|
||||
|
||||
/* Constructor function for struct iwl_mld_vif */
|
||||
static int
|
||||
static void
|
||||
iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
int ret;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
mld_vif->mld = mld;
|
||||
mld_vif->roc_activity = ROC_NUM_ACTIVITIES;
|
||||
|
||||
ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!mld->fw_status.in_hw_restart) {
|
||||
wiphy_work_init(&mld_vif->emlsr.unblock_tpt_wk,
|
||||
iwl_mld_emlsr_unblock_tpt_wk);
|
||||
|
|
@ -415,8 +414,6 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
|||
iwl_mld_mlo_scan_start_wk);
|
||||
}
|
||||
iwl_mld_init_internal_sta(&mld_vif->aux_sta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
||||
|
|
@ -426,7 +423,13 @@ int iwl_mld_add_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
|||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
ret = iwl_mld_init_vif(mld, vif);
|
||||
iwl_mld_init_vif(mld, vif);
|
||||
|
||||
/* NAN interface type is not known to FW */
|
||||
if (vif->type == NL80211_IFTYPE_NAN)
|
||||
return 0;
|
||||
|
||||
ret = iwl_mld_allocate_vif_fw_id(mld, &mld_vif->fw_id, vif);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ enum iwl_mld_cca_40mhz_wa_status {
|
|||
* link is preventing EMLSR. This is a temporary blocking that is set when
|
||||
* there is an indication that a non-BSS interface is to be added.
|
||||
* @IWL_MLD_EMLSR_BLOCKED_TPT: throughput is too low to make EMLSR worthwhile
|
||||
* @IWL_MLD_EMLSR_BLOCKED_NAN: NAN is preventing EMLSR.
|
||||
*/
|
||||
enum iwl_mld_emlsr_blocked {
|
||||
IWL_MLD_EMLSR_BLOCKED_PREVENTION = 0x1,
|
||||
|
|
@ -40,6 +41,7 @@ enum iwl_mld_emlsr_blocked {
|
|||
IWL_MLD_EMLSR_BLOCKED_NON_BSS = 0x8,
|
||||
IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS = 0x10,
|
||||
IWL_MLD_EMLSR_BLOCKED_TPT = 0x20,
|
||||
IWL_MLD_EMLSR_BLOCKED_NAN = 0x40,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@
|
|||
{ \
|
||||
.max = 1, \
|
||||
.types = BIT(NL80211_IFTYPE_P2P_DEVICE), \
|
||||
}
|
||||
},
|
||||
|
||||
static const struct ieee80211_iface_limit iwl_mld_limits[] = {
|
||||
IWL_MLD_LIMITS(0)
|
||||
|
|
@ -60,6 +60,22 @@ static const struct ieee80211_iface_limit iwl_mld_limits_ap[] = {
|
|||
IWL_MLD_LIMITS(BIT(NL80211_IFTYPE_AP))
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_limit iwl_mld_limits_nan[] = {
|
||||
{
|
||||
.max = 2,
|
||||
.types = BIT(NL80211_IFTYPE_STATION),
|
||||
},
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_NAN),
|
||||
},
|
||||
/* Removed when two channels are permitted */
|
||||
{
|
||||
.max = 1,
|
||||
.types = BIT(NL80211_IFTYPE_AP),
|
||||
},
|
||||
};
|
||||
|
||||
static const struct ieee80211_iface_combination
|
||||
iwl_mld_iface_combinations[] = {
|
||||
{
|
||||
|
|
@ -74,6 +90,19 @@ iwl_mld_iface_combinations[] = {
|
|||
.limits = iwl_mld_limits_ap,
|
||||
.n_limits = ARRAY_SIZE(iwl_mld_limits_ap),
|
||||
},
|
||||
/* NAN combinations follow, these exclude P2P */
|
||||
{
|
||||
.num_different_channels = 2,
|
||||
.max_interfaces = 3,
|
||||
.limits = iwl_mld_limits_nan,
|
||||
.n_limits = ARRAY_SIZE(iwl_mld_limits_nan) - 1,
|
||||
},
|
||||
{
|
||||
.num_different_channels = 1,
|
||||
.max_interfaces = 4,
|
||||
.limits = iwl_mld_limits_nan,
|
||||
.n_limits = ARRAY_SIZE(iwl_mld_limits_nan),
|
||||
}
|
||||
};
|
||||
|
||||
static const u8 ext_capa_base[IWL_MLD_STA_EXT_CAPA_SIZE] = {
|
||||
|
|
@ -305,8 +334,38 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld)
|
|||
|
||||
wiphy->hw_timestamp_max_peers = 1;
|
||||
|
||||
wiphy->iface_combinations = iwl_mld_iface_combinations;
|
||||
wiphy->n_iface_combinations = ARRAY_SIZE(iwl_mld_iface_combinations);
|
||||
if (iwl_mld_nan_supported(mld)) {
|
||||
hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_NAN);
|
||||
hw->wiphy->iface_combinations = iwl_mld_iface_combinations;
|
||||
hw->wiphy->n_iface_combinations =
|
||||
ARRAY_SIZE(iwl_mld_iface_combinations);
|
||||
|
||||
hw->wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ);
|
||||
if (mld->nvm_data->bands[NL80211_BAND_5GHZ].n_channels)
|
||||
hw->wiphy->nan_supported_bands |=
|
||||
BIT(NL80211_BAND_5GHZ);
|
||||
|
||||
hw->wiphy->nan_capa.flags = WIPHY_NAN_FLAGS_CONFIGURABLE_SYNC |
|
||||
WIPHY_NAN_FLAGS_USERSPACE_DE;
|
||||
|
||||
hw->wiphy->nan_capa.op_mode = NAN_OP_MODE_PHY_MODE_MASK |
|
||||
NAN_OP_MODE_80P80MHZ |
|
||||
NAN_OP_MODE_160MHZ;
|
||||
|
||||
/* Support 2 antenna's for Tx and Rx */
|
||||
hw->wiphy->nan_capa.n_antennas = 0x22;
|
||||
|
||||
/* Maximal channel switch time is 4 msec */
|
||||
hw->wiphy->nan_capa.max_channel_switch_time = 4;
|
||||
hw->wiphy->nan_capa.dev_capabilities =
|
||||
NAN_DEV_CAPA_EXT_KEY_ID_SUPPORTED |
|
||||
NAN_DEV_CAPA_NDPE_SUPPORTED;
|
||||
} else {
|
||||
wiphy->iface_combinations = iwl_mld_iface_combinations;
|
||||
/* Do not include NAN combinations */
|
||||
wiphy->n_iface_combinations =
|
||||
ARRAY_SIZE(iwl_mld_iface_combinations) - 2;
|
||||
}
|
||||
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_DFS_CONCURRENT);
|
||||
|
|
@ -318,6 +377,8 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld)
|
|||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_MAX_CHANNEL_TIME);
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_OCE_PROBE_REQ_HIGH_TX_RATE);
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
|
||||
wiphy_ext_feature_set(wiphy,
|
||||
NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS);
|
||||
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SPP_AMSDU_SUPPORT);
|
||||
|
||||
if (fw_has_capa(ucode_capa, IWL_UCODE_TLV_CAPA_PROTECTED_TWT))
|
||||
|
|
@ -616,10 +677,11 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw,
|
|||
* Add the default link, but not if this is an MLD vif as that implies
|
||||
* the HW is restarting and it will be configured by change_vif_links.
|
||||
*/
|
||||
if (!ieee80211_vif_is_mld(vif))
|
||||
if (vif->type != NL80211_IFTYPE_NAN && !ieee80211_vif_is_mld(vif)) {
|
||||
ret = iwl_mld_add_link(mld, &vif->bss_conf);
|
||||
if (ret)
|
||||
goto err;
|
||||
if (ret)
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION) {
|
||||
vif->driver_flags |= IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC;
|
||||
|
|
@ -647,6 +709,9 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw,
|
|||
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
mld->p2p_device_vif = vif;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_NAN)
|
||||
mld->nan_device_vif = vif;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
|
|
@ -674,7 +739,10 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw,
|
|||
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
mld->p2p_device_vif = NULL;
|
||||
|
||||
iwl_mld_remove_link(mld, &vif->bss_conf);
|
||||
if (vif->type == NL80211_IFTYPE_NAN)
|
||||
mld->nan_device_vif = NULL;
|
||||
else
|
||||
iwl_mld_remove_link(mld, &vif->bss_conf);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
debugfs_remove(iwl_mld_vif_from_mac80211(vif)->dbgfs_slink);
|
||||
|
|
@ -984,7 +1052,9 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
{
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
|
||||
unsigned int n_active = iwl_mld_count_active_links(mld, vif);
|
||||
struct iwl_mld_link *temp_mld_link;
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
u16 final_active_links = 0;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
|
@ -992,10 +1062,7 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
if (WARN_ON(!mld_link))
|
||||
return -EINVAL;
|
||||
|
||||
/* if the assigned one was not counted yet, count it now */
|
||||
if (!rcu_access_pointer(mld_link->chan_ctx)) {
|
||||
n_active++;
|
||||
|
||||
/* Track addition of non-BSS link */
|
||||
if (ieee80211_vif_type_p2p(vif) != NL80211_IFTYPE_STATION) {
|
||||
ret = iwl_mld_emlsr_check_non_bss_block(mld, 1);
|
||||
|
|
@ -1016,17 +1083,25 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
|
||||
rcu_assign_pointer(mld_link->chan_ctx, ctx);
|
||||
|
||||
if (n_active > 1) {
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
/* We cannot rely on vif->active_links at this stage as it contains
|
||||
* both the removed links and the newly added links.
|
||||
* Therefore, we create our own bitmap of the final active links,
|
||||
* which does not include the removed links.
|
||||
*/
|
||||
for_each_mld_vif_valid_link(mld_vif, temp_mld_link) {
|
||||
if (rcu_access_pointer(temp_mld_link->chan_ctx))
|
||||
final_active_links |= BIT(link_id);
|
||||
}
|
||||
|
||||
if (hweight16(final_active_links) > 1) {
|
||||
/* Indicate to mac80211 that EML is enabled */
|
||||
vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE;
|
||||
mld_vif->emlsr.last_entry_ts = jiffies;
|
||||
|
||||
if (vif->active_links & BIT(mld_vif->emlsr.selected_links))
|
||||
if (final_active_links == mld_vif->emlsr.selected_links)
|
||||
mld_vif->emlsr.primary = mld_vif->emlsr.selected_primary;
|
||||
else
|
||||
mld_vif->emlsr.primary = __ffs(vif->active_links);
|
||||
mld_vif->emlsr.primary = __ffs(final_active_links);
|
||||
|
||||
iwl_dbg_tlv_time_point(&mld->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP,
|
||||
NULL);
|
||||
|
|
@ -1506,6 +1581,9 @@ iwl_mld_mac80211_conf_tx(struct ieee80211_hw *hw,
|
|||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_NAN)
|
||||
return 0;
|
||||
|
||||
link = iwl_mld_link_dereference_check(mld_vif, link_id);
|
||||
if (!link)
|
||||
return -EINVAL;
|
||||
|
|
@ -1706,6 +1784,9 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,
|
|||
/* Ensure any block due to a non-BSS link is synced */
|
||||
iwl_mld_emlsr_check_non_bss_block(mld, 0);
|
||||
|
||||
/* Ensure NAN block is synced */
|
||||
iwl_mld_emlsr_check_nan_block(mld, vif);
|
||||
|
||||
/* Block EMLSR until a certain throughput it reached */
|
||||
if (!mld->fw_status.in_hw_restart &&
|
||||
IWL_MLD_ENTER_EMLSR_TPT_THRESH > 0)
|
||||
|
|
@ -2699,4 +2780,7 @@ const struct ieee80211_ops iwl_mld_hw_ops = {
|
|||
.set_hw_timestamp = iwl_mld_set_hw_timestamp,
|
||||
.start_pmsr = iwl_mld_start_pmsr,
|
||||
.can_neg_ttlm = iwl_mld_can_neg_ttlm,
|
||||
.start_nan = iwl_mld_start_nan,
|
||||
.stop_nan = iwl_mld_stop_nan,
|
||||
.nan_change_conf = iwl_mld_nan_change_config,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -234,6 +234,9 @@ static const struct iwl_hcmd_names iwl_mld_mac_conf_names[] = {
|
|||
HCMD_NAME(AUX_STA_CMD),
|
||||
HCMD_NAME(STA_REMOVE_CMD),
|
||||
HCMD_NAME(ROC_CMD),
|
||||
HCMD_NAME(NAN_CFG_CMD),
|
||||
HCMD_NAME(NAN_DW_END_NOTIF),
|
||||
HCMD_NAME(NAN_JOINED_CLUSTER_NOTIF),
|
||||
HCMD_NAME(MISSED_BEACONS_NOTIF),
|
||||
HCMD_NAME(EMLSR_TRANS_FAIL_NOTIF),
|
||||
HCMD_NAME(ROC_NOTIF),
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
#include "ptp.h"
|
||||
#include "time_sync.h"
|
||||
#include "ftm-initiator.h"
|
||||
#include "nan.h"
|
||||
|
||||
/**
|
||||
* DOC: Introduction
|
||||
|
|
@ -199,6 +200,7 @@
|
|||
* @ptp_data: data of the PTP clock
|
||||
* @time_sync: time sync data.
|
||||
* @ftm_initiator: FTM initiator data
|
||||
* @nan_device_vif: points to the NAN device vif if exists
|
||||
*/
|
||||
struct iwl_mld {
|
||||
/* Add here fields that need clean up on restart */
|
||||
|
|
@ -228,6 +230,7 @@ struct iwl_mld {
|
|||
#endif /* CONFIG_PM_SLEEP */
|
||||
struct ieee80211_vif *p2p_device_vif;
|
||||
bool bt_is_active;
|
||||
struct ieee80211_vif *nan_device_vif;
|
||||
);
|
||||
struct ieee80211_link_sta __rcu *fw_id_to_link_sta[IWL_STATION_COUNT_MAX];
|
||||
/* And here fields that survive a fw restart */
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@
|
|||
HOW(ROC) \
|
||||
HOW(NON_BSS) \
|
||||
HOW(TMP_NON_BSS) \
|
||||
HOW(TPT)
|
||||
HOW(TPT) \
|
||||
HOW(NAN)
|
||||
|
||||
static const char *
|
||||
iwl_mld_get_emlsr_blocked_string(enum iwl_mld_emlsr_blocked blocked)
|
||||
|
|
@ -451,29 +452,49 @@ static void iwl_mld_count_non_bss_links(void *_data, u8 *mac,
|
|||
|
||||
struct iwl_mld_update_emlsr_block_data {
|
||||
bool block;
|
||||
enum iwl_mld_emlsr_blocked reason;
|
||||
int result;
|
||||
};
|
||||
|
||||
static void
|
||||
iwl_mld_vif_iter_update_emlsr_non_bss_block(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
iwl_mld_vif_iter_update_emlsr_block(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mld_update_emlsr_block_data *data = _data;
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
int ret;
|
||||
|
||||
if (!iwl_mld_vif_has_emlsr_cap(vif))
|
||||
return;
|
||||
|
||||
if (data->block) {
|
||||
ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif,
|
||||
IWL_MLD_EMLSR_BLOCKED_NON_BSS,
|
||||
data->reason,
|
||||
iwl_mld_get_primary_link(vif));
|
||||
if (ret)
|
||||
data->result = ret;
|
||||
} else {
|
||||
iwl_mld_unblock_emlsr(mld_vif->mld, vif,
|
||||
IWL_MLD_EMLSR_BLOCKED_NON_BSS);
|
||||
data->reason);
|
||||
}
|
||||
}
|
||||
|
||||
int iwl_mld_update_emlsr_block(struct iwl_mld *mld, bool block,
|
||||
enum iwl_mld_emlsr_blocked reason)
|
||||
{
|
||||
struct iwl_mld_update_emlsr_block_data block_data = {
|
||||
.block = block,
|
||||
.reason = reason,
|
||||
};
|
||||
|
||||
ieee80211_iterate_active_interfaces_mtx(mld->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mld_vif_iter_update_emlsr_block,
|
||||
&block_data);
|
||||
|
||||
return block_data.result;
|
||||
}
|
||||
|
||||
int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld,
|
||||
int pending_link_changes)
|
||||
{
|
||||
|
|
@ -481,7 +502,6 @@ int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld,
|
|||
* block EMLSR on the bss vif. Upon deactivation, check if this link
|
||||
* was the last non-station link active, and if so unblock the bss vif
|
||||
*/
|
||||
struct iwl_mld_update_emlsr_block_data block_data = {};
|
||||
int count = pending_link_changes;
|
||||
|
||||
/* No need to count if we are activating a non-BSS link */
|
||||
|
|
@ -495,14 +515,8 @@ int iwl_mld_emlsr_check_non_bss_block(struct iwl_mld *mld,
|
|||
* We could skip updating it if the block change did not change (and
|
||||
* pending_link_changes is non-zero).
|
||||
*/
|
||||
block_data.block = !!count;
|
||||
|
||||
ieee80211_iterate_active_interfaces_mtx(mld->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mld_vif_iter_update_emlsr_non_bss_block,
|
||||
&block_data);
|
||||
|
||||
return block_data.result;
|
||||
return iwl_mld_update_emlsr_block(mld, !!count,
|
||||
IWL_MLD_EMLSR_BLOCKED_NON_BSS);
|
||||
}
|
||||
|
||||
#define EMLSR_SEC_LINK_MIN_PERC 10
|
||||
|
|
@ -844,9 +858,9 @@ iwl_mld_emlsr_pair_state(struct ieee80211_vif *vif,
|
|||
if (c_low->chan->center_freq > c_high->chan->center_freq)
|
||||
swap(c_low, c_high);
|
||||
|
||||
c_low_upper_edge = c_low->chan->center_freq +
|
||||
c_low_upper_edge = c_low->center_freq1 +
|
||||
cfg80211_chandef_get_width(c_low) / 2;
|
||||
c_high_lower_edge = c_high->chan->center_freq -
|
||||
c_high_lower_edge = c_high->center_freq1 -
|
||||
cfg80211_chandef_get_width(c_high) / 2;
|
||||
|
||||
if (a->chandef->chan->band == NL80211_BAND_5GHZ &&
|
||||
|
|
@ -1197,3 +1211,16 @@ void iwl_mld_stop_ignoring_tpt_updates(struct iwl_mld *mld)
|
|||
iwl_mld_ignore_tpt_iter,
|
||||
&start);
|
||||
}
|
||||
|
||||
int iwl_mld_emlsr_check_nan_block(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
||||
{
|
||||
if (mld->nan_device_vif &&
|
||||
ieee80211_vif_nan_started(mld->nan_device_vif))
|
||||
return iwl_mld_block_emlsr_sync(mld, vif,
|
||||
IWL_MLD_EMLSR_BLOCKED_NAN,
|
||||
iwl_mld_get_primary_link(vif));
|
||||
|
||||
iwl_mld_unblock_emlsr(mld, vif, IWL_MLD_EMLSR_BLOCKED_NAN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,6 +150,11 @@ void iwl_mld_emlsr_check_chan_load(struct ieee80211_hw *hw,
|
|||
*/
|
||||
void iwl_mld_retry_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif);
|
||||
|
||||
int iwl_mld_emlsr_check_nan_block(struct iwl_mld *mld, struct ieee80211_vif *vif);
|
||||
|
||||
int iwl_mld_update_emlsr_block(struct iwl_mld *mld, bool block,
|
||||
enum iwl_mld_emlsr_blocked reason);
|
||||
|
||||
struct iwl_mld_link_sel_data {
|
||||
u8 link_id;
|
||||
const struct cfg80211_chan_def *chandef;
|
||||
|
|
|
|||
299
drivers/net/wireless/intel/iwlwifi/mld/nan.c
Normal file
299
drivers/net/wireless/intel/iwlwifi/mld/nan.c
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#include "mld.h"
|
||||
#include "iface.h"
|
||||
#include "mlo.h"
|
||||
#include "fw/api/mac-cfg.h"
|
||||
|
||||
#define IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU 512
|
||||
#define IWL_NAN_RSSI_CLOSE 55
|
||||
#define IWL_NAN_RSSI_MIDDLE 70
|
||||
|
||||
bool iwl_mld_nan_supported(struct iwl_mld *mld)
|
||||
{
|
||||
return fw_has_capa(&mld->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT);
|
||||
}
|
||||
|
||||
static int iwl_mld_nan_send_config_cmd(struct iwl_mld *mld,
|
||||
struct iwl_nan_config_cmd *cmd,
|
||||
u8 *beacon_data, size_t beacon_data_len)
|
||||
{
|
||||
struct iwl_host_cmd hcmd = {
|
||||
.id = WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD),
|
||||
};
|
||||
|
||||
hcmd.len[0] = sizeof(*cmd);
|
||||
hcmd.data[0] = cmd;
|
||||
|
||||
if (beacon_data_len) {
|
||||
hcmd.len[1] = beacon_data_len;
|
||||
hcmd.data[1] = beacon_data;
|
||||
hcmd.dataflags[1] = IWL_HCMD_DFL_DUP;
|
||||
}
|
||||
|
||||
return iwl_mld_send_cmd(mld, &hcmd);
|
||||
}
|
||||
|
||||
static int iwl_mld_nan_config(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_conf *conf,
|
||||
enum iwl_ctxt_action action)
|
||||
{
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
struct iwl_nan_config_cmd cmd = {
|
||||
.action = cpu_to_le32(action),
|
||||
};
|
||||
u8 *data __free(kfree) = NULL;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
ether_addr_copy(cmd.nmi_addr, vif->addr);
|
||||
cmd.master_pref = conf->master_pref;
|
||||
|
||||
if (conf->cluster_id)
|
||||
memcpy(cmd.cluster_id, conf->cluster_id + 4,
|
||||
sizeof(cmd.cluster_id));
|
||||
|
||||
cmd.scan_period = conf->scan_period < 255 ? conf->scan_period : 255;
|
||||
cmd.dwell_time =
|
||||
conf->scan_dwell_time < 255 ? conf->scan_dwell_time : 255;
|
||||
|
||||
if (conf->discovery_beacon_interval)
|
||||
cmd.discovery_beacon_interval =
|
||||
cpu_to_le32(conf->discovery_beacon_interval);
|
||||
else
|
||||
cmd.discovery_beacon_interval =
|
||||
cpu_to_le32(IWL_NAN_DISOVERY_BEACON_INTERNVAL_TU);
|
||||
|
||||
if (conf->enable_dw_notification)
|
||||
cmd.flags = IWL_NAN_FLAG_DW_END_NOTIF_ENABLED;
|
||||
|
||||
/* 2 GHz band must be supported */
|
||||
cmd.band_config[IWL_NAN_BAND_2GHZ].rssi_close =
|
||||
abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_close);
|
||||
cmd.band_config[IWL_NAN_BAND_2GHZ].rssi_middle =
|
||||
abs(conf->band_cfgs[NL80211_BAND_2GHZ].rssi_middle);
|
||||
cmd.band_config[IWL_NAN_BAND_2GHZ].dw_interval =
|
||||
conf->band_cfgs[NL80211_BAND_2GHZ].awake_dw_interval;
|
||||
|
||||
/* 5 GHz band operation is optional. Configure its operation if
|
||||
* supported. Note that conf->bands might be zero, so we need to check
|
||||
* the channel pointer, not the band mask.
|
||||
*/
|
||||
if (conf->band_cfgs[NL80211_BAND_5GHZ].chan) {
|
||||
cmd.hb_channel =
|
||||
conf->band_cfgs[NL80211_BAND_5GHZ].chan->hw_value;
|
||||
|
||||
cmd.band_config[IWL_NAN_BAND_5GHZ].rssi_close =
|
||||
abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_close);
|
||||
cmd.band_config[IWL_NAN_BAND_5GHZ].rssi_middle =
|
||||
abs(conf->band_cfgs[NL80211_BAND_5GHZ].rssi_middle);
|
||||
cmd.band_config[IWL_NAN_BAND_5GHZ].dw_interval =
|
||||
conf->band_cfgs[NL80211_BAND_5GHZ].awake_dw_interval;
|
||||
}
|
||||
|
||||
if (conf->extra_nan_attrs_len || conf->vendor_elems_len) {
|
||||
data = kmalloc(conf->extra_nan_attrs_len +
|
||||
conf->vendor_elems_len, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd.nan_attr_len = cpu_to_le32(conf->extra_nan_attrs_len);
|
||||
cmd.nan_vendor_elems_len = cpu_to_le32(conf->vendor_elems_len);
|
||||
|
||||
if (conf->extra_nan_attrs_len)
|
||||
memcpy(data, conf->extra_nan_attrs,
|
||||
conf->extra_nan_attrs_len);
|
||||
|
||||
if (conf->vendor_elems_len)
|
||||
memcpy(data + conf->extra_nan_attrs_len,
|
||||
conf->vendor_elems,
|
||||
conf->vendor_elems_len);
|
||||
}
|
||||
|
||||
cmd.sta_id = mld_vif->aux_sta.sta_id;
|
||||
return iwl_mld_nan_send_config_cmd(mld, &cmd, data,
|
||||
conf->extra_nan_attrs_len +
|
||||
conf->vendor_elems_len);
|
||||
}
|
||||
|
||||
int iwl_mld_start_nan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_conf *conf)
|
||||
{
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
struct iwl_mld_int_sta *aux_sta = &mld_vif->aux_sta;
|
||||
int ret;
|
||||
|
||||
IWL_DEBUG_MAC80211(mld, "NAN: start: bands=0x%x\n", conf->bands);
|
||||
|
||||
ret = iwl_mld_update_emlsr_block(mld, true, IWL_MLD_EMLSR_BLOCKED_NAN);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = iwl_mld_add_aux_sta(mld, aux_sta);
|
||||
if (ret)
|
||||
goto unblock_emlsr;
|
||||
|
||||
ret = iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_ADD);
|
||||
if (ret) {
|
||||
IWL_ERR(mld, "Failed to start NAN. ret=%d\n", ret);
|
||||
goto remove_aux;
|
||||
}
|
||||
return 0;
|
||||
|
||||
remove_aux:
|
||||
iwl_mld_remove_aux_sta(mld, vif);
|
||||
unblock_emlsr:
|
||||
iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_mld_nan_change_config(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_conf *conf,
|
||||
u32 changes)
|
||||
{
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
|
||||
IWL_DEBUG_MAC80211(mld, "NAN: change: changes=0x%x, bands=0x%x\n",
|
||||
changes, conf->bands);
|
||||
|
||||
/* Note that we do not use 'changes' as the FW always expects the
|
||||
* complete configuration, and mac80211 always provides the complete
|
||||
* configuration.
|
||||
*/
|
||||
return iwl_mld_nan_config(mld, vif, conf, FW_CTXT_ACTION_MODIFY);
|
||||
}
|
||||
|
||||
int iwl_mld_stop_nan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
struct iwl_nan_config_cmd cmd = {
|
||||
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
|
||||
};
|
||||
int ret;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
ret = iwl_mld_send_cmd_pdu(mld,
|
||||
WIDE_ID(MAC_CONF_GROUP, NAN_CFG_CMD),
|
||||
&cmd);
|
||||
if (ret)
|
||||
IWL_ERR(mld, "NAN: Failed to stop NAN. ret=%d\n", ret);
|
||||
|
||||
/* assume that higher layer guarantees that no additional frames are
|
||||
* added before calling this callback
|
||||
*/
|
||||
iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id);
|
||||
iwl_mld_remove_aux_sta(mld, vif);
|
||||
|
||||
/* cancel based on object type being NAN, as the NAN objects do
|
||||
* not have a unique identifier associated with them
|
||||
*/
|
||||
iwl_mld_cancel_notifications_of_object(mld,
|
||||
IWL_MLD_OBJECT_TYPE_NAN,
|
||||
0);
|
||||
|
||||
iwl_mld_update_emlsr_block(mld, false, IWL_MLD_EMLSR_BLOCKED_NAN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
struct iwl_nan_cluster_notif *notif = (void *)pkt->data;
|
||||
struct wireless_dev *wdev = mld->nan_device_vif ?
|
||||
ieee80211_vif_to_wdev(mld->nan_device_vif) : NULL;
|
||||
bool new_cluster = !!(notif->flags &
|
||||
IWL_NAN_CLUSTER_NOTIF_FLAG_NEW_CLUSTER);
|
||||
u8 cluster_id[ETH_ALEN] = {
|
||||
0x50, 0x6f, 0x9a, 0x01,
|
||||
notif->cluster_id[0], notif->cluster_id[1]
|
||||
};
|
||||
|
||||
IWL_DEBUG_INFO(mld,
|
||||
"NAN: cluster event: cluster_id=%pM, flags=0x%x\n",
|
||||
cluster_id, notif->flags);
|
||||
|
||||
if (IWL_FW_CHECK(mld, !wdev, "NAN: cluster event without wdev\n"))
|
||||
return;
|
||||
|
||||
if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif),
|
||||
"NAN: cluster event without NAN started\n"))
|
||||
return;
|
||||
|
||||
cfg80211_nan_cluster_joined(wdev, cluster_id, new_cluster, GFP_KERNEL);
|
||||
}
|
||||
|
||||
bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt,
|
||||
u32 obj_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt,
|
||||
u32 obj_id)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
struct iwl_nan_dw_end_notif *notif = (void *)pkt->data;
|
||||
struct iwl_mld_vif *mld_vif = mld->nan_device_vif ?
|
||||
iwl_mld_vif_from_mac80211(mld->nan_device_vif) :
|
||||
NULL;
|
||||
struct wireless_dev *wdev;
|
||||
struct ieee80211_channel *chan;
|
||||
|
||||
IWL_INFO(mld, "NAN: DW end: band=%u\n", notif->band);
|
||||
|
||||
if (IWL_FW_CHECK(mld, !mld_vif, "NAN: DW end without mld_vif\n"))
|
||||
return;
|
||||
|
||||
if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif),
|
||||
"NAN: DW end without NAN started\n"))
|
||||
return;
|
||||
|
||||
if (WARN_ON(mld_vif->aux_sta.sta_id == IWL_INVALID_STA))
|
||||
return;
|
||||
|
||||
IWL_DEBUG_INFO(mld, "NAN: flush queues for aux sta=%u\n",
|
||||
mld_vif->aux_sta.sta_id);
|
||||
|
||||
iwl_mld_flush_link_sta_txqs(mld, mld_vif->aux_sta.sta_id);
|
||||
|
||||
/* TODO: currently the notification specified the band on which the DW
|
||||
* ended. Need to change that to the actual channel on which the next DW
|
||||
* will be started.
|
||||
*/
|
||||
switch (notif->band) {
|
||||
case IWL_NAN_BAND_2GHZ:
|
||||
chan = ieee80211_get_channel(mld->wiphy, 2437);
|
||||
break;
|
||||
case IWL_NAN_BAND_5GHZ:
|
||||
/* TODO: use the actual channel */
|
||||
chan = ieee80211_get_channel(mld->wiphy, 5745);
|
||||
break;
|
||||
default:
|
||||
IWL_FW_CHECK(mld, false,
|
||||
"NAN: Invalid band %u in DW end notif\n",
|
||||
notif->band);
|
||||
return;
|
||||
}
|
||||
|
||||
wdev = ieee80211_vif_to_wdev(mld->nan_device_vif);
|
||||
cfg80211_next_nan_dw_notif(wdev, chan, GFP_KERNEL);
|
||||
}
|
||||
28
drivers/net/wireless/intel/iwlwifi/mld/nan.h
Normal file
28
drivers/net/wireless/intel/iwlwifi/mld/nan.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <net/cfg80211.h>
|
||||
#include <linux/etherdevice.h>
|
||||
|
||||
bool iwl_mld_nan_supported(struct iwl_mld *mld);
|
||||
int iwl_mld_start_nan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_conf *conf);
|
||||
int iwl_mld_nan_change_config(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct cfg80211_nan_conf *conf,
|
||||
u32 changes);
|
||||
int iwl_mld_stop_nan(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif);
|
||||
void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt);
|
||||
void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt);
|
||||
bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt,
|
||||
u32 obj_id);
|
||||
bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt,
|
||||
u32 obj_id);
|
||||
|
|
@ -111,6 +111,9 @@ static bool iwl_mld_cancel_##name##_notif(struct iwl_mld *mld, \
|
|||
#define RX_HANDLER_OF_FTM_REQ(_grp, _cmd, _name) \
|
||||
RX_HANDLER_OF_OBJ(_grp, _cmd, _name, FTM_REQ)
|
||||
|
||||
#define RX_HANDLER_OF_NAN(_grp, _cmd, _name) \
|
||||
RX_HANDLER_OF_OBJ(_grp, _cmd, _name, NAN)
|
||||
|
||||
static void iwl_mld_handle_mfuart_notif(struct iwl_mld *mld,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
|
|
@ -344,6 +347,8 @@ CMD_VERSIONS(time_sync_confirm_notif,
|
|||
CMD_VER_ENTRY(1, iwl_time_msmt_cfm_notify))
|
||||
CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy))
|
||||
CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif))
|
||||
CMD_VERSIONS(nan_cluster_notif, CMD_VER_ENTRY(1, iwl_nan_cluster_notif))
|
||||
CMD_VERSIONS(nan_dw_end_notif, CMD_VER_ENTRY(1, iwl_nan_dw_end_notif))
|
||||
|
||||
DEFINE_SIMPLE_CANCELLATION(session_prot, iwl_session_prot_notif, mac_link_id)
|
||||
DEFINE_SIMPLE_CANCELLATION(tlc, iwl_tlc_update_notif, sta_id)
|
||||
|
|
@ -459,6 +464,10 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = {
|
|||
beacon_filter_notif)
|
||||
RX_HANDLER_OF_FTM_REQ(LOCATION_GROUP, TOF_RANGE_RESPONSE_NOTIF,
|
||||
ftm_resp_notif)
|
||||
RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_JOINED_CLUSTER_NOTIF,
|
||||
nan_cluster_notif)
|
||||
RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_DW_END_NOTIF,
|
||||
nan_dw_end_notif)
|
||||
};
|
||||
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_rx_handlers);
|
||||
|
||||
|
|
@ -531,6 +540,8 @@ static void iwl_mld_rx_notif(struct iwl_mld *mld,
|
|||
struct iwl_rx_cmd_buffer *rxb,
|
||||
struct iwl_rx_packet *pkt)
|
||||
{
|
||||
union iwl_dbg_tlv_tp_data tp_data = { .fw_pkt = pkt };
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(iwl_mld_rx_handlers); i++) {
|
||||
const struct iwl_rx_handler *rx_h = &iwl_mld_rx_handlers[i];
|
||||
struct iwl_async_handler_entry *entry;
|
||||
|
|
@ -571,6 +582,8 @@ static void iwl_mld_rx_notif(struct iwl_mld *mld,
|
|||
}
|
||||
|
||||
iwl_notification_wait_notify(&mld->notif_wait, pkt);
|
||||
iwl_dbg_tlv_time_point(&mld->fwrt,
|
||||
IWL_FW_INI_TIME_POINT_FW_RSP_OR_NOTIF, &tp_data);
|
||||
}
|
||||
|
||||
void iwl_mld_rx(struct iwl_op_mode *op_mode, struct napi_struct *napi,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ enum iwl_mld_object_type {
|
|||
IWL_MLD_OBJECT_TYPE_ROC,
|
||||
IWL_MLD_OBJECT_TYPE_SCAN,
|
||||
IWL_MLD_OBJECT_TYPE_FTM_REQ,
|
||||
IWL_MLD_OBJECT_TYPE_NAN,
|
||||
};
|
||||
|
||||
void iwl_mld_cancel_notifications_of_object(struct iwl_mld *mld,
|
||||
|
|
|
|||
|
|
@ -328,6 +328,33 @@ iwl_mld_tpe_sta_cmd_data(struct iwl_txpower_constraints_cmd *cmd,
|
|||
link->tpe.max_reg_client[0].power[i]);
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_mld_set_ap_power_type(struct iwl_txpower_constraints_cmd *cmd,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link)
|
||||
{
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (link->power_type) {
|
||||
case IEEE80211_REG_LPI_AP:
|
||||
cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_LPI);
|
||||
break;
|
||||
case IEEE80211_REG_SP_AP:
|
||||
cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_SP);
|
||||
break;
|
||||
case IEEE80211_REG_VLP_AP:
|
||||
cmd->ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
iwl_mld_send_ap_tx_power_constraint_cmd(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
|
|
@ -349,15 +376,13 @@ iwl_mld_send_ap_tx_power_constraint_cmd(struct iwl_mld *mld,
|
|||
memset(cmd.psd_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.psd_pwr));
|
||||
memset(cmd.eirp_pwr, DEFAULT_TPE_TX_POWER, sizeof(cmd.eirp_pwr));
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP) {
|
||||
cmd.ap_type = cpu_to_le16(IWL_6GHZ_AP_TYPE_VLP);
|
||||
} else if (link->power_type == IEEE80211_REG_UNSET_AP) {
|
||||
if (iwl_mld_set_ap_power_type(&cmd, vif, link))
|
||||
return;
|
||||
} else {
|
||||
cmd.ap_type = cpu_to_le16(link->power_type - 1);
|
||||
iwl_mld_tpe_sta_cmd_data(&cmd, link);
|
||||
}
|
||||
|
||||
if (vif->type != NL80211_IFTYPE_AP)
|
||||
iwl_mld_tpe_sta_cmd_data(&cmd, link);
|
||||
|
||||
IWL_DEBUG_POWER(mld, "AP power type: %d\n", le16_to_cpu(cmd.ap_type));
|
||||
ret = iwl_mld_send_cmd_pdu(mld,
|
||||
WIDE_ID(PHY_OPS_GROUP,
|
||||
AP_TX_POWER_CONSTRAINTS_CMD),
|
||||
|
|
|
|||
|
|
@ -165,8 +165,8 @@ static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld)
|
|||
{
|
||||
struct iwl_fw_runtime *fwrt = &mld->fwrt;
|
||||
union iwl_ppag_table_cmd cmd = {
|
||||
.v7.ppag_config_info.table_source = fwrt->ppag_bios_source,
|
||||
.v7.ppag_config_info.table_revision = fwrt->ppag_bios_rev,
|
||||
.v7.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source,
|
||||
.v7.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev,
|
||||
.v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags),
|
||||
};
|
||||
int ret;
|
||||
|
|
@ -206,11 +206,27 @@ int iwl_mld_init_ppag(struct iwl_mld *mld)
|
|||
return iwl_mld_ppag_send_cmd(mld);
|
||||
}
|
||||
|
||||
static __le32 iwl_mld_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val);
|
||||
if (!ret) {
|
||||
if (val == DSM_VALUE_SRD_PASSIVE)
|
||||
return cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
|
||||
else if (val == DSM_VALUE_SRD_DISABLE)
|
||||
return cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iwl_mld_configure_lari(struct iwl_mld *mld)
|
||||
{
|
||||
struct iwl_fw_runtime *fwrt = &mld->fwrt;
|
||||
struct iwl_lari_config_change_cmd cmd = {
|
||||
.config_bitmap = iwl_get_lari_config_bitmap(fwrt),
|
||||
.config_bitmap = iwl_mld_get_lari_config_bitmap(fwrt),
|
||||
};
|
||||
bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
|
||||
|
|
@ -265,6 +281,14 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
if (!ret)
|
||||
cmd.oem_11be_allow_bitmap = cpu_to_le32(value);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BN, &value);
|
||||
if (!ret)
|
||||
cmd.oem_11bn_allow_bitmap = cpu_to_le32(value);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII_9, &value);
|
||||
if (!ret)
|
||||
cmd.oem_unii9_enable = cpu_to_le32(value);
|
||||
|
||||
if (!cmd.config_bitmap &&
|
||||
!cmd.oem_uhb_allow_bitmap &&
|
||||
!cmd.oem_11ax_allow_bitmap &&
|
||||
|
|
@ -273,9 +297,14 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
!cmd.force_disable_channels_bitmap &&
|
||||
!cmd.edt_bitmap &&
|
||||
!cmd.oem_320mhz_allow_bitmap &&
|
||||
!cmd.oem_11be_allow_bitmap)
|
||||
!cmd.oem_11be_allow_bitmap &&
|
||||
!cmd.oem_11bn_allow_bitmap &&
|
||||
!cmd.oem_unii9_enable)
|
||||
return;
|
||||
|
||||
cmd.bios_hdr.table_source = fwrt->dsm_source;
|
||||
cmd.bios_hdr.table_revision = fwrt->dsm_revision;
|
||||
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.config_bitmap),
|
||||
|
|
@ -295,9 +324,28 @@ void iwl_mld_configure_lari(struct iwl_mld *mld)
|
|||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.oem_11be_allow_bitmap));
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, oem_11bn_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd.oem_11bn_allow_bitmap));
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"sending LARI_CONFIG_CHANGE, oem_unii9_enable=0x%x\n",
|
||||
le32_to_cpu(cmd.oem_unii9_enable));
|
||||
|
||||
ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE), &cmd);
|
||||
if (iwl_fw_lookup_cmd_ver(mld->fw,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE), 12) == 12) {
|
||||
int cmd_size = offsetof(typeof(cmd), oem_11bn_allow_bitmap);
|
||||
|
||||
ret = iwl_mld_send_cmd_pdu(mld,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE),
|
||||
&cmd, cmd_size);
|
||||
} else {
|
||||
ret = iwl_mld_send_cmd_pdu(mld,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE),
|
||||
&cmd);
|
||||
}
|
||||
if (ret)
|
||||
IWL_DEBUG_RADIO(mld,
|
||||
"Failed to send LARI_CONFIG_CHANGE (%d)\n",
|
||||
|
|
@ -373,8 +421,8 @@ void iwl_mld_init_tas(struct iwl_mld *mld)
|
|||
for (u8 i = 0; i < data.block_list_size; i++)
|
||||
cmd.block_list_array[i] =
|
||||
cpu_to_le16(data.block_list_array[i]);
|
||||
cmd.tas_config_info.table_source = data.table_source;
|
||||
cmd.tas_config_info.table_revision = data.table_revision;
|
||||
cmd.tas_config_info.hdr.table_source = data.table_source;
|
||||
cmd.tas_config_info.hdr.table_revision = data.table_revision;
|
||||
cmd.tas_config_info.value = cpu_to_le32(data.tas_selection);
|
||||
|
||||
ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd);
|
||||
|
|
|
|||
|
|
@ -207,6 +207,134 @@ static void iwl_mld_fill_signal(struct iwl_mld *mld, int link_id,
|
|||
rx_status->chain_signal[1] = energy_b;
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_mld_decode_vht_phy_data(struct iwl_mld_rx_phy_data *phy_data,
|
||||
struct ieee80211_radiotap_vht *vht,
|
||||
struct ieee80211_rx_status *rx_status)
|
||||
{
|
||||
bool stbc;
|
||||
|
||||
vht->known = cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH |
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_GROUP_ID |
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_STBC |
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_GI |
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_SGI_NSYM_DIS |
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_LDPC_EXTRA_OFDM_SYM |
|
||||
IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED);
|
||||
|
||||
switch (le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_BANDWIDTH)) {
|
||||
case 0:
|
||||
vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_20;
|
||||
break;
|
||||
case 1:
|
||||
vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_40;
|
||||
break;
|
||||
case 2:
|
||||
vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_80;
|
||||
break;
|
||||
case 3:
|
||||
vht->bandwidth = IEEE80211_RADIOTAP_VHT_BW_160;
|
||||
break;
|
||||
}
|
||||
|
||||
vht->group_id = le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_GRP_ID);
|
||||
|
||||
stbc = le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_STBC);
|
||||
if (stbc)
|
||||
vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_STBC;
|
||||
|
||||
if (le32_get_bits(phy_data->ntfy->sigs.vht.a2,
|
||||
OFDM_RX_FRAME_VHT_SHORT_GI))
|
||||
vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_SGI;
|
||||
|
||||
if (le32_get_bits(phy_data->ntfy->sigs.vht.a2,
|
||||
OFDM_RX_FRAME_VHT_SHORT_GI_AMBIG))
|
||||
vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_SGI_NSYM_M10_9;
|
||||
|
||||
if (le32_get_bits(phy_data->ntfy->sigs.vht.a2,
|
||||
OFDM_RX_FRAME_VHT_CODING_EXTRA_SYM))
|
||||
vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_LDPC_EXTRA_OFDM_SYM;
|
||||
|
||||
if (vht->group_id != 0 && vht->group_id != 63) {
|
||||
/* MU frame */
|
||||
int user = le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_MU_MIMO_USER_POSITION);
|
||||
int nsts;
|
||||
|
||||
/* Always beamformed */
|
||||
vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED;
|
||||
|
||||
/* No MCS information in the a1/a2 data for MU frames */
|
||||
nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_STS_USER0);
|
||||
vht->mcs_nss[0] = (stbc ? nsts / 2 : nsts) | 0xf0;
|
||||
|
||||
nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_MU_STS_USER1);
|
||||
vht->mcs_nss[1] = (stbc ? nsts / 2 : nsts) | 0xf0;
|
||||
|
||||
nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_MU_STS_USER2);
|
||||
vht->mcs_nss[2] = (stbc ? nsts / 2 : nsts) | 0xf0;
|
||||
|
||||
nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_MU_STS_USER3);
|
||||
vht->mcs_nss[3] = (stbc ? nsts / 2 : nsts) | 0xf0;
|
||||
|
||||
/* Report current user MCS from rate_n_flags via rx_status */
|
||||
vht->mcs_nss[user] &= 0x0f;
|
||||
vht->mcs_nss[user] |= rx_status->rate_idx << 4;
|
||||
|
||||
/* Report LDPC for current user */
|
||||
if (rx_status->enc_flags & RX_ENC_FLAG_LDPC)
|
||||
vht->coding = 0x1 << user;
|
||||
} else {
|
||||
int nsts;
|
||||
|
||||
/* SU frame */
|
||||
vht->known |= cpu_to_le16(IEEE80211_RADIOTAP_VHT_KNOWN_PARTIAL_AID);
|
||||
|
||||
if (le32_get_bits(phy_data->ntfy->sigs.vht.a2,
|
||||
OFDM_RX_FRAME_VHT_BF_OR_MU_RESERVED))
|
||||
vht->flags |= IEEE80211_RADIOTAP_VHT_FLAG_BEAMFORMED;
|
||||
|
||||
vht->partial_aid =
|
||||
cpu_to_le16(le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_PARTIAL_AID_OR_MU_STS));
|
||||
|
||||
nsts = le32_get_bits(phy_data->ntfy->sigs.vht.a1,
|
||||
OFDM_RX_FRAME_VHT_STS) + 1;
|
||||
vht->mcs_nss[0] =
|
||||
(stbc ? nsts / 2 : nsts) |
|
||||
le32_get_bits(phy_data->ntfy->sigs.vht.a2,
|
||||
OFDM_RX_FRAME_VHT_MCS_OR_MU_CODING) << 4;
|
||||
vht->mcs_nss[1] = 0;
|
||||
vht->mcs_nss[2] = 0;
|
||||
vht->mcs_nss[3] = 0;
|
||||
|
||||
if (rx_status->enc_flags & RX_ENC_FLAG_LDPC)
|
||||
vht->coding = 0x1;
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mld_rx_vht(struct sk_buff *skb,
|
||||
struct iwl_mld_rx_phy_data *phy_data)
|
||||
{
|
||||
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
|
||||
struct ieee80211_radiotap_vht *vht;
|
||||
|
||||
if (likely(!phy_data->ntfy))
|
||||
return;
|
||||
|
||||
vht = skb_put_zero(skb, sizeof(*vht));
|
||||
rx_status->flag |= RX_FLAG_RADIOTAP_VHT;
|
||||
|
||||
iwl_mld_decode_vht_phy_data(phy_data, vht, rx_status);
|
||||
}
|
||||
|
||||
static void
|
||||
iwl_mld_he_set_ru_alloc(struct ieee80211_rx_status *rx_status,
|
||||
struct ieee80211_radiotap_he *he,
|
||||
|
|
@ -268,11 +396,11 @@ iwl_mld_decode_he_mu(struct iwl_mld_rx_phy_data *phy_data,
|
|||
{
|
||||
u32 rate_n_flags = phy_data->rate_n_flags;
|
||||
|
||||
he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b,
|
||||
OFDM_RX_FRAME_HE_SIGB_DCM,
|
||||
he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1,
|
||||
OFDM_RX_FRAME_HE_DCM,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_DCM);
|
||||
he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b,
|
||||
OFDM_RX_FRAME_HE_SIGB_MCS,
|
||||
he_mu->flags1 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1,
|
||||
OFDM_RX_FRAME_HE_MCS,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS1_SIG_B_MCS);
|
||||
he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a1,
|
||||
OFDM_RX_FRAME_HE_PRMBL_PUNC_TYPE,
|
||||
|
|
@ -280,7 +408,7 @@ iwl_mld_decode_he_mu(struct iwl_mld_rx_phy_data *phy_data,
|
|||
he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2,
|
||||
OFDM_RX_FRAME_HE_MU_NUM_OF_SIGB_SYM_OR_USER_NUM,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_SYMS_USERS);
|
||||
he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.b,
|
||||
he_mu->flags2 |= RTAP_ENC_HE(phy_data->ntfy->sigs.he.a2,
|
||||
OFDM_RX_FRAME_HE_MU_SIGB_COMP,
|
||||
IEEE80211_RADIOTAP_HE_MU_FLAGS2_SIG_B_COMP);
|
||||
|
||||
|
|
@ -1377,6 +1505,10 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id,
|
|||
|
||||
iwl_mld_set_rx_rate(mld, phy_data, rx_status);
|
||||
|
||||
/* must be before HE data (radiotap field order) */
|
||||
if (format == RATE_MCS_MOD_TYPE_VHT)
|
||||
iwl_mld_rx_vht(skb, phy_data);
|
||||
|
||||
/* must be before L-SIG data (radiotap field order) */
|
||||
if (format == RATE_MCS_MOD_TYPE_HE)
|
||||
iwl_mld_rx_he(skb, phy_data);
|
||||
|
|
|
|||
|
|
@ -1063,14 +1063,15 @@ static int
|
|||
iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld,
|
||||
struct iwl_mld_scan_params *params,
|
||||
struct ieee80211_vif *vif,
|
||||
struct iwl_scan_req_params_v17 *scan_p,
|
||||
enum iwl_mld_scan_status scan_status)
|
||||
struct iwl_scan_req_params_v17 *scan_p)
|
||||
{
|
||||
struct iwl_scan_channel_params_v7 *chan_p = &scan_p->channel_params;
|
||||
struct iwl_scan_probe_params_v4 *probe_p = &scan_p->probe_params;
|
||||
|
||||
chan_p->flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif,
|
||||
scan_status);
|
||||
/* Explicitly clear the flags since most of them are not
|
||||
* relevant for 6 GHz scan.
|
||||
*/
|
||||
chan_p->flags = 0;
|
||||
chan_p->count = iwl_mld_scan_cfg_channels_6g(mld, params,
|
||||
params->n_channels,
|
||||
probe_p, chan_p,
|
||||
|
|
@ -1106,8 +1107,7 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
|
|||
|
||||
if (params->scan_6ghz)
|
||||
return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params,
|
||||
vif, scan_p,
|
||||
scan_status);
|
||||
vif, scan_p);
|
||||
|
||||
/* relevant only for 2.4 GHz/5 GHz scan */
|
||||
cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif,
|
||||
|
|
|
|||
|
|
@ -1163,7 +1163,8 @@ void iwl_mld_remove_aux_sta(struct iwl_mld *mld,
|
|||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
|
||||
if (WARN_ON(vif->type != NL80211_IFTYPE_P2P_DEVICE &&
|
||||
vif->type != NL80211_IFTYPE_STATION))
|
||||
vif->type != NL80211_IFTYPE_STATION &&
|
||||
vif->type != NL80211_IFTYPE_NAN))
|
||||
return;
|
||||
|
||||
iwl_mld_remove_internal_sta(mld, &mld_vif->aux_sta, false,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "tlc.h"
|
||||
#include "hcmd.h"
|
||||
#include "sta.h"
|
||||
#include "phy.h"
|
||||
|
||||
#include "fw/api/rs.h"
|
||||
#include "fw/api/context.h"
|
||||
|
|
@ -447,11 +448,48 @@ iwl_mld_fill_supp_rates(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
|||
}
|
||||
}
|
||||
|
||||
static void iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd,
|
||||
struct iwl_tlc_config_cmd_v4 *cmd_v4)
|
||||
static int iwl_mld_convert_tlc_cmd_to_v5(struct iwl_tlc_config_cmd *cmd,
|
||||
struct iwl_tlc_config_cmd_v5 *cmd_v5)
|
||||
{
|
||||
if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1))
|
||||
return -EINVAL;
|
||||
|
||||
/* Convert sta_mask to sta_id */
|
||||
cmd_v5->sta_id = __ffs(le32_to_cpu(cmd->sta_mask));
|
||||
|
||||
/* Copy all the rest */
|
||||
cmd_v5->max_ch_width = cmd->max_ch_width;
|
||||
cmd_v5->mode = cmd->mode;
|
||||
cmd_v5->chains = cmd->chains;
|
||||
cmd_v5->sgi_ch_width_supp = cmd->sgi_ch_width_supp;
|
||||
cmd_v5->flags = cmd->flags;
|
||||
cmd_v5->non_ht_rates = cmd->non_ht_rates;
|
||||
|
||||
BUILD_BUG_ON(sizeof(cmd_v5->ht_rates) != sizeof(cmd->ht_rates));
|
||||
memcpy(cmd_v5->ht_rates, cmd->ht_rates, sizeof(cmd->ht_rates));
|
||||
|
||||
cmd_v5->max_mpdu_len = cmd->max_mpdu_len;
|
||||
cmd_v5->max_tx_op = cmd->max_tx_op;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd,
|
||||
struct iwl_tlc_config_cmd_v4 *cmd_v4)
|
||||
{
|
||||
if (WARN_ON_ONCE(hweight32(le32_to_cpu(cmd->sta_mask)) != 1))
|
||||
return -EINVAL;
|
||||
|
||||
/* Convert sta_mask to sta_id */
|
||||
cmd_v4->sta_id = __ffs(le32_to_cpu(cmd->sta_mask));
|
||||
|
||||
/* Copy everything until ht_rates */
|
||||
memcpy(cmd_v4, cmd, offsetof(struct iwl_tlc_config_cmd, ht_rates));
|
||||
cmd_v4->max_ch_width = cmd->max_ch_width;
|
||||
cmd_v4->mode = cmd->mode;
|
||||
cmd_v4->chains = cmd->chains;
|
||||
cmd_v4->sgi_ch_width_supp = cmd->sgi_ch_width_supp;
|
||||
cmd_v4->flags = cmd->flags;
|
||||
cmd_v4->non_ht_rates = cmd->non_ht_rates;
|
||||
|
||||
/* Convert ht_rates from __le32 to __le16 */
|
||||
BUILD_BUG_ON(ARRAY_SIZE(cmd_v4->ht_rates) != ARRAY_SIZE(cmd->ht_rates));
|
||||
|
|
@ -465,14 +503,17 @@ static void iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd,
|
|||
/* Copy the rest */
|
||||
cmd_v4->max_mpdu_len = cmd->max_mpdu_len;
|
||||
cmd_v4->max_tx_op = cmd->max_tx_op;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ieee80211_link_sta *link_sta,
|
||||
enum nl80211_band band)
|
||||
struct ieee80211_bss_conf *link)
|
||||
{
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
|
||||
enum nl80211_band band = link->chanreq.oper.chan->band;
|
||||
struct ieee80211_supported_band *sband = mld->hw->wiphy->bands[band];
|
||||
const struct ieee80211_sta_he_cap *own_he_cap =
|
||||
ieee80211_get_he_iftype_cap_vif(sband, vif);
|
||||
|
|
@ -492,25 +533,44 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
|
|||
int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
|
||||
u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD);
|
||||
u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0);
|
||||
struct iwl_tlc_config_cmd_v4 cmd_v4;
|
||||
struct ieee80211_chanctx_conf *chan_ctx;
|
||||
struct iwl_tlc_config_cmd_v5 cmd_v5 = {};
|
||||
struct iwl_tlc_config_cmd_v4 cmd_v4 = {};
|
||||
void *cmd_ptr;
|
||||
u8 cmd_size;
|
||||
u32 phy_id;
|
||||
int ret;
|
||||
|
||||
if (fw_sta_id < 0)
|
||||
return;
|
||||
|
||||
cmd.sta_id = fw_sta_id;
|
||||
cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id));
|
||||
|
||||
chan_ctx = rcu_dereference_wiphy(mld->wiphy, link->chanctx_conf);
|
||||
if (WARN_ON(!chan_ctx))
|
||||
return;
|
||||
|
||||
phy_id = iwl_mld_phy_from_mac80211(chan_ctx)->fw_id;
|
||||
cmd.phy_id = cpu_to_le32(phy_id);
|
||||
|
||||
iwl_mld_fill_supp_rates(mld, vif, link_sta, sband,
|
||||
own_he_cap, own_eht_cap,
|
||||
&cmd);
|
||||
|
||||
if (cmd_ver == 5) {
|
||||
if (cmd_ver == 6) {
|
||||
cmd_ptr = &cmd;
|
||||
cmd_size = sizeof(cmd);
|
||||
} else if (cmd_ver == 5) {
|
||||
/* TODO: remove support once FW moves to version 6 */
|
||||
ret = iwl_mld_convert_tlc_cmd_to_v5(&cmd, &cmd_v5);
|
||||
if (ret)
|
||||
return;
|
||||
cmd_ptr = &cmd_v5;
|
||||
cmd_size = sizeof(cmd_v5);
|
||||
} else if (cmd_ver == 4) {
|
||||
iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4);
|
||||
ret = iwl_mld_convert_tlc_cmd_to_v4(&cmd, &cmd_v4);
|
||||
if (ret)
|
||||
return;
|
||||
cmd_ptr = &cmd_v4;
|
||||
cmd_size = sizeof(cmd_v4);
|
||||
} else {
|
||||
|
|
@ -520,8 +580,9 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
|
|||
}
|
||||
|
||||
IWL_DEBUG_RATE(mld,
|
||||
"TLC CONFIG CMD, sta_id=%d, max_ch_width=%d, mode=%d\n",
|
||||
cmd.sta_id, cmd.max_ch_width, cmd.mode);
|
||||
"TLC CONFIG CMD, sta_mask=0x%x, max_ch_width=%d, mode=%d, phy_id=%d\n",
|
||||
le32_to_cpu(cmd.sta_mask), cmd.max_ch_width, cmd.mode,
|
||||
le32_to_cpu(cmd.phy_id));
|
||||
|
||||
/* Send async since this can be called within a RCU-read section */
|
||||
ret = iwl_mld_send_cmd_with_flags_pdu(mld, cmd_id, CMD_ASYNC, cmd_ptr,
|
||||
|
|
@ -561,7 +622,6 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld,
|
|||
struct ieee80211_link_sta *link_sta)
|
||||
{
|
||||
struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
|
||||
enum nl80211_band band;
|
||||
|
||||
if (WARN_ON_ONCE(!link_conf->chanreq.oper.chan))
|
||||
return;
|
||||
|
|
@ -575,8 +635,7 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld,
|
|||
ieee80211_sta_recalc_aggregates(link_sta->sta);
|
||||
}
|
||||
|
||||
band = link_conf->chanreq.oper.chan->band;
|
||||
iwl_mld_send_tlc_cmd(mld, vif, link_sta, band);
|
||||
iwl_mld_send_tlc_cmd(mld, vif, link_sta, link_conf);
|
||||
}
|
||||
|
||||
void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
|
|
|
|||
|
|
@ -345,6 +345,11 @@ u8 iwl_mld_get_lowest_rate(struct iwl_mld *mld,
|
|||
|
||||
iwl_mld_get_basic_rates_and_band(mld, vif, info, &basic_rates, &band);
|
||||
|
||||
if (band >= NUM_NL80211_BANDS) {
|
||||
WARN_ON(vif->type != NL80211_IFTYPE_NAN);
|
||||
return IWL_FIRST_OFDM_RATE;
|
||||
}
|
||||
|
||||
sband = mld->hw->wiphy->bands[band];
|
||||
for_each_set_bit(i, &basic_rates, BITS_PER_LONG) {
|
||||
u16 hw = sband->bitrates[i].hw_value;
|
||||
|
|
@ -666,6 +671,12 @@ iwl_mld_get_tx_queue_id(struct iwl_mld *mld, struct ieee80211_txq *txq,
|
|||
}
|
||||
|
||||
WARN_ON(!ieee80211_is_mgmt(fc));
|
||||
return mld_vif->aux_sta.queue_id;
|
||||
case NL80211_IFTYPE_NAN:
|
||||
mld_vif = iwl_mld_vif_from_mac80211(info->control.vif);
|
||||
|
||||
WARN_ON(!ieee80211_is_mgmt(fc));
|
||||
|
||||
return mld_vif->aux_sta.queue_id;
|
||||
default:
|
||||
WARN_ONCE(1, "Unsupported vif type\n");
|
||||
|
|
|
|||
|
|
@ -726,8 +726,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
struct iwl_time_quota_data *quota;
|
||||
u32 status;
|
||||
|
||||
if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm) ||
|
||||
ieee80211_vif_is_mld(vif)))
|
||||
if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm)))
|
||||
return -EINVAL;
|
||||
|
||||
/* add back the PHY */
|
||||
|
|
@ -1248,7 +1247,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif = NULL;
|
||||
struct iwl_mvm_vif *mvmvif = NULL;
|
||||
struct ieee80211_sta *ap_sta = NULL;
|
||||
struct iwl_mvm_vif_link_info *mvm_link;
|
||||
struct iwl_d3_manager_config d3_cfg_cmd = {
|
||||
/*
|
||||
* Program the minimum sleep time to 10 seconds, as many
|
||||
|
|
@ -1280,13 +1278,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
mvm_link = mvmvif->link[iwl_mvm_get_primary_link(vif)];
|
||||
if (WARN_ON_ONCE(!mvm_link)) {
|
||||
ret = -EINVAL;
|
||||
goto out_noreset;
|
||||
}
|
||||
|
||||
if (mvm_link->ap_sta_id == IWL_INVALID_STA) {
|
||||
if (mvmvif->deflink.ap_sta_id == IWL_INVALID_STA) {
|
||||
/* if we're not associated, this must be netdetect */
|
||||
if (!wowlan->nd_config) {
|
||||
ret = 1;
|
||||
|
|
@ -1304,10 +1296,10 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
.offloading_tid = 0,
|
||||
};
|
||||
|
||||
wowlan_config_cmd.sta_id = mvm_link->ap_sta_id;
|
||||
wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id;
|
||||
|
||||
ap_sta = rcu_dereference_protected(
|
||||
mvm->fw_id_to_mac_id[mvm_link->ap_sta_id],
|
||||
mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (IS_ERR_OR_NULL(ap_sta)) {
|
||||
ret = -EINVAL;
|
||||
|
|
@ -1324,7 +1316,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
|
|||
if (ret)
|
||||
goto out_noreset;
|
||||
ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd,
|
||||
vif, mvmvif, mvm_link, ap_sta);
|
||||
vif, mvmvif, &mvmvif->deflink,
|
||||
ap_sta);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
|
|
@ -1819,10 +1812,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw,
|
|||
struct iwl_mvm_d3_gtk_iter_data *data = _data;
|
||||
struct iwl_wowlan_status_data *status = data->status;
|
||||
s8 keyidx;
|
||||
int link_id = vif->active_links ? __ffs(vif->active_links) : -1;
|
||||
|
||||
if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id)
|
||||
return;
|
||||
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
|
|
@ -1876,7 +1865,6 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
|
|||
{
|
||||
int i, j;
|
||||
struct ieee80211_key_conf *key;
|
||||
int link_id = vif->active_links ? __ffs(vif->active_links) : -1;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(status->gtk); i++) {
|
||||
if (!status->gtk[i].len)
|
||||
|
|
@ -1888,8 +1876,7 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
|
|||
|
||||
key = ieee80211_gtk_rekey_add(vif, status->gtk[i].id,
|
||||
status->gtk[i].key,
|
||||
sizeof(status->gtk[i].key),
|
||||
link_id);
|
||||
sizeof(status->gtk[i].key), -1);
|
||||
if (IS_ERR(key)) {
|
||||
/* FW may send also the old keys */
|
||||
if (PTR_ERR(key) == -EALREADY)
|
||||
|
|
@ -1918,14 +1905,13 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,
|
|||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct ieee80211_key_conf *key_config;
|
||||
struct ieee80211_key_seq seq;
|
||||
int link_id = vif->active_links ? __ffs(vif->active_links) : -1;
|
||||
s8 keyidx = key_data->id;
|
||||
|
||||
if (!key_data->len)
|
||||
return true;
|
||||
|
||||
key_config = ieee80211_gtk_rekey_add(vif, keyidx, key_data->key,
|
||||
sizeof(key_data->key), link_id);
|
||||
sizeof(key_data->key), -1);
|
||||
if (IS_ERR(key_config)) {
|
||||
/* FW may send also the old keys */
|
||||
return PTR_ERR(key_config) == -EALREADY;
|
||||
|
|
@ -1935,13 +1921,9 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,
|
|||
ieee80211_set_key_rx_seq(key_config, 0, &seq);
|
||||
|
||||
if (keyidx == 4 || keyidx == 5) {
|
||||
struct iwl_mvm_vif_link_info *mvm_link;
|
||||
|
||||
link_id = link_id < 0 ? 0 : link_id;
|
||||
mvm_link = mvmvif->link[link_id];
|
||||
if (mvm_link->igtk)
|
||||
mvm_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
|
||||
mvm_link->igtk = key_config;
|
||||
if (mvmvif->deflink.igtk)
|
||||
mvmvif->deflink.igtk->hw_key_idx = STA_KEY_IDX_INVALID;
|
||||
mvmvif->deflink.igtk = key_config;
|
||||
}
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_STATION && (keyidx == 6 || keyidx == 7))
|
||||
|
|
@ -2396,23 +2378,19 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
bool keep = false;
|
||||
struct iwl_mvm_sta *mvm_ap_sta;
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
int link_id = vif->active_links ? __ffs(vif->active_links) : 0;
|
||||
struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id];
|
||||
int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw,
|
||||
PROT_OFFLOAD_GROUP,
|
||||
WOWLAN_INFO_NOTIFICATION,
|
||||
IWL_FW_CMD_VER_UNKNOWN);
|
||||
|
||||
if (WARN_ON(!mvm_link))
|
||||
goto out_unlock;
|
||||
|
||||
if (!status)
|
||||
goto out_unlock;
|
||||
|
||||
IWL_DEBUG_WOWLAN(mvm, "wakeup reason 0x%x\n",
|
||||
status->wakeup_reasons);
|
||||
|
||||
mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, mvm_link->ap_sta_id);
|
||||
mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm,
|
||||
mvmvif->deflink.ap_sta_id);
|
||||
if (!mvm_ap_sta)
|
||||
goto out_unlock;
|
||||
|
||||
|
|
@ -2756,9 +2734,6 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm,
|
|||
u8 sta_id = mvm->net_detect ? IWL_INVALID_STA :
|
||||
mvmvif->deflink.ap_sta_id;
|
||||
|
||||
/* bug - FW with MLO has status notification */
|
||||
WARN_ON(ieee80211_vif_is_mld(vif));
|
||||
|
||||
d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1135,8 +1135,9 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
|
|||
for (u16 i = 0; i < data.block_list_size; i++)
|
||||
cmd_v5.block_list_array[i] =
|
||||
cpu_to_le16(data.block_list_array[i]);
|
||||
cmd_v5.tas_config_info.table_source = data.table_source;
|
||||
cmd_v5.tas_config_info.table_revision = data.table_revision;
|
||||
cmd_v5.tas_config_info.hdr.table_source = data.table_source;
|
||||
cmd_v5.tas_config_info.hdr.table_revision =
|
||||
data.table_revision;
|
||||
cmd_v5.tas_config_info.value = cpu_to_le32(data.tas_selection);
|
||||
} else if (fw_ver == 4) {
|
||||
cmd_size = sizeof(cmd_v2_v4.common) + sizeof(cmd_v2_v4.v4);
|
||||
|
|
@ -1165,13 +1166,208 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm)
|
|||
IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret);
|
||||
}
|
||||
|
||||
static __le32 iwl_mvm_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt)
|
||||
{
|
||||
int ret;
|
||||
u32 val;
|
||||
__le32 config_bitmap = 0;
|
||||
|
||||
switch (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id)) {
|
||||
case IWL_CFG_RF_TYPE_HR1:
|
||||
case IWL_CFG_RF_TYPE_HR2:
|
||||
case IWL_CFG_RF_TYPE_JF1:
|
||||
case IWL_CFG_RF_TYPE_JF2:
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2,
|
||||
&val);
|
||||
|
||||
if (!ret && val == DSM_VALUE_INDONESIA_ENABLE)
|
||||
config_bitmap |=
|
||||
cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val);
|
||||
if (!ret) {
|
||||
if (val == DSM_VALUE_SRD_PASSIVE)
|
||||
config_bitmap |=
|
||||
cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK);
|
||||
else if (val == DSM_VALUE_SRD_DISABLE)
|
||||
config_bitmap |=
|
||||
cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK);
|
||||
}
|
||||
|
||||
if (fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) {
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG,
|
||||
&val);
|
||||
/*
|
||||
* China 2022 enable if the BIOS object does not exist or
|
||||
* if it is enabled in BIOS.
|
||||
*/
|
||||
if (ret < 0 || val & DSM_MASK_CHINA_22_REG)
|
||||
config_bitmap |=
|
||||
cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK);
|
||||
}
|
||||
|
||||
return config_bitmap;
|
||||
}
|
||||
|
||||
static size_t iwl_mvm_get_lari_config_cmd_size(u8 cmd_ver)
|
||||
{
|
||||
size_t cmd_size;
|
||||
|
||||
switch (cmd_ver) {
|
||||
case 12:
|
||||
cmd_size = offsetof(struct iwl_lari_config_change_cmd,
|
||||
oem_11bn_allow_bitmap);
|
||||
break;
|
||||
case 8:
|
||||
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v8);
|
||||
break;
|
||||
case 6:
|
||||
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6);
|
||||
break;
|
||||
default:
|
||||
cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1);
|
||||
break;
|
||||
}
|
||||
return cmd_size;
|
||||
}
|
||||
|
||||
static int iwl_mvm_fill_lari_config(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_lari_config_change_cmd *cmd,
|
||||
size_t *cmd_size)
|
||||
{
|
||||
int ret;
|
||||
u32 value;
|
||||
bool has_raw_dsm_capa = fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE);
|
||||
u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
LARI_CONFIG_CHANGE), 1);
|
||||
|
||||
memset(cmd, 0, sizeof(*cmd));
|
||||
*cmd_size = iwl_mvm_get_lari_config_cmd_size(cmd_ver);
|
||||
|
||||
cmd->config_bitmap = iwl_mvm_get_lari_config_bitmap(fwrt);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= DSM_11AX_ALLOW_BITMAP;
|
||||
cmd->oem_11ax_allow_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= DSM_UNII4_ALLOW_BITMAP;
|
||||
|
||||
/* Since version 12, bits 4 and 5 are supported
|
||||
* regardless of this capability, By pass this masking
|
||||
* if firmware has capability of accepting raw DSM table.
|
||||
*/
|
||||
if (!has_raw_dsm_capa && cmd_ver < 12 &&
|
||||
!fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_5G9_FOR_CA))
|
||||
value &= ~(DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK |
|
||||
DSM_VALUE_UNII4_CANADA_EN_MSK);
|
||||
|
||||
cmd->oem_unii4_allow_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V12;
|
||||
|
||||
if (!has_raw_dsm_capa && cmd_ver < 8)
|
||||
value &= ~ACTIVATE_5G2_IN_WW_MASK;
|
||||
|
||||
/* Since version 12, bits 5 and 6 are supported
|
||||
* regardless of this capability, By pass this masking
|
||||
* if firmware has capability of accepting raw DSM table.
|
||||
*/
|
||||
if (!has_raw_dsm_capa && cmd_ver < 12 &&
|
||||
!fw_has_capa(&fwrt->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_BIOS_OVERRIDE_UNII4_US_CA))
|
||||
value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V8;
|
||||
|
||||
cmd->chan_state_active_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value);
|
||||
if (!ret)
|
||||
cmd->oem_uhb_allow_bitmap = cpu_to_le32(value);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= DSM_FORCE_DISABLE_CHANNELS_ALLOWED_BITMAP;
|
||||
cmd->force_disable_channels_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD,
|
||||
&value);
|
||||
if (!ret) {
|
||||
if (!has_raw_dsm_capa)
|
||||
value &= DSM_EDT_ALLOWED_BITMAP;
|
||||
cmd->edt_bitmap = cpu_to_le32(value);
|
||||
}
|
||||
|
||||
ret = iwl_bios_get_wbem(fwrt, &value);
|
||||
if (!ret)
|
||||
cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value);
|
||||
|
||||
ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value);
|
||||
if (!ret)
|
||||
cmd->oem_11be_allow_bitmap = cpu_to_le32(value);
|
||||
|
||||
if (cmd->config_bitmap ||
|
||||
cmd->oem_uhb_allow_bitmap ||
|
||||
cmd->oem_11ax_allow_bitmap ||
|
||||
cmd->oem_unii4_allow_bitmap ||
|
||||
cmd->chan_state_active_bitmap ||
|
||||
cmd->force_disable_channels_bitmap ||
|
||||
cmd->edt_bitmap ||
|
||||
cmd->oem_320mhz_allow_bitmap ||
|
||||
cmd->oem_11be_allow_bitmap) {
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd->config_bitmap),
|
||||
le32_to_cpu(cmd->oem_11ax_allow_bitmap));
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n",
|
||||
le32_to_cpu(cmd->oem_unii4_allow_bitmap),
|
||||
le32_to_cpu(cmd->chan_state_active_bitmap),
|
||||
cmd_ver);
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd->oem_uhb_allow_bitmap),
|
||||
le32_to_cpu(cmd->force_disable_channels_bitmap));
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd->edt_bitmap),
|
||||
le32_to_cpu(cmd->oem_320mhz_allow_bitmap));
|
||||
IWL_DEBUG_RADIO(fwrt,
|
||||
"sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n",
|
||||
le32_to_cpu(cmd->oem_11be_allow_bitmap));
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm)
|
||||
{
|
||||
struct iwl_lari_config_change_cmd cmd;
|
||||
size_t cmd_size;
|
||||
int ret;
|
||||
|
||||
ret = iwl_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size);
|
||||
ret = iwl_mvm_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size);
|
||||
if (!ret) {
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm,
|
||||
WIDE_ID(REGULATORY_AND_NVM_GROUP,
|
||||
|
|
|
|||
|
|
@ -285,28 +285,6 @@ int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
return ret;
|
||||
}
|
||||
|
||||
u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
/* relevant data is written with both locks held, so read with either */
|
||||
lockdep_assert(lockdep_is_held(&mvmvif->mvm->mutex) ||
|
||||
lockdep_is_held(&mvmvif->mvm->hw->wiphy->mtx));
|
||||
|
||||
if (!ieee80211_vif_is_mld(vif))
|
||||
return 0;
|
||||
|
||||
/* In AP mode, there is no primary link */
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
return __ffs(vif->active_links);
|
||||
|
||||
if (mvmvif->esr_active &&
|
||||
!WARN_ON(!(BIT(mvmvif->primary_link) & vif->active_links)))
|
||||
return mvmvif->primary_link;
|
||||
|
||||
return __ffs(vif->active_links);
|
||||
}
|
||||
|
||||
void iwl_mvm_init_link(struct iwl_mvm_vif_link_info *link)
|
||||
{
|
||||
link->bcast_sta.sta_id = IWL_INVALID_STA;
|
||||
|
|
|
|||
|
|
@ -873,7 +873,6 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,
|
|||
struct ieee80211_tx_info *info,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct ieee80211_supported_band *sband;
|
||||
unsigned long basic = vif->bss_conf.basic_rates;
|
||||
u16 lowest_cck = IWL_RATE_COUNT, lowest_ofdm = IWL_RATE_COUNT;
|
||||
|
|
@ -883,16 +882,6 @@ u8 iwl_mvm_mac_ctxt_get_lowest_rate(struct iwl_mvm *mvm,
|
|||
u8 rate;
|
||||
u32 i;
|
||||
|
||||
if (link_id == IEEE80211_LINK_UNSPECIFIED && ieee80211_vif_is_mld(vif)) {
|
||||
for (i = 0; i < ARRAY_SIZE(mvmvif->link); i++) {
|
||||
if (!mvmvif->link[i])
|
||||
continue;
|
||||
/* shouldn't do this when >1 link is active */
|
||||
WARN_ON_ONCE(link_id != IEEE80211_LINK_UNSPECIFIED);
|
||||
link_id = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (link_id < IEEE80211_LINK_UNSPECIFIED) {
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
|
||||
|
|
@ -1761,6 +1750,20 @@ void iwl_mvm_probe_resp_data_notif(struct iwl_mvm *mvm,
|
|||
|
||||
mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
|
||||
/*
|
||||
* len_low should be 2 + n*13 (where n is the number of descriptors.
|
||||
* 13 is the size of a NoA descriptor). We can have either one or two
|
||||
* descriptors.
|
||||
*/
|
||||
if (IWL_FW_CHECK(mvm, notif->noa_active &&
|
||||
notif->noa_attr.len_low != 2 +
|
||||
sizeof(struct ieee80211_p2p_noa_desc) &&
|
||||
notif->noa_attr.len_low != 2 +
|
||||
sizeof(struct ieee80211_p2p_noa_desc) * 2,
|
||||
"Invalid noa_attr.len_low (%d)\n",
|
||||
notif->noa_attr.len_low))
|
||||
return;
|
||||
|
||||
new_data = kzalloc(sizeof(*new_data), GFP_KERNEL);
|
||||
if (!new_data)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1109,7 +1109,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
|
|||
mvmvif->ba_enabled = false;
|
||||
mvmvif->ap_sta = NULL;
|
||||
|
||||
mvmvif->esr_active = false;
|
||||
vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;
|
||||
|
||||
for_each_mvm_vif_valid_link(mvmvif, link_id) {
|
||||
|
|
@ -1129,39 +1128,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
|
|||
RCU_INIT_POINTER(mvmvif->deflink.probe_resp_data, NULL);
|
||||
}
|
||||
|
||||
static void iwl_mvm_cleanup_sta_iterator(void *data, struct ieee80211_sta *sta)
|
||||
{
|
||||
struct iwl_mvm *mvm = data;
|
||||
struct iwl_mvm_sta *mvm_sta;
|
||||
struct ieee80211_vif *vif;
|
||||
int link_id;
|
||||
|
||||
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
|
||||
vif = mvm_sta->vif;
|
||||
|
||||
if (!sta->valid_links)
|
||||
return;
|
||||
|
||||
for (link_id = 0; link_id < ARRAY_SIZE((sta)->link); link_id++) {
|
||||
struct iwl_mvm_link_sta *mvm_link_sta;
|
||||
|
||||
mvm_link_sta =
|
||||
rcu_dereference_check(mvm_sta->link[link_id],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (mvm_link_sta && !(vif->active_links & BIT(link_id))) {
|
||||
/*
|
||||
* We have a link STA but the link is inactive in
|
||||
* mac80211. This will happen if we failed to
|
||||
* deactivate the link but mac80211 roll back the
|
||||
* deactivation of the link.
|
||||
* Delete the stale data to avoid issues later on.
|
||||
*/
|
||||
iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_link_sta,
|
||||
link_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
||||
{
|
||||
iwl_mvm_stop_device(mvm);
|
||||
|
|
@ -1184,10 +1150,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
|
|||
*/
|
||||
ieee80211_iterate_interfaces(mvm->hw, 0, iwl_mvm_cleanup_iterator, mvm);
|
||||
|
||||
/* cleanup stations as links may be gone after restart */
|
||||
ieee80211_iterate_stations_atomic(mvm->hw,
|
||||
iwl_mvm_cleanup_sta_iterator, mvm);
|
||||
|
||||
mvm->p2p_device_vif = NULL;
|
||||
|
||||
iwl_mvm_reset_phy_ctxts(mvm);
|
||||
|
|
@ -2639,7 +2601,7 @@ static void iwl_mvm_cfg_he_sta(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
u32 duration_override, unsigned int link_id)
|
||||
u32 duration_override)
|
||||
{
|
||||
u32 duration = IWL_MVM_TE_SESSION_PROTECTION_MAX_TIME_MS;
|
||||
u32 min_duration = IWL_MVM_TE_SESSION_PROTECTION_MIN_TIME_MS;
|
||||
|
|
@ -2659,8 +2621,7 @@ void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
if (fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))
|
||||
iwl_mvm_schedule_session_protection(mvm, vif, 900,
|
||||
min_duration, false,
|
||||
link_id);
|
||||
min_duration, false);
|
||||
else
|
||||
iwl_mvm_protect_session(mvm, vif, duration,
|
||||
min_duration, 500, false);
|
||||
|
|
@ -2860,7 +2821,7 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
|
|||
* time could be small without us having heard
|
||||
* a beacon yet.
|
||||
*/
|
||||
iwl_mvm_protect_assoc(mvm, vif, 0, 0);
|
||||
iwl_mvm_protect_assoc(mvm, vif, 0);
|
||||
}
|
||||
|
||||
iwl_mvm_sf_update(mvm, vif, false);
|
||||
|
|
@ -3921,12 +3882,6 @@ iwl_mvm_sta_state_assoc_to_authorized(struct iwl_mvm *mvm,
|
|||
|
||||
mvmvif->authorized = 1;
|
||||
|
||||
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
|
||||
mvmvif->link_selection_res = vif->active_links;
|
||||
mvmvif->link_selection_primary =
|
||||
vif->active_links ? __ffs(vif->active_links) : 0;
|
||||
}
|
||||
|
||||
callbacks->mac_ctxt_changed(mvm, vif, false);
|
||||
iwl_mvm_mei_host_associated(mvm, vif, mvm_sta);
|
||||
}
|
||||
|
|
@ -3972,7 +3927,6 @@ iwl_mvm_sta_state_authorized_to_assoc(struct iwl_mvm *mvm,
|
|||
* time.
|
||||
*/
|
||||
mvmvif->authorized = 0;
|
||||
mvmvif->link_selection_res = 0;
|
||||
|
||||
/* disable beacon filtering */
|
||||
iwl_mvm_disable_beacon_filter(mvm, vif);
|
||||
|
|
@ -4197,7 +4151,7 @@ void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
|
|||
return;
|
||||
|
||||
guard(mvm)(mvm);
|
||||
iwl_mvm_protect_assoc(mvm, vif, info->duration, info->link_id);
|
||||
iwl_mvm_protect_assoc(mvm, vif, info->duration);
|
||||
}
|
||||
|
||||
void iwl_mvm_mac_mgd_complete_tx(struct ieee80211_hw *hw,
|
||||
|
|
@ -5568,8 +5522,7 @@ static int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm,
|
|||
if (!vif->cfg.assoc || !vif->bss_conf.dtim_period)
|
||||
return -EBUSY;
|
||||
|
||||
if (chsw->delay > IWL_MAX_CSA_BLOCK_TX &&
|
||||
hweight16(vif->valid_links) <= 1)
|
||||
if (chsw->delay > IWL_MAX_CSA_BLOCK_TX)
|
||||
schedule_delayed_work(&mvmvif->csa_work, 0);
|
||||
|
||||
if (chsw->block_tx) {
|
||||
|
|
@ -5733,15 +5686,8 @@ void iwl_mvm_mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
|||
return;
|
||||
}
|
||||
|
||||
if (!drop && hweight16(vif->active_links) <= 1) {
|
||||
int link_id = vif->active_links ? __ffs(vif->active_links) : 0;
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
|
||||
link_conf = wiphy_dereference(hw->wiphy,
|
||||
vif->link_conf[link_id]);
|
||||
if (WARN_ON(!link_conf))
|
||||
return;
|
||||
if (link_conf->csa_active && mvmvif->csa_blocks_tx)
|
||||
if (!drop) {
|
||||
if (vif->bss_conf.csa_active && mvmvif->csa_blocks_tx)
|
||||
drop = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2022 - 2024 Intel Corporation
|
||||
* Copyright (C) 2022 - 2025 Intel Corporation
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <net/mac80211.h>
|
||||
|
|
@ -43,11 +43,11 @@ static u32 iwl_mvm_get_sec_sta_mask(struct iwl_mvm *mvm,
|
|||
* group keys have no sta pointer), so we don't have a STA now.
|
||||
* Since this happens for group keys only, just use the link_info as
|
||||
* the group keys are per link; make sure that is the case by checking
|
||||
* we do have a link_id or are not doing MLO.
|
||||
* we do have a link_id.
|
||||
* Of course the same can be done during add as well, but we must do
|
||||
* it during remove, since we don't have the mvmvif->ap_sta pointer.
|
||||
*/
|
||||
if (!sta && (keyconf->link_id >= 0 || !ieee80211_vif_is_mld(vif)))
|
||||
if (!sta && keyconf->link_id >= 0)
|
||||
return BIT(link_info->ap_sta_id);
|
||||
|
||||
/* STA should be non-NULL now, but iwl_mvm_sta_fw_id_mask() checks */
|
||||
|
|
|
|||
|
|
@ -56,23 +56,6 @@ static void iwl_mvm_mld_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
|
|||
if (iwlwifi_mod_params.disable_11ax)
|
||||
return;
|
||||
|
||||
/* If we have MLO enabled, then the firmware needs to enable
|
||||
* address translation for the station(s) we add. That depends
|
||||
* on having EHT enabled in firmware, which in turn depends on
|
||||
* mac80211 in the code below.
|
||||
* However, mac80211 doesn't enable HE/EHT until it has parsed
|
||||
* the association response successfully, so just skip all that
|
||||
* and enable both when we have MLO.
|
||||
*/
|
||||
if (ieee80211_vif_is_mld(vif)) {
|
||||
iwl_mvm_mld_set_he_support(mvm, vif, cmd, cmd_ver);
|
||||
if (cmd_ver == 2)
|
||||
cmd->wifi_gen_v2.eht_support = cpu_to_le32(1);
|
||||
else
|
||||
cmd->wifi_gen.eht_support = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
for (link_id = 0; link_id < ARRAY_SIZE((vif)->link_conf); link_id++) {
|
||||
link_conf = rcu_dereference(vif->link_conf[link_id]);
|
||||
|
|
@ -116,7 +99,6 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
|
|||
u32 action, bool force_assoc_off)
|
||||
{
|
||||
struct iwl_mac_config_cmd cmd = {};
|
||||
u16 esr_transition_timeout;
|
||||
|
||||
WARN_ON(vif->type != NL80211_IFTYPE_STATION);
|
||||
|
||||
|
|
@ -154,17 +136,6 @@ static int iwl_mvm_mld_mac_ctxt_cmd_sta(struct iwl_mvm *mvm,
|
|||
}
|
||||
|
||||
cmd.client.assoc_id = cpu_to_le16(vif->cfg.aid);
|
||||
if (ieee80211_vif_is_mld(vif)) {
|
||||
esr_transition_timeout =
|
||||
u16_get_bits(vif->cfg.eml_cap,
|
||||
IEEE80211_EML_CAP_TRANSITION_TIMEOUT);
|
||||
|
||||
cmd.client.esr_transition_timeout =
|
||||
min_t(u16, IEEE80211_EML_CAP_TRANSITION_TIMEOUT_128TU,
|
||||
esr_transition_timeout);
|
||||
cmd.client.medium_sync_delay =
|
||||
cpu_to_le16(vif->cfg.eml_med_sync_delay);
|
||||
}
|
||||
|
||||
if (vif->probe_req_reg && vif->cfg.assoc && vif->p2p)
|
||||
cmd.filter_flags |= cpu_to_le32(MAC_CFG_FILTER_ACCEPT_PROBE_REQ);
|
||||
|
|
|
|||
|
|
@ -60,19 +60,12 @@ static int iwl_mvm_mld_mac_add_interface(struct ieee80211_hw *hw,
|
|||
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
/* We want link[0] to point to the default link. */
|
||||
mvmvif->link[0] = &mvmvif->deflink;
|
||||
|
||||
ret = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
|
||||
if (ret)
|
||||
goto out_free_bf;
|
||||
}
|
||||
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
|
||||
|
|
@ -181,58 +174,6 @@ static void iwl_mvm_mld_mac_remove_interface(struct ieee80211_hw *hw,
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int iwl_mvm_mld_count_active_links(struct iwl_mvm_vif *mvmvif)
|
||||
{
|
||||
unsigned int n_active = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
|
||||
if (mvmvif->link[i] && mvmvif->link[i]->phy_ctxt)
|
||||
n_active++;
|
||||
}
|
||||
|
||||
return n_active;
|
||||
}
|
||||
|
||||
static int iwl_mvm_esr_mode_active(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
int link_id, ret = 0;
|
||||
|
||||
mvmvif->esr_active = true;
|
||||
|
||||
/* Indicate to mac80211 that EML is enabled */
|
||||
vif->driver_flags |= IEEE80211_VIF_EML_ACTIVE;
|
||||
|
||||
iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW,
|
||||
IEEE80211_SMPS_OFF);
|
||||
|
||||
for_each_mvm_vif_valid_link(mvmvif, link_id) {
|
||||
struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id];
|
||||
|
||||
if (!link->phy_ctxt)
|
||||
continue;
|
||||
|
||||
ret = iwl_mvm_phy_send_rlc(mvm, link->phy_ctxt, 2, 2);
|
||||
if (ret)
|
||||
break;
|
||||
|
||||
link->phy_ctxt->rlc_disabled = true;
|
||||
}
|
||||
|
||||
if (vif->active_links == mvmvif->link_selection_res &&
|
||||
!WARN_ON(!(vif->active_links & BIT(mvmvif->link_selection_primary))))
|
||||
mvmvif->primary_link = mvmvif->link_selection_primary;
|
||||
else
|
||||
mvmvif->primary_link = __ffs(vif->active_links);
|
||||
|
||||
iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_UP,
|
||||
NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
__iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
|
|
@ -243,17 +184,12 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
|
|||
u16 *phy_ctxt_id = (u16 *)ctx->drv_priv;
|
||||
struct iwl_mvm_phy_ctxt *phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id];
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif);
|
||||
unsigned int link_id = link_conf->link_id;
|
||||
int ret;
|
||||
|
||||
if (WARN_ON_ONCE(!mvmvif->link[link_id]))
|
||||
return -EINVAL;
|
||||
|
||||
/* if the assigned one was not counted yet, count it now */
|
||||
if (!mvmvif->link[link_id]->phy_ctxt)
|
||||
n_active++;
|
||||
|
||||
/* 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.
|
||||
|
|
@ -268,15 +204,6 @@ __iwl_mvm_mld_assign_vif_chanctx(struct iwl_mvm *mvm,
|
|||
|
||||
mvmvif->link[link_id]->phy_ctxt = phy_ctxt;
|
||||
|
||||
if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
|
||||
mvmvif->link[link_id]->listen_lmac = true;
|
||||
ret = iwl_mvm_esr_mode_active(mvm, vif);
|
||||
if (ret) {
|
||||
IWL_ERR(mvm, "failed to activate ESR mode (%d)\n", ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (switching_chanctx) {
|
||||
/* reactivate if we turned this off during channel switch */
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
|
|
@ -341,55 +268,6 @@ static int iwl_mvm_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
return __iwl_mvm_mld_assign_vif_chanctx(mvm, vif, link_conf, ctx, false);
|
||||
}
|
||||
|
||||
static int iwl_mvm_esr_mode_inactive(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
int link_id, ret = 0;
|
||||
|
||||
mvmvif->esr_active = false;
|
||||
|
||||
vif->driver_flags &= ~IEEE80211_VIF_EML_ACTIVE;
|
||||
|
||||
iwl_mvm_update_smps_on_active_links(mvm, vif, IWL_MVM_SMPS_REQ_FW,
|
||||
IEEE80211_SMPS_AUTOMATIC);
|
||||
|
||||
for_each_vif_active_link(vif, link_conf, link_id) {
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct iwl_mvm_phy_ctxt *phy_ctxt;
|
||||
u8 static_chains, dynamic_chains;
|
||||
|
||||
mvmvif->link[link_id]->listen_lmac = false;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
chanctx_conf = rcu_dereference(link_conf->chanctx_conf);
|
||||
phy_ctxt = mvmvif->link[link_id]->phy_ctxt;
|
||||
|
||||
if (!chanctx_conf || !phy_ctxt) {
|
||||
rcu_read_unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
phy_ctxt->rlc_disabled = false;
|
||||
static_chains = chanctx_conf->rx_chains_static;
|
||||
dynamic_chains = chanctx_conf->rx_chains_dynamic;
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
ret = iwl_mvm_phy_send_rlc(mvm, phy_ctxt, static_chains,
|
||||
dynamic_chains);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
||||
iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_ESR_LINK_DOWN,
|
||||
NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
__iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
|
|
@ -399,7 +277,6 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|||
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
unsigned int n_active = iwl_mvm_mld_count_active_links(mvmvif);
|
||||
unsigned int link_id = link_conf->link_id;
|
||||
|
||||
/* shouldn't happen, but verify link_id is valid before accessing */
|
||||
|
|
@ -421,14 +298,6 @@ __iwl_mvm_mld_unassign_vif_chanctx(struct iwl_mvm *mvm,
|
|||
iwl_mvm_link_changed(mvm, vif, link_conf,
|
||||
LINK_CONTEXT_MODIFY_ACTIVE, false);
|
||||
|
||||
if (iwl_mvm_is_esr_supported(mvm->fwrt.trans) && n_active > 1) {
|
||||
int ret = iwl_mvm_esr_mode_inactive(mvm, vif);
|
||||
|
||||
if (ret)
|
||||
IWL_ERR(mvm, "failed to deactivate ESR mode (%d)\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_MONITOR)
|
||||
iwl_mvm_mld_rm_snif_sta(mvm, vif);
|
||||
|
||||
|
|
@ -448,9 +317,8 @@ static void iwl_mvm_mld_unassign_vif_chanctx(struct ieee80211_hw *hw,
|
|||
|
||||
mutex_lock(&mvm->mutex);
|
||||
__iwl_mvm_mld_unassign_vif_chanctx(mvm, vif, link_conf, ctx, false);
|
||||
/* in the non-MLD case, remove/re-add the link to clean up FW state */
|
||||
if (!ieee80211_vif_is_mld(vif) && !mvmvif->ap_sta &&
|
||||
!WARN_ON_ONCE(vif->cfg.assoc)) {
|
||||
/* Remove/re-add the link to clean up FW state */
|
||||
if (!mvmvif->ap_sta && !WARN_ON_ONCE(vif->cfg.assoc)) {
|
||||
iwl_mvm_remove_link(mvm, vif, link_conf);
|
||||
iwl_mvm_add_link(mvm, vif, link_conf);
|
||||
}
|
||||
|
|
@ -785,12 +653,6 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,
|
|||
|
||||
if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status) &&
|
||||
protect) {
|
||||
/* We are in assoc so only one link is active-
|
||||
* The association link
|
||||
*/
|
||||
unsigned int link_id =
|
||||
ffs(vif->active_links) - 1;
|
||||
|
||||
/* If we're not restarting and still haven't
|
||||
* heard a beacon (dtim period unknown) then
|
||||
* make sure we still have enough minimum time
|
||||
|
|
@ -800,7 +662,7 @@ static void iwl_mvm_mld_vif_cfg_changed_station(struct iwl_mvm *mvm,
|
|||
* time could be small without us having heard
|
||||
* a beacon yet.
|
||||
*/
|
||||
iwl_mvm_protect_assoc(mvm, vif, 0, link_id);
|
||||
iwl_mvm_protect_assoc(mvm, vif, 0);
|
||||
}
|
||||
|
||||
iwl_mvm_sf_update(mvm, vif, false);
|
||||
|
|
@ -1096,14 +958,6 @@ iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
|
|||
if (new_links == 0) {
|
||||
mvmvif->link[0] = &mvmvif->deflink;
|
||||
err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
|
||||
if (err == 0)
|
||||
mvmvif->primary_link = 0;
|
||||
} else if (!(new_links & BIT(mvmvif->primary_link))) {
|
||||
/*
|
||||
* Ensure we always have a valid primary_link, the real
|
||||
* decision happens later when PHY is activated.
|
||||
*/
|
||||
mvmvif->primary_link = __ffs(new_links);
|
||||
}
|
||||
|
||||
out_err:
|
||||
|
|
@ -1128,44 +982,17 @@ iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw,
|
|||
return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links);
|
||||
}
|
||||
|
||||
bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
||||
{
|
||||
const struct wiphy_iftype_ext_capab *ext_capa;
|
||||
|
||||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
if (!ieee80211_vif_is_mld(vif) || !vif->cfg.assoc ||
|
||||
hweight16(ieee80211_vif_usable_links(vif)) == 1)
|
||||
return false;
|
||||
|
||||
if (!(vif->cfg.eml_cap & IEEE80211_EML_CAP_EMLSR_SUPP))
|
||||
return false;
|
||||
|
||||
ext_capa = cfg80211_get_iftype_ext_capa(mvm->hw->wiphy,
|
||||
ieee80211_vif_type_p2p(vif));
|
||||
return (ext_capa &&
|
||||
(ext_capa->eml_capabilities & IEEE80211_EML_CAP_EMLSR_SUPP));
|
||||
}
|
||||
|
||||
static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u16 desired_links)
|
||||
{
|
||||
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
|
||||
int n_links = hweight16(desired_links);
|
||||
|
||||
if (n_links <= 1)
|
||||
return true;
|
||||
|
||||
guard(mvm)(mvm);
|
||||
|
||||
/* Check if HW supports the wanted number of links */
|
||||
if (n_links > iwl_mvm_max_active_links(mvm, vif))
|
||||
return false;
|
||||
|
||||
/* If it is an eSR device, check that we can enter eSR */
|
||||
return iwl_mvm_is_esr_supported(mvm->fwrt.trans) &&
|
||||
iwl_mvm_vif_has_esr_cap(mvm, vif);
|
||||
WARN_ON(1);
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum ieee80211_neg_ttlm_res
|
||||
|
|
|
|||
|
|
@ -9,40 +9,14 @@
|
|||
u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
int filter_link_id)
|
||||
{
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
struct iwl_mvm_sta *mvmsta;
|
||||
struct ieee80211_vif *vif;
|
||||
unsigned int link_id;
|
||||
u32 result = 0;
|
||||
|
||||
if (!sta)
|
||||
return 0;
|
||||
|
||||
mvmsta = iwl_mvm_sta_from_mac80211(sta);
|
||||
vif = mvmsta->vif;
|
||||
|
||||
/* it's easy when the STA is not an MLD */
|
||||
if (!sta->valid_links)
|
||||
return BIT(mvmsta->deflink.sta_id);
|
||||
|
||||
/* but if it is an MLD, get the mask of all the FW STAs it has ... */
|
||||
for_each_sta_active_link(vif, sta, link_sta, link_id) {
|
||||
struct iwl_mvm_link_sta *mvm_link_sta;
|
||||
|
||||
/* unless we have a specific link in mind */
|
||||
if (filter_link_id >= 0 && link_id != filter_link_id)
|
||||
continue;
|
||||
|
||||
mvm_link_sta =
|
||||
rcu_dereference_check(mvmsta->link[link_id],
|
||||
lockdep_is_held(&mvm->mutex));
|
||||
if (!mvm_link_sta)
|
||||
continue;
|
||||
|
||||
result |= BIT(mvm_link_sta->sta_id);
|
||||
}
|
||||
|
||||
return result;
|
||||
return BIT(mvmsta->deflink.sta_id);
|
||||
}
|
||||
|
||||
static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm,
|
||||
|
|
|
|||
|
|
@ -120,7 +120,6 @@ struct iwl_mvm_time_event_data {
|
|||
* if the te is in the time event list or not (when id == TE_MAX)
|
||||
*/
|
||||
u32 id;
|
||||
s8 link_id;
|
||||
};
|
||||
|
||||
/* Power management */
|
||||
|
|
@ -380,14 +379,7 @@ struct iwl_mvm_vif_link_info {
|
|||
* @bcn_prot: beacon protection data (keys; FIXME: needs to be per link)
|
||||
* @deflink: default link data for use in non-MLO
|
||||
* @link: link data for each link in MLO
|
||||
* @esr_active: indicates eSR mode is active
|
||||
* @pm_enabled: indicates powersave is enabled
|
||||
* @link_selection_res: bitmap of active links as it was decided in the last
|
||||
* link selection. Valid only for a MLO vif after assoc. 0 if there wasn't
|
||||
* any link selection yet.
|
||||
* @link_selection_primary: primary link selected by link selection
|
||||
* @primary_link: primary link in eSR. Valid only for an associated MLD vif,
|
||||
* and in eSR mode. Valid only for a STA.
|
||||
* @roc_activity: currently running ROC activity for this vif (or
|
||||
* ROC_NUM_ACTIVITIES if no activity is running).
|
||||
* @session_prot_connection_loss: the connection was lost due to session
|
||||
|
|
@ -434,7 +426,6 @@ struct iwl_mvm_vif {
|
|||
bool ap_ibss_active;
|
||||
bool pm_enabled;
|
||||
bool monitor_active;
|
||||
bool esr_active;
|
||||
bool session_prot_connection_loss;
|
||||
|
||||
u8 low_latency: 6;
|
||||
|
|
@ -515,10 +506,6 @@ struct iwl_mvm_vif {
|
|||
|
||||
u16 max_tx_op;
|
||||
|
||||
u16 link_selection_res;
|
||||
u8 link_selection_primary;
|
||||
u8 primary_link;
|
||||
|
||||
struct iwl_mvm_vif_link_info deflink;
|
||||
struct iwl_mvm_vif_link_info *link[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
};
|
||||
|
|
@ -1619,40 +1606,6 @@ static inline bool iwl_mvm_is_ctdp_supported(struct iwl_mvm *mvm)
|
|||
IWL_UCODE_TLV_CAPA_CTDP_SUPPORT);
|
||||
}
|
||||
|
||||
static inline bool iwl_mvm_is_esr_supported(struct iwl_trans *trans)
|
||||
{
|
||||
if (CSR_HW_RFID_IS_CDB(trans->info.hw_rf_id))
|
||||
return false;
|
||||
|
||||
switch (CSR_HW_RFID_TYPE(trans->info.hw_rf_id)) {
|
||||
case IWL_CFG_RF_TYPE_FM:
|
||||
/* Step A doesn't support eSR */
|
||||
return CSR_HW_RFID_STEP(trans->info.hw_rf_id);
|
||||
case IWL_CFG_RF_TYPE_WH:
|
||||
case IWL_CFG_RF_TYPE_PE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int iwl_mvm_max_active_links(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_trans *trans = mvm->fwrt.trans;
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_AP)
|
||||
return mvm->fw->ucode_capa.num_beacons;
|
||||
|
||||
/* Check if HW supports eSR or STR */
|
||||
if (iwl_mvm_is_esr_supported(trans) ||
|
||||
(CSR_HW_RFID_TYPE(trans->info.hw_rf_id) == IWL_CFG_RF_TYPE_FM &&
|
||||
CSR_HW_RFID_IS_CDB(trans->info.hw_rf_id)))
|
||||
return IWL_FW_MAX_ACTIVE_LINKS_NUM;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
extern const u8 iwl_mvm_ac_to_tx_fifo[];
|
||||
extern const u8 iwl_mvm_ac_to_gen2_tx_fifo[];
|
||||
extern const u8 iwl_mvm_ac_to_bz_tx_fifo[];
|
||||
|
|
@ -2008,15 +1961,6 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
struct ieee80211_bss_conf *link_conf);
|
||||
|
||||
u8 iwl_mvm_get_primary_link(struct ieee80211_vif *vif);
|
||||
|
||||
struct iwl_mvm_link_sel_data {
|
||||
u8 link_id;
|
||||
const struct cfg80211_chan_def *chandef;
|
||||
s32 signal;
|
||||
u16 grade;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
|
||||
extern const struct iwl_hcmd_arr iwl_mvm_groups[];
|
||||
extern const unsigned int iwl_mvm_groups_size;
|
||||
|
|
@ -2064,7 +2008,7 @@ int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
|
|||
struct ieee80211_vif *vif);
|
||||
/*Session Protection */
|
||||
void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
u32 duration_override, unsigned int link_id);
|
||||
u32 duration_override);
|
||||
|
||||
/* Quota management */
|
||||
static inline size_t iwl_mvm_quota_cmd_size(struct iwl_mvm *mvm)
|
||||
|
|
@ -2884,8 +2828,6 @@ int iwl_mvm_roc_add_cmd(struct iwl_mvm *mvm,
|
|||
struct ieee80211_vif *vif,
|
||||
int duration, enum iwl_roc_activity activity);
|
||||
|
||||
/* EMLSR */
|
||||
bool iwl_mvm_vif_has_esr_cap(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
|
||||
void
|
||||
iwl_mvm_send_ap_tx_power_constraint_cmd(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
|
|
|
|||
|
|
@ -2254,17 +2254,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
|
|||
IWL_RX_MPDU_STATUS_STA_ID);
|
||||
|
||||
if (!WARN_ON_ONCE(sta_id >= mvm->fw->ucode_capa.num_stations)) {
|
||||
struct ieee80211_link_sta *link_sta;
|
||||
|
||||
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
link_sta = rcu_dereference(mvm->fw_id_to_link_sta[sta_id]);
|
||||
|
||||
if (sta && sta->valid_links && link_sta) {
|
||||
rx_status->link_valid = 1;
|
||||
rx_status->link_id = link_sta->link_id;
|
||||
}
|
||||
}
|
||||
} else if (!is_multicast_ether_addr(hdr->addr2)) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -2568,16 +2568,16 @@ static int iwl_mvm_scan_umac_v14_and_above(struct iwl_mvm *mvm,
|
|||
bitmap_ssid,
|
||||
version);
|
||||
return 0;
|
||||
} else {
|
||||
pb->preq = params->preq;
|
||||
}
|
||||
|
||||
cp->flags = iwl_mvm_scan_umac_chan_flags_v2(mvm, params, vif);
|
||||
cp->n_aps_override[0] = IWL_SCAN_ADWELL_N_APS_GO_FRIENDLY;
|
||||
cp->n_aps_override[1] = IWL_SCAN_ADWELL_N_APS_SOCIAL_CHS;
|
||||
pb->preq = params->preq;
|
||||
|
||||
iwl_mvm_umac_scan_fill_6g_chan_list(mvm, params, pb);
|
||||
|
||||
/* Explicitly clear the flags since most of them are not
|
||||
* relevant for 6 GHz scan.
|
||||
*/
|
||||
cp->flags = 0;
|
||||
cp->count = iwl_mvm_umac_scan_cfg_channels_v7_6g(mvm, params,
|
||||
params->n_channels,
|
||||
pb, cp, vif->type,
|
||||
|
|
@ -3023,12 +3023,8 @@ static int _iwl_mvm_single_scan_start(struct iwl_mvm *mvm,
|
|||
params.iter_notif = true;
|
||||
|
||||
params.tsf_report_link_id = req->tsf_report_link_id;
|
||||
if (params.tsf_report_link_id < 0) {
|
||||
if (vif->active_links)
|
||||
params.tsf_report_link_id = __ffs(vif->active_links);
|
||||
else
|
||||
params.tsf_report_link_id = 0;
|
||||
}
|
||||
if (params.tsf_report_link_id < 0)
|
||||
params.tsf_report_link_id = 0;
|
||||
|
||||
iwl_mvm_build_scan_probe(mvm, vif, ies, ¶ms);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
/*
|
||||
* Copyright (C) 2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2017 Intel Deutschland GmbH
|
||||
* Copyright (C) 2018-2020, 2022-2024 Intel Corporation
|
||||
* Copyright (C) 2018-2020, 2022-2025 Intel Corporation
|
||||
*/
|
||||
#include <linux/etherdevice.h>
|
||||
#include "mvm.h"
|
||||
|
|
@ -155,7 +155,7 @@ void iwl_mvm_mac_mgd_protect_tdls_discover(struct ieee80211_hw *hw,
|
|||
if (fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_SESSION_PROT_CMD))
|
||||
iwl_mvm_schedule_session_protection(mvm, vif, duration,
|
||||
duration, true, link_id);
|
||||
duration, true);
|
||||
else
|
||||
iwl_mvm_protect_session(mvm, vif, duration,
|
||||
duration, 100, true);
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@ void iwl_mvm_te_clear_data(struct iwl_mvm *mvm,
|
|||
te_data->uid = 0;
|
||||
te_data->id = TE_MAX;
|
||||
te_data->vif = NULL;
|
||||
te_data->link_id = -1;
|
||||
}
|
||||
|
||||
static void iwl_mvm_cleanup_roc(struct iwl_mvm *mvm)
|
||||
|
|
@ -721,8 +720,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
|
|||
|
||||
/* Determine whether mac or link id should be used, and validate the link id */
|
||||
static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
s8 link_id)
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
int ver = iwl_fw_lookup_cmd_ver(mvm->fw,
|
||||
|
|
@ -732,22 +730,18 @@ static int iwl_mvm_get_session_prot_id(struct iwl_mvm *mvm,
|
|||
if (ver < 2)
|
||||
return mvmvif->id;
|
||||
|
||||
if (WARN(link_id < 0 || !mvmvif->link[link_id],
|
||||
"Invalid link ID for session protection: %u\n", link_id))
|
||||
if (WARN(!mvmvif->deflink.active,
|
||||
"Session Protection on an inactive link\n"))
|
||||
return -EINVAL;
|
||||
|
||||
if (WARN(!mvmvif->link[link_id]->active,
|
||||
"Session Protection on an inactive link: %u\n", link_id))
|
||||
return -EINVAL;
|
||||
|
||||
return mvmvif->link[link_id]->fw_link_id;
|
||||
return mvmvif->deflink.fw_link_id;
|
||||
}
|
||||
|
||||
static void iwl_mvm_cancel_session_protection(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
u32 id, s8 link_id)
|
||||
u32 id)
|
||||
{
|
||||
int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, link_id);
|
||||
int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif);
|
||||
struct iwl_session_prot_cmd cmd = {
|
||||
.id_and_color = cpu_to_le32(mac_link_id),
|
||||
.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE),
|
||||
|
|
@ -791,7 +785,6 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
|
|||
struct ieee80211_vif *vif = te_data->vif;
|
||||
struct iwl_mvm_vif *mvmvif;
|
||||
enum nl80211_iftype iftype;
|
||||
s8 link_id;
|
||||
bool p2p_aux = iwl_mvm_has_p2p_over_aux(mvm);
|
||||
u8 roc_ver = iwl_fw_lookup_cmd_ver(mvm->fw,
|
||||
WIDE_ID(MAC_CONF_GROUP, ROC_CMD), 0);
|
||||
|
|
@ -811,7 +804,6 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
|
|||
/* Save time event uid before clearing its data */
|
||||
*uid = te_data->uid;
|
||||
id = te_data->id;
|
||||
link_id = te_data->link_id;
|
||||
|
||||
/*
|
||||
* The clear_data function handles time events that were already removed
|
||||
|
|
@ -837,8 +829,7 @@ static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
|
|||
*/
|
||||
if (mvmvif && id < SESSION_PROTECT_CONF_MAX_ID) {
|
||||
/* Session protection is still ongoing. Cancel it */
|
||||
iwl_mvm_cancel_session_protection(mvm, vif, id,
|
||||
link_id);
|
||||
iwl_mvm_cancel_session_protection(mvm, vif, id);
|
||||
if (iftype == NL80211_IFTYPE_P2P_DEVICE) {
|
||||
iwl_mvm_roc_finished(mvm);
|
||||
}
|
||||
|
|
@ -1007,7 +998,6 @@ void iwl_mvm_rx_session_protect_notif(struct iwl_mvm *mvm,
|
|||
if (!le32_to_cpu(notif->status) || !le32_to_cpu(notif->start)) {
|
||||
/* End TE, notify mac80211 */
|
||||
mvmvif->time_event_data.id = SESSION_PROTECT_CONF_MAX_ID;
|
||||
mvmvif->time_event_data.link_id = -1;
|
||||
/* set the bit so the ROC cleanup will actually clean up */
|
||||
set_bit(IWL_MVM_STATUS_ROC_P2P_RUNNING, &mvm->status);
|
||||
iwl_mvm_roc_finished(mvm);
|
||||
|
|
@ -1132,7 +1122,7 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm,
|
|||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_session_prot_cmd cmd = {
|
||||
.id_and_color =
|
||||
cpu_to_le32(iwl_mvm_get_session_prot_id(mvm, vif, 0)),
|
||||
cpu_to_le32(iwl_mvm_get_session_prot_id(mvm, vif)),
|
||||
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
|
||||
.duration_tu = cpu_to_le32(MSEC_TO_TU(duration)),
|
||||
};
|
||||
|
|
@ -1143,8 +1133,6 @@ iwl_mvm_start_p2p_roc_session_protection(struct iwl_mvm *mvm,
|
|||
* protection's configuration.
|
||||
*/
|
||||
|
||||
mvmvif->time_event_data.link_id = 0;
|
||||
|
||||
switch (type) {
|
||||
case IEEE80211_ROC_TYPE_NORMAL:
|
||||
mvmvif->time_event_data.id =
|
||||
|
|
@ -1290,8 +1278,7 @@ void iwl_mvm_stop_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
|
|||
return;
|
||||
}
|
||||
iwl_mvm_cancel_session_protection(mvm, vif,
|
||||
te_data->id,
|
||||
te_data->link_id);
|
||||
te_data->id);
|
||||
} else {
|
||||
iwl_mvm_remove_aux_roc_te(mvm, mvmvif,
|
||||
&mvmvif->hs_time_event_data);
|
||||
|
|
@ -1423,14 +1410,13 @@ static bool iwl_mvm_session_prot_notif(struct iwl_notif_wait_data *notif_wait,
|
|||
void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
u32 duration, u32 min_duration,
|
||||
bool wait_for_notif,
|
||||
unsigned int link_id)
|
||||
bool wait_for_notif)
|
||||
{
|
||||
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
|
||||
struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
|
||||
const u16 notif[] = { WIDE_ID(MAC_CONF_GROUP, SESSION_PROTECTION_NOTIF) };
|
||||
struct iwl_notification_wait wait_notif;
|
||||
int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif, (s8)link_id);
|
||||
int mac_link_id = iwl_mvm_get_session_prot_id(mvm, vif);
|
||||
struct iwl_session_prot_cmd cmd = {
|
||||
.id_and_color = cpu_to_le32(mac_link_id),
|
||||
.action = cpu_to_le32(FW_CTXT_ACTION_ADD),
|
||||
|
|
@ -1444,7 +1430,7 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,
|
|||
lockdep_assert_held(&mvm->mutex);
|
||||
|
||||
spin_lock_bh(&mvm->time_event_lock);
|
||||
if (te_data->running && te_data->link_id == link_id &&
|
||||
if (te_data->running &&
|
||||
time_after(te_data->end_jiffies, TU_TO_EXP_TIME(min_duration))) {
|
||||
IWL_DEBUG_TE(mvm, "We have enough time in the current TE: %u\n",
|
||||
jiffies_to_msecs(te_data->end_jiffies - jiffies));
|
||||
|
|
@ -1461,7 +1447,6 @@ void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,
|
|||
te_data->id = le32_to_cpu(cmd.conf_id);
|
||||
te_data->duration = le32_to_cpu(cmd.duration_tu);
|
||||
te_data->vif = vif;
|
||||
te_data->link_id = link_id;
|
||||
spin_unlock_bh(&mvm->time_event_lock);
|
||||
|
||||
IWL_DEBUG_TE(mvm, "Add new session protection, duration %d TU\n",
|
||||
|
|
|
|||
|
|
@ -210,13 +210,11 @@ iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data)
|
|||
* @duration: the requested duration of the protection
|
||||
* @min_duration: the minimum duration of the protection
|
||||
* @wait_for_notif: if true, will block until the start of the protection
|
||||
* @link_id: The link to schedule a session protection for
|
||||
*/
|
||||
void iwl_mvm_schedule_session_protection(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
u32 duration, u32 min_duration,
|
||||
bool wait_for_notif,
|
||||
unsigned int link_id);
|
||||
bool wait_for_notif);
|
||||
|
||||
/**
|
||||
* iwl_mvm_rx_session_protect_notif - handles %SESSION_PROTECTION_NOTIF
|
||||
|
|
|
|||
|
|
@ -817,28 +817,15 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
|
|||
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 (WARN_ON(!link))
|
||||
return -1;
|
||||
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
sta_id = link->bcast_sta.sta_id;
|
||||
sta_id = mvmvif->deflink.bcast_sta.sta_id;
|
||||
else
|
||||
sta_id = link->mcast_sta.sta_id;
|
||||
sta_id = mvmvif->deflink.mcast_sta.sta_id;
|
||||
|
||||
queue = iwl_mvm_get_ctrl_vif_queue(mvm, link, &info,
|
||||
skb);
|
||||
queue = iwl_mvm_get_ctrl_vif_queue(mvm,
|
||||
&mvmvif->deflink,
|
||||
&info, skb);
|
||||
} else if (info.control.vif->type == NL80211_IFTYPE_MONITOR) {
|
||||
queue = mvm->snif_queue;
|
||||
sta_id = mvm->snif_sta.sta_id;
|
||||
|
|
@ -895,33 +882,9 @@ unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
|
|||
*/
|
||||
val = mvmsta->max_amsdu_len;
|
||||
|
||||
if (hweight16(sta->valid_links) <= 1) {
|
||||
if (sta->valid_links) {
|
||||
struct ieee80211_bss_conf *link_conf;
|
||||
unsigned int link = ffs(sta->valid_links) - 1;
|
||||
band = mvmsta->vif->bss_conf.chanreq.oper.chan->band;
|
||||
|
||||
rcu_read_lock();
|
||||
link_conf = rcu_dereference(mvmsta->vif->link_conf[link]);
|
||||
if (WARN_ON(!link_conf))
|
||||
band = NL80211_BAND_2GHZ;
|
||||
else
|
||||
band = link_conf->chanreq.oper.chan->band;
|
||||
rcu_read_unlock();
|
||||
} else {
|
||||
band = mvmsta->vif->bss_conf.chanreq.oper.chan->band;
|
||||
}
|
||||
|
||||
lmac = iwl_mvm_get_lmac_id(mvm, band);
|
||||
} else if (fw_has_capa(&mvm->fw->ucode_capa,
|
||||
IWL_UCODE_TLV_CAPA_CDB_SUPPORT)) {
|
||||
/* for real MLO restrict to both LMACs if they exist */
|
||||
lmac = IWL_LMAC_5G_INDEX;
|
||||
val = min_t(unsigned int, val,
|
||||
mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
|
||||
lmac = IWL_LMAC_24G_INDEX;
|
||||
} else {
|
||||
lmac = IWL_LMAC_24G_INDEX;
|
||||
}
|
||||
lmac = iwl_mvm_get_lmac_id(mvm, band);
|
||||
|
||||
return min_t(unsigned int, val,
|
||||
mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
|
||||
|
|
|
|||
|
|
@ -308,10 +308,6 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
|||
smps_mode = IEEE80211_SMPS_DYNAMIC;
|
||||
}
|
||||
|
||||
/* SMPS is disabled in eSR */
|
||||
if (mvmvif->esr_active)
|
||||
smps_mode = IEEE80211_SMPS_OFF;
|
||||
|
||||
ieee80211_request_smps(vif, link_id, smps_mode);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user