mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-09 00:36:51 -04:00
Merge tag 'iwlwifi-next-2025-06-25' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next
Miri Korenblit says: ==================== iwlwifi-next - iwlwifi features Mostly cleanups. A few fixes and small features. ==================== Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
@@ -12521,7 +12521,7 @@ M: Miri Korenblit <miriam.rachel.korenblit@intel.com>
|
||||
L: linux-wireless@vger.kernel.org
|
||||
S: Supported
|
||||
W: https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
|
||||
T: git https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git/
|
||||
F: drivers/net/wireless/intel/iwlwifi/
|
||||
|
||||
INTEL WMI SLIM BOOTLOADER (SBL) FIRMWARE UPDATE DRIVER
|
||||
|
||||
@@ -97,6 +97,7 @@ config IWLWIFI_OPMODE_MODULAR
|
||||
default y if IWLDVM=m
|
||||
default y if IWLMVM=m
|
||||
default y if IWLMLD=m
|
||||
default y if IWLWIFI_KUNIT_TESTS=m
|
||||
|
||||
comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM or IWLMLD"
|
||||
depends on IWLDVM=n && IWLMVM=n && IWLMLD=n
|
||||
|
||||
@@ -7,9 +7,11 @@ iwlwifi-objs += iwl-debug.o
|
||||
iwlwifi-objs += iwl-nvm-utils.o
|
||||
iwlwifi-objs += iwl-utils.o
|
||||
iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.o
|
||||
iwlwifi-objs += pcie/drv.o pcie/rx.o pcie/tx.o pcie/trans.o
|
||||
iwlwifi-objs += pcie/ctxt-info.o pcie/ctxt-info-v2.o
|
||||
iwlwifi-objs += pcie/trans-gen2.o pcie/tx-gen2.o
|
||||
|
||||
# Bus
|
||||
iwlwifi-objs += pcie/ctxt-info.o pcie/ctxt-info-v2.o pcie/drv.o pcie/utils.o
|
||||
iwlwifi-objs += pcie/gen1_2/rx.o pcie/gen1_2/tx.o pcie/gen1_2/trans.o
|
||||
iwlwifi-objs += pcie/gen1_2/trans-gen2.o pcie/gen1_2/tx-gen2.o
|
||||
|
||||
CFLAGS_pcie/drv.o += -Wno-override-init
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define IWL_BZ_UCODE_API_MAX 99
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL_BZ_UCODE_API_MIN 93
|
||||
#define IWL_BZ_UCODE_API_MIN 94
|
||||
|
||||
/* Memory offsets and lengths */
|
||||
#define IWL_BZ_SMEM_OFFSET 0x400000
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#define IWL_DR_UCODE_API_MAX 99
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL_DR_UCODE_API_MIN 97
|
||||
#define IWL_DR_UCODE_API_MIN 98
|
||||
|
||||
/* Memory offsets and lengths */
|
||||
#define IWL_DR_SMEM_OFFSET 0x400000
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#define IWL_SC_UCODE_API_MAX 99
|
||||
|
||||
/* Lowest firmware API version supported */
|
||||
#define IWL_SC_UCODE_API_MIN 97
|
||||
#define IWL_SC_UCODE_API_MIN 98
|
||||
|
||||
/* NVM versions */
|
||||
#define IWL_SC_NVM_VERSION 0x0a1d
|
||||
|
||||
@@ -397,6 +397,8 @@ static inline void iwl_dvm_set_pmi(struct iwl_priv *priv, bool state)
|
||||
* returns a (newly allocated) struct containing all the
|
||||
* relevant values for driver use. The struct must be freed
|
||||
* later with iwl_free_nvm_data().
|
||||
*
|
||||
* Return: the parsed NVM data
|
||||
*/
|
||||
struct iwl_nvm_data *
|
||||
iwl_parse_eeprom_data(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2005-2014, 2023-2024 Intel Corporation
|
||||
* Copyright (C) 2005-2014, 2023-2025 Intel Corporation
|
||||
*/
|
||||
/*
|
||||
* Please use this file (commands.h) only for uCode API definitions.
|
||||
@@ -614,7 +614,7 @@ struct iwl_rxon_time_cmd {
|
||||
* REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response)
|
||||
*/
|
||||
/**
|
||||
* struct iwl5000_channel_switch_cmd
|
||||
* struct iwl5000_channel_switch_cmd - channel switch command (5000 series)
|
||||
* @band: 0- 5.2GHz, 1- 2.4GHz
|
||||
* @expect_beacon: 0- resume transmits after channel switch
|
||||
* 1- wait for beacon to resume transmits
|
||||
@@ -635,7 +635,7 @@ struct iwl5000_channel_switch_cmd {
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct iwl6000_channel_switch_cmd
|
||||
* struct iwl6000_channel_switch_cmd - channel switch command (6000 series)
|
||||
* @band: 0- 5.2GHz, 1- 2.4GHz
|
||||
* @expect_beacon: 0- resume transmits after channel switch
|
||||
* 1- wait for beacon to resume transmits
|
||||
@@ -791,7 +791,7 @@ struct iwl_keyinfo {
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct sta_id_modify
|
||||
* struct sta_id_modify - station modify command
|
||||
* @addr: station's MAC address
|
||||
* @reserved1: reserved for alignment
|
||||
* @sta_id: index of station in uCode's station table
|
||||
@@ -2026,7 +2026,7 @@ struct iwl_spectrum_notification {
|
||||
u8 channel;
|
||||
u8 type; /* see enum iwl_measurement_type */
|
||||
u8 reserved1;
|
||||
/* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only
|
||||
/* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only
|
||||
* valid if applicable for measurement type requested. */
|
||||
__le32 cca_ofdm; /* cca fraction time in 40Mhz clock periods */
|
||||
__le32 cca_cck; /* cca fraction time in 44Mhz clock periods */
|
||||
@@ -2992,7 +2992,7 @@ struct iwl_missed_beacon_notif {
|
||||
#define SENSITIVITY_CMD_CONTROL_WORK_TABLE cpu_to_le16(1)
|
||||
|
||||
/**
|
||||
* struct iwl_sensitivity_cmd
|
||||
* struct iwl_sensitivity_cmd - sensitivity configuration command
|
||||
* @control: (1) updates working table, (0) updates default table
|
||||
* @table: energy threshold values, use HD_* as index into table
|
||||
*
|
||||
@@ -3848,7 +3848,7 @@ struct iwlagn_wowlan_status {
|
||||
#define IWL_MIN_SLOT_TIME 20
|
||||
|
||||
/**
|
||||
* struct iwl_wipan_slot
|
||||
* struct iwl_wipan_slot - WiPAN slot configuration
|
||||
* @width: Time in TU
|
||||
* @type:
|
||||
* 0 - BSS
|
||||
@@ -3868,7 +3868,7 @@ struct iwl_wipan_slot {
|
||||
#define IWL_WIPAN_PARAMS_FLG_FULL_SLOTTED_MODE BIT(5)
|
||||
|
||||
/**
|
||||
* struct iwl_wipan_params_cmd
|
||||
* struct iwl_wipan_params_cmd - WiPAN parameters
|
||||
* @flags:
|
||||
* bit0: reserved
|
||||
* bit1: CP leave channel with CTS
|
||||
|
||||
@@ -104,7 +104,7 @@ struct iwl_qos_info {
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_agg_state
|
||||
* enum iwl_agg_state - aggregation state
|
||||
*
|
||||
* The state machine of the BA agreement establishment / tear down.
|
||||
* These states relate to a specific RA / TID.
|
||||
@@ -519,7 +519,7 @@ enum iwl_scan_type {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_hw_params
|
||||
* struct iwl_hw_params - HW parameters
|
||||
*
|
||||
* Holds the module parameters
|
||||
*
|
||||
|
||||
@@ -55,6 +55,7 @@ static void iwl1000_nic_config(struct iwl_priv *priv)
|
||||
* iwl_beacon_time_mask_low - mask of lower 32 bit of beacon time
|
||||
* @priv: pointer to iwl_priv data structure
|
||||
* @tsf_bits: number of bits need to shift for masking)
|
||||
* Return: low 32 bits of beacon time mask
|
||||
*/
|
||||
static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
|
||||
u16 tsf_bits)
|
||||
@@ -66,6 +67,7 @@ static inline u32 iwl_beacon_time_mask_low(struct iwl_priv *priv,
|
||||
* iwl_beacon_time_mask_high - mask of higher 32 bit of beacon time
|
||||
* @priv: pointer to iwl_priv data structure
|
||||
* @tsf_bits: number of bits need to shift for masking)
|
||||
* Return: high 32 bits of beacon time mask
|
||||
*/
|
||||
static inline u32 iwl_beacon_time_mask_high(struct iwl_priv *priv,
|
||||
u16 tsf_bits)
|
||||
|
||||
@@ -1049,9 +1049,11 @@ static void iwl_bg_restart(struct work_struct *data)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
static int iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
{
|
||||
priv->workqueue = alloc_ordered_workqueue(DRV_NAME, 0);
|
||||
if (!priv->workqueue)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_WORK(&priv->restart, iwl_bg_restart);
|
||||
INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
|
||||
@@ -1068,6 +1070,8 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
|
||||
timer_setup(&priv->statistics_periodic, iwl_bg_statistics_periodic, 0);
|
||||
|
||||
timer_setup(&priv->ucode_trace, iwl_bg_ucode_trace, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void iwl_cancel_deferred_work(struct iwl_priv *priv)
|
||||
@@ -1463,7 +1467,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
/********************
|
||||
* 6. Setup services
|
||||
********************/
|
||||
iwl_setup_deferred_work(priv);
|
||||
if (iwl_setup_deferred_work(priv))
|
||||
goto out_uninit_drv;
|
||||
|
||||
iwl_setup_rx_handlers(priv);
|
||||
|
||||
iwl_power_initialize(priv);
|
||||
@@ -1502,6 +1508,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
|
||||
iwl_cancel_deferred_work(priv);
|
||||
destroy_workqueue(priv->workqueue);
|
||||
priv->workqueue = NULL;
|
||||
out_uninit_drv:
|
||||
iwl_uninit_drv(priv);
|
||||
out_free_eeprom_blob:
|
||||
kfree(priv->eeprom_blob);
|
||||
|
||||
@@ -23,6 +23,4 @@ int iwl_power_set_mode(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd,
|
||||
int iwl_power_update_mode(struct iwl_priv *priv, bool force);
|
||||
void iwl_power_initialize(struct iwl_priv *priv);
|
||||
|
||||
extern bool no_sleep_autoadjust;
|
||||
|
||||
#endif /* __iwl_power_setting_h__ */
|
||||
|
||||
@@ -2899,7 +2899,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv,
|
||||
/* Repeat initial/next rate.
|
||||
* For legacy IWL_NUMBER_TRY == 1, this loop will not execute.
|
||||
* For HT IWL_HT_NUMBER_TRY == 3, this executes twice. */
|
||||
while (repeat_rate > 0 && (index < LINK_QUAL_MAX_RETRY_NUM)) {
|
||||
while (repeat_rate > 0 && index < (LINK_QUAL_MAX_RETRY_NUM - 1)) {
|
||||
if (is_legacy(tbl_type.lq_type)) {
|
||||
if (ant_toggle_cnt < NUM_TRY_BEFORE_ANT_TOGGLE)
|
||||
ant_toggle_cnt++;
|
||||
|
||||
@@ -429,7 +429,7 @@ static void iwlagn_rx_statistics(struct iwl_priv *priv,
|
||||
* thermal update even if the uCode doesn't give
|
||||
* us one */
|
||||
mod_timer(&priv->statistics_periodic, jiffies +
|
||||
msecs_to_jiffies(reg_recalib_period * 1000));
|
||||
secs_to_jiffies(reg_recalib_period));
|
||||
|
||||
if (unlikely(!test_bit(STATUS_SCANNING, &priv->status)) &&
|
||||
(pkt->hdr.cmd == STATISTICS_NOTIFICATION)) {
|
||||
|
||||
@@ -232,6 +232,8 @@ static void iwlagn_tx_cmd_build_hwcrypto(struct iwl_priv *priv,
|
||||
* that may be %NULL, for example during TX or key setup. In
|
||||
* that case, we need to use the broadcast station, so this
|
||||
* inline wraps that pattern.
|
||||
*
|
||||
* Return: station ID for mac80211 station (or broadcast if %NULL)
|
||||
*/
|
||||
static int iwl_sta_id_or_broadcast(struct iwl_rxon_context *context,
|
||||
struct ieee80211_sta *sta)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2015-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
@@ -19,9 +19,11 @@ enum iwl_d0i3_flags {
|
||||
/**
|
||||
* enum iwl_d3_wakeup_flags - D3 manager wakeup flags
|
||||
* @IWL_WAKEUP_D3_CONFIG_FW_ERROR: wake up on firmware sysassert
|
||||
* @IWL_WAKEUP_D3_HOST_TIMER: wake up on host timer expiry
|
||||
*/
|
||||
enum iwl_d3_wakeup_flags {
|
||||
IWL_WAKEUP_D3_CONFIG_FW_ERROR = BIT(0),
|
||||
IWL_WAKEUP_D3_CONFIG_FW_ERROR = BIT(0),
|
||||
IWL_WAKEUP_D3_HOST_TIMER = BIT(1),
|
||||
}; /* D3_MANAGER_WAKEUP_CONFIG_API_E_VER_3 */
|
||||
|
||||
/**
|
||||
|
||||
@@ -864,7 +864,7 @@ struct iwl_extended_beacon_notif {
|
||||
|
||||
/**
|
||||
* enum iwl_dump_control - dump (flush) control flags
|
||||
* @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the the FIFO is empty
|
||||
* @DUMP_TX_FIFO_FLUSH: Dump MSDUs until the FIFO is empty
|
||||
* and the TFD queues are empty.
|
||||
*/
|
||||
enum iwl_dump_control {
|
||||
|
||||
@@ -1106,6 +1106,7 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt,
|
||||
u32 prph_val;
|
||||
u32 dphy_state;
|
||||
u32 dphy_addr;
|
||||
u32 prph_stts;
|
||||
int i;
|
||||
|
||||
range->internal_base_addr = cpu_to_le32(addr);
|
||||
@@ -1133,6 +1134,21 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt,
|
||||
|
||||
iwl_write_prph_no_grab(fwrt->trans, indirect_wr_addr,
|
||||
WMAL_INDRCT_CMD(addr + i));
|
||||
|
||||
if (fwrt->trans->info.hw_rf_id != IWL_CFG_RF_TYPE_JF1 &&
|
||||
fwrt->trans->info.hw_rf_id != IWL_CFG_RF_TYPE_JF2 &&
|
||||
fwrt->trans->info.hw_rf_id != IWL_CFG_RF_TYPE_HR1 &&
|
||||
fwrt->trans->info.hw_rf_id != IWL_CFG_RF_TYPE_HR2) {
|
||||
udelay(2);
|
||||
prph_stts = iwl_read_prph_no_grab(fwrt->trans,
|
||||
WMAL_MRSPF_STTS);
|
||||
|
||||
/* Abort dump if status is 0xA5A5A5A2 or FIFO1 empty */
|
||||
if (prph_stts == WMAL_TIMEOUT_VAL ||
|
||||
!WMAL_MRSPF_STTS_IS_FIFO1_NOT_EMPTY(prph_stts))
|
||||
break;
|
||||
}
|
||||
|
||||
prph_val = iwl_read_prph_no_grab(fwrt->trans,
|
||||
indirect_rd_addr);
|
||||
*val++ = cpu_to_le32(prph_val);
|
||||
@@ -3008,6 +3024,7 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dump_desc *desc;
|
||||
unsigned int delay = 0;
|
||||
bool monitor_only = false;
|
||||
int ret;
|
||||
|
||||
if (trigger) {
|
||||
u16 occurrences = le16_to_cpu(trigger->occurrences) - 1;
|
||||
@@ -3038,7 +3055,11 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt,
|
||||
desc->trig_desc.type = cpu_to_le32(trig);
|
||||
memcpy(desc->trig_desc.data, str, len);
|
||||
|
||||
return iwl_fw_dbg_collect_desc(fwrt, desc, monitor_only, delay);
|
||||
ret = iwl_fw_dbg_collect_desc(fwrt, desc, monitor_only, delay);
|
||||
if (ret)
|
||||
kfree(desc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect);
|
||||
|
||||
@@ -3046,7 +3067,7 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
|
||||
struct iwl_fw_dbg_trigger_tlv *trigger,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
int ret, len = 0;
|
||||
int len = 0;
|
||||
char buf[64];
|
||||
|
||||
if (iwl_trans_dbg_ini_valid(fwrt->trans))
|
||||
@@ -3068,13 +3089,8 @@ int iwl_fw_dbg_collect_trig(struct iwl_fw_runtime *fwrt,
|
||||
len = strlen(buf) + 1;
|
||||
}
|
||||
|
||||
ret = iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len,
|
||||
trigger);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
return iwl_fw_dbg_collect(fwrt, le32_to_cpu(trigger->id), buf, len,
|
||||
trigger);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_fw_dbg_collect_trig);
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ void iwl_fw_trigger_timestamp(struct iwl_fw_runtime *fwrt, u32 delay)
|
||||
|
||||
iwl_fw_cancel_timestamp(fwrt);
|
||||
|
||||
fwrt->timestamp.delay = msecs_to_jiffies(delay * 1000);
|
||||
fwrt->timestamp.delay = secs_to_jiffies(delay);
|
||||
|
||||
schedule_delayed_work(&fwrt->timestamp.wk,
|
||||
round_jiffies_relative(fwrt->timestamp.delay));
|
||||
|
||||
@@ -53,8 +53,8 @@ struct iwl_ucode_capabilities {
|
||||
u32 num_stations;
|
||||
u32 num_links;
|
||||
u32 num_beacons;
|
||||
unsigned long _api[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_API)];
|
||||
unsigned long _capa[BITS_TO_LONGS(NUM_IWL_UCODE_TLV_CAPA)];
|
||||
DECLARE_BITMAP(_api, NUM_IWL_UCODE_TLV_API);
|
||||
DECLARE_BITMAP(_capa, NUM_IWL_UCODE_TLV_CAPA);
|
||||
|
||||
const struct iwl_fw_cmd_version *cmd_versions;
|
||||
u32 n_cmd_versions;
|
||||
|
||||
@@ -332,7 +332,7 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans,
|
||||
ret = iwl_trans_load_pnvm(trans, pnvm_data, capa);
|
||||
if (ret)
|
||||
goto free;
|
||||
IWL_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version);
|
||||
IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version);
|
||||
|
||||
set:
|
||||
iwl_trans_set_pnvm(trans, capa);
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
#define CSR_IPC_STATE_RESET_SW_READY 1
|
||||
#define CSR_IPC_STATE_RESET_TOP_READY 2
|
||||
#define CSR_IPC_STATE_RESET_TOP_FOLLOWER 3
|
||||
#define CSR_IPC_STATE_TOP_RESET_REQ BIT(6)
|
||||
|
||||
#define CSR_IPC_SLEEP_CONTROL (CSR_BASE + 0x114)
|
||||
#define CSR_IPC_SLEEP_CONTROL_SUSPEND 0x3
|
||||
|
||||
@@ -1276,8 +1276,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
|
||||
|
||||
if (tlv_len != sizeof(*fseq_ver))
|
||||
goto invalid_tlv_len;
|
||||
IWL_INFO(drv, "TLV_FW_FSEQ_VERSION: %.32s\n",
|
||||
fseq_ver->version);
|
||||
IWL_DEBUG_INFO(drv, "TLV_FW_FSEQ_VERSION: %.32s\n",
|
||||
fseq_ver->version);
|
||||
}
|
||||
break;
|
||||
case IWL_UCODE_TLV_FW_NUM_STATIONS:
|
||||
|
||||
@@ -160,23 +160,26 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = {
|
||||
* @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?)
|
||||
* @NVM_CHANNEL_VLP: client support connection to UHB VLP AP
|
||||
* @NVM_CHANNEL_AFC: client support connection to UHB AFC AP
|
||||
* @NVM_CHANNEL_VLP_AP_NOT_ALLOWED: UHB VLP AP not allowed,
|
||||
* Valid only when %NVM_CHANNEL_VLP is enabled.
|
||||
*/
|
||||
enum iwl_nvm_channel_flags {
|
||||
NVM_CHANNEL_VALID = BIT(0),
|
||||
NVM_CHANNEL_IBSS = BIT(1),
|
||||
NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY = BIT(2),
|
||||
NVM_CHANNEL_ACTIVE = BIT(3),
|
||||
NVM_CHANNEL_RADAR = BIT(4),
|
||||
NVM_CHANNEL_INDOOR_ONLY = BIT(5),
|
||||
NVM_CHANNEL_GO_CONCURRENT = BIT(6),
|
||||
NVM_CHANNEL_UNIFORM = BIT(7),
|
||||
NVM_CHANNEL_20MHZ = BIT(8),
|
||||
NVM_CHANNEL_40MHZ = BIT(9),
|
||||
NVM_CHANNEL_80MHZ = BIT(10),
|
||||
NVM_CHANNEL_160MHZ = BIT(11),
|
||||
NVM_CHANNEL_DC_HIGH = BIT(12),
|
||||
NVM_CHANNEL_VLP = BIT(13),
|
||||
NVM_CHANNEL_AFC = BIT(14),
|
||||
NVM_CHANNEL_VALID = BIT(0),
|
||||
NVM_CHANNEL_IBSS = BIT(1),
|
||||
NVM_CHANNEL_ALLOW_20MHZ_ACTIVITY = BIT(2),
|
||||
NVM_CHANNEL_ACTIVE = BIT(3),
|
||||
NVM_CHANNEL_RADAR = BIT(4),
|
||||
NVM_CHANNEL_INDOOR_ONLY = BIT(5),
|
||||
NVM_CHANNEL_GO_CONCURRENT = BIT(6),
|
||||
NVM_CHANNEL_UNIFORM = BIT(7),
|
||||
NVM_CHANNEL_20MHZ = BIT(8),
|
||||
NVM_CHANNEL_40MHZ = BIT(9),
|
||||
NVM_CHANNEL_80MHZ = BIT(10),
|
||||
NVM_CHANNEL_160MHZ = BIT(11),
|
||||
NVM_CHANNEL_DC_HIGH = BIT(12),
|
||||
NVM_CHANNEL_VLP = BIT(13),
|
||||
NVM_CHANNEL_AFC = BIT(14),
|
||||
NVM_CHANNEL_VLP_AP_NOT_ALLOWED = BIT(15),
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1044,6 +1047,7 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans,
|
||||
case IWL_CFG_RF_TYPE_GF:
|
||||
case IWL_CFG_RF_TYPE_FM:
|
||||
case IWL_CFG_RF_TYPE_WH:
|
||||
case IWL_CFG_RF_TYPE_PE:
|
||||
iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |=
|
||||
IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU;
|
||||
if (!is_ap)
|
||||
@@ -1629,8 +1633,7 @@ IWL_EXPORT_SYMBOL(iwl_parse_nvm_data);
|
||||
|
||||
static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan,
|
||||
int ch_idx, u16 nvm_flags,
|
||||
struct iwl_reg_capa reg_capa,
|
||||
const struct iwl_rf_cfg *cfg)
|
||||
struct iwl_reg_capa reg_capa)
|
||||
{
|
||||
u32 flags = NL80211_RRF_NO_HT40;
|
||||
|
||||
@@ -1685,10 +1688,12 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan,
|
||||
}
|
||||
|
||||
/* Set the AP type for the UHB case. */
|
||||
if (nvm_flags & NVM_CHANNEL_VLP)
|
||||
flags |= NL80211_RRF_ALLOW_6GHZ_VLP_AP;
|
||||
else
|
||||
if (nvm_flags & NVM_CHANNEL_VLP) {
|
||||
if (!(nvm_flags & NVM_CHANNEL_VLP_AP_NOT_ALLOWED))
|
||||
flags |= NL80211_RRF_ALLOW_6GHZ_VLP_AP;
|
||||
} else {
|
||||
flags |= NL80211_RRF_NO_6GHZ_VLP_CLIENT;
|
||||
}
|
||||
|
||||
if (!(nvm_flags & NVM_CHANNEL_AFC))
|
||||
flags |= NL80211_RRF_NO_6GHZ_AFC_CLIENT;
|
||||
@@ -1815,8 +1820,8 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
|
||||
}
|
||||
|
||||
reg_rule_flags = iwl_nvm_get_regdom_bw_flags(nvm_chan, ch_idx,
|
||||
ch_flags, reg_capa,
|
||||
cfg);
|
||||
ch_flags,
|
||||
reg_capa);
|
||||
|
||||
/* we can't continue the same rule */
|
||||
if (ch_idx == 0 || prev_reg_rule_flags != reg_rule_flags ||
|
||||
|
||||
@@ -147,6 +147,8 @@ struct iwl_fw_error_dump_mode {
|
||||
* Op_mode needs to reset its internal state because the device did not
|
||||
* survive the system state transition. The firmware is no longer running,
|
||||
* etc...
|
||||
* @dump: Op_mode needs to collect the firmware dump upon this handler
|
||||
* being called.
|
||||
*/
|
||||
struct iwl_op_mode_ops {
|
||||
struct iwl_op_mode *(*start)(struct iwl_trans *trans,
|
||||
@@ -174,6 +176,7 @@ struct iwl_op_mode_ops {
|
||||
enum iwl_fw_ini_time_point tp_id,
|
||||
union iwl_dbg_tlv_tp_data *tp_data);
|
||||
void (*device_powered_off)(struct iwl_op_mode *op_mode);
|
||||
void (*dump)(struct iwl_op_mode *op_mode);
|
||||
};
|
||||
|
||||
int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops);
|
||||
@@ -286,4 +289,11 @@ static inline void iwl_op_mode_device_powered_off(struct iwl_op_mode *op_mode)
|
||||
op_mode->ops->device_powered_off(op_mode);
|
||||
}
|
||||
|
||||
static inline void iwl_op_mode_dump(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
if (!op_mode || !op_mode->ops || !op_mode->ops->dump)
|
||||
return;
|
||||
op_mode->ops->dump(op_mode);
|
||||
}
|
||||
|
||||
#endif /* __iwl_op_mode_h__ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2005-2014, 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2005-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016 Intel Deutschland GmbH
|
||||
*/
|
||||
@@ -514,6 +514,14 @@ enum {
|
||||
#define WMAL_INDRCT_CMD(addr) \
|
||||
((WMAL_CMD_READ_BURST_ACCESS << WMAL_INDRCT_RD_CMD1_OPMOD_POS) | \
|
||||
((addr) & WMAL_INDRCT_RD_CMD1_BYTE_ADDRESS_MSK))
|
||||
#define WMAL_MRSPF_STTS 0xADFC24
|
||||
#define WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_POS 15
|
||||
#define WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_MSK 0x8000
|
||||
#define WMAL_TIMEOUT_VAL 0xA5A5A5A2
|
||||
#define WMAL_MRSPF_STTS_IS_FIFO1_NOT_EMPTY(val) \
|
||||
(((val) >> (WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_POS)) & \
|
||||
((WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_MSK) >> \
|
||||
(WMAL_MRSPF_STTS_FIFO1_NOT_EMPTY_POS)))
|
||||
|
||||
#define WFPM_LMAC1_PS_CTL_RW 0xA03380
|
||||
#define WFPM_LMAC2_PS_CTL_RW 0xA033C0
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#include "iwl-fh.h"
|
||||
#include <linux/dmapool.h>
|
||||
#include "fw/api/commands.h"
|
||||
#include "pcie/internal.h"
|
||||
#include "iwl-context-info-v2.h"
|
||||
#include "pcie/gen1_2/internal.h"
|
||||
#include "pcie/iwl-context-info-v2.h"
|
||||
|
||||
struct iwl_trans_dev_restart_data {
|
||||
struct list_head list;
|
||||
@@ -497,7 +497,19 @@ IWL_EXPORT_SYMBOL(iwl_trans_read_mem);
|
||||
int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr,
|
||||
const void *buf, int dwords)
|
||||
{
|
||||
return iwl_trans_pcie_write_mem(trans, addr, buf, dwords);
|
||||
int offs, ret = 0;
|
||||
const u32 *vals = buf;
|
||||
|
||||
if (iwl_trans_grab_nic_access(trans)) {
|
||||
iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
|
||||
for (offs = 0; offs < dwords; offs++)
|
||||
iwl_write32(trans, HBUS_TARG_MEM_WDAT,
|
||||
vals ? vals[offs] : 0);
|
||||
iwl_trans_release_nic_access(trans);
|
||||
} else {
|
||||
ret = -EBUSY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_trans_write_mem);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
*/
|
||||
#include <net/gso.h>
|
||||
#include <linux/ieee80211.h>
|
||||
@@ -82,3 +82,114 @@ int iwl_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_tx_tso_segment);
|
||||
#endif /* CONFIG_INET */
|
||||
|
||||
static u32 iwl_div_by_db(u32 value, u8 db)
|
||||
{
|
||||
/*
|
||||
* 2^32 * 10**(i / 10) for i = [1, 10], skipping 0 and simply stopping
|
||||
* at 10 dB and looping instead of using a much larger table.
|
||||
*
|
||||
* Using 64 bit math is overkill, but means the helper does not require
|
||||
* a limit on the input range.
|
||||
*/
|
||||
static const u32 db_to_val[] = {
|
||||
0xcb59185e, 0xa1866ba8, 0x804dce7a, 0x65ea59fe, 0x50f44d89,
|
||||
0x404de61f, 0x331426af, 0x2892c18b, 0x203a7e5b, 0x1999999a,
|
||||
};
|
||||
|
||||
while (value && db > 0) {
|
||||
u8 change = min_t(u8, db, ARRAY_SIZE(db_to_val));
|
||||
|
||||
value = (((u64)value) * db_to_val[change - 1]) >> 32;
|
||||
|
||||
db -= change;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len)
|
||||
{
|
||||
int average_magnitude;
|
||||
u32 average_factor;
|
||||
int sum_magnitude = -128;
|
||||
u32 sum_factor = 0;
|
||||
int i, count = 0;
|
||||
|
||||
/*
|
||||
* To properly average the decibel values (signal values given in dBm)
|
||||
* we need to do the math in linear space. Doing a linear average of
|
||||
* dB (dBm) values is a bit annoying though due to the large range of
|
||||
* at least -10 to -110 dBm that will not fit into a 32 bit integer.
|
||||
*
|
||||
* A 64 bit integer should be sufficient, but then we still have the
|
||||
* problem that there are no directly usable utility functions
|
||||
* available.
|
||||
*
|
||||
* So, lets not deal with that and instead do much of the calculation
|
||||
* with a 16.16 fixed point integer along with a base in dBm. 16.16 bit
|
||||
* gives us plenty of head-room for adding up a few values and even
|
||||
* doing some math on it. And the tail should be accurate enough too
|
||||
* (1/2^16 is somewhere around -48 dB, so effectively zero).
|
||||
*
|
||||
* i.e. the real value of sum is:
|
||||
* sum = sum_factor / 2^16 * 10^(sum_magnitude / 10) mW
|
||||
*
|
||||
* However, that does mean we need to be able to bring two values to
|
||||
* a common base, so we need a helper for that.
|
||||
*
|
||||
* Note that this function takes an input with unsigned negative dBm
|
||||
* values but returns a signed dBm (i.e. a negative value).
|
||||
*/
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int val_magnitude;
|
||||
u32 val_factor;
|
||||
|
||||
/* Assume invalid */
|
||||
if (neg_dbm_values[i] == 0xff)
|
||||
continue;
|
||||
|
||||
val_factor = 0x10000;
|
||||
val_magnitude = -neg_dbm_values[i];
|
||||
|
||||
if (val_magnitude <= sum_magnitude) {
|
||||
u8 div_db = sum_magnitude - val_magnitude;
|
||||
|
||||
val_factor = iwl_div_by_db(val_factor, div_db);
|
||||
val_magnitude = sum_magnitude;
|
||||
} else {
|
||||
u8 div_db = val_magnitude - sum_magnitude;
|
||||
|
||||
sum_factor = iwl_div_by_db(sum_factor, div_db);
|
||||
sum_magnitude = val_magnitude;
|
||||
}
|
||||
|
||||
sum_factor += val_factor;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* No valid noise measurement, return a very high noise level */
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
average_magnitude = sum_magnitude;
|
||||
average_factor = sum_factor / count;
|
||||
|
||||
/*
|
||||
* average_factor will be a number smaller than 1.0 (0x10000) at this
|
||||
* point. What we need to do now is to adjust average_magnitude so that
|
||||
* average_factor is between -0.5 dB and 0.5 dB.
|
||||
*
|
||||
* Just do -1 dB steps and find the point where
|
||||
* -0.5 dB * -i dB = 0x10000 * 10^(-0.5/10) / i dB
|
||||
* = div_by_db(0xe429, i)
|
||||
* is smaller than average_factor.
|
||||
*/
|
||||
for (i = 0; average_factor < iwl_div_by_db(0xe429, i); i++) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
return clamp(average_magnitude - i, -128, 0);
|
||||
}
|
||||
IWL_EXPORT_SYMBOL(iwl_average_neg_dbm);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
*/
|
||||
#ifndef __iwl_utils_h__
|
||||
#define __iwl_utils_h__
|
||||
@@ -53,4 +53,6 @@ u32 iwl_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)
|
||||
return ie - beacon;
|
||||
}
|
||||
|
||||
s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len);
|
||||
|
||||
#endif /* __iwl_utils_h__ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2021 - 2022 Intel Corporation
|
||||
* Copyright (C) 2021 - 2022, 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __sap_h__
|
||||
@@ -340,12 +340,12 @@ enum iwl_sap_wifi_auth_type {
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_sap_wifi_cipher_alg
|
||||
* @SAP_WIFI_CIPHER_ALG_NONE: TBD
|
||||
* @SAP_WIFI_CIPHER_ALG_TKIP: TBD
|
||||
* @SAP_WIFI_CIPHER_ALG_CCMP: TBD
|
||||
* @SAP_WIFI_CIPHER_ALG_GCMP: TBD
|
||||
* @SAP_WIFI_CIPHER_ALG_GCMP_256: TBD
|
||||
* enum iwl_sap_wifi_cipher_alg - MEI WiFi cipher algorithm IDs
|
||||
* @SAP_WIFI_CIPHER_ALG_NONE: No encryption
|
||||
* @SAP_WIFI_CIPHER_ALG_TKIP: TKIPO
|
||||
* @SAP_WIFI_CIPHER_ALG_CCMP: CCMP
|
||||
* @SAP_WIFI_CIPHER_ALG_GCMP: GCMP-128
|
||||
* @SAP_WIFI_CIPHER_ALG_GCMP_256: GCMP-256
|
||||
*/
|
||||
enum iwl_sap_wifi_cipher_alg {
|
||||
SAP_WIFI_CIPHER_ALG_NONE = IWL_MEI_CIPHER_NONE,
|
||||
@@ -601,7 +601,7 @@ enum iwl_sap_flex_filter_flags {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_sap_flex_filter -
|
||||
* struct iwl_sap_flex_filter - filter configuration
|
||||
* @src_port: Source port in network format.
|
||||
* @dst_port: Destination port in network format.
|
||||
* @flags: Flags and protocol, see &enum iwl_sap_flex_filter_flags.
|
||||
@@ -633,7 +633,7 @@ enum iwl_sap_ipv4_filter_flags {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_sap_ipv4_filter-
|
||||
* struct iwl_sap_ipv4_filter - IPv4 filter configuration
|
||||
* @ipv4_addr: The IP address to filer.
|
||||
* @flags: See &enum iwl_sap_ipv4_filter_flags.
|
||||
*/
|
||||
@@ -643,7 +643,7 @@ struct iwl_sap_ipv4_filter {
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum iwl_sap_ipv6_filter_flags -
|
||||
* enum iwl_sap_ipv6_filter_flags - IPv6 filter flags
|
||||
* @SAP_IPV6_ADDR_FILTER_COPY: Pass packets to the host.
|
||||
* @SAP_IPV6_ADDR_FILTER_ENABLED: If false, the filter should be ignored.
|
||||
*/
|
||||
@@ -653,7 +653,7 @@ enum iwl_sap_ipv6_filter_flags {
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iwl_sap_ipv6_filter -
|
||||
* struct iwl_sap_ipv6_filter - IPv6 filter configuration
|
||||
* @addr_lo24: Lowest 24 bits of the IPv6 address.
|
||||
* @flags: See &enum iwl_sap_ipv6_filter_flags.
|
||||
*/
|
||||
@@ -663,7 +663,7 @@ struct iwl_sap_ipv6_filter {
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum iwl_sap_icmpv6_filter_flags -
|
||||
* enum iwl_sap_icmpv6_filter_flags - ICMPv6 filter flags
|
||||
* @SAP_ICMPV6_FILTER_ENABLED: If false, the filter should be ignored.
|
||||
* @SAP_ICMPV6_FILTER_COPY: Pass packets to the host.
|
||||
*/
|
||||
@@ -673,8 +673,8 @@ enum iwl_sap_icmpv6_filter_flags {
|
||||
};
|
||||
|
||||
/**
|
||||
* enum iwl_sap_vlan_filter_flags -
|
||||
* @SAP_VLAN_FILTER_VLAN_ID_MSK: TBD
|
||||
* enum iwl_sap_vlan_filter_flags - VLAN filter flags
|
||||
* @SAP_VLAN_FILTER_VLAN_ID_MSK: VLAN ID
|
||||
* @SAP_VLAN_FILTER_ENABLED: If false, the filter should be ignored.
|
||||
*/
|
||||
enum iwl_sap_vlan_filter_flags {
|
||||
@@ -751,7 +751,7 @@ struct iwl_sap_pldr_data {
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* enum iwl_sap_pldr_status -
|
||||
* enum iwl_sap_pldr_status - product reset status
|
||||
* @SAP_PLDR_STATUS_SUCCESS: PLDR started/ended successfully
|
||||
* @SAP_PLDR_STATUS_FAILURE: PLDR failed to start/end
|
||||
*/
|
||||
|
||||
@@ -9,8 +9,4 @@ iwlmld-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o
|
||||
iwlmld-$(CONFIG_IWLWIFI_LEDS) += led.o
|
||||
iwlmld-$(CONFIG_PM_SLEEP) += d3.o
|
||||
|
||||
# non-upstream things
|
||||
iwlmld-$(CONFIG_IWL_VENDOR_CMDS) += vendor-cmd.o
|
||||
iwlmld-$(CONFIG_IWLMVM_AX_SOFTAP_TESTMODE) += ax-softap-testmode.o
|
||||
|
||||
subdir-ccflags-y += -I$(src)/../
|
||||
|
||||
@@ -204,66 +204,6 @@ void iwl_mld_ipv6_addr_change(struct ieee80211_hw *hw,
|
||||
}
|
||||
#endif
|
||||
|
||||
enum rt_status {
|
||||
FW_ALIVE,
|
||||
FW_NEEDS_RESET,
|
||||
FW_ERROR,
|
||||
};
|
||||
|
||||
static enum rt_status iwl_mld_check_err_tables(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
u32 err_id;
|
||||
|
||||
/* check for lmac1 error */
|
||||
if (iwl_fwrt_read_err_table(mld->trans,
|
||||
mld->trans->dbg.lmac_error_event_table[0],
|
||||
&err_id)) {
|
||||
if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) {
|
||||
struct cfg80211_wowlan_wakeup wakeup = {
|
||||
.rfkill_release = true,
|
||||
};
|
||||
ieee80211_report_wowlan_wakeup(vif, &wakeup,
|
||||
GFP_KERNEL);
|
||||
|
||||
return FW_NEEDS_RESET;
|
||||
}
|
||||
return FW_ERROR;
|
||||
}
|
||||
|
||||
/* check if we have lmac2 set and check for error */
|
||||
if (iwl_fwrt_read_err_table(mld->trans,
|
||||
mld->trans->dbg.lmac_error_event_table[1],
|
||||
NULL))
|
||||
return FW_ERROR;
|
||||
|
||||
/* check for umac error */
|
||||
if (iwl_fwrt_read_err_table(mld->trans,
|
||||
mld->trans->dbg.umac_error_event_table,
|
||||
NULL))
|
||||
return FW_ERROR;
|
||||
|
||||
return FW_ALIVE;
|
||||
}
|
||||
|
||||
static bool iwl_mld_fw_needs_restart(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
enum rt_status rt_status = iwl_mld_check_err_tables(mld, vif);
|
||||
|
||||
if (rt_status == FW_ALIVE)
|
||||
return false;
|
||||
|
||||
if (rt_status == FW_ERROR) {
|
||||
IWL_ERR(mld, "FW Error occurred during suspend\n");
|
||||
iwl_fwrt_dump_error_logs(&mld->fwrt);
|
||||
iwl_dbg_tlv_time_point(&mld->fwrt,
|
||||
IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
iwl_mld_netdetect_config(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif,
|
||||
@@ -928,7 +868,7 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
static void
|
||||
iwl_mld_add_all_rekeys(struct ieee80211_vif *vif,
|
||||
struct iwl_mld_wowlan_status *wowlan_status,
|
||||
struct iwl_mld_resume_key_iter_data *key_iter_data,
|
||||
@@ -941,21 +881,19 @@ iwl_mld_add_all_rekeys(struct ieee80211_vif *vif,
|
||||
&wowlan_status->gtk[i],
|
||||
link_conf,
|
||||
key_iter_data->gtk_cipher))
|
||||
return false;
|
||||
return;
|
||||
|
||||
if (!iwl_mld_add_mcast_rekey(vif, key_iter_data->mld,
|
||||
&wowlan_status->igtk,
|
||||
link_conf, key_iter_data->igtk_cipher))
|
||||
return false;
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wowlan_status->bigtk); i++)
|
||||
if (!iwl_mld_add_mcast_rekey(vif, key_iter_data->mld,
|
||||
&wowlan_status->bigtk[i],
|
||||
link_conf,
|
||||
key_iter_data->bigtk_cipher))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
static bool
|
||||
@@ -1317,6 +1255,13 @@ int iwl_mld_no_wowlan_suspend(struct iwl_mld *mld)
|
||||
struct iwl_d3_manager_config d3_cfg_cmd_data = {};
|
||||
int ret;
|
||||
|
||||
if (mld->debug_max_sleep) {
|
||||
d3_cfg_cmd_data.wakeup_host_timer =
|
||||
cpu_to_le32(mld->debug_max_sleep);
|
||||
d3_cfg_cmd_data.wakeup_flags =
|
||||
cpu_to_le32(IWL_WAKEUP_D3_HOST_TIMER);
|
||||
}
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
IWL_DEBUG_WOWLAN(mld, "Starting the no wowlan suspend flow\n");
|
||||
@@ -1376,10 +1321,7 @@ int iwl_mld_no_wowlan_resume(struct iwl_mld *mld)
|
||||
mld->fw_status.in_d3 = false;
|
||||
iwl_fw_dbg_read_d3_debug_data(&mld->fwrt);
|
||||
|
||||
if (iwl_mld_fw_needs_restart(mld, NULL))
|
||||
ret = -ENODEV;
|
||||
else
|
||||
ret = iwl_mld_wait_d3_notif(mld, &resume_data, false);
|
||||
ret = iwl_mld_wait_d3_notif(mld, &resume_data, false);
|
||||
|
||||
if (!ret && (resume_data.d3_end_flags & IWL_D0I3_RESET_REQUIRE))
|
||||
return -ENODEV;
|
||||
@@ -1928,15 +1870,10 @@ int iwl_mld_wowlan_resume(struct iwl_mld *mld)
|
||||
|
||||
iwl_fw_dbg_read_d3_debug_data(&mld->fwrt);
|
||||
|
||||
if (iwl_mld_fw_needs_restart(mld, bss_vif)) {
|
||||
fw_err = true;
|
||||
goto err;
|
||||
}
|
||||
|
||||
resume_data.wowlan_status = kzalloc(sizeof(*resume_data.wowlan_status),
|
||||
GFP_KERNEL);
|
||||
if (!resume_data.wowlan_status)
|
||||
return -1;
|
||||
return -ENOMEM;
|
||||
|
||||
if (mld->netdetect)
|
||||
resume_data.notifs_expected |= IWL_D3_ND_MATCH_INFO;
|
||||
|
||||
@@ -546,6 +546,11 @@ iwl_mld_add_debugfs_files(struct iwl_mld *mld, struct dentry *debugfs_dir)
|
||||
#endif
|
||||
MLD_DEBUGFS_ADD_FILE(inject_packet, debugfs_dir, 0200);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
debugfs_create_u32("max_sleep", 0600, debugfs_dir,
|
||||
&mld->debug_max_sleep);
|
||||
#endif
|
||||
|
||||
debugfs_create_bool("rx_ts_ptp", 0600, debugfs_dir,
|
||||
&mld->monitor.ptp_time);
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ iwl_mld_ftm_set_target_chandef(struct iwl_mld *mld,
|
||||
IWL_ERR(mld, "Unsupported BW in FTM request (%d)\n",
|
||||
peer->chandef.width);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/* non EDCA based measurement must use HE preamble */
|
||||
if (peer->ftm.trigger_based || peer->ftm.non_trigger_based)
|
||||
|
||||
@@ -55,6 +55,8 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
|
||||
|
||||
ieee80211_iter_keys(mld->hw, vif, iwl_mld_cleanup_keys_iter, NULL);
|
||||
|
||||
wiphy_delayed_work_cancel(mld->wiphy, &mld_vif->mlo_scan_start_wk);
|
||||
|
||||
CLEANUP_STRUCT(mld_vif);
|
||||
}
|
||||
|
||||
@@ -385,6 +387,17 @@ int iwl_mld_mac_fw_action(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
return iwl_mld_send_mac_cmd(mld, &cmd);
|
||||
}
|
||||
|
||||
static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy,
|
||||
struct wiphy_work *wk)
|
||||
{
|
||||
struct iwl_mld_vif *mld_vif = container_of(wk, struct iwl_mld_vif,
|
||||
mlo_scan_start_wk.work);
|
||||
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
|
||||
iwl_mld_int_mlo_scan(mld, iwl_mld_vif_to_mac80211(mld_vif));
|
||||
}
|
||||
|
||||
IWL_MLD_ALLOC_FN(vif, vif)
|
||||
|
||||
/* Constructor function for struct iwl_mld_vif */
|
||||
@@ -412,6 +425,8 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
||||
iwl_mld_emlsr_prevent_done_wk);
|
||||
wiphy_delayed_work_init(&mld_vif->emlsr.tmp_non_bss_done_wk,
|
||||
iwl_mld_emlsr_tmp_non_bss_done_wk);
|
||||
wiphy_delayed_work_init(&mld_vif->mlo_scan_start_wk,
|
||||
iwl_mld_mlo_scan_start_wk);
|
||||
}
|
||||
iwl_mld_init_internal_sta(&mld_vif->aux_sta);
|
||||
|
||||
|
||||
@@ -87,6 +87,8 @@ enum iwl_mld_emlsr_exit {
|
||||
* @last_exit_reason: Reason for the last EMLSR exit
|
||||
* @last_exit_ts: Time of the last EMLSR exit (if @last_exit_reason is non-zero)
|
||||
* @exit_repeat_count: Number of times EMLSR was exited for the same reason
|
||||
* @last_entry_ts: the time of the last EMLSR entry (if iwl_mld_emlsr_active()
|
||||
* is true)
|
||||
* @unblock_tpt_wk: Unblock EMLSR because the throughput limit was reached
|
||||
* @check_tpt_wk: a worker to check if IWL_MLD_EMLSR_BLOCKED_TPT should be
|
||||
* added, for example if there is no longer enough traffic.
|
||||
@@ -105,6 +107,7 @@ struct iwl_mld_emlsr {
|
||||
enum iwl_mld_emlsr_exit last_exit_reason;
|
||||
unsigned long last_exit_ts;
|
||||
u8 exit_repeat_count;
|
||||
unsigned long last_entry_ts;
|
||||
);
|
||||
|
||||
struct wiphy_work unblock_tpt_wk;
|
||||
@@ -133,6 +136,8 @@ struct iwl_mld_emlsr {
|
||||
* @low_latency_causes: bit flags, indicating the causes for low-latency,
|
||||
* see @iwl_mld_low_latency_cause.
|
||||
* @ps_disabled: indicates that PS is disabled for this interface
|
||||
* @last_link_activation_time: last time a link was activated, for
|
||||
* deferring MLO scans (to make them more reliable)
|
||||
* @mld: pointer to the mld structure.
|
||||
* @deflink: default link data, for use in non-MLO,
|
||||
* @link: reference to link data for each valid link, for use in MLO.
|
||||
@@ -144,6 +149,7 @@ struct iwl_mld_emlsr {
|
||||
* @roc_activity: the id of the roc_activity running. Relevant for STA and
|
||||
* p2p device only. Set to %ROC_NUM_ACTIVITIES when not in use.
|
||||
* @aux_sta: station used for remain on channel. Used in P2P device.
|
||||
* @mlo_scan_start_wk: worker to start a deferred MLO scan
|
||||
*/
|
||||
struct iwl_mld_vif {
|
||||
/* Add here fields that need clean up on restart */
|
||||
@@ -161,6 +167,7 @@ struct iwl_mld_vif {
|
||||
#endif
|
||||
u8 low_latency_causes;
|
||||
bool ps_disabled;
|
||||
time64_t last_link_activation_time;
|
||||
);
|
||||
/* And here fields that survive a fw restart */
|
||||
struct iwl_mld *mld;
|
||||
@@ -179,6 +186,8 @@ struct iwl_mld_vif {
|
||||
#endif
|
||||
enum iwl_roc_activity roc_activity;
|
||||
struct iwl_mld_int_sta aux_sta;
|
||||
|
||||
struct wiphy_delayed_work mlo_scan_start_wk;
|
||||
};
|
||||
|
||||
static inline struct iwl_mld_vif *
|
||||
@@ -187,6 +196,12 @@ iwl_mld_vif_from_mac80211(struct ieee80211_vif *vif)
|
||||
return (void *)vif->drv_priv;
|
||||
}
|
||||
|
||||
static inline struct ieee80211_vif *
|
||||
iwl_mld_vif_to_mac80211(struct iwl_mld_vif *mld_vif)
|
||||
{
|
||||
return container_of((void *)mld_vif, struct ieee80211_vif, drv_priv);
|
||||
}
|
||||
|
||||
#define iwl_mld_link_dereference_check(mld_vif, link_id) \
|
||||
rcu_dereference_check((mld_vif)->link[link_id], \
|
||||
lockdep_is_held(&mld_vif->mld->wiphy->mtx))
|
||||
|
||||
@@ -404,6 +404,7 @@ int iwl_mld_activate_link(struct iwl_mld *mld,
|
||||
struct ieee80211_bss_conf *link)
|
||||
{
|
||||
struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(mld_link->vif);
|
||||
int ret;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
@@ -418,6 +419,9 @@ int iwl_mld_activate_link(struct iwl_mld *mld,
|
||||
LINK_CONTEXT_MODIFY_ACTIVE);
|
||||
if (ret)
|
||||
mld_link->active = false;
|
||||
else
|
||||
mld_vif->last_link_activation_time =
|
||||
ktime_get_boottime_seconds();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -508,8 +508,15 @@ int iwl_mld_mac80211_start(struct ieee80211_hw *hw)
|
||||
if (in_d3) {
|
||||
/* mac80211 already cleaned up the state, no need for cleanup */
|
||||
ret = iwl_mld_no_wowlan_resume(mld);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
iwl_mld_stop_fw(mld);
|
||||
/* We're not really restarting in the sense of
|
||||
* in_hw_restart even if we got an error during
|
||||
* this. We'll just start again below and have
|
||||
* nothing to recover, mac80211 will do anyway.
|
||||
*/
|
||||
mld->fw_status.in_hw_restart = false;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
@@ -1003,6 +1010,7 @@ int iwl_mld_assign_vif_chanctx(struct ieee80211_hw *hw,
|
||||
|
||||
/* 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))
|
||||
mld_vif->emlsr.primary = mld_vif->emlsr.selected_primary;
|
||||
@@ -1470,7 +1478,7 @@ void iwl_mld_mac80211_mgd_prepare_tx(struct ieee80211_hw *hw,
|
||||
struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
|
||||
u32 duration = IWL_MLD_SESSION_PROTECTION_ASSOC_TIME_MS;
|
||||
|
||||
/* After a successful association the connection is etalibeshed
|
||||
/* After a successful association the connection is established
|
||||
* and we can rely on the quota to send the disassociation frame.
|
||||
*/
|
||||
if (info->was_assoc)
|
||||
@@ -2575,28 +2583,6 @@ static int iwl_mld_mac80211_tx_last_beacon(struct ieee80211_hw *hw)
|
||||
return mld->ibss_manager;
|
||||
}
|
||||
|
||||
#define IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS_TIMEOUT (5 * HZ)
|
||||
|
||||
static void iwl_mld_vif_iter_emlsr_block_tmp_non_bss(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
int ret;
|
||||
|
||||
if (!iwl_mld_vif_has_emlsr_cap(vif))
|
||||
return;
|
||||
|
||||
ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif,
|
||||
IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS,
|
||||
iwl_mld_get_primary_link(vif));
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
wiphy_delayed_work_queue(mld_vif->mld->wiphy,
|
||||
&mld_vif->emlsr.tmp_non_bss_done_wk,
|
||||
IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS_TIMEOUT);
|
||||
}
|
||||
|
||||
static void iwl_mld_prep_add_interface(struct ieee80211_hw *hw,
|
||||
enum nl80211_iftype type)
|
||||
{
|
||||
@@ -2609,10 +2595,7 @@ static void iwl_mld_prep_add_interface(struct ieee80211_hw *hw,
|
||||
type == NL80211_IFTYPE_P2P_CLIENT))
|
||||
return;
|
||||
|
||||
ieee80211_iterate_active_interfaces_mtx(mld->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mld_vif_iter_emlsr_block_tmp_non_bss,
|
||||
NULL);
|
||||
iwl_mld_emlsr_block_tmp_non_bss(mld);
|
||||
}
|
||||
|
||||
static int iwl_mld_set_hw_timestamp(struct ieee80211_hw *hw,
|
||||
@@ -2642,6 +2625,23 @@ static int iwl_mld_start_pmsr(struct ieee80211_hw *hw,
|
||||
return iwl_mld_ftm_start(mld, vif, request);
|
||||
}
|
||||
|
||||
static enum ieee80211_neg_ttlm_res
|
||||
iwl_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_neg_ttlm *neg_ttlm)
|
||||
{
|
||||
u16 map;
|
||||
|
||||
/* Verify all TIDs are mapped to the same links set */
|
||||
map = neg_ttlm->downlink[0];
|
||||
for (int i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) {
|
||||
if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] ||
|
||||
neg_ttlm->uplink[i] != map)
|
||||
return NEG_TTLM_RES_REJECT;
|
||||
}
|
||||
|
||||
return NEG_TTLM_RES_ACCEPT;
|
||||
}
|
||||
|
||||
const struct ieee80211_ops iwl_mld_hw_ops = {
|
||||
.tx = iwl_mld_mac80211_tx,
|
||||
.start = iwl_mld_mac80211_start,
|
||||
@@ -2711,4 +2711,5 @@ const struct ieee80211_ops iwl_mld_hw_ops = {
|
||||
.prep_add_interface = iwl_mld_prep_add_interface,
|
||||
.set_hw_timestamp = iwl_mld_set_hw_timestamp,
|
||||
.start_pmsr = iwl_mld_start_pmsr,
|
||||
.can_neg_ttlm = iwl_mld_can_neg_ttlm,
|
||||
};
|
||||
|
||||
@@ -357,7 +357,7 @@ iwl_mld_configure_trans(struct iwl_op_mode *op_mode)
|
||||
trans->conf.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
|
||||
|
||||
trans->conf.rx_mpdu_cmd = REPLY_RX_MPDU_CMD;
|
||||
trans->conf.rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_res_start);
|
||||
trans->conf.rx_mpdu_cmd_hdr_size = sizeof(struct iwl_rx_mpdu_desc);
|
||||
trans->conf.wide_cmd_header = true;
|
||||
|
||||
iwl_trans_op_mode_enter(trans, op_mode);
|
||||
@@ -725,6 +725,17 @@ static void iwl_mld_device_powered_off(struct iwl_op_mode *op_mode)
|
||||
{}
|
||||
#endif
|
||||
|
||||
static void iwl_mld_dump(struct iwl_op_mode *op_mode)
|
||||
{
|
||||
struct iwl_mld *mld = IWL_OP_MODE_GET_MLD(op_mode);
|
||||
struct iwl_fw_runtime *fwrt = &mld->fwrt;
|
||||
|
||||
if (!iwl_trans_fw_running(fwrt->trans))
|
||||
return;
|
||||
|
||||
iwl_dbg_tlv_time_point(fwrt, IWL_FW_INI_TIME_POINT_USER_TRIGGER, NULL);
|
||||
}
|
||||
|
||||
static const struct iwl_op_mode_ops iwl_mld_ops = {
|
||||
.start = iwl_op_mode_mld_start,
|
||||
.stop = iwl_op_mode_mld_stop,
|
||||
@@ -739,6 +750,7 @@ static const struct iwl_op_mode_ops iwl_mld_ops = {
|
||||
.sw_reset = iwl_mld_sw_reset,
|
||||
.time_point = iwl_mld_time_point,
|
||||
.device_powered_off = pm_sleep_ptr(iwl_mld_device_powered_off),
|
||||
.dump = iwl_mld_dump,
|
||||
};
|
||||
|
||||
struct iwl_mld_mod_params iwlmld_mod_params = {
|
||||
|
||||
@@ -159,6 +159,7 @@
|
||||
* @addresses: device MAC addresses.
|
||||
* @scan: instance of the scan object
|
||||
* @wowlan: WoWLAN support data.
|
||||
* @debug_max_sleep: maximum sleep time in D3 (for debug purposes)
|
||||
* @led: the led device
|
||||
* @mcc_src: the source id of the MCC, comes from the firmware
|
||||
* @bios_enable_puncturing: is puncturing enabled by bios
|
||||
@@ -252,6 +253,7 @@ struct iwl_mld {
|
||||
struct iwl_mld_scan scan;
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
struct wiphy_wowlan_support wowlan;
|
||||
u32 debug_max_sleep;
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
#ifdef CONFIG_IWLWIFI_LEDS
|
||||
struct led_classdev led;
|
||||
|
||||
@@ -287,6 +287,36 @@ int iwl_mld_block_emlsr_sync(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
return _iwl_mld_emlsr_block(mld, vif, reason, link_to_keep, true);
|
||||
}
|
||||
|
||||
#define IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS_TIMEOUT (10 * HZ)
|
||||
|
||||
static void iwl_mld_vif_iter_emlsr_block_tmp_non_bss(void *_data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
int ret;
|
||||
|
||||
if (!iwl_mld_vif_has_emlsr_cap(vif))
|
||||
return;
|
||||
|
||||
ret = iwl_mld_block_emlsr_sync(mld_vif->mld, vif,
|
||||
IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS,
|
||||
iwl_mld_get_primary_link(vif));
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
wiphy_delayed_work_queue(mld_vif->mld->wiphy,
|
||||
&mld_vif->emlsr.tmp_non_bss_done_wk,
|
||||
IWL_MLD_EMLSR_BLOCKED_TMP_NON_BSS_TIMEOUT);
|
||||
}
|
||||
|
||||
void iwl_mld_emlsr_block_tmp_non_bss(struct iwl_mld *mld)
|
||||
{
|
||||
ieee80211_iterate_active_interfaces_mtx(mld->hw,
|
||||
IEEE80211_IFACE_ITER_NORMAL,
|
||||
iwl_mld_vif_iter_emlsr_block_tmp_non_bss,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void _iwl_mld_select_links(struct iwl_mld *mld,
|
||||
struct ieee80211_vif *vif);
|
||||
|
||||
@@ -530,10 +560,12 @@ void iwl_mld_emlsr_check_tpt(struct wiphy *wiphy, struct wiphy_work *wk)
|
||||
/*
|
||||
* TPT is unblocked, need to check if the TPT criteria is still met.
|
||||
*
|
||||
* If EMLSR is active, then we also need to check the secondar link
|
||||
* requirements.
|
||||
* If EMLSR is active for at least 5 seconds, then we also
|
||||
* need to check the secondary link requirements.
|
||||
*/
|
||||
if (iwl_mld_emlsr_active(vif)) {
|
||||
if (iwl_mld_emlsr_active(vif) &&
|
||||
time_is_before_jiffies(mld_vif->emlsr.last_entry_ts +
|
||||
IWL_MLD_TPT_COUNT_WINDOW)) {
|
||||
sec_link_id = iwl_mld_get_other_link(vif, iwl_mld_get_primary_link(vif));
|
||||
sec_link = iwl_mld_link_dereference_check(mld_vif, sec_link_id);
|
||||
if (WARN_ON_ONCE(!sec_link))
|
||||
@@ -1167,8 +1199,8 @@ void iwl_mld_retry_emlsr(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
|
||||
if (!iwl_mld_vif_has_emlsr_cap(vif) || iwl_mld_emlsr_active(vif) ||
|
||||
mld_vif->emlsr.blocked_reasons)
|
||||
if (!IWL_MLD_AUTO_EML_ENABLE || !iwl_mld_vif_has_emlsr_cap(vif) ||
|
||||
iwl_mld_emlsr_active(vif) || mld_vif->emlsr.blocked_reasons)
|
||||
return;
|
||||
|
||||
iwl_mld_int_mlo_scan(mld, vif);
|
||||
|
||||
@@ -157,6 +157,8 @@ struct iwl_mld_link_sel_data {
|
||||
u16 grade;
|
||||
};
|
||||
|
||||
void iwl_mld_emlsr_block_tmp_non_bss(struct iwl_mld *mld);
|
||||
|
||||
#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS)
|
||||
u32 iwl_mld_emlsr_pair_state(struct ieee80211_vif *vif,
|
||||
struct iwl_mld_link_sel_data *a,
|
||||
|
||||
@@ -181,7 +181,7 @@ int iwl_mld_send_phy_cfg_cmd(struct iwl_mld *mld)
|
||||
.phy_specific_cfg = mld->fwrt.phy_filters,
|
||||
};
|
||||
|
||||
IWL_INFO(mld, "Sending Phy CFG command: 0x%x\n", cmd.phy_cfg);
|
||||
IWL_DEBUG_INFO(mld, "Sending Phy CFG command: 0x%x\n", cmd.phy_cfg);
|
||||
|
||||
return iwl_mld_send_cmd_pdu(mld, PHY_CONFIGURATION_CMD, &cmd);
|
||||
}
|
||||
|
||||
@@ -1752,6 +1752,10 @@ int iwl_mld_regular_scan_start(struct iwl_mld *mld, struct ieee80211_vif *vif,
|
||||
struct cfg80211_scan_request *req,
|
||||
struct ieee80211_scan_ies *ies)
|
||||
{
|
||||
|
||||
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
|
||||
iwl_mld_emlsr_block_tmp_non_bss(mld);
|
||||
|
||||
return _iwl_mld_single_scan_start(mld, vif, req, ies,
|
||||
IWL_MLD_SCAN_REGULAR);
|
||||
}
|
||||
@@ -1800,17 +1804,20 @@ static void iwl_mld_int_mlo_scan_start(struct iwl_mld *mld,
|
||||
IWL_DEBUG_SCAN(mld, "Internal MLO scan: ret=%d\n", ret);
|
||||
}
|
||||
|
||||
#define IWL_MLD_MLO_SCAN_BLOCKOUT_TIME 5 /* seconds */
|
||||
|
||||
void iwl_mld_int_mlo_scan(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ieee80211_channel *channels[IEEE80211_MLD_MAX_NUM_LINKS];
|
||||
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
|
||||
unsigned long usable_links = ieee80211_vif_usable_links(vif);
|
||||
size_t n_channels = 0;
|
||||
u8 link_id;
|
||||
|
||||
lockdep_assert_wiphy(mld->wiphy);
|
||||
|
||||
if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif) ||
|
||||
hweight16(vif->valid_links) == 1)
|
||||
if (!IWL_MLD_AUTO_EML_ENABLE || !vif->cfg.assoc ||
|
||||
!ieee80211_vif_is_mld(vif) || hweight16(vif->valid_links) == 1)
|
||||
return;
|
||||
|
||||
if (mld->scan.status & IWL_MLD_SCAN_INT_MLO) {
|
||||
@@ -1818,6 +1825,15 @@ void iwl_mld_int_mlo_scan(struct iwl_mld *mld, struct ieee80211_vif *vif)
|
||||
return;
|
||||
}
|
||||
|
||||
if (mld_vif->last_link_activation_time > ktime_get_boottime_seconds() -
|
||||
IWL_MLD_MLO_SCAN_BLOCKOUT_TIME) {
|
||||
/* timing doesn't matter much, so use the blockout time */
|
||||
wiphy_delayed_work_queue(mld->wiphy,
|
||||
&mld_vif->mlo_scan_start_wk,
|
||||
IWL_MLD_MLO_SCAN_BLOCKOUT_TIME);
|
||||
return;
|
||||
}
|
||||
|
||||
for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) {
|
||||
struct ieee80211_bss_conf *link_conf =
|
||||
link_conf_dereference_check(vif, link_id);
|
||||
|
||||
@@ -130,7 +130,7 @@ struct iwl_mld_scan {
|
||||
void *cmd;
|
||||
unsigned long last_6ghz_passive_jiffies;
|
||||
unsigned long last_start_time_jiffies;
|
||||
unsigned long last_mlo_scan_time;
|
||||
u64 last_mlo_scan_time;
|
||||
};
|
||||
|
||||
#endif /* __iwl_mld_scan_h__ */
|
||||
|
||||
@@ -120,19 +120,17 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
|
||||
switch (key->cipher) {
|
||||
case WLAN_CIPHER_SUITE_WEP40:
|
||||
case WLAN_CIPHER_SUITE_WEP104: { /* hack it for now */
|
||||
struct {
|
||||
struct iwl_mvm_wep_key_cmd wep_key_cmd;
|
||||
struct iwl_mvm_wep_key wep_key;
|
||||
} __packed wkc = {
|
||||
.wep_key_cmd.mac_id_n_color =
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
|
||||
mvmvif->color)),
|
||||
.wep_key_cmd.num_keys = 1,
|
||||
/* firmware sets STA_KEY_FLG_WEP_13BYTES */
|
||||
.wep_key_cmd.decryption_type = STA_KEY_FLG_WEP,
|
||||
.wep_key.key_index = key->keyidx,
|
||||
.wep_key.key_size = key->keylen,
|
||||
};
|
||||
DEFINE_RAW_FLEX(struct iwl_mvm_wep_key_cmd, wkc, wep_key, 1);
|
||||
struct iwl_mvm_wep_key *wep_key = wkc->wep_key;
|
||||
|
||||
wkc->mac_id_n_color =
|
||||
cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id,
|
||||
mvmvif->color));
|
||||
wkc->num_keys = 1;
|
||||
/* firmware sets STA_KEY_FLG_WEP_13BYTES */
|
||||
wkc->decryption_type = STA_KEY_FLG_WEP;
|
||||
wep_key->key_index = key->keyidx;
|
||||
wep_key->key_size = key->keylen;
|
||||
|
||||
/*
|
||||
* This will fail -- the key functions don't set support
|
||||
@@ -142,18 +140,19 @@ static void iwl_mvm_wowlan_program_keys(struct ieee80211_hw *hw,
|
||||
if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE)
|
||||
break;
|
||||
|
||||
memcpy(&wkc.wep_key.key[3], key->key, key->keylen);
|
||||
memcpy(&wep_key->key[3], key->key, key->keylen);
|
||||
if (key->keyidx == mvmvif->tx_key_idx) {
|
||||
/* TX key must be at offset 0 */
|
||||
wkc.wep_key.key_offset = 0;
|
||||
wep_key->key_offset = 0;
|
||||
} else {
|
||||
/* others start at 1 */
|
||||
data->wep_key_idx++;
|
||||
wkc.wep_key.key_offset = data->wep_key_idx;
|
||||
wep_key->key_offset = data->wep_key_idx;
|
||||
}
|
||||
|
||||
mutex_lock(&mvm->mutex);
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0, sizeof(wkc), &wkc);
|
||||
ret = iwl_mvm_send_cmd_pdu(mvm, WEP_KEY, 0,
|
||||
__struct_size(wkc), wkc);
|
||||
data->error = ret != 0;
|
||||
|
||||
mvm->ptk_ivlen = key->iv_len;
|
||||
@@ -2061,10 +2060,8 @@ static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status,
|
||||
struct iwl_wowlan_mlo_gtk *mlo_key = &status->mlo_keys[i];
|
||||
struct ieee80211_key_conf *key, *old_key;
|
||||
struct ieee80211_key_seq seq;
|
||||
struct {
|
||||
struct ieee80211_key_conf conf;
|
||||
u8 key[32];
|
||||
} conf = {};
|
||||
DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key,
|
||||
WOWLAN_KEY_MAX_SIZE);
|
||||
u16 flags = le16_to_cpu(mlo_key->flags);
|
||||
int j, link_id, key_id, key_type;
|
||||
|
||||
@@ -2081,40 +2078,40 @@ static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status,
|
||||
key_type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES))
|
||||
continue;
|
||||
|
||||
conf.conf.cipher = old_keys->cipher[link_id][key_type];
|
||||
conf->cipher = old_keys->cipher[link_id][key_type];
|
||||
/* WARN_ON? */
|
||||
if (!conf.conf.cipher)
|
||||
if (!conf->cipher)
|
||||
continue;
|
||||
|
||||
conf.conf.keylen = 0;
|
||||
switch (conf.conf.cipher) {
|
||||
conf->keylen = 0;
|
||||
switch (conf->cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_CCMP;
|
||||
conf->keylen = WLAN_KEY_LEN_CCMP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;
|
||||
conf->keylen = WLAN_KEY_LEN_GCMP_256;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128;
|
||||
conf->keylen = WLAN_KEY_LEN_BIP_GMAC_128;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256;
|
||||
conf->keylen = WLAN_KEY_LEN_BIP_GMAC_256;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC;
|
||||
conf->keylen = WLAN_KEY_LEN_AES_CMAC;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256;
|
||||
conf->keylen = WLAN_KEY_LEN_BIP_CMAC_256;
|
||||
break;
|
||||
}
|
||||
|
||||
if (WARN_ON(!conf.conf.keylen ||
|
||||
conf.conf.keylen > sizeof(conf.key)))
|
||||
if (WARN_ON(!conf->keylen ||
|
||||
conf->keylen > WOWLAN_KEY_MAX_SIZE))
|
||||
continue;
|
||||
|
||||
memcpy(conf.conf.key, mlo_key->key, conf.conf.keylen);
|
||||
conf.conf.keyidx = key_id;
|
||||
memcpy(conf->key, mlo_key->key, conf->keylen);
|
||||
conf->keyidx = key_id;
|
||||
|
||||
old_key = old_keys->key[link_id][key_id];
|
||||
if (old_key) {
|
||||
@@ -2126,7 +2123,7 @@ static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status,
|
||||
|
||||
IWL_DEBUG_WOWLAN(mvm, "Add MLO key id %d, link id %d\n",
|
||||
key_id, link_id);
|
||||
key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);
|
||||
key = ieee80211_gtk_rekey_add(vif, conf, link_id);
|
||||
if (WARN_ON(IS_ERR(key))) {
|
||||
ret = false;
|
||||
goto out;
|
||||
@@ -2156,30 +2153,28 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
|
||||
{
|
||||
int i, j;
|
||||
struct ieee80211_key_conf *key;
|
||||
struct {
|
||||
struct ieee80211_key_conf conf;
|
||||
u8 key[32];
|
||||
} conf = {
|
||||
.conf.cipher = gtk_cipher,
|
||||
};
|
||||
DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key,
|
||||
WOWLAN_KEY_MAX_SIZE);
|
||||
int link_id = vif->active_links ? __ffs(vif->active_links) : -1;
|
||||
|
||||
conf->cipher = gtk_cipher;
|
||||
|
||||
BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP);
|
||||
BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP);
|
||||
BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_GCMP_256);
|
||||
BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_TKIP);
|
||||
BUILD_BUG_ON(sizeof(conf.key) < sizeof(status->gtk[0].key));
|
||||
BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_CCMP);
|
||||
BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_GCMP_256);
|
||||
BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < WLAN_KEY_LEN_TKIP);
|
||||
BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(status->gtk[0].key));
|
||||
|
||||
switch (gtk_cipher) {
|
||||
case WLAN_CIPHER_SUITE_CCMP:
|
||||
case WLAN_CIPHER_SUITE_GCMP:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_CCMP;
|
||||
conf->keylen = WLAN_KEY_LEN_CCMP;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_GCMP_256:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_GCMP_256;
|
||||
conf->keylen = WLAN_KEY_LEN_GCMP_256;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_TKIP:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_TKIP;
|
||||
conf->keylen = WLAN_KEY_LEN_TKIP;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
@@ -2189,14 +2184,14 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status,
|
||||
if (!status->gtk[i].len)
|
||||
continue;
|
||||
|
||||
conf.conf.keyidx = status->gtk[i].id;
|
||||
conf->keyidx = status->gtk[i].id;
|
||||
IWL_DEBUG_WOWLAN(mvm,
|
||||
"Received from FW GTK cipher %d, key index %d\n",
|
||||
conf.conf.cipher, conf.conf.keyidx);
|
||||
memcpy(conf.conf.key, status->gtk[i].key,
|
||||
conf->cipher, conf->keyidx);
|
||||
memcpy(conf->key, status->gtk[i].key,
|
||||
sizeof(status->gtk[i].key));
|
||||
|
||||
key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);
|
||||
key = ieee80211_gtk_rekey_add(vif, conf, link_id);
|
||||
if (IS_ERR(key))
|
||||
return false;
|
||||
|
||||
@@ -2218,42 +2213,40 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status,
|
||||
struct ieee80211_vif *vif, u32 cipher,
|
||||
struct iwl_multicast_key_data *key_data)
|
||||
{
|
||||
DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key,
|
||||
WOWLAN_KEY_MAX_SIZE);
|
||||
struct ieee80211_key_conf *key_config;
|
||||
struct {
|
||||
struct ieee80211_key_conf conf;
|
||||
u8 key[WOWLAN_KEY_MAX_SIZE];
|
||||
} conf = {
|
||||
.conf.cipher = cipher,
|
||||
.conf.keyidx = key_data->id,
|
||||
};
|
||||
struct ieee80211_key_seq seq;
|
||||
int link_id = vif->active_links ? __ffs(vif->active_links) : -1;
|
||||
|
||||
conf->cipher = cipher;
|
||||
conf->keyidx = key_data->id;
|
||||
|
||||
if (!key_data->len)
|
||||
return true;
|
||||
|
||||
iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf.conf.cipher);
|
||||
iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, &seq, conf->cipher);
|
||||
|
||||
switch (cipher) {
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_128:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128;
|
||||
conf->keylen = WLAN_KEY_LEN_BIP_GMAC_128;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_GMAC_256:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256;
|
||||
conf->keylen = WLAN_KEY_LEN_BIP_GMAC_256;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_AES_CMAC:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC;
|
||||
conf->keylen = WLAN_KEY_LEN_AES_CMAC;
|
||||
break;
|
||||
case WLAN_CIPHER_SUITE_BIP_CMAC_256:
|
||||
conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256;
|
||||
conf->keylen = WLAN_KEY_LEN_BIP_CMAC_256;
|
||||
break;
|
||||
default:
|
||||
WARN_ON(1);
|
||||
}
|
||||
BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key));
|
||||
memcpy(conf.conf.key, key_data->key, conf.conf.keylen);
|
||||
BUILD_BUG_ON(WOWLAN_KEY_MAX_SIZE < sizeof(key_data->key));
|
||||
memcpy(conf->key, key_data->key, conf->keylen);
|
||||
|
||||
key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id);
|
||||
key_config = ieee80211_gtk_rekey_add(vif, conf, link_id);
|
||||
if (IS_ERR(key_config))
|
||||
return false;
|
||||
ieee80211_set_key_rx_seq(key_config, 0, &seq);
|
||||
|
||||
@@ -314,7 +314,8 @@ int iwl_mvm_op_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant,
|
||||
|
||||
/* This has been tested on those devices only */
|
||||
if (mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_9000 &&
|
||||
mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_22000)
|
||||
mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_22000 &&
|
||||
mvm->trans->mac_cfg->device_family != IWL_DEVICE_FAMILY_AX210)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!mvm->nvm_data)
|
||||
|
||||
@@ -2133,7 +2133,6 @@ bool iwl_mvm_mld_valid_link_pair(struct ieee80211_vif *vif,
|
||||
|
||||
s8 iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif);
|
||||
|
||||
|
||||
extern const struct iwl_hcmd_arr iwl_mvm_groups[];
|
||||
extern const unsigned int iwl_mvm_groups_size;
|
||||
#endif
|
||||
|
||||
@@ -61,8 +61,10 @@ static int __init iwl_mvm_init(void)
|
||||
}
|
||||
|
||||
ret = iwl_opmode_register("iwlmvm", &iwl_mvm_ops);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pr_err("Unable to register MVM op_mode: %d\n", ret);
|
||||
iwl_mvm_rate_control_unregister();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -411,6 +411,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
* with the mac80211 subsystem. This should be performed prior to calling
|
||||
* ieee80211_register_hw
|
||||
*
|
||||
* Return: negative error code, or 0 on success
|
||||
*/
|
||||
int iwl_mvm_rate_control_register(void);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2018-2024 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2018-2025 Intel Corporation
|
||||
* Copyright (C) 2013-2015 Intel Mobile Communications GmbH
|
||||
* Copyright (C) 2016-2017 Intel Deutschland GmbH
|
||||
*/
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "mvm.h"
|
||||
#include "fw/api/scan.h"
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-utils.h"
|
||||
|
||||
#define IWL_DENSE_EBS_SCAN_RATIO 5
|
||||
#define IWL_SPARSE_EBS_SCAN_RATIO 1
|
||||
@@ -3685,117 +3686,6 @@ static int iwl_mvm_chanidx_from_phy(struct iwl_mvm *mvm,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static u32 iwl_mvm_div_by_db(u32 value, u8 db)
|
||||
{
|
||||
/*
|
||||
* 2^32 * 10**(i / 10) for i = [1, 10], skipping 0 and simply stopping
|
||||
* at 10 dB and looping instead of using a much larger table.
|
||||
*
|
||||
* Using 64 bit math is overkill, but means the helper does not require
|
||||
* a limit on the input range.
|
||||
*/
|
||||
static const u32 db_to_val[] = {
|
||||
0xcb59185e, 0xa1866ba8, 0x804dce7a, 0x65ea59fe, 0x50f44d89,
|
||||
0x404de61f, 0x331426af, 0x2892c18b, 0x203a7e5b, 0x1999999a,
|
||||
};
|
||||
|
||||
while (value && db > 0) {
|
||||
u8 change = min_t(u8, db, ARRAY_SIZE(db_to_val));
|
||||
|
||||
value = (((u64)value) * db_to_val[change - 1]) >> 32;
|
||||
|
||||
db -= change;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
VISIBLE_IF_IWLWIFI_KUNIT s8
|
||||
iwl_mvm_average_dbm_values(const struct iwl_umac_scan_channel_survey_notif *notif)
|
||||
{
|
||||
s8 average_magnitude;
|
||||
u32 average_factor;
|
||||
s8 sum_magnitude = -128;
|
||||
u32 sum_factor = 0;
|
||||
int i, count = 0;
|
||||
|
||||
/*
|
||||
* To properly average the decibel values (signal values given in dBm)
|
||||
* we need to do the math in linear space. Doing a linear average of
|
||||
* dB (dBm) values is a bit annoying though due to the large range of
|
||||
* at least -10 to -110 dBm that will not fit into a 32 bit integer.
|
||||
*
|
||||
* A 64 bit integer should be sufficient, but then we still have the
|
||||
* problem that there are no directly usable utility functions
|
||||
* available.
|
||||
*
|
||||
* So, lets not deal with that and instead do much of the calculation
|
||||
* with a 16.16 fixed point integer along with a base in dBm. 16.16 bit
|
||||
* gives us plenty of head-room for adding up a few values and even
|
||||
* doing some math on it. And the tail should be accurate enough too
|
||||
* (1/2^16 is somewhere around -48 dB, so effectively zero).
|
||||
*
|
||||
* i.e. the real value of sum is:
|
||||
* sum = sum_factor / 2^16 * 10^(sum_magnitude / 10) mW
|
||||
*
|
||||
* However, that does mean we need to be able to bring two values to
|
||||
* a common base, so we need a helper for that.
|
||||
*
|
||||
* Note that this function takes an input with unsigned negative dBm
|
||||
* values but returns a signed dBm (i.e. a negative value).
|
||||
*/
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(notif->noise); i++) {
|
||||
s8 val_magnitude;
|
||||
u32 val_factor;
|
||||
|
||||
if (notif->noise[i] == 0xff)
|
||||
continue;
|
||||
|
||||
val_factor = 0x10000;
|
||||
val_magnitude = -notif->noise[i];
|
||||
|
||||
if (val_magnitude <= sum_magnitude) {
|
||||
u8 div_db = sum_magnitude - val_magnitude;
|
||||
|
||||
val_factor = iwl_mvm_div_by_db(val_factor, div_db);
|
||||
val_magnitude = sum_magnitude;
|
||||
} else {
|
||||
u8 div_db = val_magnitude - sum_magnitude;
|
||||
|
||||
sum_factor = iwl_mvm_div_by_db(sum_factor, div_db);
|
||||
sum_magnitude = val_magnitude;
|
||||
}
|
||||
|
||||
sum_factor += val_factor;
|
||||
count++;
|
||||
}
|
||||
|
||||
/* No valid noise measurement, return a very high noise level */
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
average_magnitude = sum_magnitude;
|
||||
average_factor = sum_factor / count;
|
||||
|
||||
/*
|
||||
* average_factor will be a number smaller than 1.0 (0x10000) at this
|
||||
* point. What we need to do now is to adjust average_magnitude so that
|
||||
* average_factor is between -0.5 dB and 0.5 dB.
|
||||
*
|
||||
* Just do -1 dB steps and find the point where
|
||||
* -0.5 dB * -i dB = 0x10000 * 10^(-0.5/10) / i dB
|
||||
* = div_by_db(0xe429, i)
|
||||
* is smaller than average_factor.
|
||||
*/
|
||||
for (i = 0; average_factor < iwl_mvm_div_by_db(0xe429, i); i++) {
|
||||
/* nothing */
|
||||
}
|
||||
|
||||
return average_magnitude - i;
|
||||
}
|
||||
EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_average_dbm_values);
|
||||
|
||||
void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm,
|
||||
struct iwl_rx_cmd_buffer *rxb)
|
||||
{
|
||||
@@ -3853,5 +3743,6 @@ void iwl_mvm_rx_channel_survey_notif(struct iwl_mvm *mvm,
|
||||
info->time_busy = le32_to_cpu(notif->busy_time);
|
||||
info->time_rx = le32_to_cpu(notif->rx_time);
|
||||
info->time_tx = le32_to_cpu(notif->tx_time);
|
||||
info->noise = iwl_mvm_average_dbm_values(notif);
|
||||
info->noise =
|
||||
iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise));
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ struct iwl_mvm_vif;
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum iwl_mvm_agg_state
|
||||
* enum iwl_mvm_agg_state - aggregation session state
|
||||
*
|
||||
* The state machine of the BA agreement establishment / tear down.
|
||||
* These states relate to a specific RA / TID.
|
||||
@@ -483,6 +483,7 @@ struct iwl_mvm_int_sta {
|
||||
* about. Otherwise (if this is a new STA), this should be false.
|
||||
* @flags: if update==true, this marks what is being changed via ORs of values
|
||||
* from enum iwl_sta_modify_flag. Otherwise, this is ignored.
|
||||
* Return: negative error code or 0 on success
|
||||
*/
|
||||
int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
|
||||
bool update, unsigned int flags);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
iwlmvm-tests-y += module.o links.o scan.o hcmd.o
|
||||
iwlmvm-tests-y += module.o links.o hcmd.o
|
||||
|
||||
obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += iwlmvm-tests.o
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
|
||||
/*
|
||||
* Copyright (C) 2012-2014, 2019-2020, 2023 Intel Corporation
|
||||
* Copyright (C) 2012-2014, 2019-2020, 2023, 2025 Intel Corporation
|
||||
* Copyright (C) 2013-2014 Intel Mobile Communications GmbH
|
||||
*/
|
||||
#ifndef __time_event_h__
|
||||
@@ -124,6 +124,8 @@ void iwl_mvm_rx_roc_notif(struct iwl_mvm *mvm,
|
||||
* ROC request, it will issue a notification to the driver that it is on the
|
||||
* requested channel. Once the FW completes the ROC request it will issue
|
||||
* another notification to the driver.
|
||||
*
|
||||
* Return: negative error code or 0 on success
|
||||
*/
|
||||
int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
|
||||
int duration, enum ieee80211_roc_type type);
|
||||
@@ -179,6 +181,8 @@ void iwl_mvm_remove_csa_period(struct iwl_mvm *mvm,
|
||||
*
|
||||
* This function is used to schedule NoA time event and is used to perform
|
||||
* the channel switch flow.
|
||||
*
|
||||
* Return: negative error code or 0 on success
|
||||
*/
|
||||
int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
|
||||
struct ieee80211_vif *vif,
|
||||
@@ -188,7 +192,7 @@ int iwl_mvm_schedule_csa_period(struct iwl_mvm *mvm,
|
||||
* iwl_mvm_te_scheduled - check if the fw received the TE cmd
|
||||
* @te_data: the time event data that corresponds to that time event
|
||||
*
|
||||
* This function returns true iff this TE is added to the fw.
|
||||
* Return: %true if this TE is added to the fw, %false otherwise
|
||||
*/
|
||||
static inline bool
|
||||
iwl_mvm_te_scheduled(struct iwl_mvm_time_event_data *te_data)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-fh.h"
|
||||
#include "iwl-context-info-v2.h"
|
||||
#include "internal.h"
|
||||
#include "gen1_2/internal.h"
|
||||
#include "iwl-prph.h"
|
||||
|
||||
static const struct dmi_system_id dmi_force_scu_active_approved_list[] = {
|
||||
@@ -391,13 +391,13 @@ static int iwl_pcie_load_payloads_segments
|
||||
{
|
||||
struct iwl_dram_data *cur_payload_dram = &dram_regions->drams[0];
|
||||
struct iwl_dram_data *desc_dram = &dram_regions->prph_scratch_mem_desc;
|
||||
struct iwl_prph_scrath_mem_desc_addr_array *addresses;
|
||||
struct iwl_prph_scratch_mem_desc_addr_array *addresses;
|
||||
const void *data;
|
||||
u32 len;
|
||||
int i;
|
||||
|
||||
/* allocate and init DRAM descriptors array */
|
||||
len = sizeof(struct iwl_prph_scrath_mem_desc_addr_array);
|
||||
len = sizeof(struct iwl_prph_scratch_mem_desc_addr_array);
|
||||
desc_dram->block = iwl_pcie_ctxt_info_dma_alloc_coherent
|
||||
(trans,
|
||||
len,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-fh.h"
|
||||
#include "iwl-context-info.h"
|
||||
#include "internal.h"
|
||||
#include "gen1_2/internal.h"
|
||||
#include "iwl-prph.h"
|
||||
|
||||
static void *_iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "internal.h"
|
||||
#include "gen1_2/internal.h"
|
||||
|
||||
#define _IS_A(cfg, _struct) __builtin_types_compatible_p(typeof(cfg), \
|
||||
struct _struct)
|
||||
@@ -545,6 +545,7 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct pci_device_id iwl_hw_card_ids[] = {
|
||||
{IWL_PCI_DEVICE(0xE340, PCI_ANY_ID, iwl_sc_mac_cfg)},
|
||||
{IWL_PCI_DEVICE(0xD340, PCI_ANY_ID, iwl_sc_mac_cfg)},
|
||||
{IWL_PCI_DEVICE(0x6E70, PCI_ANY_ID, iwl_sc_mac_cfg)},
|
||||
{IWL_PCI_DEVICE(0xD240, PCI_ANY_ID, iwl_sc_mac_cfg)},
|
||||
#endif /* CONFIG_IWLMLD */
|
||||
|
||||
{0}
|
||||
@@ -1580,12 +1581,21 @@ static const struct dev_pm_ops iwl_dev_pm_ops = {
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
static void iwl_pci_dump(struct device *device)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(device);
|
||||
struct iwl_trans *trans = pci_get_drvdata(pdev);
|
||||
|
||||
iwl_op_mode_dump(trans->op_mode);
|
||||
}
|
||||
|
||||
static struct pci_driver iwl_pci_driver = {
|
||||
.name = DRV_NAME,
|
||||
.id_table = iwl_hw_card_ids,
|
||||
.probe = iwl_pci_probe,
|
||||
.remove = iwl_pci_remove,
|
||||
.driver.pm = IWL_PM_OPS,
|
||||
.driver.coredump = iwl_pci_dump,
|
||||
};
|
||||
|
||||
int __must_check iwl_pci_register_driver(void)
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "iwl-io.h"
|
||||
#include "iwl-op-mode.h"
|
||||
#include "iwl-drv.h"
|
||||
#include "iwl-context-info.h"
|
||||
#include "pcie/iwl-context-info.h"
|
||||
|
||||
/*
|
||||
* RX related structures and functions
|
||||
@@ -39,7 +39,7 @@ struct iwl_host_cmd;
|
||||
* trans_pcie layer */
|
||||
|
||||
/**
|
||||
* struct iwl_rx_mem_buffer
|
||||
* struct iwl_rx_mem_buffer - driver-side RX buffer descriptor
|
||||
* @page_dma: bus address of rxb page
|
||||
* @page: driver's pointer to the rxb page
|
||||
* @list: list entry for the membuffer
|
||||
@@ -190,6 +190,7 @@ struct iwl_rb_allocator {
|
||||
* iwl_get_closed_rb_stts - get closed rb stts from different structs
|
||||
* @trans: transport pointer (for configuration)
|
||||
* @rxq: the rxq to get the rb stts from
|
||||
* Return: last closed RB index
|
||||
*/
|
||||
static inline u16 iwl_get_closed_rb_stts(struct iwl_trans *trans,
|
||||
struct iwl_rxq *rxq)
|
||||
@@ -382,8 +383,7 @@ struct iwl_pcie_txqs {
|
||||
* @irq_lock: lock to synchronize IRQ handling
|
||||
* @txq_memory: TXQ allocation array
|
||||
* @sx_waitq: waitqueue for Sx transitions
|
||||
* @sx_complete: completion for Sx transitions
|
||||
* @pcie_dbg_dumped_once: indicates PCIe regs were dumped already
|
||||
* @sx_state: state tracking Sx transitions
|
||||
* @opmode_down: indicates opmode went away
|
||||
* @num_rx_bufs: number of RX buffers to allocate/use
|
||||
* @affinity_mask: IRQ affinity mask for each RX queue
|
||||
@@ -448,13 +448,17 @@ struct iwl_trans_pcie {
|
||||
u8 __iomem *hw_base;
|
||||
|
||||
bool ucode_write_complete;
|
||||
bool sx_complete;
|
||||
enum {
|
||||
IWL_SX_INVALID = 0,
|
||||
IWL_SX_WAITING,
|
||||
IWL_SX_ERROR,
|
||||
IWL_SX_COMPLETE,
|
||||
} sx_state;
|
||||
wait_queue_head_t ucode_write_waitq;
|
||||
wait_queue_head_t sx_waitq;
|
||||
|
||||
u16 num_rx_bufs;
|
||||
|
||||
bool pcie_dbg_dumped_once;
|
||||
u32 rx_page_order;
|
||||
u32 rx_buf_bytes;
|
||||
u32 supported_dma_mask;
|
||||
@@ -698,6 +702,7 @@ static inline void iwl_txq_stop(struct iwl_trans *trans, struct iwl_txq *txq)
|
||||
* iwl_txq_inc_wrap - increment queue index, wrap back to beginning
|
||||
* @trans: the transport (for configuration data)
|
||||
* @index: current index
|
||||
* Return: the queue index incremented, subject to wrapping
|
||||
*/
|
||||
static inline int iwl_txq_inc_wrap(struct iwl_trans *trans, int index)
|
||||
{
|
||||
@@ -709,6 +714,7 @@ static inline int iwl_txq_inc_wrap(struct iwl_trans *trans, int index)
|
||||
* iwl_txq_dec_wrap - decrement queue index, wrap back to end
|
||||
* @trans: the transport (for configuration data)
|
||||
* @index: current index
|
||||
* Return: the queue index decremented, subject to wrapping
|
||||
*/
|
||||
static inline int iwl_txq_dec_wrap(struct iwl_trans *trans, int index)
|
||||
{
|
||||
@@ -1028,40 +1034,12 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
|
||||
CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
|
||||
}
|
||||
|
||||
static inline void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans,
|
||||
u32 reg, u32 mask, u32 value)
|
||||
{
|
||||
u32 v;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
WARN_ON_ONCE(value & ~mask);
|
||||
#endif
|
||||
|
||||
v = iwl_read32(trans, reg);
|
||||
v &= ~mask;
|
||||
v |= value;
|
||||
iwl_write32(trans, reg, v);
|
||||
}
|
||||
|
||||
static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans,
|
||||
u32 reg, u32 mask)
|
||||
{
|
||||
__iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0);
|
||||
}
|
||||
|
||||
static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
|
||||
u32 reg, u32 mask)
|
||||
{
|
||||
__iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask);
|
||||
}
|
||||
|
||||
static inline bool iwl_pcie_dbg_on(struct iwl_trans *trans)
|
||||
{
|
||||
return (trans->dbg.dest_tlv || iwl_trans_dbg_ini_valid(trans));
|
||||
}
|
||||
|
||||
void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq);
|
||||
void iwl_trans_pcie_dump_regs(struct iwl_trans *trans);
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUGFS
|
||||
void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans);
|
||||
@@ -1074,6 +1052,7 @@ void iwl_pcie_rx_allocator_work(struct work_struct *data);
|
||||
|
||||
/* common trans ops for all generations transports */
|
||||
void iwl_trans_pcie_op_mode_enter(struct iwl_trans *trans);
|
||||
int _iwl_trans_pcie_start_hw(struct iwl_trans *trans);
|
||||
int iwl_trans_pcie_start_hw(struct iwl_trans *trans);
|
||||
void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans);
|
||||
void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val);
|
||||
@@ -1083,8 +1062,6 @@ u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg);
|
||||
void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, u32 val);
|
||||
int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
|
||||
void *buf, int dwords);
|
||||
int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
|
||||
const void *buf, int dwords);
|
||||
int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership);
|
||||
struct iwl_trans_dump_data *
|
||||
iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask,
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "iwl-io.h"
|
||||
#include "internal.h"
|
||||
#include "iwl-op-mode.h"
|
||||
#include "iwl-context-info-v2.h"
|
||||
#include "pcie/iwl-context-info-v2.h"
|
||||
#include "fw/dbg.h"
|
||||
|
||||
/******************************************************************************
|
||||
@@ -1700,6 +1700,15 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
|
||||
timer_delete(&trans_pcie->txqs.txq[i]->stuck_timer);
|
||||
}
|
||||
|
||||
if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) {
|
||||
u32 val = iwl_read32(trans, CSR_IPC_STATE);
|
||||
|
||||
if (val & CSR_IPC_STATE_TOP_RESET_REQ) {
|
||||
IWL_ERR(trans, "FW requested TOP reset for FSEQ\n");
|
||||
trans->do_top_reset = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* The STATUS_FW_ERROR bit is set in this function. This must happen
|
||||
* before we wake up the command caller, to ensure a proper cleanup. */
|
||||
iwl_trans_fw_error(trans, IWL_ERR_TYPE_IRQ);
|
||||
@@ -1852,7 +1861,12 @@ static void iwl_trans_pcie_handle_reset_interrupt(struct iwl_trans *trans)
|
||||
}
|
||||
fallthrough;
|
||||
case CSR_IPC_STATE_RESET_TOP_READY:
|
||||
/* FIXME: handle this case when requesting TOP reset */
|
||||
if (trans_pcie->fw_reset_state == FW_RESET_TOP_REQUESTED) {
|
||||
IWL_DEBUG_ISR(trans, "TOP Reset continues\n");
|
||||
trans_pcie->fw_reset_state = FW_RESET_OK;
|
||||
wake_up(&trans_pcie->fw_reset_waitq);
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
case CSR_IPC_STATE_RESET_NONE:
|
||||
IWL_FW_CHECK_FAILED(trans,
|
||||
@@ -2380,6 +2394,11 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
||||
} else {
|
||||
iwl_pcie_irq_handle_error(trans);
|
||||
}
|
||||
|
||||
if (trans_pcie->sx_state == IWL_SX_WAITING) {
|
||||
trans_pcie->sx_state = IWL_SX_ERROR;
|
||||
wake_up(&trans_pcie->sx_waitq);
|
||||
}
|
||||
}
|
||||
|
||||
/* After checking FH register check HW register */
|
||||
@@ -2414,13 +2433,20 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id)
|
||||
if (inta_hw & MSIX_HW_INT_CAUSES_REG_WAKEUP && trans_pcie->prph_info) {
|
||||
u32 sleep_notif =
|
||||
le32_to_cpu(trans_pcie->prph_info->sleep_notif);
|
||||
|
||||
if (sleep_notif == IWL_D3_SLEEP_STATUS_SUSPEND ||
|
||||
sleep_notif == IWL_D3_SLEEP_STATUS_RESUME) {
|
||||
IWL_DEBUG_ISR(trans,
|
||||
"Sx interrupt: sleep notification = 0x%x\n",
|
||||
sleep_notif);
|
||||
trans_pcie->sx_complete = true;
|
||||
wake_up(&trans_pcie->sx_waitq);
|
||||
if (trans_pcie->sx_state == IWL_SX_WAITING) {
|
||||
trans_pcie->sx_state = IWL_SX_COMPLETE;
|
||||
wake_up(&trans_pcie->sx_waitq);
|
||||
} else {
|
||||
IWL_ERR(trans,
|
||||
"unexpected Sx interrupt (0x%x)\n",
|
||||
sleep_notif);
|
||||
}
|
||||
} else {
|
||||
/* uCode wakes up after power-down sleep */
|
||||
IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
#include "iwl-trans.h"
|
||||
#include "iwl-prph.h"
|
||||
#include "iwl-context-info.h"
|
||||
#include "iwl-context-info-v2.h"
|
||||
#include "pcie/iwl-context-info.h"
|
||||
#include "pcie/iwl-context-info-v2.h"
|
||||
#include "internal.h"
|
||||
#include "fw/dbg.h"
|
||||
|
||||
@@ -610,6 +610,11 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans,
|
||||
msleep(10);
|
||||
IWL_INFO(trans, "TOP reset successful, reinit now\n");
|
||||
/* now load the firmware again properly */
|
||||
ret = _iwl_trans_pcie_start_hw(trans);
|
||||
if (ret) {
|
||||
IWL_ERR(trans, "failed to start HW after TOP reset\n");
|
||||
goto out;
|
||||
}
|
||||
trans_pcie->prph_scratch->ctrl_cfg.control.control_flags &=
|
||||
~cpu_to_le32(IWL_PRPH_SCRATCH_TOP_RESET);
|
||||
top_reset_done = true;
|
||||
@@ -28,106 +28,13 @@
|
||||
#include "mei/iwl-mei.h"
|
||||
#include "internal.h"
|
||||
#include "iwl-fh.h"
|
||||
#include "iwl-context-info-v2.h"
|
||||
#include "pcie/iwl-context-info-v2.h"
|
||||
#include "pcie/utils.h"
|
||||
|
||||
/* extended range in FW SRAM */
|
||||
#define IWL_FW_MEM_EXTENDED_START 0x40000
|
||||
#define IWL_FW_MEM_EXTENDED_END 0x57FFF
|
||||
|
||||
void iwl_trans_pcie_dump_regs(struct iwl_trans *trans)
|
||||
{
|
||||
#define PCI_DUMP_SIZE 352
|
||||
#define PCI_MEM_DUMP_SIZE 64
|
||||
#define PCI_PARENT_DUMP_SIZE 524
|
||||
#define PREFIX_LEN 32
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
struct pci_dev *pdev = trans_pcie->pci_dev;
|
||||
u32 i, pos, alloc_size, *ptr, *buf;
|
||||
char *prefix;
|
||||
|
||||
if (trans_pcie->pcie_dbg_dumped_once)
|
||||
return;
|
||||
|
||||
/* Should be a multiple of 4 */
|
||||
BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3);
|
||||
BUILD_BUG_ON(PCI_MEM_DUMP_SIZE > 4096 || PCI_MEM_DUMP_SIZE & 0x3);
|
||||
BUILD_BUG_ON(PCI_PARENT_DUMP_SIZE > 4096 || PCI_PARENT_DUMP_SIZE & 0x3);
|
||||
|
||||
/* Alloc a max size buffer */
|
||||
alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN;
|
||||
alloc_size = max_t(u32, alloc_size, PCI_DUMP_SIZE + PREFIX_LEN);
|
||||
alloc_size = max_t(u32, alloc_size, PCI_MEM_DUMP_SIZE + PREFIX_LEN);
|
||||
alloc_size = max_t(u32, alloc_size, PCI_PARENT_DUMP_SIZE + PREFIX_LEN);
|
||||
|
||||
buf = kmalloc(alloc_size, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return;
|
||||
prefix = (char *)buf + alloc_size - PREFIX_LEN;
|
||||
|
||||
IWL_ERR(trans, "iwlwifi transaction failed, dumping registers\n");
|
||||
|
||||
/* Print wifi device registers */
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
IWL_ERR(trans, "iwlwifi device config registers:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
IWL_ERR(trans, "iwlwifi device memory mapped registers:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_MEM_DUMP_SIZE; i += 4, ptr++)
|
||||
*ptr = iwl_read32(trans, i);
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
IWL_ERR(trans, "iwlwifi device AER capability structure:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_ERR_ROOT_COMMAND; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, pos + i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
|
||||
32, 4, buf, i, 0);
|
||||
}
|
||||
|
||||
/* Print parent device registers next */
|
||||
if (!pdev->bus->self)
|
||||
goto out;
|
||||
|
||||
pdev = pdev->bus->self;
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
|
||||
IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n",
|
||||
pci_name(pdev));
|
||||
for (i = 0, ptr = buf; i < PCI_PARENT_DUMP_SIZE; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
/* Print root port AER registers */
|
||||
pos = 0;
|
||||
pdev = pcie_find_root_port(pdev);
|
||||
if (pdev)
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
IWL_ERR(trans, "iwlwifi root port (%s) AER cap structure:\n",
|
||||
pci_name(pdev));
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
for (i = 0, ptr = buf; i <= PCI_ERR_ROOT_ERR_SRC; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, pos + i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32,
|
||||
4, buf, i, 0);
|
||||
}
|
||||
goto out;
|
||||
|
||||
err_read:
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
IWL_ERR(trans, "Read failed at 0x%X\n", i);
|
||||
out:
|
||||
trans_pcie->pcie_dbg_dumped_once = 1;
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership)
|
||||
{
|
||||
/* Reset entire device - do controller reset (results in SHRD_HW_RST) */
|
||||
@@ -387,8 +294,8 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
|
||||
u32 dl_cfg_reg;
|
||||
|
||||
/* Force XTAL ON */
|
||||
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
|
||||
iwl_trans_set_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
|
||||
|
||||
ret = iwl_trans_pcie_sw_reset(trans, true);
|
||||
|
||||
@@ -397,8 +304,8 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
|
||||
|
||||
if (WARN_ON(ret)) {
|
||||
/* Release XTAL ON request */
|
||||
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
|
||||
iwl_trans_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -449,12 +356,12 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans)
|
||||
iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
|
||||
|
||||
/* Activates XTAL resources monitor */
|
||||
__iwl_trans_pcie_set_bit(trans, CSR_MONITOR_CFG_REG,
|
||||
CSR_MONITOR_XTAL_RESOURCES);
|
||||
iwl_trans_set_bit(trans, CSR_MONITOR_CFG_REG,
|
||||
CSR_MONITOR_XTAL_RESOURCES);
|
||||
|
||||
/* Release XTAL ON request */
|
||||
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
|
||||
iwl_trans_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_XTAL_ON);
|
||||
udelay(10);
|
||||
|
||||
/* Release APMG XTAL */
|
||||
@@ -704,7 +611,7 @@ static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans,
|
||||
trans_pcie->ucode_write_complete, 5 * HZ);
|
||||
if (!ret) {
|
||||
IWL_ERR(trans, "Failed to load firmware chunk!\n");
|
||||
iwl_trans_pcie_dump_regs(trans);
|
||||
iwl_trans_pcie_dump_regs(trans, trans_pcie->pci_dev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -1536,30 +1443,41 @@ static int iwl_pcie_d3_handshake(struct iwl_trans *trans, bool suspend)
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int ret;
|
||||
|
||||
if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210)
|
||||
return 0;
|
||||
|
||||
trans_pcie->sx_state = IWL_SX_WAITING;
|
||||
|
||||
if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_AX210)
|
||||
iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6,
|
||||
suspend ? UREG_DOORBELL_TO_ISR6_SUSPEND :
|
||||
UREG_DOORBELL_TO_ISR6_RESUME);
|
||||
else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
|
||||
else
|
||||
iwl_write32(trans, CSR_IPC_SLEEP_CONTROL,
|
||||
suspend ? CSR_IPC_SLEEP_CONTROL_SUSPEND :
|
||||
CSR_IPC_SLEEP_CONTROL_RESUME);
|
||||
else
|
||||
return 0;
|
||||
|
||||
ret = wait_event_timeout(trans_pcie->sx_waitq,
|
||||
trans_pcie->sx_complete, 2 * HZ);
|
||||
|
||||
/* Invalidate it toward next suspend or resume */
|
||||
trans_pcie->sx_complete = false;
|
||||
|
||||
trans_pcie->sx_state != IWL_SX_WAITING,
|
||||
2 * HZ);
|
||||
if (!ret) {
|
||||
IWL_ERR(trans, "Timeout %s D3\n",
|
||||
suspend ? "entering" : "exiting");
|
||||
return -ETIMEDOUT;
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (trans_pcie->sx_state == IWL_SX_ERROR) {
|
||||
IWL_ERR(trans, "FW error while %s D3\n",
|
||||
suspend ? "entering" : "exiting");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
||||
/* Invalidate it toward next suspend or resume */
|
||||
trans_pcie->sx_state = IWL_SX_INVALID;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test, bool reset)
|
||||
@@ -1845,7 +1763,7 @@ static int iwl_pcie_gen2_force_power_gating(struct iwl_trans *trans)
|
||||
return iwl_trans_pcie_sw_reset(trans, true);
|
||||
}
|
||||
|
||||
static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans)
|
||||
int _iwl_trans_pcie_start_hw(struct iwl_trans *trans)
|
||||
{
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
int err;
|
||||
@@ -2412,7 +2330,7 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
|
||||
}
|
||||
|
||||
/* this bit wakes up the NIC */
|
||||
__iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, write);
|
||||
iwl_trans_set_bit(trans, CSR_GP_CNTRL, write);
|
||||
if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_8000)
|
||||
udelay(2);
|
||||
|
||||
@@ -2449,7 +2367,7 @@ bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent)
|
||||
"Timeout waiting for hardware access (CSR_GP_CNTRL 0x%08x)\n",
|
||||
cntrl);
|
||||
|
||||
iwl_trans_pcie_dump_regs(trans);
|
||||
iwl_trans_pcie_dump_regs(trans, trans_pcie->pci_dev);
|
||||
|
||||
if (iwlwifi_mod_params.remove_when_gone && cntrl == ~0U)
|
||||
iwl_trans_pcie_reset(trans,
|
||||
@@ -2501,11 +2419,11 @@ iwl_trans_pcie_release_nic_access(struct iwl_trans *trans)
|
||||
if (trans_pcie->cmd_hold_nic_awake)
|
||||
goto out;
|
||||
if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ)
|
||||
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ);
|
||||
iwl_trans_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ);
|
||||
else
|
||||
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
iwl_trans_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
/*
|
||||
* Above we read the CSR_GP_CNTRL register, which will flush
|
||||
* any previous writes, but we need the write that clears the
|
||||
@@ -2567,24 +2485,6 @@ int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iwl_trans_pcie_write_mem(struct iwl_trans *trans, u32 addr,
|
||||
const void *buf, int dwords)
|
||||
{
|
||||
int offs, ret = 0;
|
||||
const u32 *vals = buf;
|
||||
|
||||
if (iwl_trans_grab_nic_access(trans)) {
|
||||
iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr);
|
||||
for (offs = 0; offs < dwords; offs++)
|
||||
iwl_write32(trans, HBUS_TARG_MEM_WDAT,
|
||||
vals ? vals[offs] : 0);
|
||||
iwl_trans_release_nic_access(trans);
|
||||
} else {
|
||||
ret = -EBUSY;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs,
|
||||
u32 *val)
|
||||
{
|
||||
@@ -2704,7 +2604,7 @@ void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
|
||||
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
|
||||
|
||||
spin_lock_bh(&trans_pcie->reg_lock);
|
||||
__iwl_trans_pcie_set_bits_mask(trans, reg, mask, value);
|
||||
_iwl_trans_set_bits_mask(trans, reg, mask, value);
|
||||
spin_unlock_bh(&trans_pcie->reg_lock);
|
||||
}
|
||||
|
||||
@@ -4046,7 +3946,7 @@ int iwl_trans_pcie_copy_imr(struct iwl_trans *trans,
|
||||
IMR_D2S_REQUESTED, 5 * HZ);
|
||||
if (!ret || trans_pcie->imr_status == IMR_D2S_ERROR) {
|
||||
IWL_ERR(trans, "Failed to copy IMR Memory chunk!\n");
|
||||
iwl_trans_pcie_dump_regs(trans);
|
||||
iwl_trans_pcie_dump_regs(trans, trans_pcie->pci_dev);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
trans_pcie->imr_status = IMR_D2S_IDLE;
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "iwl-op-mode.h"
|
||||
#include "internal.h"
|
||||
#include "fw/api/tx.h"
|
||||
#include "pcie/utils.h"
|
||||
|
||||
/*************** DMA-QUEUE-GENERAL-FUNCTIONS *****
|
||||
* DMA services
|
||||
@@ -203,8 +204,8 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
|
||||
}
|
||||
|
||||
trans_pcie->cmd_hold_nic_awake = false;
|
||||
__iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
iwl_trans_clear_bit(trans, CSR_GP_CNTRL,
|
||||
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
|
||||
spin_unlock(&trans_pcie->reg_lock);
|
||||
}
|
||||
|
||||
@@ -494,9 +495,9 @@ void iwl_pcie_tx_start(struct iwl_trans *trans)
|
||||
iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
|
||||
|
||||
/* reset context data, TX status and translation data */
|
||||
iwl_trans_pcie_write_mem(trans, trans_pcie->scd_base_addr +
|
||||
SCD_CONTEXT_MEM_LOWER_BOUND,
|
||||
NULL, clear_dwords);
|
||||
iwl_trans_write_mem(trans, trans_pcie->scd_base_addr +
|
||||
SCD_CONTEXT_MEM_LOWER_BOUND,
|
||||
NULL, clear_dwords);
|
||||
|
||||
iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
|
||||
trans_pcie->txqs.scd_bc_tbls.dma >> 10);
|
||||
@@ -1292,9 +1293,8 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
|
||||
if (configure_scd) {
|
||||
iwl_scd_txq_set_inactive(trans, txq_id);
|
||||
|
||||
iwl_trans_pcie_write_mem(trans, stts_addr,
|
||||
(const void *)zero_val,
|
||||
ARRAY_SIZE(zero_val));
|
||||
iwl_trans_write_mem(trans, stts_addr, (const void *)zero_val,
|
||||
ARRAY_SIZE(zero_val));
|
||||
}
|
||||
|
||||
iwl_pcie_txq_unmap(trans, txq_id);
|
||||
@@ -130,11 +130,11 @@ struct iwl_prph_scratch_pnvm_cfg {
|
||||
} __packed; /* PERIPH_SCRATCH_PNVM_CFG_S */
|
||||
|
||||
/**
|
||||
* struct iwl_prph_scrath_mem_desc_addr_array
|
||||
* struct iwl_prph_scratch_mem_desc_addr_array - DRAM
|
||||
* @mem_descs: array of dram addresses.
|
||||
* Each address is the beggining of a pnvm payload.
|
||||
* Each address is the beginning of a PNVM payload.
|
||||
*/
|
||||
struct iwl_prph_scrath_mem_desc_addr_array {
|
||||
struct iwl_prph_scratch_mem_desc_addr_array {
|
||||
__le64 mem_descs[IPC_DRAM_MAP_ENTRY_NUM_MAX];
|
||||
} __packed; /* PERIPH_SCRATCH_MEM_DESC_ADDR_ARRAY_S_VER_1 */
|
||||
|
||||
104
drivers/net/wireless/intel/iwlwifi/pcie/utils.c
Normal file
104
drivers/net/wireless/intel/iwlwifi/pcie/utils.c
Normal file
@@ -0,0 +1,104 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include <linux/gfp.h>
|
||||
|
||||
#include "iwl-io.h"
|
||||
#include "pcie/utils.h"
|
||||
|
||||
void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev)
|
||||
{
|
||||
#define PCI_DUMP_SIZE 352
|
||||
#define PCI_MEM_DUMP_SIZE 64
|
||||
#define PCI_PARENT_DUMP_SIZE 524
|
||||
#define PREFIX_LEN 32
|
||||
|
||||
static bool pcie_dbg_dumped_once = 0;
|
||||
u32 i, pos, alloc_size, *ptr, *buf;
|
||||
char *prefix;
|
||||
|
||||
if (pcie_dbg_dumped_once)
|
||||
return;
|
||||
|
||||
/* Should be a multiple of 4 */
|
||||
BUILD_BUG_ON(PCI_DUMP_SIZE > 4096 || PCI_DUMP_SIZE & 0x3);
|
||||
BUILD_BUG_ON(PCI_MEM_DUMP_SIZE > 4096 || PCI_MEM_DUMP_SIZE & 0x3);
|
||||
BUILD_BUG_ON(PCI_PARENT_DUMP_SIZE > 4096 || PCI_PARENT_DUMP_SIZE & 0x3);
|
||||
|
||||
/* Alloc a max size buffer */
|
||||
alloc_size = PCI_ERR_ROOT_ERR_SRC + 4 + PREFIX_LEN;
|
||||
alloc_size = max_t(u32, alloc_size, PCI_DUMP_SIZE + PREFIX_LEN);
|
||||
alloc_size = max_t(u32, alloc_size, PCI_MEM_DUMP_SIZE + PREFIX_LEN);
|
||||
alloc_size = max_t(u32, alloc_size, PCI_PARENT_DUMP_SIZE + PREFIX_LEN);
|
||||
|
||||
buf = kmalloc(alloc_size, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return;
|
||||
prefix = (char *)buf + alloc_size - PREFIX_LEN;
|
||||
|
||||
IWL_ERR(trans, "iwlwifi transaction failed, dumping registers\n");
|
||||
|
||||
/* Print wifi device registers */
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
IWL_ERR(trans, "iwlwifi device config registers:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_DUMP_SIZE; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
IWL_ERR(trans, "iwlwifi device memory mapped registers:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_MEM_DUMP_SIZE; i += 4, ptr++)
|
||||
*ptr = iwl_read32(trans, i);
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
IWL_ERR(trans, "iwlwifi device AER capability structure:\n");
|
||||
for (i = 0, ptr = buf; i < PCI_ERR_ROOT_COMMAND; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, pos + i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
|
||||
32, 4, buf, i, 0);
|
||||
}
|
||||
|
||||
/* Print parent device registers next */
|
||||
if (!pdev->bus->self)
|
||||
goto out;
|
||||
|
||||
pdev = pdev->bus->self;
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
|
||||
IWL_ERR(trans, "iwlwifi parent port (%s) config registers:\n",
|
||||
pci_name(pdev));
|
||||
for (i = 0, ptr = buf; i < PCI_PARENT_DUMP_SIZE; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
|
||||
/* Print root port AER registers */
|
||||
pos = 0;
|
||||
pdev = pcie_find_root_port(pdev);
|
||||
if (pdev)
|
||||
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
|
||||
if (pos) {
|
||||
IWL_ERR(trans, "iwlwifi root port (%s) AER cap structure:\n",
|
||||
pci_name(pdev));
|
||||
sprintf(prefix, "iwlwifi %s: ", pci_name(pdev));
|
||||
for (i = 0, ptr = buf; i <= PCI_ERR_ROOT_ERR_SRC; i += 4, ptr++)
|
||||
if (pci_read_config_dword(pdev, pos + i, ptr))
|
||||
goto err_read;
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32,
|
||||
4, buf, i, 0);
|
||||
}
|
||||
goto out;
|
||||
|
||||
err_read:
|
||||
print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET, 32, 4, buf, i, 0);
|
||||
IWL_ERR(trans, "Read failed at 0x%X\n", i);
|
||||
out:
|
||||
pcie_dbg_dumped_once = 1;
|
||||
kfree(buf);
|
||||
}
|
||||
38
drivers/net/wireless/intel/iwlwifi/pcie/utils.h
Normal file
38
drivers/net/wireless/intel/iwlwifi/pcie/utils.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
/*
|
||||
* Copyright (C) 2025 Intel Corporation
|
||||
*/
|
||||
|
||||
#ifndef __iwl_pcie_utils_h__
|
||||
#define __iwl_pcie_utils_h__
|
||||
|
||||
void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev);
|
||||
|
||||
static inline void _iwl_trans_set_bits_mask(struct iwl_trans *trans,
|
||||
u32 reg, u32 mask, u32 value)
|
||||
{
|
||||
u32 v;
|
||||
|
||||
#ifdef CONFIG_IWLWIFI_DEBUG
|
||||
WARN_ON_ONCE(value & ~mask);
|
||||
#endif
|
||||
|
||||
v = iwl_read32(trans, reg);
|
||||
v &= ~mask;
|
||||
v |= value;
|
||||
iwl_write32(trans, reg, v);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_clear_bit(struct iwl_trans *trans,
|
||||
u32 reg, u32 mask)
|
||||
{
|
||||
_iwl_trans_set_bits_mask(trans, reg, mask, 0);
|
||||
}
|
||||
|
||||
static inline void iwl_trans_set_bit(struct iwl_trans *trans,
|
||||
u32 reg, u32 mask)
|
||||
{
|
||||
_iwl_trans_set_bits_mask(trans, reg, mask, mask);
|
||||
}
|
||||
|
||||
#endif /* __iwl_pcie_utils_h__ */
|
||||
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
|
||||
|
||||
iwlwifi-tests-y += module.o devinfo.o
|
||||
iwlwifi-tests-y += module.o devinfo.o utils.o
|
||||
|
||||
ccflags-y += -I$(src)/../
|
||||
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* KUnit tests for channel helper functions
|
||||
* KUnit tests for utilities
|
||||
*
|
||||
* Copyright (C) 2024 Intel Corporation
|
||||
* Copyright (C) 2024-2025 Intel Corporation
|
||||
*/
|
||||
#include <net/mac80211.h>
|
||||
#include "../mvm.h"
|
||||
#include "../iwl-utils.h"
|
||||
#include <kunit/test.h>
|
||||
|
||||
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
|
||||
MODULE_IMPORT_NS("IWLWIFI");
|
||||
|
||||
static const struct acs_average_db_case {
|
||||
static const struct average_neg_db_case {
|
||||
const char *desc;
|
||||
u8 neg_dbm[22];
|
||||
s8 result;
|
||||
} acs_average_db_cases[] = {
|
||||
} average_neg_db_cases[] = {
|
||||
{
|
||||
.desc = "Smallest possible value, all filled",
|
||||
.neg_dbm = {
|
||||
@@ -73,38 +72,38 @@ static const struct acs_average_db_case {
|
||||
},
|
||||
};
|
||||
|
||||
KUNIT_ARRAY_PARAM_DESC(acs_average_db, acs_average_db_cases, desc)
|
||||
KUNIT_ARRAY_PARAM_DESC(average_neg_db, average_neg_db_cases, desc)
|
||||
|
||||
static void test_acs_average_db(struct kunit *test)
|
||||
static void test_average_neg_db(struct kunit *test)
|
||||
{
|
||||
const struct acs_average_db_case *params = test->param_value;
|
||||
struct iwl_umac_scan_channel_survey_notif notif;
|
||||
const struct average_neg_db_case *params = test->param_value;
|
||||
u8 reversed[ARRAY_SIZE(params->neg_dbm)];
|
||||
int i;
|
||||
|
||||
/* Test the values in the given order */
|
||||
for (i = 0; i < ARRAY_SIZE(params->neg_dbm); i++)
|
||||
notif.noise[i] = params->neg_dbm[i];
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
iwl_mvm_average_dbm_values(¬if),
|
||||
iwl_average_neg_dbm(params->neg_dbm,
|
||||
ARRAY_SIZE(params->neg_dbm)),
|
||||
params->result);
|
||||
|
||||
/* Test in reverse order */
|
||||
for (i = 0; i < ARRAY_SIZE(params->neg_dbm); i++)
|
||||
notif.noise[ARRAY_SIZE(params->neg_dbm) - i - 1] =
|
||||
reversed[ARRAY_SIZE(params->neg_dbm) - i - 1] =
|
||||
params->neg_dbm[i];
|
||||
KUNIT_ASSERT_EQ(test,
|
||||
iwl_mvm_average_dbm_values(¬if),
|
||||
iwl_average_neg_dbm(reversed,
|
||||
ARRAY_SIZE(params->neg_dbm)),
|
||||
params->result);
|
||||
}
|
||||
|
||||
static struct kunit_case acs_average_db_case[] = {
|
||||
KUNIT_CASE_PARAM(test_acs_average_db, acs_average_db_gen_params),
|
||||
static struct kunit_case average_db_case[] = {
|
||||
KUNIT_CASE_PARAM(test_average_neg_db, average_neg_db_gen_params),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite acs_average_db = {
|
||||
.name = "iwlmvm-acs-average-db",
|
||||
.test_cases = acs_average_db_case,
|
||||
static struct kunit_suite average_db = {
|
||||
.name = "iwl-average-db",
|
||||
.test_cases = average_db_case,
|
||||
};
|
||||
|
||||
kunit_test_suite(acs_average_db);
|
||||
kunit_test_suite(average_db);
|
||||
Reference in New Issue
Block a user