diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 2a74efe09cf0..504381b4aac7 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -1,7 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 # common obj-$(CONFIG_IWLWIFI) += iwlwifi.o -iwlwifi-objs += iwl-io.o iwlwifi-objs += iwl-drv.o iwlwifi-objs += iwl-debug.o iwlwifi-objs += iwl-nvm-utils.o @@ -9,9 +8,9 @@ iwlwifi-objs += iwl-utils.o iwlwifi-objs += iwl-phy-db.o iwl-nvm-parse.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 +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 pcie/trans-gen2.o pcie/tx-gen2.o +iwlwifi-objs += pcie/utils.o CFLAGS_pcie/drv.o += -Wno-override-init diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index 1099d8cfe6aa..f6e0f0c8a82e 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,14 +10,11 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_BZ_UCODE_CORE_MAX 107 +#define IWL_BZ_UCODE_CORE_MAX 109 /* Lowest firmware core release supported */ #define IWL_BZ_UCODE_CORE_MIN 102 -#define IWL_BZ_A_FM_B_FW_PRE "iwlwifi-bz-a0-fm-b0" -#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" -#define IWL_BZ_A_FM4_B_FW_PRE "iwlwifi-bz-a0-fm4-b0" #define IWL_GL_B_FM_B_FW_PRE "iwlwifi-gl-b0-fm-b0" #define IWL_GL_C_FM_C_FW_PRE "iwlwifi-gl-c0-fm-c0" @@ -92,8 +89,5 @@ const struct iwl_mac_cfg iwl_gl_mac_cfg = { .low_latency_xtal = true, }; -IWL_CORE_FW(IWL_BZ_A_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); -IWL_CORE_FW(IWL_BZ_A_FM4_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); IWL_CORE_FW(IWL_GL_B_FM_B_FW_PRE, IWL_BZ_UCODE_CORE_MAX); IWL_CORE_FW(IWL_GL_C_FM_C_FW_PRE, IWL_BZ_UCODE_CORE_MAX); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index a89a2c75687f..f62a0bf29754 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c @@ -9,7 +9,7 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_DR_UCODE_CORE_MAX 107 +#define IWL_DR_UCODE_CORE_MAX 109 /* Lowest firmware core release supported */ #define IWL_DR_UCODE_CORE_MIN 102 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c index 35b1618f3474..a7770cd61213 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c @@ -5,6 +5,8 @@ */ #include "iwl-config.h" +#define IWL_BZ_A_FM_C_FW_PRE "iwlwifi-bz-a0-fm-c0" + #define IWL_DEVICE_FM \ .ht_params = { \ .stbc = true, \ @@ -48,3 +50,5 @@ const char iwl_be201_name[] = "Intel(R) Wi-Fi 7 BE201 320MHz"; const char iwl_be200_name[] = "Intel(R) Wi-Fi 7 BE200 320MHz"; const char iwl_be202_name[] = "Intel(R) Wi-Fi 7 BE202 160MHz"; const char iwl_be401_name[] = "Intel(R) Wi-Fi 7 BE401 320MHz"; + +IWL_CORE_FW(IWL_BZ_A_FM_C_FW_PRE, 107); diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 16abf0147fe4..220b0d181f42 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware core release supported */ -#define IWL_SC_UCODE_CORE_MAX 107 +#define IWL_SC_UCODE_CORE_MAX 109 /* Lowest firmware core release supported */ #define IWL_SC_UCODE_CORE_MIN 102 diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c index ec94c43ba28c..799599efdd06 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/debugfs.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2018, 2025 Intel Corporation + * Copyright (C) 2018, 2025-2026 Intel Corporation *****************************************************************************/ #include @@ -14,7 +14,6 @@ #include "iwl-debug.h" #include "iwl-trans.h" -#include "iwl-io.h" #include "dev.h" #include "agn.h" @@ -1788,7 +1787,7 @@ static ssize_t iwl_dbgfs_power_save_status_read(struct file *file, const size_t bufsz = sizeof(buf); u32 pwrsave_status; - pwrsave_status = iwl_read32(priv->trans, CSR_GP_CNTRL) & + pwrsave_status = iwl_trans_read32(priv->trans, CSR_GP_CNTRL) & CSR_GP_REG_POWER_SAVE_STATUS_MSK; pos += scnprintf(buf + pos, bufsz - pos, "Power Save Status: "); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/devices.c b/drivers/net/wireless/intel/iwlwifi/dvm/devices.c index 7f83f1bbdaad..b7bd5e6deb5d 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/devices.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2019, 2025 Intel Corporation + * Copyright (C) 2019, 2025-2026 Intel Corporation *****************************************************************************/ #include @@ -10,7 +10,7 @@ /* * DVM device-specific data & functions */ -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "iwl-nvm-utils.h" @@ -45,10 +45,10 @@ static void iwl1000_set_ct_threshold(struct iwl_priv *priv) static void iwl1000_nic_config(struct iwl_priv *priv) { /* Setting digital SVR for 1000 card to 1.32V */ - /* locking is acquired in iwl_set_bits_mask_prph() function */ - iwl_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG, - APMG_SVR_DIGITAL_VOLTAGE_1_32, - ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); + /* locking is acquired in iwl_trans_set_bits_mask_prph() function */ + iwl_trans_set_bits_mask_prph(priv->trans, APMG_DIGITAL_SVR_REG, + APMG_SVR_DIGITAL_VOLTAGE_1_32, + ~APMG_SVR_VOLTAGE_CONFIG_BIT_MSK); } /** @@ -184,8 +184,8 @@ static void iwl2000_set_ct_threshold(struct iwl_priv *priv) /* NIC configuration for 2000 series */ static void iwl2000_nic_config(struct iwl_priv *priv) { - iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); + iwl_trans_set_bit(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_IQ_INVER); } static const struct iwl_sensitivity_ranges iwl2000_sensitivity = { @@ -490,22 +490,22 @@ static void iwl6000_nic_config(struct iwl_priv *priv) break; case IWL_DEVICE_FAMILY_6000i: /* 2x2 IPA phy type */ - iwl_write32(priv->trans, CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); + iwl_trans_write32(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_RADIO_SKU_2x2_IPA); break; case IWL_DEVICE_FAMILY_6050: /* Indicate calibration version to uCode. */ if (priv->nvm_data->calib_version >= 6) - iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); + iwl_trans_set_bit(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); break; case IWL_DEVICE_FAMILY_6150: /* Indicate calibration version to uCode. */ if (priv->nvm_data->calib_version >= 6) - iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); - iwl_set_bit(priv->trans, CSR_GP_DRIVER_REG, - CSR_GP_DRIVER_REG_BIT_6050_1x2); + iwl_trans_set_bit(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_CALIB_VERSION6); + iwl_trans_set_bit(priv->trans, CSR_GP_DRIVER_REG, + CSR_GP_DRIVER_REG_BIT_6050_1x2); break; default: WARN_ON(1); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c b/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c index 6de2517188f7..190e482849ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2019, 2021, 2024-2025 Intel Corporation + * Copyright (C) 2005-2014, 2018-2019, 2021, 2024-2026 Intel Corporation */ #include #include @@ -8,7 +8,7 @@ #include "iwl-drv.h" #include "iwl-debug.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "iwl-csr.h" #include "agn.h" @@ -672,13 +672,13 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans) for (count = 0; count < IWL_EEPROM_SEM_RETRY_LIMIT; count++) { /* Request semaphore */ - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM, - IWL_EEPROM_SEM_TIMEOUT); + ret = iwl_trans_poll_bits(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM, + IWL_EEPROM_SEM_TIMEOUT); if (!ret) { IWL_DEBUG_EEPROM(trans->dev, "Acquired semaphore after %d tries.\n", @@ -692,13 +692,13 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans) static void iwl_eeprom_release_semaphore(struct iwl_trans *trans) { - iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM); + iwl_trans_clear_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM); } static int iwl_eeprom_verify_signature(struct iwl_trans *trans, bool nvm_is_otp) { - u32 gp = iwl_read32(trans, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; + u32 gp = iwl_trans_read32(trans, CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK; IWL_DEBUG_EEPROM(trans->dev, "EEPROM signature=0x%08x\n", gp); @@ -734,10 +734,10 @@ static int iwl_eeprom_verify_signature(struct iwl_trans *trans, bool nvm_is_otp) static void iwl_set_otp_access_absolute(struct iwl_trans *trans) { - iwl_read32(trans, CSR_OTP_GP_REG); + iwl_trans_read32(trans, CSR_OTP_GP_REG); - iwl_clear_bit(trans, CSR_OTP_GP_REG, - CSR_OTP_GP_REG_OTP_ACCESS_MODE); + iwl_trans_clear_bit(trans, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_OTP_ACCESS_MODE); } static int iwl_nvm_is_otp(struct iwl_trans *trans) @@ -755,7 +755,7 @@ static int iwl_nvm_is_otp(struct iwl_trans *trans) case CSR_HW_REV_TYPE_5150: return 0; default: - otpgp = iwl_read32(trans, CSR_OTP_GP_REG); + otpgp = iwl_trans_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) return 1; return 0; @@ -770,19 +770,19 @@ static int iwl_init_otp_access(struct iwl_trans *trans) if (ret) return ret; - iwl_set_bits_prph(trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); + iwl_trans_set_bits_prph(trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); udelay(5); - iwl_clear_bits_prph(trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_RESET_REQ); + iwl_trans_clear_bits_prph(trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_RESET_REQ); /* * CSR auto clock gate disable bit - * this is only applicable for HW with OTP shadow RAM */ if (trans->mac_cfg->base->shadow_ram_support) - iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, - CSR_RESET_LINK_PWR_MGMT_DISABLED); + iwl_trans_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); return 0; } @@ -794,31 +794,31 @@ static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, u32 r; u32 otpgp; - iwl_write32(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bits(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); + iwl_trans_write32(trans, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + ret = iwl_trans_poll_bits(trans, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); if (ret) { IWL_ERR(trans, "Time out reading OTP[%d]\n", addr); return ret; } - r = iwl_read32(trans, CSR_EEPROM_REG); + r = iwl_trans_read32(trans, CSR_EEPROM_REG); /* check for ECC errors: */ - otpgp = iwl_read32(trans, CSR_OTP_GP_REG); + otpgp = iwl_trans_read32(trans, CSR_OTP_GP_REG); if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) { /* stop in this case */ /* set the uncorrectable OTP ECC bit for acknowledgment */ - iwl_set_bit(trans, CSR_OTP_GP_REG, - CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); + iwl_trans_set_bit(trans, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); IWL_ERR(trans, "Uncorrectable OTP ECC error, abort OTP read\n"); return -EINVAL; } if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) { /* continue in this case */ /* set the correctable OTP ECC bit for acknowledgment */ - iwl_set_bit(trans, CSR_OTP_GP_REG, - CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); + iwl_trans_set_bit(trans, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK); IWL_ERR(trans, "Correctable OTP ECC error, continue read\n"); } *eeprom_data = cpu_to_le16(r >> 16); @@ -918,7 +918,7 @@ static int iwl_find_otp_image(struct iwl_trans *trans, int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size) { __le16 *e; - u32 gp = iwl_read32(trans, CSR_EEPROM_GP); + u32 gp = iwl_trans_read32(trans, CSR_EEPROM_GP); int sz; int ret; u16 addr; @@ -960,13 +960,13 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size) goto err_unlock; } - iwl_write32(trans, CSR_EEPROM_GP, - iwl_read32(trans, CSR_EEPROM_GP) & - ~CSR_EEPROM_GP_IF_OWNER_MSK); + iwl_trans_write32(trans, CSR_EEPROM_GP, + iwl_trans_read32(trans, CSR_EEPROM_GP) & + ~CSR_EEPROM_GP_IF_OWNER_MSK); - iwl_set_bit(trans, CSR_OTP_GP_REG, - CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | - CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); + iwl_trans_set_bit(trans, CSR_OTP_GP_REG, + CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK | + CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK); /* traversing the linked list if no shadow ram supported */ if (!trans->mac_cfg->base->shadow_ram_support) { ret = iwl_find_otp_image(trans, &validblockaddr); @@ -988,18 +988,18 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size) for (addr = 0; addr < sz; addr += sizeof(u16)) { u32 r; - iwl_write32(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + iwl_trans_write32(trans, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bits(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); + ret = iwl_trans_poll_bits(trans, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); if (ret) { IWL_ERR(trans, "Time out reading EEPROM[%d]\n", addr); goto err_unlock; } - r = iwl_read32(trans, CSR_EEPROM_REG); + r = iwl_trans_read32(trans, CSR_EEPROM_REG); e[addr / 2] = cpu_to_le16(r >> 16); } } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/led.c b/drivers/net/wireless/intel/iwlwifi/dvm/led.c index cec2ebdfd651..17b045ddb910 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/led.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2019, 2025 Intel Corporation + * Copyright (C) 2019, 2025-2026 Intel Corporation *****************************************************************************/ @@ -14,7 +14,6 @@ #include #include #include -#include "iwl-io.h" #include "iwl-trans.h" #include "iwl-modparams.h" #include "dev.h" @@ -49,7 +48,7 @@ static const struct ieee80211_tpt_blink iwl_blink[] = { /* Set led register off */ void iwlagn_led_enable(struct iwl_priv *priv) { - iwl_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON); + iwl_trans_write32(priv->trans, CSR_LED_REG, CSR_LED_REG_TURN_ON); } /* @@ -85,10 +84,10 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) }; u32 reg; - reg = iwl_read32(priv->trans, CSR_LED_REG); + reg = iwl_trans_read32(priv->trans, CSR_LED_REG); if (reg != (reg & CSR_LED_BSM_CTRL_MSK)) - iwl_write32(priv->trans, CSR_LED_REG, - reg & CSR_LED_BSM_CTRL_MSK); + iwl_trans_write32(priv->trans, CSR_LED_REG, + reg & CSR_LED_BSM_CTRL_MSK); return iwl_dvm_send_cmd(priv, &cmd); } diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c index 2e16799818e4..37d6f2cf7efb 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/lib.c @@ -2,6 +2,7 @@ /****************************************************************************** * * Copyright(c) 2008 - 2014, 2022 Intel Corporation. All rights reserved. + * Copyright (C) 2026 Intel Corporation *****************************************************************************/ #include #include @@ -9,7 +10,6 @@ #include #include -#include "iwl-io.h" #include "iwl-agn-hw.h" #include "iwl-trans.h" #include "iwl-modparams.h" diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c index a0a26ef482a5..e83bf615c161 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. - * Copyright(C) 2018 - 2019, 2022 - 2025 Intel Corporation + * Copyright(C) 2018 - 2019, 2022 - 2026 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -23,7 +23,6 @@ #include -#include "iwl-io.h" #include "iwl-trans.h" #include "iwl-op-mode.h" #include "iwl-modparams.h" @@ -375,8 +374,8 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw, goto error; /* let the ucode operate on its own */ - iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); + iwl_trans_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); iwl_trans_d3_suspend(priv->trans, true); @@ -455,8 +454,8 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw) goto out_unlock; /* uCode is no longer operating by itself */ - iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); + iwl_trans_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE); base = priv->device_pointers.error_event_table; if (!iwlagn_hw_valid_rtc_data_addr(base)) { diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index 6bd5b6d84b2a..4bf69f7a35a6 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014, 2018 - 2022 Intel Corporation. All rights reserved. - * Copyright(c) 2024-2025 Intel Corporation. All rights reserved. + * Copyright(c) 2024-2026 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH * * Portions of this file are derived from the ipw3945 project, as well @@ -27,8 +27,8 @@ #include #include "iwl-nvm-utils.h" -#include "iwl-io.h" #include "iwl-trans.h" +#include "iwl-devtrace.h" #include "iwl-op-mode.h" #include "iwl-drv.h" #include "iwl-modparams.h" @@ -413,7 +413,7 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, return; /* Set starting address; reads will auto-increment */ - iwl_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr); + iwl_trans_write32(priv->trans, HBUS_TARG_MEM_RADDR, ptr); /* * Refuse to read more than would have fit into the log from @@ -429,13 +429,13 @@ static void iwl_print_cont_event_trace(struct iwl_priv *priv, u32 base, * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); - time = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); + ev = iwl_trans_read32(priv->trans, HBUS_TARG_MEM_RDAT); + time = iwl_trans_read32(priv->trans, HBUS_TARG_MEM_RDAT); if (mode == 0) { trace_iwlwifi_dev_ucode_cont_event( priv->trans->dev, 0, time, ev); } else { - data = iwl_read32(priv->trans, HBUS_TARG_MEM_RDAT); + data = iwl_trans_read32(priv->trans, HBUS_TARG_MEM_RDAT); trace_iwlwifi_dev_ucode_cont_event( priv->trans->dev, time, data, ev); } @@ -661,8 +661,8 @@ static void iwl_rf_kill_ct_config(struct iwl_priv *priv) struct iwl_ct_kill_throttling_config adv_cmd; int ret = 0; - iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + iwl_trans_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = false; @@ -1731,13 +1731,13 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, return pos; /* Set starting address; reads will auto-increment */ - iwl_write32(trans, HBUS_TARG_MEM_RADDR, ptr); + iwl_trans_write32(trans, HBUS_TARG_MEM_RADDR, ptr); /* "time" is actually "data" for mode 0 (no timestamp). * place event id # at far right for easier visual parsing. */ for (i = 0; i < num_events; i++) { - ev = iwl_read32(trans, HBUS_TARG_MEM_RDAT); - time = iwl_read32(trans, HBUS_TARG_MEM_RDAT); + ev = iwl_trans_read32(trans, HBUS_TARG_MEM_RDAT); + time = iwl_trans_read32(trans, HBUS_TARG_MEM_RDAT); if (mode == 0) { /* data, ev */ if (bufsz) { @@ -1751,7 +1751,7 @@ static int iwl_print_event_log(struct iwl_priv *priv, u32 start_idx, time, ev); } } else { - data = iwl_read32(trans, HBUS_TARG_MEM_RDAT); + data = iwl_trans_read32(trans, HBUS_TARG_MEM_RDAT); if (bufsz) { pos += scnprintf(*buf + pos, bufsz - pos, "EVT_LOGT:%010u:0x%08x:%04u\n", @@ -2028,17 +2028,17 @@ static void iwl_nic_config(struct iwl_op_mode *op_mode) } /* set CSR_HW_CONFIG_REG for uCode use */ - iwl_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | - CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); + iwl_trans_set_bit(priv->trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_RADIO_SI | + CSR_HW_IF_CONFIG_REG_BIT_MAC_SI); /* W/A : NIC is stuck in a reset state after Early PCIe power off * (PCIe power is lost before PERST# is asserted), * causing ME FW to lose ownership and not being able to obtain it back. */ - iwl_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, - ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); + iwl_trans_set_bits_mask_prph(priv->trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, + ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); if (priv->lib->nic_config) priv->lib->nic_config(priv); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/power.c b/drivers/net/wireless/intel/iwlwifi/dvm/power.c index e7dbba7134f7..4e19799d15d7 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/power.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2019, 2025 Intel Corporation + * Copyright (C) 2019, 2025-2026 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -13,7 +13,6 @@ #include #include #include -#include "iwl-io.h" #include "iwl-debug.h" #include "iwl-trans.h" #include "iwl-modparams.h" diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c index 088302a238de..fa2aff5bea6c 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rx.c @@ -3,7 +3,7 @@ * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright(c) 2018, 2020-2021, 2025 Intel Corporation + * Copyright(c) 2018, 2020-2021, 2025-2026 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portionhelp of the ieee80211 subsystem header files. @@ -16,7 +16,6 @@ #include #include "iwl-trans.h" -#include "iwl-io.h" #include "dev.h" #include "calib.h" #include "agn.h" @@ -482,17 +481,17 @@ static void iwlagn_rx_card_state_notif(struct iwl_priv *priv, if (flags & (SW_CARD_DISABLED | HW_CARD_DISABLED | CT_CARD_DISABLED)) { - iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_trans_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + iwl_trans_write_direct32(priv->trans, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); if (!(flags & RXON_CARD_DISABLED)) { - iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); - iwl_write_direct32(priv->trans, HBUS_TARG_MBX_C, - HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); + iwl_trans_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_trans_write_direct32(priv->trans, HBUS_TARG_MBX_C, + HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED); } if (flags & CT_CARD_DISABLED) iwl_tt_enter_ct_kill(priv); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c index fc9cf0531024..a414eb7c2446 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tt.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. - * Copyright (C) 2018, 2020 Intel Corporation + * Copyright (C) 2018, 2020, 2026 Intel Corporation * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -13,7 +13,7 @@ #include #include #include -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-modparams.h" #include "iwl-debug.h" #include "agn.h" @@ -146,15 +146,15 @@ static void iwl_tt_check_exit_ct_kill(struct timer_list *t) if (tt->state == IWL_TI_CT_KILL) { if (priv->thermal_throttle.ct_kill_toggle) { - iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + iwl_trans_write32(priv->trans, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = false; } else { - iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, - CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); + iwl_trans_write32(priv->trans, CSR_UCODE_DRV_GP1_SET, + CSR_UCODE_DRV_GP1_REG_BIT_CT_KILL_EXIT); priv->thermal_throttle.ct_kill_toggle = true; } - iwl_read32(priv->trans, CSR_UCODE_DRV_GP1); + iwl_trans_read32(priv->trans, CSR_UCODE_DRV_GP1); if (iwl_trans_grab_nic_access(priv->trans)) iwl_trans_release_nic_access(priv->trans); diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c index 1a0167f67c7b..8dbc52971e7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/tx.c @@ -3,14 +3,13 @@ * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright (C) 2019 Intel Corporation - * Copyright (C) 2023, 2025 Intel Corporation + * Copyright (C) 2023, 2025-2026 Intel Corporation *****************************************************************************/ #include #include #include #include -#include "iwl-io.h" #include "iwl-trans.h" #include "iwl-agn-hw.h" #include "dev.h" diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c b/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c index ac90191a3973..2ab1a32d774e 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/ucode.c @@ -3,12 +3,11 @@ * * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2015 Intel Deutschland GmbH - * Copyright (C) 2025 Intel Corporation + * Copyright (C) 2025-2026 Intel Corporation *****************************************************************************/ #include -#include "iwl-io.h" #include "iwl-agn-hw.h" #include "iwl-trans.h" #include "iwl-fh.h" diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c index 71e0950d0193..7b11316a3062 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c @@ -525,6 +525,83 @@ iwl_acpi_parse_chains_table(union acpi_object *table, return 0; } +static int +iwl_acpi_parse_extended_sar_profiles(union acpi_object *wifi_pkg, + struct iwl_sar_profile *sar_profiles, + u8 num_sub_bands, bool has_cdb) +{ + int n_profiles, pos, ret; + bool enabled; + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) + return -EINVAL; + + if (WARN_ON(ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands > + ARRAY_SIZE(sar_profiles[0].chains) * + ARRAY_SIZE(sar_profiles[0].chains[0].subbands))) + return -EINVAL; + + enabled = !!(wifi_pkg->package.elements[1].integer.value); + n_profiles = wifi_pkg->package.elements[2].integer.value; + + if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) + return -EINVAL; + + /* the tables start at element 3 */ + pos = 3; + + BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0 != ACPI_SAR_NUM_CHAINS_REV1); + BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2 != 2 * ACPI_SAR_NUM_CHAINS_REV0); + + /* parse non-cdb chains for all profiles */ + for (int i = 0; i < n_profiles; i++) { + union acpi_object *table = &wifi_pkg->package.elements[pos]; + + ret = iwl_acpi_parse_chains_table(table, + sar_profiles[i + 1].chains, + ACPI_SAR_NUM_CHAINS_REV0, + num_sub_bands); + if (ret < 0) + return ret; + + /* go to the next table */ + pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands; + } + + if (!has_cdb) + goto set_enabled; + + if (WARN_ON(ACPI_SAR_NUM_CHAINS_REV0 * 2 * num_sub_bands > + ARRAY_SIZE(sar_profiles[0].chains) * + ARRAY_SIZE(sar_profiles[0].chains[0].subbands))) + return -EINVAL; + + /* parse cdb chains for all profiles */ + for (int i = 0; i < n_profiles; i++) { + struct iwl_sar_profile_chain *chains; + union acpi_object *table; + + table = &wifi_pkg->package.elements[pos]; + chains = &sar_profiles[i + 1].chains[ACPI_SAR_NUM_CHAINS_REV0]; + ret = iwl_acpi_parse_chains_table(table, + chains, + ACPI_SAR_NUM_CHAINS_REV0, + num_sub_bands); + if (ret < 0) + return ret; + + /* go to the next table */ + pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands; + } + +set_enabled: + for (int i = 0; i < n_profiles; i++) + sar_profiles[i + 1].enabled = enabled; + + return 0; +} + int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *table, *data; @@ -629,8 +706,12 @@ int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) */ ret = iwl_acpi_parse_chains_table(table, fwrt->sar_profiles[0].chains, num_chains, num_sub_bands); - if (!ret && flags & IWL_SAR_ENABLE_MSK) + if (ret) + goto out_free; + + if (flags & IWL_SAR_ENABLE_MSK) fwrt->sar_profiles[0].enabled = true; + fwrt->wrds_table_revision = tbl_rev; out_free: kfree(data); @@ -640,8 +721,7 @@ int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data; - bool enabled; - int i, n_profiles, tbl_rev, pos; + int tbl_rev; int ret = 0; u8 num_sub_bands; @@ -713,95 +793,149 @@ int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) goto out_free; read_table: - if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || - wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER) { - ret = -EINVAL; + ret = iwl_acpi_parse_extended_sar_profiles(wifi_pkg, + fwrt->sar_profiles, + num_sub_bands, + tbl_rev >= 2); + if (ret) goto out_free; - } - if (WARN_ON(ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands > - ARRAY_SIZE(fwrt->sar_profiles[0].chains) * - ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) { - ret = -EINVAL; - goto out_free; - } - - enabled = !!(wifi_pkg->package.elements[1].integer.value); - n_profiles = wifi_pkg->package.elements[2].integer.value; - - /* - * Check the validity of n_profiles. The EWRD profiles start - * from index 1, so the maximum value allowed here is - * ACPI_SAR_PROFILES_NUM - 1. - */ - if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { - ret = -EINVAL; - goto out_free; - } - - /* the tables start at element 3 */ - pos = 3; - - BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV0 != ACPI_SAR_NUM_CHAINS_REV1); - BUILD_BUG_ON(ACPI_SAR_NUM_CHAINS_REV2 != 2 * ACPI_SAR_NUM_CHAINS_REV0); - - /* parse non-cdb chains for all profiles */ - for (i = 0; i < n_profiles; i++) { - union acpi_object *table = &wifi_pkg->package.elements[pos]; - - /* The EWRD profiles officially go from 2 to 4, but we - * save them in sar_profiles[1-3] (because we don't - * have profile 0). So in the array we start from 1. - */ - ret = iwl_acpi_parse_chains_table(table, - fwrt->sar_profiles[i + 1].chains, - ACPI_SAR_NUM_CHAINS_REV0, - num_sub_bands); - if (ret < 0) - goto out_free; - - /* go to the next table */ - pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands; - } - - /* non-cdb table revisions */ - if (tbl_rev < 2) - goto set_enabled; - - if (WARN_ON(ACPI_SAR_NUM_CHAINS_REV0 * 2 * num_sub_bands > - ARRAY_SIZE(fwrt->sar_profiles[0].chains) * - ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) { - ret = -EINVAL; - goto out_free; - } - - /* parse cdb chains for all profiles */ - for (i = 0; i < n_profiles; i++) { - struct iwl_sar_profile_chain *chains; - union acpi_object *table; - - table = &wifi_pkg->package.elements[pos]; - chains = &fwrt->sar_profiles[i + 1].chains[ACPI_SAR_NUM_CHAINS_REV0]; - ret = iwl_acpi_parse_chains_table(table, - chains, - ACPI_SAR_NUM_CHAINS_REV0, - num_sub_bands); - if (ret < 0) - goto out_free; - - /* go to the next table */ - pos += ACPI_SAR_NUM_CHAINS_REV0 * num_sub_bands; - } - -set_enabled: - for (i = 0; i < n_profiles; i++) - fwrt->sar_profiles[i + 1].enabled = enabled; + fwrt->ewrd_table_revision = tbl_rev; out_free: kfree(data); return ret; } +int iwl_acpi_get_wsss_table(struct iwl_fw_runtime *fwrt) +{ + union acpi_object *data __free(kfree) = NULL; + union acpi_object *wifi_pkg, *table; + u8 num_chains, num_sub_bands; + int ret, tbl_rev; + u32 flags; + + if (fwrt->wrds_table_revision == IWL_BIOS_REVISION_UNSET) { + IWL_DEBUG_RADIO(fwrt, + "Skipping standalone SAR: WRDS table was not read\n"); + return -EINVAL; + } + + data = iwl_acpi_get_object(fwrt->dev, ACPI_WSSS_METHOD); + if (IS_ERR(data)) + return PTR_ERR(data); + + switch (fwrt->wrds_table_revision) { + case 3: + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV3, + &tbl_rev); + num_chains = ACPI_SAR_NUM_CHAINS_REV2; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV3; + break; + case 2: + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV2, + &tbl_rev); + num_chains = ACPI_SAR_NUM_CHAINS_REV2; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; + break; + default: + return -EINVAL; + } + + if (IS_ERR(wifi_pkg)) + return PTR_ERR(wifi_pkg); + + if (fwrt->wrds_table_revision != tbl_rev) { + IWL_DEBUG_RADIO(fwrt, + "Skipping standalone SAR: WRDS/WSSS revision mismatch (WRDS rev %d, WSSS rev %d)\n", + fwrt->wrds_table_revision, + tbl_rev); + return -EINVAL; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) + return -EINVAL; + + if (WARN_ON(num_chains * num_sub_bands > + ARRAY_SIZE(fwrt->sar_standalone_profiles[0].chains) * + ARRAY_SIZE(fwrt->sar_standalone_profiles[0].chains[0].subbands))) + return -EINVAL; + + IWL_DEBUG_RADIO(fwrt, "Reading WSSS (WRDS Standalone) tbl_rev=%d\n", + tbl_rev); + + flags = wifi_pkg->package.elements[1].integer.value; + + /* position of the actual table */ + table = &wifi_pkg->package.elements[2]; + + ret = iwl_acpi_parse_chains_table(table, + fwrt->sar_standalone_profiles[0].chains, + num_chains, num_sub_bands); + if (ret) + return ret; + + if (flags & IWL_SAR_ENABLE_MSK) + fwrt->sar_standalone_profiles[0].enabled = true; + + return ret; +} + +int iwl_acpi_get_ewss_table(struct iwl_fw_runtime *fwrt) +{ + union acpi_object *data __free(kfree) = NULL; + union acpi_object *wifi_pkg; + u8 num_sub_bands; + int tbl_rev; + + if (fwrt->ewrd_table_revision == IWL_BIOS_REVISION_UNSET) { + IWL_DEBUG_RADIO(fwrt, + "Skipping standalone SAR: EWRD table was not read\n"); + return -EINVAL; + } + + data = iwl_acpi_get_object(fwrt->dev, ACPI_EWSS_METHOD); + if (IS_ERR(data)) + return PTR_ERR(data); + + switch (fwrt->ewrd_table_revision) { + case 3: + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_EWRD_WIFI_DATA_SIZE_REV3, + &tbl_rev); + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV3; + break; + case 2: + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_EWRD_WIFI_DATA_SIZE_REV2, + &tbl_rev); + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; + break; + default: + return -EINVAL; + } + + if (IS_ERR(wifi_pkg)) + return PTR_ERR(wifi_pkg); + + if (fwrt->ewrd_table_revision != tbl_rev) { + IWL_DEBUG_RADIO(fwrt, + "Skipping standalone SAR: EWRD/EWSS revision mismatch (EWRD rev %d, EWSS rev %d)\n", + fwrt->ewrd_table_revision, tbl_rev); + return -EINVAL; + } + + IWL_DEBUG_RADIO(fwrt, "Reading EWSS (EWRD Standalone) tbl_rev=%d\n", + tbl_rev); + + return iwl_acpi_parse_extended_sar_profiles(wifi_pkg, + fwrt->sar_standalone_profiles, + num_sub_bands, + fwrt->ewrd_table_revision >= 2); +} + int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data; @@ -1153,7 +1287,8 @@ void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) } if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || - wifi_pkg->package.elements[1].integer.value > ACPI_GLAI_MAX_STATUS) + wifi_pkg->package.elements[1].integer.value > + UEFI_CNV_GUID_TEST_MODE) goto out_free; fwrt->uefi_tables_lock_status = @@ -1165,7 +1300,6 @@ void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) out_free: kfree(data); } -IWL_EXPORT_SYMBOL(iwl_acpi_get_guid_lock_status); int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value) { diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h index 45eb35ffb637..b722beae2f00 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h @@ -14,6 +14,8 @@ #define ACPI_WRDS_METHOD "WRDS" #define ACPI_EWRD_METHOD "EWRD" +#define ACPI_WSSS_METHOD "WSSS" +#define ACPI_EWSS_METHOD "EWSS" #define ACPI_WGDS_METHOD "WGDS" #define ACPI_WRDD_METHOD "WRDD" #define ACPI_SPLC_METHOD "SPLC" @@ -89,7 +91,6 @@ * and one for the status */ #define ACPI_GLAI_WIFI_DATA_SIZE 2 -#define ACPI_GLAI_MAX_STATUS 2 /* * TAS size: 1 elelment for type, * 1 element for enabled field, @@ -111,9 +112,6 @@ #define ACPI_PPAG_WIFI_DATA_SIZE_V3 ((ACPI_PPAG_NUM_CHAINS * \ ACPI_PPAG_NUM_BANDS_V3) + 2) -/* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */ -#define UEFI_WIFI_GUID_UNLOCKED 0 - #define ACPI_DSM_REV 0 #define DSM_INTERNAL_FUNC_GET_PLAT_INFO 1 @@ -179,6 +177,10 @@ int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_wsss_table(struct iwl_fw_runtime *fwrt); + +int iwl_acpi_get_ewss_table(struct iwl_fw_runtime *fwrt); + int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, @@ -233,6 +235,16 @@ static inline int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) return -ENOENT; } +static inline int iwl_acpi_get_wsss_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_acpi_get_ewss_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + static inline int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) { return 1; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h index f76f76e54c4e..dbb0e7c194df 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/commands.h @@ -569,8 +569,9 @@ enum iwl_legacy_cmds { /** * @WOWLAN_KEK_KCK_MATERIAL: &struct iwl_wowlan_kek_kck_material_cmd_v2, - * &struct iwl_wowlan_kek_kck_material_cmd_v3 or - * &struct iwl_wowlan_kek_kck_material_cmd_v4 + * &struct iwl_wowlan_kek_kck_material_cmd_v3, + * &struct iwl_wowlan_kek_kck_material_cmd_v4 or + * &struct iwl_wowlan_kek_kck_material_cmd */ WOWLAN_KEK_KCK_MATERIAL = 0xe4, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/ctxt-info-v2.h b/drivers/net/wireless/intel/iwlwifi/fw/api/ctxt-info-v2.h new file mode 100644 index 000000000000..dd2ca1949735 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/ctxt-info-v2.h @@ -0,0 +1,328 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2026 Intel Corporation + */ +#ifndef __iwl_fw_api_context_info_v2_h__ +#define __iwl_fw_api_context_info_v2_h__ + +#include +#include +#include "ctxt-info.h" + +/* CSR addresses used by context info v2 */ +#define CSR_CTXT_INFO_BOOT_CTRL 0x0 +#define CSR_CTXT_INFO_ADDR 0x118 +#define CSR_IML_DATA_ADDR 0x120 +#define CSR_IML_SIZE_ADDR 0x128 +#define CSR_IML_RESP_ADDR 0x12c + +#define UNFRAGMENTED_PNVM_PAYLOADS_NUMBER 2 + +/* Set bit for enabling automatic function boot */ +#define CSR_AUTO_FUNC_BOOT_ENA BIT(1) +/* Set bit for initiating function boot */ +#define CSR_AUTO_FUNC_INIT BIT(7) + +/** + * enum iwl_prph_scratch_mtr_format - tfd size configuration + * @IWL_PRPH_MTR_FORMAT_16B: 16 bit tfd + * @IWL_PRPH_MTR_FORMAT_32B: 32 bit tfd + * @IWL_PRPH_MTR_FORMAT_64B: 64 bit tfd + * @IWL_PRPH_MTR_FORMAT_256B: 256 bit tfd + */ +enum iwl_prph_scratch_mtr_format { + IWL_PRPH_MTR_FORMAT_16B = 0x0, + IWL_PRPH_MTR_FORMAT_32B = 0x40000, + IWL_PRPH_MTR_FORMAT_64B = 0x80000, + IWL_PRPH_MTR_FORMAT_256B = 0xC0000, +}; + +/** + * enum iwl_prph_scratch_flags - PRPH scratch control flags + * @IWL_PRPH_SCRATCH_IMR_DEBUG_EN: IMR support for debug + * @IWL_PRPH_SCRATCH_EARLY_DEBUG_EN: enable early debug conf + * @IWL_PRPH_SCRATCH_EDBG_DEST_DRAM: use DRAM, with size allocated + * in hwm config. + * @IWL_PRPH_SCRATCH_EDBG_DEST_INTERNAL: use buffer on SRAM + * @IWL_PRPH_SCRATCH_EDBG_DEST_ST_ARBITER: use st arbiter, mainly for + * multicomm. + * @IWL_PRPH_SCRATCH_EDBG_DEST_TB22DTF: route debug data to SoC HW + * @IWL_PRPH_SCRATCH_RB_SIZE_4K: Use 4K RB size (the default is 2K) + * @IWL_PRPH_SCRATCH_MTR_MODE: format used for completion - 0: for + * completion descriptor, 1 for responses (legacy) + * @IWL_PRPH_SCRATCH_MTR_FORMAT: a mask for the size of the tfd. + * There are 4 optional values: 0: 16 bit, 1: 32 bit, 2: 64 bit, + * 3: 256 bit. + * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_MASK: RB size full information, ignored + * by older firmware versions, so set IWL_PRPH_SCRATCH_RB_SIZE_4K + * appropriately; use the below values for this. + * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_8K: 8kB RB size + * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_12K: 12kB RB size + * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_16K: 16kB RB size + * @IWL_PRPH_SCRATCH_SCU_FORCE_ACTIVE: Indicate fw to set SCU_FORCE_ACTIVE + * upon reset. + * @IWL_PRPH_SCRATCH_TOP_RESET: request TOP reset + */ +enum iwl_prph_scratch_flags { + IWL_PRPH_SCRATCH_IMR_DEBUG_EN = BIT(1), + IWL_PRPH_SCRATCH_EARLY_DEBUG_EN = BIT(4), + IWL_PRPH_SCRATCH_EDBG_DEST_DRAM = BIT(8), + IWL_PRPH_SCRATCH_EDBG_DEST_INTERNAL = BIT(9), + IWL_PRPH_SCRATCH_EDBG_DEST_ST_ARBITER = BIT(10), + IWL_PRPH_SCRATCH_EDBG_DEST_TB22DTF = BIT(11), + IWL_PRPH_SCRATCH_RB_SIZE_4K = BIT(16), + IWL_PRPH_SCRATCH_MTR_MODE = BIT(17), + IWL_PRPH_SCRATCH_MTR_FORMAT = BIT(18) | BIT(19), + IWL_PRPH_SCRATCH_RB_SIZE_EXT_MASK = 0xf << 20, + IWL_PRPH_SCRATCH_RB_SIZE_EXT_8K = 8 << 20, + IWL_PRPH_SCRATCH_RB_SIZE_EXT_12K = 9 << 20, + IWL_PRPH_SCRATCH_RB_SIZE_EXT_16K = 10 << 20, + IWL_PRPH_SCRATCH_SCU_FORCE_ACTIVE = BIT(29), + IWL_PRPH_SCRATCH_TOP_RESET = BIT(30), +}; + +/** + * enum iwl_prph_scratch_ext_flags - PRPH scratch control ext flags + * @IWL_PRPH_SCRATCH_EXT_EXT_FSEQ: external FSEQ image provided + * @IWL_PRPH_SCRATCH_EXT_URM_FW: switch to URM mode based on fw setting + * @IWL_PRPH_SCRATCH_EXT_URM_PERM: switch to permanent URM mode + * @IWL_PRPH_SCRATCH_EXT_32KHZ_CLK_VALID: use external 32 KHz clock + */ +enum iwl_prph_scratch_ext_flags { + IWL_PRPH_SCRATCH_EXT_EXT_FSEQ = BIT(0), + IWL_PRPH_SCRATCH_EXT_URM_FW = BIT(4), + IWL_PRPH_SCRATCH_EXT_URM_PERM = BIT(5), + IWL_PRPH_SCRATCH_EXT_32KHZ_CLK_VALID = BIT(8), +}; + +/** + * struct iwl_prph_scratch_version - version structure + * @mac_id: SKU and revision id + * @version: prph scratch information version id + * @size: the size of the context information in DWs + * @reserved: reserved + */ +struct iwl_prph_scratch_version { + __le16 mac_id; + __le16 version; + __le16 size; + __le16 reserved; +} __packed; /* PERIPH_SCRATCH_VERSION_S */ + +/** + * struct iwl_prph_scratch_control - control structure + * @control_flags: context information flags see &enum iwl_prph_scratch_flags + * @control_flags_ext: context information for extended flags, + * see &enum iwl_prph_scratch_ext_flags + */ +struct iwl_prph_scratch_control { + __le32 control_flags; + __le32 control_flags_ext; +} __packed; /* PERIPH_SCRATCH_CONTROL_S */ + +/** + * struct iwl_prph_scratch_pnvm_cfg - PNVM scratch + * @pnvm_base_addr: PNVM start address + * @pnvm_size: the size of the PNVM image in bytes + * @reserved: reserved + */ +struct iwl_prph_scratch_pnvm_cfg { + __le64 pnvm_base_addr; + __le32 pnvm_size; + __le32 reserved; +} __packed; /* PERIPH_SCRATCH_PNVM_CFG_S */ + +/** + * struct iwl_prph_scratch_mem_desc_addr_array - DRAM + * @mem_descs: array of dram addresses. + * Each address is the beginning of a PNVM payload. + */ +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 */ + +/** + * struct iwl_prph_scratch_hwm_cfg - hwm config + * @hwm_base_addr: hwm start address + * @hwm_size: hwm size in DWs + * @debug_token_config: debug preset + */ +struct iwl_prph_scratch_hwm_cfg { + __le64 hwm_base_addr; + __le32 hwm_size; + __le32 debug_token_config; +} __packed; /* PERIPH_SCRATCH_HWM_CFG_S */ + +/** + * struct iwl_prph_scratch_rbd_cfg - RBDs configuration + * @free_rbd_addr: default queue free RB CB base address + * @reserved: reserved + */ +struct iwl_prph_scratch_rbd_cfg { + __le64 free_rbd_addr; + __le32 reserved; +} __packed; /* PERIPH_SCRATCH_RBD_CFG_S */ + +/** + * struct iwl_prph_scratch_uefi_cfg - prph scratch reduce power table + * @base_addr: reduce power table address + * @size: the size of the entire power table image + * @reserved: (reserved) + */ +struct iwl_prph_scratch_uefi_cfg { + __le64 base_addr; + __le32 size; + __le32 reserved; +} __packed; /* PERIPH_SCRATCH_UEFI_CFG_S */ + +/** + * struct iwl_prph_scratch_step_cfg - prph scratch step configuration + * @mbx_addr_0: [0:7] revision, + * [8:15] cnvi_to_cnvr length, + * [16:23] cnvr_to_cnvi channel length, + * [24:31] radio1 reserved + * @mbx_addr_1: [0:7] radio2 reserved + */ +struct iwl_prph_scratch_step_cfg { + __le32 mbx_addr_0; + __le32 mbx_addr_1; +} __packed; + +/** + * struct iwl_prph_scratch_ctrl_cfg - prph scratch ctrl and config + * @version: version information of context info and HW + * @control: control flags of FH configurations + * @pnvm_cfg: ror configuration + * @hwm_cfg: hwm configuration + * @rbd_cfg: default RX queue configuration + * @reduce_power_cfg: UEFI power reduction table + * @step_cfg: step configuration + */ +struct iwl_prph_scratch_ctrl_cfg { + struct iwl_prph_scratch_version version; + struct iwl_prph_scratch_control control; + struct iwl_prph_scratch_pnvm_cfg pnvm_cfg; + struct iwl_prph_scratch_hwm_cfg hwm_cfg; + struct iwl_prph_scratch_rbd_cfg rbd_cfg; + struct iwl_prph_scratch_uefi_cfg reduce_power_cfg; + struct iwl_prph_scratch_step_cfg step_cfg; +} __packed; /* PERIPH_SCRATCH_CTRL_CFG_S */ + +/** + * struct iwl_context_info_v2 - device INIT configuration + * @version: version of the context information + * @size: size of context information in DWs + * @config: context in which the peripheral would execute - a subset of + * capability csr register published by the peripheral + * @prph_info_base_addr: the peripheral information structure start address + * @cr_head_idx_arr_base_addr: the completion ring head index array + * start address + * @tr_tail_idx_arr_base_addr: the transfer ring tail index array + * start address + * @cr_tail_idx_arr_base_addr: the completion ring tail index array + * start address + * @tr_head_idx_arr_base_addr: the transfer ring head index array + * start address + * @cr_idx_arr_size: number of entries in the completion ring index array + * @tr_idx_arr_size: number of entries in the transfer ring index array + * @mtr_base_addr: the message transfer ring start address + * @mcr_base_addr: the message completion ring start address + * @mtr_size: number of entries which the message transfer ring can hold + * @mcr_size: number of entries which the message completion ring can hold + * @mtr_doorbell_vec: the doorbell vector associated with the message + * transfer ring + * @mcr_doorbell_vec: the doorbell vector associated with the message + * completion ring + * @mtr_msi_vec: the MSI which shall be generated by the peripheral after + * completing a transfer descriptor in the message transfer ring + * @mcr_msi_vec: the MSI which shall be generated by the peripheral after + * completing a completion descriptor in the message completion ring + * @mtr_opt_header_size: the size of the optional header in the transfer + * descriptor associated with the message transfer ring in DWs + * @mtr_opt_footer_size: the size of the optional footer in the transfer + * descriptor associated with the message transfer ring in DWs + * @mcr_opt_header_size: the size of the optional header in the completion + * descriptor associated with the message completion ring in DWs + * @mcr_opt_footer_size: the size of the optional footer in the completion + * descriptor associated with the message completion ring in DWs + * @msg_rings_ctrl_flags: message rings control flags + * @prph_info_msi_vec: the MSI which shall be generated by the peripheral + * after updating the Peripheral Information structure + * @prph_scratch_base_addr: the peripheral scratch structure start address + * @prph_scratch_size: the size of the peripheral scratch structure in DWs + * @reserved: reserved + */ +struct iwl_context_info_v2 { + __le16 version; + __le16 size; + __le32 config; + __le64 prph_info_base_addr; + __le64 cr_head_idx_arr_base_addr; + __le64 tr_tail_idx_arr_base_addr; + __le64 cr_tail_idx_arr_base_addr; + __le64 tr_head_idx_arr_base_addr; + __le16 cr_idx_arr_size; + __le16 tr_idx_arr_size; + __le64 mtr_base_addr; + __le64 mcr_base_addr; + __le16 mtr_size; + __le16 mcr_size; + __le16 mtr_doorbell_vec; + __le16 mcr_doorbell_vec; + __le16 mtr_msi_vec; + __le16 mcr_msi_vec; + u8 mtr_opt_header_size; + u8 mtr_opt_footer_size; + u8 mcr_opt_header_size; + u8 mcr_opt_footer_size; + __le16 msg_rings_ctrl_flags; + __le16 prph_info_msi_vec; + __le64 prph_scratch_base_addr; + __le32 prph_scratch_size; + __le32 reserved; +} __packed; /* IPC_CONTEXT_INFO_S */ + +#define IWL_NUM_DRAM_FSEQ_ENTRIES 8 + +/** + * struct iwl_context_info_dram_fseq - images DRAM map (with fseq) + * each entry in the map represents a DRAM chunk of up to 32 KB + * @common: UMAC/LMAC/virtual images + * @fseq_img: FSEQ image DRAM map + */ +struct iwl_context_info_dram_fseq { + struct iwl_context_info_dram_nonfseq common; + __le64 fseq_img[IWL_NUM_DRAM_FSEQ_ENTRIES]; +} __packed; /* PERIPH_SCRATCH_DRAM_MAP_S */ + +/** + * struct iwl_prph_scratch - peripheral scratch mapping + * @ctrl_cfg: control and configuration of prph scratch + * @dram: firmware images addresses in DRAM + * @fseq_override: FSEQ override parameters + * @step_analog_params: STEP analog calibration values + * @reserved: reserved + */ +struct iwl_prph_scratch { + struct iwl_prph_scratch_ctrl_cfg ctrl_cfg; + __le32 fseq_override; + __le32 step_analog_params; + __le32 reserved[8]; + struct iwl_context_info_dram_fseq dram; +} __packed; /* PERIPH_SCRATCH_S */ + +/** + * struct iwl_prph_info - peripheral information + * @boot_stage_mirror: reflects the value in the Boot Stage CSR register + * @ipc_status_mirror: reflects the value in the IPC Status CSR register + * @sleep_notif: indicates the peripheral sleep status + * @reserved: reserved + */ +struct iwl_prph_info { + __le32 boot_stage_mirror; + __le32 ipc_status_mirror; + __le32 sleep_notif; + __le32 reserved; +} __packed; /* PERIPH_INFO_S */ + +#endif /* __iwl_fw_api_context_info_v2_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/ctxt-info.h b/drivers/net/wireless/intel/iwlwifi/fw/api/ctxt-info.h new file mode 100644 index 000000000000..40a087b22150 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/ctxt-info.h @@ -0,0 +1,185 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2026 Intel Corporation + */ +#ifndef __iwl_fw_api_context_info_h__ +#define __iwl_fw_api_context_info_h__ + +#include + +/* maximum number of DRAM map entries supported by FW */ +#define IWL_MAX_DRAM_ENTRY 64 +#define CSR_CTXT_INFO_BA 0x40 + +/** + * enum iwl_context_info_flags - Context information control flags + * @IWL_CTXT_INFO_AUTO_FUNC_INIT: If set, FW will not wait before interrupting + * the init done for driver command that configures several system modes + * @IWL_CTXT_INFO_EARLY_DEBUG: enable early debug + * @IWL_CTXT_INFO_ENABLE_CDMP: enable core dump + * @IWL_CTXT_INFO_RB_CB_SIZE: mask of the RBD Cyclic Buffer Size + * exponent, the actual size is 2**value, valid sizes are 8-2048. + * The value is four bits long. Maximum valid exponent is 12 + * @IWL_CTXT_INFO_TFD_FORMAT_LONG: use long TFD Format (the + * default is short format - not supported by the driver) + * @IWL_CTXT_INFO_RB_SIZE: RB size mask + * (values are IWL_CTXT_INFO_RB_SIZE_*K) + * @IWL_CTXT_INFO_RB_SIZE_1K: Value for 1K RB size + * @IWL_CTXT_INFO_RB_SIZE_2K: Value for 2K RB size + * @IWL_CTXT_INFO_RB_SIZE_4K: Value for 4K RB size + * @IWL_CTXT_INFO_RB_SIZE_8K: Value for 8K RB size + * @IWL_CTXT_INFO_RB_SIZE_12K: Value for 12K RB size + * @IWL_CTXT_INFO_RB_SIZE_16K: Value for 16K RB size + * @IWL_CTXT_INFO_RB_SIZE_20K: Value for 20K RB size + * @IWL_CTXT_INFO_RB_SIZE_24K: Value for 24K RB size + * @IWL_CTXT_INFO_RB_SIZE_28K: Value for 28K RB size + * @IWL_CTXT_INFO_RB_SIZE_32K: Value for 32K RB size + */ +enum iwl_context_info_flags { + IWL_CTXT_INFO_AUTO_FUNC_INIT = 0x0001, + IWL_CTXT_INFO_EARLY_DEBUG = 0x0002, + IWL_CTXT_INFO_ENABLE_CDMP = 0x0004, + IWL_CTXT_INFO_RB_CB_SIZE = 0x00f0, + IWL_CTXT_INFO_TFD_FORMAT_LONG = 0x0100, + IWL_CTXT_INFO_RB_SIZE = 0x1e00, + IWL_CTXT_INFO_RB_SIZE_1K = 0x1, + IWL_CTXT_INFO_RB_SIZE_2K = 0x2, + IWL_CTXT_INFO_RB_SIZE_4K = 0x4, + IWL_CTXT_INFO_RB_SIZE_8K = 0x8, + IWL_CTXT_INFO_RB_SIZE_12K = 0x9, + IWL_CTXT_INFO_RB_SIZE_16K = 0xa, + IWL_CTXT_INFO_RB_SIZE_20K = 0xb, + IWL_CTXT_INFO_RB_SIZE_24K = 0xc, + IWL_CTXT_INFO_RB_SIZE_28K = 0xd, + IWL_CTXT_INFO_RB_SIZE_32K = 0xe, +}; + +/** + * struct iwl_context_info_version - version structure + * @mac_id: SKU and revision id + * @version: context information version id + * @size: the size of the context information in DWs + * @reserved: (reserved) + */ +struct iwl_context_info_version { + __le16 mac_id; + __le16 version; + __le16 size; + __le16 reserved; +} __packed; + +/** + * struct iwl_context_info_control - version structure + * @control_flags: context information flags see &enum iwl_context_info_flags + * @reserved: (reserved) + */ +struct iwl_context_info_control { + __le32 control_flags; + __le32 reserved; +} __packed; + +/** + * struct iwl_context_info_dram_nonfseq - images DRAM map + * each entry in the map represents a DRAM chunk of up to 32 KB + * @umac_img: UMAC image DRAM map + * @lmac_img: LMAC image DRAM map + * @virtual_img: paged image DRAM map + */ +struct iwl_context_info_dram_nonfseq { + __le64 umac_img[IWL_MAX_DRAM_ENTRY]; + __le64 lmac_img[IWL_MAX_DRAM_ENTRY]; + __le64 virtual_img[IWL_MAX_DRAM_ENTRY]; +} __packed; + +/** + * struct iwl_context_info_rbd_cfg - RBDs configuration + * @free_rbd_addr: default queue free RB CB base address + * @used_rbd_addr: default queue used RB CB base address + * @status_wr_ptr: default queue used RB status write pointer + */ +struct iwl_context_info_rbd_cfg { + __le64 free_rbd_addr; + __le64 used_rbd_addr; + __le64 status_wr_ptr; +} __packed; + +/** + * struct iwl_context_info_hcmd_cfg - command queue configuration + * @cmd_queue_addr: address of command queue + * @cmd_queue_size: number of entries + * @reserved: (reserved) + */ +struct iwl_context_info_hcmd_cfg { + __le64 cmd_queue_addr; + u8 cmd_queue_size; + u8 reserved[7]; +} __packed; + +/** + * struct iwl_context_info_dump_cfg - Core Dump configuration + * @core_dump_addr: core dump (debug DRAM address) start address + * @core_dump_size: size, in DWs + * @reserved: (reserved) + */ +struct iwl_context_info_dump_cfg { + __le64 core_dump_addr; + __le32 core_dump_size; + __le32 reserved; +} __packed; + +/** + * struct iwl_context_info_pnvm_cfg - platform NVM data configuration + * @platform_nvm_addr: Platform NVM data start address + * @platform_nvm_size: size in DWs + * @reserved: (reserved) + */ +struct iwl_context_info_pnvm_cfg { + __le64 platform_nvm_addr; + __le32 platform_nvm_size; + __le32 reserved; +} __packed; + +/** + * struct iwl_context_info_early_dbg_cfg - early debug configuration for + * dumping DRAM addresses + * @early_debug_addr: early debug start address + * @early_debug_size: size in DWs + * @reserved: (reserved) + */ +struct iwl_context_info_early_dbg_cfg { + __le64 early_debug_addr; + __le32 early_debug_size; + __le32 reserved; +} __packed; + +/** + * struct iwl_context_info - device INIT configuration + * @version: version information of context info and HW + * @control: control flags of FH configurations + * @reserved0: (reserved) + * @rbd_cfg: default RX queue configuration + * @hcmd_cfg: command queue configuration + * @reserved1: (reserved) + * @dump_cfg: core dump data + * @edbg_cfg: early debug configuration + * @pnvm_cfg: platform nvm configuration + * @reserved2: (reserved) + * @dram: firmware image addresses in DRAM + * @reserved3: (reserved) + */ +struct iwl_context_info { + struct iwl_context_info_version version; + struct iwl_context_info_control control; + __le64 reserved0; + struct iwl_context_info_rbd_cfg rbd_cfg; + struct iwl_context_info_hcmd_cfg hcmd_cfg; + __le32 reserved1[4]; + struct iwl_context_info_dump_cfg dump_cfg; + struct iwl_context_info_early_dbg_cfg edbg_cfg; + struct iwl_context_info_pnvm_cfg pnvm_cfg; + __le32 reserved2[16]; + struct iwl_context_info_dram_nonfseq dram; + __le32 reserved3[16]; +} __packed; /* BOOT_LOADER_CONTEXT_INFO_S */ + +#endif /* __iwl_fw_api_context_info_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index d3bed0216df4..327a8c05f4db 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2025 Intel Corporation + * Copyright (C) 2012-2014, 2018-2026 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -366,16 +366,16 @@ enum iwl_wowlan_flags { ENABLE_L3_FILTERING = BIT(1), ENABLE_NBNS_FILTERING = BIT(2), ENABLE_DHCP_FILTERING = BIT(3), - ENABLE_STORE_BEACON = BIT(4), + EPP_ROBUST_CONNECTION = BIT(4), HAS_BEACON_PROTECTION = BIT(5), }; /** * struct iwl_wowlan_config_cmd_v6 - WoWLAN configuration (versions 5 and 6) * @wakeup_filter: filter from &enum iwl_wowlan_wakeup_filters - * @non_qos_seq: non-QoS sequence counter to use next. + * @non_qos_seq: last used non-QoS sequence counter. * Reserved if the struct has version >= 6. - * @qos_seq: QoS sequence counters to use next + * @qos_seq: last used QoS sequence counters * @wowlan_ba_teardown_tids: bitmap of BA sessions to tear down * @is_11n_connection: indicates HT connection * @offloading_tid: TID reserved for firmware use @@ -422,6 +422,7 @@ struct iwl_wowlan_config_cmd { #define WOWLAN_IGTK_MIN_INDEX 4 #define WOWLAN_BIGTK_KEYS_NUM 2 #define WOWLAN_BIGTK_MIN_INDEX 6 +#define WOWLAN_CIGTK_KEYS_NUM 2 /* * WOWLAN_TSC_RSC_PARAMS @@ -531,6 +532,20 @@ struct iwl_wowlan_kek_kck_material_cmd_v4 { __le32 bigtk_cipher; } __packed; /* KEK_KCK_MATERIAL_API_S_VER_4 */ +struct iwl_wowlan_kek_kck_material_cmd { + __le32 sta_id; + u8 kck[IWL_KCK_MAX_SIZE]; + u8 kek[IWL_KEK_MAX_SIZE]; + __le16 kck_len; + __le16 kek_len; + __le64 replay_ctr; + __le32 akm; + __le32 gtk_cipher; + __le32 igtk_cipher; + __le32 bigtk_cipher; + __le32 cigtk_cipher; +} __packed; /* KEK_KCK_MATERIAL_API_S_VER_5 */ + struct iwl_wowlan_get_status_cmd { __le32 sta_id; } __packed; /* WOWLAN_GET_STATUSES_CMD_API_S_VER_1 */ @@ -717,8 +732,8 @@ struct iwl_wowlan_igtk_status { * @gtk: GTK data * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched pattern - * @non_qos_seq_ctr: non-QoS sequence counter to use next - * @qos_seq_ctr: QoS sequence counters to use next + * @non_qos_seq_ctr: last used non-QoS sequence counter + * @qos_seq_ctr: last used QoS sequence counters * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason * @num_of_gtk_rekeys: number of GTK rekeys * @transmitted_ndps: number of transmitted neighbor discovery packets @@ -748,8 +763,8 @@ struct iwl_wowlan_status_v6 { * @igtk: IGTK data * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched pattern - * @non_qos_seq_ctr: non-QoS sequence counter to use next - * @qos_seq_ctr: QoS sequence counters to use next + * @non_qos_seq_ctr: last used non-QoS sequence counter + * @qos_seq_ctr: last used QoS sequence counters * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason * @num_of_gtk_rekeys: number of GTK rekeys * @transmitted_ndps: number of transmitted neighbor discovery packets @@ -781,7 +796,7 @@ struct iwl_wowlan_status_v7 { * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched patterns * @reserved1: reserved - * @qos_seq_ctr: QoS sequence counters to use next + * @qos_seq_ctr: last used QoS sequence counters * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason * @num_of_gtk_rekeys: number of GTK rekeys * @transmitted_ndps: number of transmitted neighbor discovery packets @@ -812,19 +827,21 @@ struct iwl_wowlan_info_notif_v1 { } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_1 */ /* MAX MLO keys of non-active links that can arrive in the notification */ -#define WOWLAN_MAX_MLO_KEYS 18 +#define WOWLAN_MAX_MLO_KEYS 24 /** * enum iwl_wowlan_mlo_gtk_type - GTK types * @WOWLAN_MLO_GTK_KEY_TYPE_GTK: GTK * @WOWLAN_MLO_GTK_KEY_TYPE_IGTK: IGTK * @WOWLAN_MLO_GTK_KEY_TYPE_BIGTK: BIGTK + * @WOWLAN_MLO_GTK_KEY_TYPE_CIGTK: CIGTK * @WOWLAN_MLO_GTK_KEY_NUM_TYPES: number of key types */ enum iwl_wowlan_mlo_gtk_type { WOWLAN_MLO_GTK_KEY_TYPE_GTK, WOWLAN_MLO_GTK_KEY_TYPE_IGTK, WOWLAN_MLO_GTK_KEY_TYPE_BIGTK, + WOWLAN_MLO_GTK_KEY_TYPE_CIGTK, WOWLAN_MLO_GTK_KEY_NUM_TYPES }; /* WOWLAN_MLO_GTK_KEY_TYPE_API_E_VER_1 */ @@ -865,7 +882,7 @@ struct iwl_wowlan_mlo_gtk { * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched patterns * @reserved1: reserved - * @qos_seq_ctr: QoS sequence counters to use next + * @qos_seq_ctr: last used QoS sequence counters * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason * @num_of_gtk_rekeys: number of GTK rekeys * @transmitted_ndps: number of transmitted neighbor discovery packets @@ -899,7 +916,7 @@ struct iwl_wowlan_info_notif_v3 { * @bigtk: BIGTK data * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched patterns - * @qos_seq_ctr: QoS sequence counters to use next + * @qos_seq_ctr: last used QoS sequence counter for @tid_offloaded_tx * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason * @num_of_gtk_rekeys: number of GTK rekeys * @transmitted_ndps: number of transmitted neighbor discovery packets @@ -932,13 +949,53 @@ struct iwl_wowlan_info_notif_v5 { } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_5 */ /** - * struct iwl_wowlan_info_notif - WoWLAN information notification + * struct iwl_wowlan_info_notif_v6 - WoWLAN information notification * @gtk: GTK data * @igtk: IGTK data * @bigtk: BIGTK data * @replay_ctr: GTK rekey replay counter * @pattern_number: number of the matched patterns - * @qos_seq_ctr: QoS sequence counters to use next + * @qos_seq_ctr: last used QoS sequence counter for @tid_offloaded_tx + * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason + * @num_of_gtk_rekeys: number of GTK rekeys + * @transmitted_ndps: number of transmitted neighbor discovery packets + * @received_beacons: number of received beacons + * @tid_tear_down: bit mask of tids whose BA sessions were closed + * in suspend state + * @station_id: station id + * @num_mlo_link_keys: number of &struct iwl_wowlan_mlo_gtk structs + * following this notif + * @tid_offloaded_tx: tid used by the firmware to transmit data packets + * while in wowlan + * @mlo_gtks: array of GTKs of size num_mlo_link_keys + */ +struct iwl_wowlan_info_notif_v6 { + struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 qos_seq_ctr; + __le32 wakeup_reasons; + __le32 num_of_gtk_rekeys; + __le32 transmitted_ndps; + __le32 received_beacons; + u8 tid_tear_down; + u8 station_id; + u8 num_mlo_link_keys; + u8 tid_offloaded_tx; + struct iwl_wowlan_mlo_gtk mlo_gtks[]; +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_6 */ + +/** + * struct iwl_wowlan_info_notif - WoWLAN information notification + * @gtk: GTK data + * @igtk: IGTK data + * @bigtk: BIGTK data + * @cigtk: CIGTK data + * @replay_ctr: GTK rekey replay counter + * @pattern_number: number of the matched patterns + * @qos_seq_ctr: last used QoS sequence counter for @tid_offloaded_tx * @wakeup_reasons: wakeup reasons, see &enum iwl_wowlan_wakeup_reason * @num_of_gtk_rekeys: number of GTK rekeys * @transmitted_ndps: number of transmitted neighbor discovery packets @@ -956,6 +1013,7 @@ struct iwl_wowlan_info_notif { struct iwl_wowlan_gtk_status gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status cigtk[WOWLAN_CIGTK_KEYS_NUM]; __le64 replay_ctr; __le16 pattern_number; __le16 qos_seq_ctr; @@ -968,7 +1026,7 @@ struct iwl_wowlan_info_notif { u8 num_mlo_link_keys; u8 tid_offloaded_tx; struct iwl_wowlan_mlo_gtk mlo_gtks[]; -} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_6 */ +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_7 */ /** * struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h index c8eb016e1a7e..eddf13325df9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/datapath.h @@ -522,17 +522,34 @@ struct iwl_rx_baid_cfg_cmd_alloc { } __packed; /* RX_BAID_ALLOCATION_ADD_CMD_API_S_VER_1 */ /** - * struct iwl_rx_baid_cfg_cmd_modify - BAID modification data + * struct iwl_rx_baid_cfg_cmd_modify_v2 - BAID modification data * @old_sta_id_mask: old station ID mask * @new_sta_id_mask: new station ID mask * @tid: TID of the BAID */ -struct iwl_rx_baid_cfg_cmd_modify { +struct iwl_rx_baid_cfg_cmd_modify_v2 { __le32 old_sta_id_mask; __le32 new_sta_id_mask; __le32 tid; } __packed; /* RX_BAID_ALLOCATION_MODIFY_CMD_API_S_VER_2 */ +/** + * struct iwl_rx_baid_cfg_cmd_modify - BAID modification data + * @old_sta_id_mask: old station ID mask + * @new_sta_id_mask: new station ID mask + * @tid: TID of the BAID + * @reserved: reserved + * @win_size: RX BA session window size to apply to the modified BAID, + * 0 means keep the current one + */ +struct iwl_rx_baid_cfg_cmd_modify { + __le32 old_sta_id_mask; + __le32 new_sta_id_mask; + u8 tid; + u8 reserved; + __le16 win_size; +} __packed; /* RX_BAID_ALLOCATION_MODIFY_CMD_API_S_VER_3 */ + /** * struct iwl_rx_baid_cfg_cmd_remove_v1 - BAID removal data * @baid: the BAID to remove @@ -555,7 +572,8 @@ struct iwl_rx_baid_cfg_cmd_remove { * struct iwl_rx_baid_cfg_cmd - BAID allocation/config command * @action: the action, from &enum iwl_rx_baid_action * @alloc: allocation data - * @modify: modify data + * @modify_v2: modify data (version 2) + * @modify: modify data (version 3) * @remove_v1: remove data (version 1) * @remove: remove data */ @@ -563,11 +581,12 @@ struct iwl_rx_baid_cfg_cmd { __le32 action; union { struct iwl_rx_baid_cfg_cmd_alloc alloc; + struct iwl_rx_baid_cfg_cmd_modify_v2 modify_v2; struct iwl_rx_baid_cfg_cmd_modify modify; struct iwl_rx_baid_cfg_cmd_remove_v1 remove_v1; struct iwl_rx_baid_cfg_cmd_remove remove; - }; /* RX_BAID_ALLOCATION_OPERATION_API_U_VER_2 */ -} __packed; /* RX_BAID_ALLOCATION_CONFIG_CMD_API_S_VER_2 */ + }; /* RX_BAID_ALLOCATION_OPERATION_API_U_VER_3 */ +} __packed; /* RX_BAID_ALLOCATION_CONFIG_CMD_API_S_VER_3 */ /** * struct iwl_rx_baid_cfg_resp - BAID allocation response @@ -589,6 +608,16 @@ enum iwl_scd_queue_cfg_operation { IWL_SCD_QUEUE_MODIFY = 2, }; +/** + * enum iwl_scd_queue_modify_flags - scheduler queue modify flags + * @IWL_SCD_QUEUE_MODIFY_FLAG_RD_PTR: update the read pointer + * @IWL_SCD_QUEUE_MODIFY_FLAG_STA_MSK: update the station mask + */ +enum iwl_scd_queue_modify_flags { + IWL_SCD_QUEUE_MODIFY_FLAG_RD_PTR = BIT(0), + IWL_SCD_QUEUE_MODIFY_FLAG_STA_MSK = BIT(1), +}; + /** * struct iwl_scd_queue_cfg_cmd - scheduler queue allocation command * @operation: the operation, see &enum iwl_scd_queue_cfg_operation @@ -606,6 +635,8 @@ enum iwl_scd_queue_cfg_operation { * @u.modify.old_sta_mask: old station mask for modify * @u.modify.tid: TID of queue to modify * @u.modify.new_sta_mask: new station mask for modify + * @u.modify.rd_ptr: new read pointer to set for the queue (version 4) + * @u.modify.flags: &enum iwl_scd_queue_modify_flags (version 4) */ struct iwl_scd_queue_cfg_cmd { __le32 operation; @@ -627,9 +658,11 @@ struct iwl_scd_queue_cfg_cmd { __le32 old_sta_mask; __le32 tid; __le32 new_sta_mask; - } __packed modify; /* TX_QUEUE_CFG_CMD_MODIFY_API_S_VER_1 */ - } __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1 */ -} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3 */ + __le16 rd_ptr; + __le16 flags; + } __packed modify; /* TX_QUEUE_CFG_CMD_MODIFY_API_S_VER_1, _VER_2 */ + } __packed u; /* TX_QUEUE_CFG_CMD_OPERATION_API_U_VER_1, _VER_2 */ +} __packed; /* TX_QUEUE_CFG_CMD_API_S_VER_3, _VER_4 */ /** * enum iwl_sec_key_flags - security key command key flags @@ -643,6 +676,7 @@ struct iwl_scd_queue_cfg_cmd { * @IWL_SEC_KEY_FLAG_MFP: MFP is in used for this key * @IWL_SEC_KEY_FLAG_MCAST_KEY: this is a multicast key * @IWL_SEC_KEY_FLAG_SPP_AMSDU: SPP A-MSDU should be used + * @IWL_SEC_KEY_FLAG_ASSOC_ENC: use this key for (Re)Assoc Req/Resp encryption */ enum iwl_sec_key_flags { IWL_SEC_KEY_FLAG_CIPHER_MASK = 0x07, @@ -655,6 +689,7 @@ enum iwl_sec_key_flags { IWL_SEC_KEY_FLAG_MFP = 0x20, IWL_SEC_KEY_FLAG_MCAST_KEY = 0x40, IWL_SEC_KEY_FLAG_SPP_AMSDU = 0x80, + IWL_SEC_KEY_FLAG_ASSOC_ENC = 0x200, }; #define IWL_SEC_WEP_KEY_OFFSET 3 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h index 09b2cddc4ad2..6e536f48acdb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h @@ -7,6 +7,8 @@ #ifndef __iwl_fw_api_mac_cfg_h__ #define __iwl_fw_api_mac_cfg_h__ +#include + #include "mac.h" #include "phy-ctxt.h" @@ -663,7 +665,13 @@ struct iwl_npca_params { * @puncture_mask: puncture mask for EHT (removed in VER_3) * @frame_time_rts_th: HE duration RTS threshold, in units of 32us * @flags: a combination from &enum iwl_link_ctx_flags - * @flags_mask: what of %flags have changed. Also &enum iwl_link_ctx_flags + * @flags_mask: what of %flags have changed. Also &enum iwl_link_ctx_flags. + * Removed in _VER_6, reused as @reserved4 / @max_bssid_indicator + * in _VER_9. + * @reserved4: reserved + * @max_bssid_indicator: N where 2**N is the max number of BSSIDs the physical + * AP can support (multi-BSS or EMCCA set). 0 disables the feature. + * Since _VER_9. * Below fields are for multi-bssid: * @ref_bssid_addr: reference BSSID used by the AP * @reserved_for_ref_bssid_addr: reserved @@ -704,17 +712,23 @@ struct iwl_link_config_cmd { /* MAC_QOS_PARAM_API_S_VER_1 */ __le32 qos_flags; struct iwl_ac_qos ac[AC_NUM + 1]; - u8 htc_trig_based_pkt_ext; - u8 rand_alloc_ecwmin; - u8 rand_alloc_ecwmax; + u8 htc_trig_based_pkt_ext; /* removed in _VER_9 */ + u8 rand_alloc_ecwmin; /* removed in _VER_9 */ + u8 rand_alloc_ecwmax; /* removed in _VER_9 */ u8 ndp_fdbk_buff_th_exp; struct iwl_he_backoff_conf trig_based_txf[AC_NUM]; __le32 bi; __le32 dtim_interval; __le16 puncture_mask; /* removed in _VER_3 */ - __le16 frame_time_rts_th; + __le16 frame_time_rts_th; /* removed in _VER_9 */ __le32 flags; - __le32 flags_mask; /* removed in _VER_6 */ + union { + __le32 flags_mask; /* removed in _VER_6 */ + struct { + u8 reserved4[3]; + u8 max_bssid_indicator; /* since _VER_9 */ + }; + }; /* The below fields are for multi-bssid */ u8 ref_bssid_addr[6]; __le16 reserved_for_ref_bssid_addr; @@ -728,7 +742,9 @@ struct iwl_link_config_cmd { struct iwl_ac_qos prio_edca_params; /* since _VER_7 */ __le32 reserved3[4]; } __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3, _VER_4, - * _VER_5, _VER_6, _VER_7, _VER_8 */ + * _VER_5, _VER_6, _VER_7, _VER_8, + * _VER_9 + */ /* Currently FW supports link ids in the range 0-3 and can have * at most two active links for each vif. @@ -868,8 +884,8 @@ struct iwl_sta_cfg_cmd_v1 { * @dps_pad_time: DPS (Dynamic Power Save) padding delay resolution to ensure * proper timing alignment * @dps_trans_delay: DPS minimal time that takes the peer to return to low power - * @mic_prep_pad_delay: MIC prep time padding - * @mic_compute_pad_delay: MIC compute time padding + * @mic_prep_pad_delay: MIC prep time padding (4 us resolution) + * @mic_compute_pad_delay: MIC compute time padding (4 us resolution) * @reserved: Reserved for alignment */ struct iwl_sta_cfg_cmd_v2 { @@ -924,8 +940,13 @@ struct iwl_sta_cfg_cmd_v2 { * @mimo_protection: indicates whether the sta uses mimo protection or not * @ack_enabled: indicates that the AP supports receiving ACK- * enabled AGG, i.e. both BACK and non-BACK frames in a single AGG - * @trig_rnd_alloc: indicates that trigger based random allocation - * is enabled according to UORA element existence + * @cip_defer: delay the usage of the unicast control frame protection until + * after association. + * Only supported from command version 4, must be left cleared otherwise. + * @epp_robust: indicates that EPP robust individually addressed management + * frame support was negotiated during association. + * Only supported from command version 4, must be left cleared otherwise. + * @reserved1: Reserved for alignment * @tx_ampdu_spacing: minimum A-MPDU spacing: * 4 - 2us density, 5 - 4us density, 6 - 8us density, 7 - 16us density * @tx_ampdu_max_size: maximum A-MPDU length: 0 - 8K, 1 - 16K, 2 - 32K, @@ -942,8 +963,8 @@ struct iwl_sta_cfg_cmd_v2 { * proper timing alignment * @dps_trans_delay: DPS minimal time that takes the peer to return to low power * @dps_enabled: flag indicating whether or not DPS is enabled - * @mic_prep_pad_delay: MIC prep time padding - * @mic_compute_pad_delay: MIC compute time padding + * @mic_prep_pad_delay: MIC prep time padding (4 us resolution) + * @mic_compute_pad_delay: MIC compute time padding (4 us resolution) * @nmi_sta_id: for an NDI peer STA, the NMI peer STA ID it relates to * @ndi_local_addr: for an NDI peer STA or NAN multicast data station, * the local NDI interface MAC address @@ -963,7 +984,9 @@ struct iwl_sta_cfg_cmd { __le32 mimo; __le32 mimo_protection; __le32 ack_enabled; - __le32 trig_rnd_alloc; + u8 cip_defer; + u8 epp_robust; + __le16 reserved1; __le32 tx_ampdu_spacing; __le32 tx_ampdu_max_size; __le32 sp_length; @@ -980,7 +1003,7 @@ struct iwl_sta_cfg_cmd { u8 nmi_sta_id; u8 ndi_local_addr[ETH_ALEN]; u8 reserved[2]; -} __packed; /* STA_CMD_API_S_VER_3 */ +} __packed; /* STA_CMD_API_S_VER_3, STA_CMD_API_S_VER_4 */ /** * struct iwl_aux_sta_cmd - command for AUX STA configuration diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h index bb801650a565..078116fab054 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/offload.h @@ -3,7 +3,7 @@ * Copyright (C) 2012-2014 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2021-2025 Intel Corporation + * Copyright (C) 2021-2026 Intel Corporation */ #ifndef __iwl_fw_api_offload_h__ #define __iwl_fw_api_offload_h__ @@ -20,7 +20,8 @@ enum iwl_prot_offload_subcmd_ids { /** * @WOWLAN_INFO_NOTIFICATION: Notification in * &struct iwl_wowlan_info_notif_v1, iwl_wowlan_info_notif_v3, - * &struct iwl_wowlan_info_notif_v5 or &struct iwl_wowlan_info_notif + * &struct iwl_wowlan_info_notif_v5, &struct iwl_wowlan_info_notif_v6 + * or &struct iwl_wowlan_info_notif */ WOWLAN_INFO_NOTIFICATION = 0xFD, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h index 115e65ba19f8..4d54a95b98ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h @@ -300,7 +300,8 @@ enum iwl_dev_tx_power_cmd_mode { IWL_TX_POWER_MODE_SET_ACK = 3, IWL_TX_POWER_MODE_SET_SAR_TIMER = 4, IWL_TX_POWER_MODE_SET_SAR_TIMER_DEFAULT_TABLE = 5, -}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_5 */; + IWL_TX_POWER_MODE_SET_STANDALONE_CHAINS = 8, /* cmd ver 12+ */ +}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_2 */; #define IWL_NUM_CHAIN_TABLES 1 #define IWL_NUM_CHAIN_TABLES_V2 2 @@ -464,31 +465,34 @@ struct iwl_dev_tx_power_cmd_v10 { __le32 flags; } __packed; /* TX_REDUCED_POWER_API_S_VER_10 */ -struct iwl_dev_tx_power_cmd_v11 { +struct iwl_dev_tx_power_cmd_v12 { __le16 per_chain[IWL_NUM_CHAIN_TABLES_V2][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V3]; u8 per_chain_restriction_changed; u8 reserved; __le32 timer_period; __le32 flags; -} __packed; /* TX_REDUCED_POWER_API_S_VER_11 */ +} __packed; /* TX_REDUCED_POWER_API_S_VER_11 + * TX_REDUCED_POWER_API_S_VER_12 + */ /* * struct iwl_dev_tx_power_cmd - TX power reduction command (multiversion) * @common: common part of the command * @v9: version 9 part of the command * @v10: version 10 part of the command - * @v11: version 11 part of the command + * @v12: version 12 part of the command (also covers v11) */ struct iwl_dev_tx_power_cmd { struct iwl_dev_tx_power_common common; union { struct iwl_dev_tx_power_cmd_v9 v9; struct iwl_dev_tx_power_cmd_v10 v10; - struct iwl_dev_tx_power_cmd_v11 v11; + struct iwl_dev_tx_power_cmd_v12 v12; }; } __packed; /* TX_REDUCED_POWER_API_S_VER_9 * TX_REDUCED_POWER_API_S_VER_10 * TX_REDUCED_POWER_API_S_VER_11 + * TX_REDUCED_POWER_API_S_VER_12 */ #define IWL_NUM_GEO_PROFILES 3 diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h index 699343cf0279..20460534fc99 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h @@ -583,7 +583,11 @@ struct iwl_rx_mpdu_desc_v3 { /** * @reserved_xsum: reserved high bits in the raw checksum */ - __le16 reserved_xsum; + u8 reserved_xsum; + /** + * @mac_context: MAC context mask, in this DW only from API version 10 + */ + u8 mac_context; /* DW11 */ /** * @rate_n_flags: RX rate/flags encoding @@ -603,9 +607,10 @@ struct iwl_rx_mpdu_desc_v3 { */ u8 channel; /** - * @mac_context: MAC context mask + * @ru: RU/MRU/DRU used for the frame, in trigger-like format; + * only from API version 10, this byte held @mac_context before */ - u8 mac_context; + u8 ru; /* DW13 */ /** * @gp2_on_air_rise: GP2 timer value on air rise (INA) @@ -647,7 +652,11 @@ struct iwl_rx_mpdu_desc_v3 { __le32 reserved[1]; } __packed; /* RX_MPDU_RES_START_API_S_VER_3, * RX_MPDU_RES_START_API_S_VER_5, - * RX_MPDU_RES_START_API_S_VER_6 + * RX_MPDU_RES_START_API_S_VER_6, + * RX_MPDU_RES_START_API_S_VER_7, + * RX_MPDU_RES_START_API_S_VER_8, + * RX_MPDU_RES_START_API_S_VER_9, + * RX_MPDU_RES_START_API_S_VER_10 */ /** @@ -737,6 +746,8 @@ struct iwl_rx_mpdu_desc { * RX_MPDU_RES_START_API_S_VER_6 * RX_MPDU_RES_START_API_S_VER_7 * RX_MPDU_RES_START_API_S_VER_8 + * RX_MPDU_RES_START_API_S_VER_9 + * RX_MPDU_RES_START_API_S_VER_10 */ #define IWL_RX_DESC_SIZE_V1 offsetofend(struct iwl_rx_mpdu_desc, v1) @@ -1347,7 +1358,7 @@ struct iwl_uhr_elr_sigs { #define OFDM_RX_VECTOR_UHR_ELR_PPDU_TYPE 0x00000003 #define OFDM_RX_VECTOR_UHR_ELR_USIG_STA_ID 0x00001ffc #define OFDM_RX_VECTOR_UHR_ELR_VALIDATE 0x0000e000 -#define OFDM_RX_VECTOR_UHR_ELR_CRC_OK 0x00010000 +#define OFDM_RX_VECTOR_UHR_ELR_CRC_OK 0x40000000 __le32 usig_a2_uhr_elr; #define OFDM_RX_VECTOR_UHR_ELR_VER_ID 0x00000007 #define OFDM_RX_VECTOR_UHR_ELR_UPLINK_FLAG 0x00000008 @@ -1363,7 +1374,7 @@ struct iwl_uhr_elr_sigs { #define OFDM_RX_VECTOR_UHR_ELR_SIG_ID_INDX 0x00000e00 #define OFDM_RX_VECTOR_UHR_ELR_STA_RU 0x000ff000 #define OFDM_RX_VECTOR_UHR_ELR_STA_RU_PS160 0x00100000 -#define OFDM_RX_VECTOR_UHR_ELR_SIG2_CRC_OK 0x00200000 +#define OFDM_RX_VECTOR_UHR_ELR_SIG2_CRC_OK 0x40000000 __le32 uhr_sig_elr2; }; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h index ee78371082b0..8994a7b840ef 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h @@ -987,6 +987,8 @@ struct iwl_scan_probe_params_v4 { #define SCAN_MAX_NUM_CHANS_V3 67 #define SCAN_MAX_NUM_CHANS_V4 68 +#define SCAN_MAX_NUM_NOTIF_RESULTS 112 + /** * struct iwl_scan_channel_params_v4 - channel params * @flags: channel flags &enum iwl_scan_channel_flags @@ -1232,7 +1234,8 @@ struct iwl_umac_scan_complete { } __packed; /* SCAN_COMPLETE_NTF_UMAC_API_S_VER_1 */ #define SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 5 -#define SCAN_OFFLOAD_MATCHING_CHANNELS_LEN 7 +#define SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V2 7 +#define SCAN_OFFLOAD_MATCHING_CHANNELS_LEN 16 /** * struct iwl_scan_offload_profile_match_v1 - match information @@ -1278,11 +1281,31 @@ struct iwl_scan_offload_profiles_query_v1 { struct iwl_scan_offload_profile_match_v1 matches[]; } __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_2 */ +/** + * struct iwl_scan_offload_profile_match_v2 - match information + * @bssid: matched bssid + * @reserved: reserved + * @channel: channel where the match occurred + * @energy: energy + * @matching_feature: feature matches + * @matching_channels: bitmap of channels that matched, referencing + * the channels passed in the scan offload request. + */ +struct iwl_scan_offload_profile_match_v2 { + u8 bssid[ETH_ALEN]; + __le16 reserved; + u8 channel; + u8 energy; + u8 matching_feature; + u8 matching_channels[SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V2]; +} __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_2 */ + /** * struct iwl_scan_offload_profile_match - match information * @bssid: matched bssid * @reserved: reserved * @channel: channel where the match occurred + * @band: band where the match occurred * @energy: energy * @matching_feature: feature matches * @matching_channels: bitmap of channels that matched, referencing @@ -1292,10 +1315,11 @@ struct iwl_scan_offload_profile_match { u8 bssid[ETH_ALEN]; __le16 reserved; u8 channel; + u8 band; u8 energy; u8 matching_feature; u8 matching_channels[SCAN_OFFLOAD_MATCHING_CHANNELS_LEN]; -} __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_2 */ +} __packed; /* SCAN_OFFLOAD_PROFILE_MATCH_RESULTS_S_VER_3 */ /** * struct iwl_scan_offload_match_info - match results information @@ -1320,12 +1344,13 @@ struct iwl_scan_offload_match_info { u8 self_recovery; __le16 reserved; struct iwl_scan_offload_profile_match matches[IWL_SCAN_MAX_PROFILES_V2]; -} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_3 and +} __packed; /* SCAN_OFFLOAD_PROFILES_QUERY_RSP_S_VER_5 and * SCAN_OFFLOAD_MATCH_INFO_NOTIFICATION_S_VER_1 */ /** - * struct iwl_umac_scan_iter_complete_notif - notifies end of scanning iteration + * struct iwl_umac_scan_iter_complete_notif_v2 - notifies end of scanning + * iteration * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @scanned_channels: number of channels scanned and number of valid elements in * results array @@ -1336,7 +1361,7 @@ struct iwl_scan_offload_match_info { * in &struct iwl_scan_req_umac. * @results: array of scan results, length in @scanned_channels */ -struct iwl_umac_scan_iter_complete_notif { +struct iwl_umac_scan_iter_complete_notif_v2 { __le32 uid; u8 scanned_channels; u8 status; @@ -1346,6 +1371,39 @@ struct iwl_umac_scan_iter_complete_notif { struct iwl_scan_results_notif results[]; } __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_2 */ +/** + * struct iwl_umac_scan_iter_complete_notif - notifies end of scanning + * iteration + * @uid: scan id, &enum iwl_umac_scan_uid_offsets + * @scanned_channels: number of channels scanned and number of valid elements in + * results array + * @status: one of SCAN_COMP_STATUS_* + * @bt_status: BT on/off status + * @last_channel: last channel that was scanned + * @start_tsf: TSF timer in usecs of the scan start time for the mac specified + * in &struct iwl_scan_req_umac. + * @results: array of scan results, only @scanned_channels of them are valid + * @ebs_status: EBS completion status, &enum iwl_scan_ebs_status + * @reserved: reserved for alignment + * @ebs_channel_status: only valid when @ebs_status is %IWL_SCAN_EBS_SUCCESS. + * Bitmap of the 5 GHz channels on which EBS found energy: + * bit i in [0..27]: channel = 36 + 4 * i (channels 36 - 144) + * bit i in [28..35]: channel = 37 + 4 * i (channels 149 - 177) + * bit 36: channel 181 (reserved, not currently covered by EBS) + */ +struct iwl_umac_scan_iter_complete_notif { + __le32 uid; + u8 scanned_channels; + u8 status; + u8 bt_status; + u8 last_channel; + __le64 start_tsf; + struct iwl_scan_results_notif results[SCAN_MAX_NUM_NOTIF_RESULTS]; + u8 ebs_status; + u8 reserved[3]; + __le64 ebs_channel_status; +} __packed; /* SCAN_ITER_COMPLETE_NTF_UMAC_API_S_VER_3 */ + /** * struct iwl_umac_scan_channel_survey_notif - data for survey * @channel: the channel scanned diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h index 8d16782a129c..e3bf5d08c7e7 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/stats.h @@ -616,7 +616,7 @@ struct iwl_stats_ntfy_coex { } __packed; /* STATISTICS_FW_NTFY_COEX_TELEMETRY_API_S_VER_1 */ /** - * struct iwl_stats_ntfy_per_phy - per PHY statistics + * struct iwl_stats_ntfy_per_phy_v2 - per PHY statistics * @channel_load: channel load * @channel_load_by_us: device contribution to MCLM * @channel_load_not_by_us: other devices' contribution to MCLM @@ -632,7 +632,7 @@ struct iwl_stats_ntfy_coex { * @last_tx_ch_width_indx: last txed frame channel width index * @coex: coex related data */ -struct iwl_stats_ntfy_per_phy { +struct iwl_stats_ntfy_per_phy_v2 { __le32 channel_load; __le32 channel_load_by_us; __le32 channel_load_not_by_us; @@ -646,6 +646,43 @@ struct iwl_stats_ntfy_per_phy { struct iwl_stats_ntfy_coex coex; } __packed; /* STATISTICS_NTFY_PER_PHY_API_S_VER_2 */ +/** + * struct iwl_stats_ntfy_per_phy - per PHY statistics + * @channel_load: channel load + * @channel_load_by_us: device contribution to MCLM + * @channel_load_not_by_us: other devices' contribution to MCLM + * @clt: CLT HW timer (TIM_CH_LOAD2) + * @act: active accumulator SW + * @elp: elapsed time accumulator SW + * @rx_detected_per_ch_width: number of deferred TX per channel width, + * 0 - 20, 1/2/3 - 40/80/160 + * @success_per_ch_width: number of frames that got ACK/BACK/CTS + * per channel BW. note, BACK counted as 1 + * @fail_per_ch_width: number of frames that didn't get ACK/BACK/CTS + * per channel BW. note BACK counted as 1 + * @last_tx_ch_width_indx: last txed frame channel width index + * @coex: coex related data + * @channel_load_npca_by_us: device NPCA contribution to MCLM + * @channel_load_npca_obss: the time FW identified for NPCA, not necessarily + * entered to NPCA state, but can be used as an indication for NPCA + * opportunities in the environment + */ +struct iwl_stats_ntfy_per_phy { + __le32 channel_load; + __le32 channel_load_by_us; + __le32 channel_load_not_by_us; + __le32 clt; + __le32 act; + __le32 elp; + __le32 rx_detected_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 success_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 fail_per_ch_width[IWL_STATS_MAX_BW_INDEX]; + __le32 last_tx_ch_width_indx; + struct iwl_stats_ntfy_coex coex; + __le32 channel_load_npca_by_us; + __le32 channel_load_npca_obss; +} __packed; /* STATISTICS_NTFY_PER_PHY_API_S_VER_3 */ + /* unknown channel load (due to not being active on channel) */ #define IWL_STATS_UNKNOWN_CHANNEL_LOAD 0xffffffff @@ -675,12 +712,27 @@ struct iwl_system_statistics_notif_oper_v3 { struct iwl_stats_ntfy_per_sta per_sta[IWL_STATION_COUNT_MAX]; } __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_3 */ +/** + * struct iwl_system_statistics_notif_oper_v4 - statistics notification + * + * @time_stamp: time when the notification is sent from firmware + * @per_link: per link statistics, &struct iwl_stats_ntfy_per_link + * @per_phy: per phy statistics, &struct iwl_stats_ntfy_per_phy_v2 + * @per_sta: per sta statistics, &struct iwl_stats_ntfy_per_sta + */ +struct iwl_system_statistics_notif_oper_v4 { + __le32 time_stamp; + struct iwl_stats_ntfy_per_link per_link[IWL_FW_MAX_LINKS]; + struct iwl_stats_ntfy_per_phy_v2 per_phy[IWL_STATS_MAX_PHY_OPERATIONAL]; + struct iwl_stats_ntfy_per_sta per_sta[IWL_STATION_COUNT_MAX]; +} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_4 */ + /** * struct iwl_system_statistics_notif_oper - statistics notification * * @time_stamp: time when the notification is sent from firmware * @per_link: per link statistics, &struct iwl_stats_ntfy_per_link - * @per_phy: per phy statistics, &struct iwl_stats_ntfy_per_phy_v1 + * @per_phy: per phy statistics, &struct iwl_stats_ntfy_per_phy * @per_sta: per sta statistics, &struct iwl_stats_ntfy_per_sta */ struct iwl_system_statistics_notif_oper { @@ -688,7 +740,7 @@ struct iwl_system_statistics_notif_oper { struct iwl_stats_ntfy_per_link per_link[IWL_FW_MAX_LINKS]; struct iwl_stats_ntfy_per_phy per_phy[IWL_STATS_MAX_PHY_OPERATIONAL]; struct iwl_stats_ntfy_per_sta per_sta[IWL_STATION_COUNT_MAX]; -} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_4 */ +} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_5 */ /** * struct iwl_system_statistics_part1_notif_oper - part1 stats notification diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h index 31d3336726b4..9d9eb320db7b 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/tx.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2025 Intel Corporation + * Copyright (C) 2012-2014, 2018-2026 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_tx_h__ @@ -292,6 +292,9 @@ struct iwl_tx_cmd_v9 { * @dram_info: FW internal DRAM storage * @rate_n_flags: rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is * cleared. Combination of RATE_MCS_*; format depends on version + * @driver_timestamp: gp2 time, in microseconds, assigned before queueing the + * MPDU. Firmware uses it to detect frames blocked for too long. + * Zero means no timestamp. Used from TX_CMD_API_S_VER_12. * @reserved: reserved * @hdr: 802.11 header */ @@ -301,10 +304,12 @@ struct iwl_tx_cmd { __le32 offload_assist; struct iwl_dram_sec_info dram_info; __le32 rate_n_flags; - u8 reserved[8]; + __le32 driver_timestamp; + u8 reserved[4]; struct ieee80211_hdr hdr[]; } __packed; /* TX_CMD_API_S_VER_10, - * TX_CMD_API_S_VER_11 + * TX_CMD_API_S_VER_11, + * TX_CMD_API_S_VER_12 */ /* diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg-old.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg-old.c index 19b1bfd0abee..09c798d2eba3 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg-old.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg-old.c @@ -9,7 +9,7 @@ #include "runtime.h" #include "dbg.h" #include "debugfs.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "iwl-csr.h" #include "iwl-fh.h" @@ -47,8 +47,8 @@ static void iwl_read_radio_regs(struct iwl_fw_runtime *fwrt, u32 rd_cmd = RADIO_RSP_RD_CMD; rd_cmd |= i << RADIO_RSP_ADDR_POS; - iwl_trans_write_prph(fwrt->trans, RSP_RADIO_CMD, rd_cmd); - *pos = (u8)iwl_trans_read_prph(fwrt->trans, RSP_RADIO_RDDAT); + iwl_trans_write_prph_no_grab(fwrt->trans, RSP_RADIO_CMD, rd_cmd); + *pos = (u8)iwl_trans_read_prph_no_grab(fwrt->trans, RSP_RADIO_RDDAT); pos++; } @@ -81,35 +81,35 @@ static void iwl_fwrt_dump_rxf(struct iwl_fw_runtime *fwrt, fifo_hdr->fifo_num = cpu_to_le32(fifo_num); fifo_hdr->available_bytes = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - RXF_RD_D_SPACE + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + RXF_RD_D_SPACE + offset)); fifo_hdr->wr_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - RXF_RD_WR_PTR + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + RXF_RD_WR_PTR + offset)); fifo_hdr->rd_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - RXF_RD_RD_PTR + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + RXF_RD_RD_PTR + offset)); fifo_hdr->fence_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - RXF_RD_FENCE_PTR + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + RXF_RD_FENCE_PTR + offset)); fifo_hdr->fence_mode = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - RXF_SET_FENCE_MODE + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + RXF_SET_FENCE_MODE + offset)); /* Lock fence */ - iwl_trans_write_prph(fwrt->trans, RXF_SET_FENCE_MODE + offset, 0x1); + iwl_trans_write_prph_no_grab(fwrt->trans, RXF_SET_FENCE_MODE + offset, 0x1); /* Set fence pointer to the same place like WR pointer */ - iwl_trans_write_prph(fwrt->trans, RXF_LD_WR2FENCE + offset, 0x1); + iwl_trans_write_prph_no_grab(fwrt->trans, RXF_LD_WR2FENCE + offset, 0x1); /* Set fence offset */ - iwl_trans_write_prph(fwrt->trans, - RXF_LD_FENCE_OFFSET_ADDR + offset, 0x0); + iwl_trans_write_prph_no_grab(fwrt->trans, + RXF_LD_FENCE_OFFSET_ADDR + offset, 0x0); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (i = 0; i < fifo_len; i++) - fifo_data[i] = iwl_trans_read_prph(fwrt->trans, - RXF_FIFO_RD_FENCE_INC + - offset); + fifo_data[i] = iwl_trans_read_prph_no_grab(fwrt->trans, + RXF_FIFO_RD_FENCE_INC + + offset); *dump_data = iwl_fw_error_next_data(*dump_data); } @@ -136,33 +136,33 @@ static void iwl_fwrt_dump_txf(struct iwl_fw_runtime *fwrt, fifo_hdr->fifo_num = cpu_to_le32(fifo_num); fifo_hdr->available_bytes = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_FIFO_ITEM_CNT + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_FIFO_ITEM_CNT + offset)); fifo_hdr->wr_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_WR_PTR + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_WR_PTR + offset)); fifo_hdr->rd_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_RD_PTR + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_RD_PTR + offset)); fifo_hdr->fence_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_FENCE_PTR + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_FENCE_PTR + offset)); fifo_hdr->fence_mode = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_LOCK_FENCE + offset)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_LOCK_FENCE + offset)); /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ - iwl_trans_write_prph(fwrt->trans, TXF_READ_MODIFY_ADDR + offset, - TXF_WR_PTR + offset); + iwl_trans_write_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_ADDR + offset, + TXF_WR_PTR + offset); /* Dummy-read to advance the read pointer to the head */ - iwl_trans_read_prph(fwrt->trans, TXF_READ_MODIFY_DATA + offset); + iwl_trans_read_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_DATA + offset); /* Read FIFO */ for (i = 0; i < fifo_len / sizeof(u32); i++) - fifo_data[i] = iwl_trans_read_prph(fwrt->trans, - TXF_READ_MODIFY_DATA + - offset); + fifo_data[i] = iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_READ_MODIFY_DATA + + offset); if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf) fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx, @@ -217,7 +217,7 @@ static void iwl_fw_dump_txf(struct iwl_fw_runtime *fwrt, /* Pull TXF data from LMAC1 */ for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ - iwl_trans_write_prph(fwrt->trans, TXF_LARC_NUM, i); + iwl_trans_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM, i); iwl_fwrt_dump_txf(fwrt, dump_data, cfg->lmac[0].txfifo_size[i], 0, i); } @@ -227,9 +227,9 @@ static void iwl_fw_dump_txf(struct iwl_fw_runtime *fwrt, for (i = 0; i < fwrt->smem_cfg.num_txfifo_entries; i++) { /* Mark the number of TXF we're pulling now */ - iwl_trans_write_prph(fwrt->trans, - TXF_LARC_NUM + - LMAC2_PRPH_OFFSET, i); + iwl_trans_write_prph_no_grab(fwrt->trans, + TXF_LARC_NUM + + LMAC2_PRPH_OFFSET, i); iwl_fwrt_dump_txf(fwrt, dump_data, cfg->lmac[1].txfifo_size[i], LMAC2_PRPH_OFFSET, @@ -262,40 +262,40 @@ static void iwl_fw_dump_txf(struct iwl_fw_runtime *fwrt, fifo_hdr->fifo_num = cpu_to_le32(i); /* Mark the number of TXF we're pulling now */ - iwl_trans_write_prph(fwrt->trans, TXF_CPU2_NUM, i + - fwrt->smem_cfg.num_txfifo_entries); + iwl_trans_write_prph_no_grab(fwrt->trans, TXF_CPU2_NUM, i + + fwrt->smem_cfg.num_txfifo_entries); fifo_hdr->available_bytes = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_CPU2_FIFO_ITEM_CNT)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_CPU2_FIFO_ITEM_CNT)); fifo_hdr->wr_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_CPU2_WR_PTR)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_CPU2_WR_PTR)); fifo_hdr->rd_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_CPU2_RD_PTR)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_CPU2_RD_PTR)); fifo_hdr->fence_ptr = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_CPU2_FENCE_PTR)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_CPU2_FENCE_PTR)); fifo_hdr->fence_mode = - cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - TXF_CPU2_LOCK_FENCE)); + cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_CPU2_LOCK_FENCE)); /* Set TXF_CPU2_READ_MODIFY_ADDR to TXF_CPU2_WR_PTR */ - iwl_trans_write_prph(fwrt->trans, - TXF_CPU2_READ_MODIFY_ADDR, - TXF_CPU2_WR_PTR); + iwl_trans_write_prph_no_grab(fwrt->trans, + TXF_CPU2_READ_MODIFY_ADDR, + TXF_CPU2_WR_PTR); /* Dummy-read to advance the read pointer to head */ - iwl_trans_read_prph(fwrt->trans, - TXF_CPU2_READ_MODIFY_DATA); + iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_CPU2_READ_MODIFY_DATA); /* Read FIFO */ fifo_len /= sizeof(u32); /* Size in DWORDS */ for (j = 0; j < fifo_len; j++) fifo_data[j] = - iwl_trans_read_prph(fwrt->trans, - TXF_CPU2_READ_MODIFY_DATA); + iwl_trans_read_prph_no_grab(fwrt->trans, + TXF_CPU2_READ_MODIFY_DATA); *dump_data = iwl_fw_error_next_data(*dump_data); } } @@ -514,7 +514,7 @@ static void iwl_read_prph_block(struct iwl_trans *trans, u32 start, u32 i; for (i = 0; i < len_bytes; i += 4) - *data++ = cpu_to_le32(iwl_trans_read_prph(trans, start + i)); + *data++ = cpu_to_le32(iwl_trans_read_prph_no_grab(trans, start + i)); } static void iwl_dump_prph(struct iwl_fw_runtime *fwrt, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c index 6621ef9358bc..e29c58575859 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.c @@ -9,7 +9,7 @@ #include "runtime.h" #include "dbg.h" #include "debugfs.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "iwl-csr.h" #include "iwl-fh.h" @@ -103,7 +103,7 @@ static int iwl_dump_ini_prph_mac_iter_common(struct iwl_fw_runtime *fwrt, range->internal_base_addr = cpu_to_le32(addr); range->range_data_size = size; for (i = 0; i < le32_to_cpu(size); i += 4) - *val++ = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, addr + i)); + *val++ = cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, addr + i)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } @@ -159,7 +159,7 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt, indirect_rd_addr += le32_to_cpu(offset); dphy_addr = (offset) ? WFPM_LMAC2_PS_CTL_RW : WFPM_LMAC1_PS_CTL_RW; - dphy_state = iwl_read_umac_prph_no_grab(fwrt->trans, dphy_addr); + dphy_state = iwl_trans_read_umac_prph_no_grab(fwrt->trans, dphy_addr); for (i = 0; i < le32_to_cpu(size); i += 4) { if (dphy_state == HBUS_TIMEOUT || @@ -169,16 +169,16 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt, continue; } - iwl_trans_write_prph(fwrt->trans, indirect_wr_addr, - WMAL_INDRCT_CMD(addr + i)); + iwl_trans_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_trans_read_prph(fwrt->trans, - WMAL_MRSPF_STTS); + prph_stts = iwl_trans_read_prph_no_grab(fwrt->trans, + WMAL_MRSPF_STTS); /* Abort dump if status is 0xA5A5A5A2 or FIFO1 empty */ if (prph_stts == WMAL_TIMEOUT_VAL || @@ -186,8 +186,8 @@ static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt, break; } - prph_val = iwl_trans_read_prph(fwrt->trans, - indirect_rd_addr); + prph_val = iwl_trans_read_prph_no_grab(fwrt->trans, + indirect_rd_addr); *val++ = cpu_to_le32(prph_val); } @@ -344,6 +344,9 @@ iwl_dump_ini_mon_dram_iter(struct iwl_fw_runtime *fwrt, struct iwl_dram_data *frag; u32 alloc_id = le32_to_cpu(reg->dram_alloc_id); + if (WARN_ON_ONCE(alloc_id >= ARRAY_SIZE(fwrt->trans->dbg.fw_mon_ini))) + return -EINVAL; + frag = &fwrt->trans->dbg.fw_mon_ini[alloc_id].frags[idx]; range->dram_base_addr = cpu_to_le64(frag->physical); @@ -443,7 +446,7 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, range->fifo_hdr.num_of_registers = cpu_to_le32(registers_num); range->range_data_size = cpu_to_le32(iter->fifo_size + registers_size); - iwl_trans_write_prph(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo); + iwl_trans_write_prph_no_grab(fwrt->trans, TXF_LARC_NUM + offs, iter->fifo); /* * read txf registers. for each register, write to the dump the @@ -453,8 +456,8 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, addr = le32_to_cpu(reg->addrs[i]) + offs; reg_dump->addr = cpu_to_le32(addr); - reg_dump->data = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - addr)); + reg_dump->data = cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + addr)); reg_dump++; } @@ -465,17 +468,17 @@ static int iwl_dump_ini_txf_iter(struct iwl_fw_runtime *fwrt, } /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */ - iwl_trans_write_prph(fwrt->trans, TXF_READ_MODIFY_ADDR + offs, - TXF_WR_PTR + offs); + iwl_trans_write_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_ADDR + offs, + TXF_WR_PTR + offs); /* Dummy-read to advance the read pointer to the head */ - iwl_trans_read_prph(fwrt->trans, TXF_READ_MODIFY_DATA + offs); + iwl_trans_read_prph_no_grab(fwrt->trans, TXF_READ_MODIFY_DATA + offs); /* Read FIFO */ addr = TXF_READ_MODIFY_DATA + offs; data = (void *)reg_dump; for (i = 0; i < iter->fifo_size; i += sizeof(*data)) - *data++ = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, addr)); + *data++ = cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, addr)); if (fwrt->sanitize_ops && fwrt->sanitize_ops->frob_txf) fwrt->sanitize_ops->frob_txf(fwrt->sanitize_ctx, @@ -505,7 +508,7 @@ iwl_dump_ini_prph_snps_dphyip_iter(struct iwl_fw_runtime *fwrt, indirect_rd_wr_addr += le32_to_cpu(offset); dphy_addr = offset ? WFPM_LMAC2_PS_CTL_RW : WFPM_LMAC1_PS_CTL_RW; - dphy_state = iwl_read_umac_prph_no_grab(fwrt->trans, dphy_addr); + dphy_state = iwl_trans_read_umac_prph_no_grab(fwrt->trans, dphy_addr); for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) { if (dphy_state == HBUS_TIMEOUT || @@ -515,12 +518,12 @@ iwl_dump_ini_prph_snps_dphyip_iter(struct iwl_fw_runtime *fwrt, continue; } - iwl_trans_write_prph(fwrt->trans, indirect_rd_wr_addr, - addr + i); + iwl_trans_write_prph_no_grab(fwrt->trans, indirect_rd_wr_addr, + addr + i); /* wait a bit for value to be ready in register */ udelay(1); - prph_val = iwl_trans_read_prph(fwrt->trans, - indirect_rd_wr_addr); + prph_val = iwl_trans_read_prph_no_grab(fwrt->trans, + indirect_rd_wr_addr); *val++ = cpu_to_le32((prph_val & DPHYIP_INDIRECT_RD_MSK) >> DPHYIP_INDIRECT_RD_SHIFT); } @@ -583,13 +586,13 @@ static void iwl_ini_get_rxf_data(struct iwl_fw_runtime *fwrt, switch (fifo_idx) { case 0: data->size = fwrt->smem_cfg.rxfifo2_size; - data->offset = iwl_umac_prph(fwrt->trans, - RXF_DIFF_FROM_PREV); + data->offset = iwl_trans_umac_prph(fwrt->trans, + RXF_DIFF_FROM_PREV); break; case 1: data->size = fwrt->smem_cfg.rxfifo2_control_size; - data->offset = iwl_umac_prph(fwrt->trans, - RXF2C_DIFF_FROM_PREV); + data->offset = iwl_trans_umac_prph(fwrt->trans, + RXF2C_DIFF_FROM_PREV); break; } } @@ -625,8 +628,8 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, addr = le32_to_cpu(reg->addrs[i]) + offs; reg_dump->addr = cpu_to_le32(addr); - reg_dump->data = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, - addr)); + reg_dump->data = cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, + addr)); reg_dump++; } @@ -639,17 +642,17 @@ static int iwl_dump_ini_rxf_iter(struct iwl_fw_runtime *fwrt, offs = rxf_data.offset; /* Lock fence */ - iwl_trans_write_prph(fwrt->trans, RXF_SET_FENCE_MODE + offs, 0x1); + iwl_trans_write_prph_no_grab(fwrt->trans, RXF_SET_FENCE_MODE + offs, 0x1); /* Set fence pointer to the same place like WR pointer */ - iwl_trans_write_prph(fwrt->trans, RXF_LD_WR2FENCE + offs, 0x1); + iwl_trans_write_prph_no_grab(fwrt->trans, RXF_LD_WR2FENCE + offs, 0x1); /* Set fence offset */ - iwl_trans_write_prph(fwrt->trans, RXF_LD_FENCE_OFFSET_ADDR + offs, 0x0); + iwl_trans_write_prph_no_grab(fwrt->trans, RXF_LD_FENCE_OFFSET_ADDR + offs, 0x0); /* Read FIFO */ addr = RXF_FIFO_RD_FENCE_INC + offs; data = (void *)reg_dump; for (i = 0; i < rxf_data.size; i += sizeof(*data)) - *data++ = cpu_to_le32(iwl_trans_read_prph(fwrt->trans, addr)); + *data++ = cpu_to_le32(iwl_trans_read_prph_no_grab(fwrt->trans, addr)); out: return sizeof(*range) + le32_to_cpu(range->range_data_size); @@ -709,10 +712,10 @@ iwl_dump_ini_dbgi_sram_iter(struct iwl_fw_runtime *fwrt, range->range_data_size = reg->dev_addr.size; for (i = 0; i < (le32_to_cpu(reg->dev_addr.size) / 4); i++) { prph_data = - iwl_trans_read_prph(fwrt->trans, - (i % 2) ? - DBGI_SRAM_TARGET_ACCESS_RDATA_MSB : - DBGI_SRAM_TARGET_ACCESS_RDATA_LSB); + iwl_trans_read_prph_no_grab(fwrt->trans, + (i % 2) ? + DBGI_SRAM_TARGET_ACCESS_RDATA_MSB : + DBGI_SRAM_TARGET_ACCESS_RDATA_LSB); if (iwl_trans_is_hw_error_value(prph_data)) return -EBUSY; *val++ = cpu_to_le32(prph_data); @@ -809,7 +812,7 @@ static __le32 iwl_get_mon_reg(struct iwl_fw_runtime *fwrt, u32 alloc_id, if (!reg_info || !reg_info->addr || !reg_info->mask) return 0; - val = iwl_trans_read_prph(fwrt->trans, reg_info->addr + offs); + val = iwl_trans_read_prph_no_grab(fwrt->trans, reg_info->addr + offs); return cpu_to_le32(mask_apply_and_normalize(val, reg_info->mask)); } @@ -957,6 +960,9 @@ iwl_dump_ini_mon_dram_ranges(struct iwl_fw_runtime *fwrt, u32 ranges = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id); int i; + if (WARN_ON_ONCE(alloc_id >= ARRAY_SIZE(fwrt->trans->dbg.fw_mon_ini))) + return 0; + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; for (i = 0; i < fw_mon->num_frags; i++) { @@ -1016,8 +1022,16 @@ static u32 iwl_dump_ini_mem_get_size(struct iwl_fw_runtime *fwrt, if (!size || !ranges) return 0; - return sizeof(struct iwl_fw_ini_error_dump) + ranges * - (size + sizeof(struct iwl_fw_ini_error_dump_range)); + if (check_add_overflow(size, + (u32)sizeof(struct iwl_fw_ini_error_dump_range), + &size) || + check_mul_overflow(ranges, size, &size) || + check_add_overflow(size, + (u32)sizeof(struct iwl_fw_ini_error_dump), + &size)) + return 0; + + return size; } static u32 @@ -1028,15 +1042,24 @@ iwl_dump_ini_mem_block_get_size(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_addr_size *pairs = (void *)reg->addrs; u32 ranges = iwl_dump_ini_mem_block_ranges(fwrt, reg_data); u32 size = sizeof(struct iwl_fw_ini_error_dump); + u32 range_hdrs; int range; if (!ranges) return 0; for (range = 0; range < ranges; range++) - size += le32_to_cpu(pairs[range].size); + if (check_add_overflow(size, le32_to_cpu(pairs[range].size), + &size)) + return 0; - return size + ranges * sizeof(struct iwl_fw_ini_error_dump_range); + if (check_mul_overflow(ranges, + (u32)sizeof(struct iwl_fw_ini_error_dump_range), + &range_hdrs) || + check_add_overflow(size, range_hdrs, &size)) + return 0; + + return size; } static u32 @@ -1068,6 +1091,9 @@ iwl_dump_ini_mon_dram_get_size(struct iwl_fw_runtime *fwrt, u32 size = 0, alloc_id = le32_to_cpu(reg->dram_alloc_id); int i; + if (WARN_ON_ONCE(alloc_id >= ARRAY_SIZE(fwrt->trans->dbg.fw_mon_ini))) + return 0; + fw_mon = &fwrt->trans->dbg.fw_mon_ini[alloc_id]; for (i = 0; i < fw_mon->num_frags; i++) { @@ -1112,8 +1138,16 @@ static u32 iwl_dump_ini_mon_dbgi_get_size(struct iwl_fw_runtime *fwrt, if (!size || !ranges) return 0; - return sizeof(struct iwl_fw_ini_monitor_dump) + ranges * - (size + sizeof(struct iwl_fw_ini_error_dump_range)); + if (check_add_overflow(size, + (u32)sizeof(struct iwl_fw_ini_error_dump_range), + &size) || + check_mul_overflow(ranges, size, &size) || + check_add_overflow(size, + (u32)sizeof(struct iwl_fw_ini_monitor_dump), + &size)) + return 0; + + return size; } static u32 iwl_dump_ini_txf_get_size(struct iwl_fw_runtime *fwrt, @@ -1786,14 +1820,14 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, cpu_to_le32(IWL_FW_INI_APPLY_POLICY_SPLIT_DUMP_RESET)) { size += iwl_dump_ini_dump_entries(fwrt, list, IWL_INI_DUMP_EARLY_REGIONS); - iwl_trans_pcie_fw_reset_handshake(fwrt->trans); + iwl_trans_fw_reset_handshake(fwrt->trans); size += iwl_dump_ini_dump_entries(fwrt, list, IWL_INI_DUMP_LATE_REGIONS); } else { if (fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT) && iwl_dump_due_to_error(tp_id)) - iwl_trans_pcie_fw_reset_handshake(fwrt->trans); + iwl_trans_fw_reset_handshake(fwrt->trans); size += iwl_dump_ini_dump_entries(fwrt, list, IWL_INI_DUMP_ALL_REGIONS); } @@ -2021,7 +2055,7 @@ int iwl_fw_dbg_collect(struct iwl_fw_runtime *fwrt, if (trigger->flags & IWL_FW_DBG_FORCE_RESTART) { IWL_WARN(fwrt, "Force restart: trigger %d fired.\n", trig); - iwl_force_nmi(fwrt->trans); + iwl_trans_force_nmi(fwrt->trans); return 0; } @@ -2199,7 +2233,8 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx) } if (fwrt->trans->dbg.last_tp_resetfw == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) - iwl_force_nmi(fwrt->trans); + iwl_trans_force_nmi(fwrt->trans); + out: if (iwl_trans_dbg_ini_valid(fwrt->trans)) { iwl_fw_error_dump_data_free(dump_data); @@ -2269,8 +2304,13 @@ void iwl_fw_error_dump_wk(struct work_struct *work) { struct iwl_fwrt_wk_data *wks = container_of(work, typeof(*wks), wk.work); - struct iwl_fw_runtime *fwrt = - container_of(wks, typeof(*fwrt), dump.wks[wks->idx]); + struct iwl_fw_runtime *fwrt; + + if (WARN_ONCE(wks->idx >= IWL_FW_RUNTIME_DUMP_WK_NUM, + "invalid worker index %d\n", wks->idx)) + return; + + fwrt = container_of(wks, typeof(*fwrt), dump.wks[wks->idx]); /* assumes the op mode mutex is locked in dump_start since * iwl_fw_dbg_collect_sync can't run in parallel @@ -2346,21 +2386,21 @@ static void iwl_fw_dbg_stop_recording(struct iwl_trans *trans, struct iwl_fw_dbg_params *params) { if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); + iwl_trans_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); return; } if (params) { - params->in_sample = iwl_read_umac_prph(trans, DBGC_IN_SAMPLE); - params->out_ctrl = iwl_read_umac_prph(trans, DBGC_OUT_CTRL); + params->in_sample = iwl_trans_read_umac_prph(trans, DBGC_IN_SAMPLE); + params->out_ctrl = iwl_trans_read_umac_prph(trans, DBGC_OUT_CTRL); } - iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, 0); + iwl_trans_write_umac_prph(trans, DBGC_IN_SAMPLE, 0); /* wait for the DBGC to finish writing the internal buffer to DRAM to * avoid halting the HW while writing */ usleep_range(700, 1000); - iwl_write_umac_prph(trans, DBGC_OUT_CTRL, 0); + iwl_trans_write_umac_prph(trans, DBGC_OUT_CTRL, 0); } static int iwl_fw_dbg_restart_recording(struct iwl_trans *trans, @@ -2370,12 +2410,12 @@ static int iwl_fw_dbg_restart_recording(struct iwl_trans *trans, return -EIO; if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_7000) { - iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); - iwl_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1); - iwl_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1); + iwl_trans_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x100); + iwl_trans_clear_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1); + iwl_trans_set_bits_prph(trans, MON_BUFF_SAMPLE_CTL, 0x1); } else { - iwl_write_umac_prph(trans, DBGC_IN_SAMPLE, params->in_sample); - iwl_write_umac_prph(trans, DBGC_OUT_CTRL, params->out_ctrl); + iwl_trans_write_umac_prph(trans, DBGC_IN_SAMPLE, params->in_sample); + iwl_trans_write_umac_prph(trans, DBGC_OUT_CTRL, params->out_ctrl); } return 0; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h index fc962a320583..70134d8f03c4 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dbg.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/dbg.h @@ -10,7 +10,7 @@ #include #include "runtime.h" #include "iwl-prph.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "file.h" #include "error-dump.h" #include "api/commands.h" diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dump.c b/drivers/net/wireless/intel/iwlwifi/fw/dump.c index bbbf3669a555..b76abc77f495 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/dump.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/dump.c @@ -9,7 +9,7 @@ #include "runtime.h" #include "dbg.h" #include "debugfs.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "iwl-csr.h" #include "pnvm.h" @@ -309,7 +309,7 @@ static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt) return; } - error = iwl_read_umac_prph(trans, error); + error = iwl_trans_read_umac_prph(trans, error); IWL_ERR(trans, "IML/ROM dump:\n"); @@ -318,11 +318,11 @@ static void iwl_fwrt_dump_iml_error_log(struct iwl_fw_runtime *fwrt) IWL_ERR(fwrt, "0x%08X | IML/ROM error/state\n", error); IWL_ERR(fwrt, "0x%08X | IML/ROM data1\n", - iwl_read_umac_prph(trans, data1)); + iwl_trans_read_umac_prph(trans, data1)); if (fwrt->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_22000) IWL_ERR(fwrt, "0x%08X | IML/ROM WFPM_AUTH_KEY_0\n", - iwl_read_umac_prph(trans, SB_MODIFY_CFG_FLAG)); + iwl_trans_read_umac_prph(trans, SB_MODIFY_CFG_FLAG)); } #define FSEQ_REG(x) { .addr = (x), .str = #x, } @@ -360,7 +360,7 @@ static void iwl_fwrt_dump_fseq_regs(struct iwl_fw_runtime *fwrt) for (i = 0; i < ARRAY_SIZE(fseq_regs); i++) IWL_ERR(fwrt, "0x%08X | %s\n", - iwl_read_prph_no_grab(trans, fseq_regs[i].addr), + iwl_trans_read_prph_no_grab(trans, fseq_regs[i].addr), fseq_regs[i].str); iwl_trans_release_nic_access(trans); @@ -398,13 +398,13 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt) count++, pc_data++) IWL_ERR(fwrt, "%s: 0x%x\n", pc_data->pc_name, - iwl_read_prph_no_grab(fwrt->trans, - pc_data->pc_address)); + iwl_trans_read_prph_no_grab(fwrt->trans, + pc_data->pc_address)); iwl_trans_release_nic_access(fwrt->trans); } if (fwrt->trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - u32 scratch = iwl_read32(fwrt->trans, CSR_FUNC_SCRATCH); + u32 scratch = iwl_trans_read32(fwrt->trans, CSR_FUNC_SCRATCH); IWL_ERR(fwrt, "Function Scratch status:\n"); IWL_ERR(fwrt, "0x%08X | Func Scratch\n", scratch); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 664ac25754e9..3a986b394dd8 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -452,6 +452,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * table data. For LARI_CONFIG_CHANGE command version 13 and above, this * capability is obsolete since raw DSM values are accepted by default. * @IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT: Supports NAN synchronization + * @IWL_UCODE_TLV_CAPA_ASSOC_ENC_SUPPORT: firmware supports association frame encryption * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -556,6 +557,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_RESET_DURING_ASSERT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 0), IWL_UCODE_TLV_CAPA_FW_ACCEPTS_RAW_DSM_TABLE = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 1), IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 2), + IWL_UCODE_TLV_CAPA_ASSOC_ENC_SUPPORT = (__force iwl_ucode_tlv_capa_t)(4 * 32 + 4), NUM_IWL_UCODE_TLV_CAPA /* * This construction make both sparse (which cannot increment the previous diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c index d1d8058ad29f..f62c6a69f0dc 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/init.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2019-2021, 2024-2025 Intel Corporation + * Copyright (C) 2019-2021, 2024-2026 Intel Corporation */ #include "iwl-drv.h" #include "runtime.h" @@ -23,6 +23,8 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, int i; memset(fwrt, 0, sizeof(*fwrt)); + fwrt->wrds_table_revision = IWL_BIOS_REVISION_UNSET; + fwrt->ewrd_table_revision = IWL_BIOS_REVISION_UNSET; fwrt->trans = trans; fwrt->fw = fw; fwrt->dev = trans->dev; @@ -31,6 +33,8 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, fwrt->sanitize_ops = sanitize_ops; fwrt->sanitize_ctx = sanitize_ctx; fwrt->ops_ctx = ops_ctx; + /* default until the connectivity GUID lock status is resolved */ + fwrt->uefi_tables_lock_status = UEFI_CNV_GUID_UNKNOWN; for (i = 0; i < IWL_FW_RUNTIME_DUMP_WK_NUM; i++) { fwrt->dump.wks[i].idx = i; INIT_DELAYED_WORK(&fwrt->dump.wks[i].wk, iwl_fw_error_dump_wk); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 545a213df71d..ccd190ab8a55 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -6,7 +6,7 @@ #include "iwl-drv.h" #include "pnvm.h" #include "iwl-prph.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "fw/api/commands.h" #include "fw/api/nvm-reg.h" #include "fw/api/alive.h" @@ -485,8 +485,8 @@ int iwl_pnvm_load(struct iwl_trans *trans, iwl_pnvm_complete_fn, trans); /* kick the doorbell */ - iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, - UREG_DOORBELL_TO_ISR6_PNVM); + iwl_trans_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + UREG_DOORBELL_TO_ISR6_PNVM); return iwl_wait_notification(notif_wait, &pnvm_wait, MVM_UCODE_PNVM_TIMEOUT); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c index 1d6d38ee55b4..b6707312c188 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c @@ -11,9 +11,7 @@ #define GET_BIOS_TABLE(__name, ...) \ do { \ - int ret = -ENOENT; \ - if (fwrt->uefi_tables_lock_status > UEFI_WIFI_GUID_UNLOCKED) \ - ret = iwl_uefi_get_ ## __name(__VA_ARGS__); \ + int ret = iwl_uefi_get_ ## __name(__VA_ARGS__); \ if (ret < 0) \ ret = iwl_acpi_get_ ## __name(__VA_ARGS__); \ return ret; \ @@ -32,6 +30,8 @@ IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name) IWL_BIOS_TABLE_LOADER(wrds_table); IWL_BIOS_TABLE_LOADER(ewrd_table); +IWL_BIOS_TABLE_LOADER(wsss_table); +IWL_BIOS_TABLE_LOADER(ewss_table); IWL_BIOS_TABLE_LOADER(wgds_table); IWL_BIOS_TABLE_LOADER(ppag_table); IWL_BIOS_TABLE_LOADER(phy_filters); @@ -49,11 +49,16 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), }, }, - { .ident = "SAMSUNG", + { .ident = "SAMSUNG_ELECTRONICS", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), }, }, + { .ident = "SAMSUNG", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Samsung"), + }, + }, { .ident = "MSFT", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), @@ -126,10 +131,15 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { DMI_MATCH(DMI_SYS_VENDOR, "HP"), }, }, - { .ident = "SAMSUNG", + { .ident = "SAMSUNG_ELECTRONICS", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), }, + }, + { .ident = "SAMSUNG", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Samsung"), + }, }, { .ident = "LENOVO", .matches = { @@ -167,6 +177,12 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { DMI_MATCH(DMI_BOARD_VENDOR, "HP"), }, }, + { .ident = "GOOGLE-ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "ASUS"), + }, + }, { .ident = "MSI", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), @@ -183,21 +199,22 @@ static const struct dmi_system_id dmi_tas_approved_list[] = { bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) { + u32 ucode_ver = fwrt->fw->ucode_ver; + /* * The PER_CHAIN_LIMIT_OFFSET_CMD command is not supported on * earlier firmware versions. Unfortunately, we don't have a - * TLV API flag to rely on, so rely on the major version which - * is in the first byte of ucode_ver. This was implemented - * initially on version 38 and then backported to 17. It was - * also backported to 29, but only for 7265D devices. The - * intention was to have it in 36 as well, but not all 8000 - * family got this feature enabled. The 8000 family is the - * only one using version 36, so skip this version entirely. + * TLV API flag to rely on, so rely on the ucode version. This + * was implemented initially on version 38 and then backported + * to 17. It was also backported to 29, but only for 7265D + * devices. The intention was to have it in 36 as well, but not + * all 8000 family got this feature enabled. The 8000 family is + * the only one using version 36, so skip this version entirely. */ - return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || - (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 && + return ucode_ver >= 38 || + (ucode_ver == 17 && fwrt->trans->info.hw_rev != CSR_HW_REV_TYPE_3160) || - (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && + (ucode_ver == 29 && ((fwrt->trans->info.hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D)); } @@ -241,17 +258,22 @@ IWL_EXPORT_SYMBOL(iwl_sar_geo_fill_table); static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, __le16 *per_chain, u32 n_subbands, - int prof_a, int prof_b) + int prof_a, int prof_b, + const struct iwl_sar_profile *profiles, + bool is_standalone) { int profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b }; int i, j; + BUILD_BUG_ON(ARRAY_SIZE(fwrt->sar_standalone_profiles[0].chains[0].subbands) != + ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands)); + if (WARN_ON_ONCE(n_subbands > ARRAY_SIZE(fwrt->sar_profiles[0].chains[0].subbands))) return -EINVAL; for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) { - struct iwl_sar_profile *prof; + const struct iwl_sar_profile *prof; /* don't allow SAR to be disabled (profile 0 means disable) */ if (profs[i] == 0) @@ -262,11 +284,13 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, return -EINVAL; /* profiles go from 1 to 4, so decrement to access the array */ - prof = &fwrt->sar_profiles[profs[i] - 1]; + prof = &profiles[profs[i] - 1]; /* if the profile is disabled, do nothing */ if (!prof->enabled) { - IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", + IWL_DEBUG_RADIO(fwrt, + "SAR %sprofile %d is disabled.\n", + is_standalone ? "standalone " : "", profs[i]); /* * if one of the profiles is disabled, we @@ -276,8 +300,8 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, return 1; } - IWL_DEBUG_INFO(fwrt, - "SAR EWRD: chain %d profile index %d\n", + IWL_DEBUG_INFO(fwrt, "SAR %s: chain %d profile index %d\n", + is_standalone ? "standalone" : "EWRD", i, profs[i]); IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); for (j = 0; j < n_subbands; j++) { @@ -293,14 +317,17 @@ static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, __le16 *per_chain, u32 n_tables, u32 n_subbands, - int prof_a, int prof_b) + int prof_a, int prof_b, + const struct iwl_sar_profile *profiles, + bool is_standalone) { int i, ret = 0; for (i = 0; i < n_tables; i++) { ret = iwl_sar_fill_table(fwrt, &per_chain[i * n_subbands * BIOS_SAR_NUM_CHAINS], - n_subbands, prof_a, prof_b); + n_subbands, prof_a, prof_b, profiles, + is_standalone); if (ret) break; } @@ -447,3 +474,27 @@ bool iwl_rfi_is_enabled_in_bios(struct iwl_fw_runtime *fwrt) return false; } IWL_EXPORT_SYMBOL(iwl_rfi_is_enabled_in_bios); + +/** + * iwl_bios_get_guid_lock_status - resolve connectivity variables lock status + * @fwrt: the firmware runtime context + * + * Determine the root-of-trust for the connectivity UEFI variables. The UEFI + * GUID Lock Indicator (GLUI) is preferred: if it attests the tables as locked + * or in test mode, that result is used. Otherwise (GLUI is missing, invalid or + * reports unlocked) the ACPI GUID Lock Indicator is consulted and can override + * the GLUI result. + * + * This only caches the result in &fwrt->uefi_tables_lock_status + * (see &enum iwl_uefi_cnv_guid_status). + */ +void iwl_bios_get_guid_lock_status(struct iwl_fw_runtime *fwrt) +{ + iwl_uefi_get_guid_lock_status(fwrt); + if (fwrt->uefi_tables_lock_status == UEFI_CNV_GUID_LOCKED || + fwrt->uefi_tables_lock_status == UEFI_CNV_GUID_TEST_MODE) + return; + + iwl_acpi_get_guid_lock_status(fwrt); +} +IWL_EXPORT_SYMBOL(iwl_bios_get_guid_lock_status); diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h index 22c97c75b83c..e32e107812b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h @@ -31,6 +31,7 @@ #define IWL_SAR_ENABLE_MSK BIT(0) #define IWL_REDUCE_POWER_FLAGS_POS 1 +#define IWL_BIOS_REVISION_UNSET 0xFF /* PPAG gain value bounds in 1/8 dBm */ #define IWL_PPAG_MIN_LB -16 @@ -47,6 +48,22 @@ #define IWL_WTAS_CANADA_UHB_MSK BIT(15) #define IWL_WTAS_USA_UHB_MSK BIT(16) +/** + * enum iwl_uefi_cnv_guid_status - lock status of the connectivity + * UEFI tables + * @UEFI_CNV_GUID_UNLOCKED: the tables are unlocked + * @UEFI_CNV_GUID_LOCKED: the tables are locked + * @UEFI_CNV_GUID_TEST_MODE: the tables are locked in test mode + * @UEFI_CNV_GUID_UNKNOWN: the lock status could not be determined. + * This value is a driver internal, not a possible BIOS reported one + */ +enum iwl_uefi_cnv_guid_status { + UEFI_CNV_GUID_UNLOCKED = 0, + UEFI_CNV_GUID_LOCKED = 1, + UEFI_CNV_GUID_TEST_MODE = 2, + UEFI_CNV_GUID_UNKNOWN = 3, +}; + struct iwl_tas_selection_data { u8 override_tas_iec:1, enable_tas_iec:1, @@ -193,7 +210,9 @@ int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt, int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt, __le16 *per_chain, u32 n_tables, u32 n_subbands, - int prof_a, int prof_b); + int prof_a, int prof_b, + const struct iwl_sar_profile *profiles, + bool is_standalone); bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt); @@ -207,6 +226,10 @@ int iwl_bios_get_wrds_table(struct iwl_fw_runtime *fwrt); int iwl_bios_get_ewrd_table(struct iwl_fw_runtime *fwrt); +int iwl_bios_get_wsss_table(struct iwl_fw_runtime *fwrt); + +int iwl_bios_get_ewss_table(struct iwl_fw_runtime *fwrt); + int iwl_bios_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_bios_get_ppag_table(struct iwl_fw_runtime *fwrt); @@ -242,6 +265,7 @@ bool iwl_puncturing_is_allowed_in_bios(u32 puncturing, u16 mcc); int iwl_bios_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value); int iwl_bios_get_phy_filters(struct iwl_fw_runtime *fwrt); +void iwl_bios_get_guid_lock_status(struct iwl_fw_runtime *fwrt); static inline void iwl_bios_setup_step(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h index ac01ac0092ee..33ce06f1a60a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h @@ -108,10 +108,14 @@ struct iwl_txf_iter_data { * @dump: debug dump data * @ap_type_cmd: AP type tables (for enablement on 6 GHz) * @ap_type_cmd_valid: if &ap_type_cmd is valid - * @uefi_tables_lock_status: The status of the WIFI GUID UEFI variables lock: - * 0: Unlocked, 1 and 2: Locked. - * Only read the UEFI variables if locked. + * @uefi_tables_lock_status: the status of the WIFI GUID UEFI variables lock, + * see &enum iwl_uefi_cnv_guid_status. + * Trust the UEFI variables if locked or in test mode. * @sar_profiles: sar profiles as read from WRDS/EWRD BIOS tables + * @sar_standalone_profiles: standalone sar profiles as read from + * WSSS/EWSS BIOS tables (for Wi-Fi HB/UHB without concurrent BT) + * @wrds_table_revision: revision of WRDS BIOS table + * @ewrd_table_revision: revision of EWRD BIOS table * @geo_profiles: geographic profiles as read from WGDS BIOS table * @geo_bios_source: see &enum bios_source * @phy_filters: specific phy filters as read from WPFC BIOS table @@ -206,6 +210,9 @@ struct iwl_fw_runtime { bool tpc_enabled; #endif /* CONFIG_IWLWIFI_DEBUGFS */ struct iwl_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM]; + struct iwl_sar_profile sar_standalone_profiles[BIOS_SAR_MAX_PROFILE_NUM]; + u8 wrds_table_revision; + u8 ewrd_table_revision; u8 sar_chain_a_profile; u8 sar_chain_b_profile; u8 reduced_power_flags; diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c index bf6a31e6f149..a654ab29ee42 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c @@ -6,7 +6,7 @@ #include "iwl-drv.h" #include "pnvm.h" #include "iwl-prph.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "fw/uefi.h" #include "fw/api/alive.h" @@ -20,6 +20,10 @@ 0x8d, 0x03, 0x77, 0x2e, \ 0xcc, 0x3d, 0xa5, 0x31) +#define IWL_EFI_GLUI_GUID EFI_GUID(0x6c5bed75, 0x0ee8, 0x4d45, \ + 0x98, 0x0b, 0x4d, 0x81, \ + 0x31, 0xba, 0x84, 0xb5) + struct iwl_uefi_pnvm_mem_desc { __le32 addr; __le32 size; @@ -27,9 +31,10 @@ struct iwl_uefi_pnvm_mem_desc { } __packed; static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid, - unsigned long *data_size) + u32 *attributes, unsigned long *data_size) { efi_status_t status; + u32 attr = 0; void *data; if (!data_size) @@ -48,15 +53,28 @@ static void *iwl_uefi_get_variable(efi_char16_t *name, efi_guid_t *guid, if (!data) return ERR_PTR(-ENOMEM); - status = efi.get_variable(name, guid, NULL, data_size, data); + status = efi.get_variable(name, guid, &attr, data_size, data); if (status != EFI_SUCCESS) { kfree(data); return ERR_PTR(-ENOENT); } + if (attributes) + *attributes = attr; + return data; } +static efi_status_t iwl_uefi_set_variable(efi_char16_t *name, efi_guid_t *guid, + u32 attributes, void *data, + unsigned long data_size) +{ + if (!efi_rt_services_supported(EFI_RT_SUPPORTED_SET_VARIABLE)) + return EFI_UNSUPPORTED; + + return efi.set_variable(name, guid, attributes, data_size, data); +} + void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { unsigned long package_size; @@ -65,7 +83,7 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) *len = 0; data = iwl_uefi_get_variable(IWL_UEFI_OEM_PNVM_NAME, &IWL_EFI_WIFI_GUID, - &package_size); + NULL, &package_size); if (IS_ERR(data)) { IWL_DEBUG_FW(trans, "PNVM UEFI variable not found 0x%lx (len %lu)\n", @@ -80,17 +98,18 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) } static void * -iwl_uefi_get_verified_variable_guid(struct iwl_trans *trans, - efi_guid_t *guid, - efi_char16_t *uefi_var_name, - char *var_name, - unsigned int expected_size, - unsigned long *size) +iwl_uefi_get_variable_guid(struct iwl_trans *trans, + efi_guid_t *guid, + efi_char16_t *uefi_var_name, + char *var_name, + unsigned int expected_size, + unsigned long *size, + u32 *attributes) { void *var; unsigned long var_size; - var = iwl_uefi_get_variable(uefi_var_name, guid, &var_size); + var = iwl_uefi_get_variable(uefi_var_name, guid, attributes, &var_size); if (IS_ERR(var)) { IWL_DEBUG_RADIO(trans, @@ -116,13 +135,72 @@ iwl_uefi_get_verified_variable_guid(struct iwl_trans *trans, } static void * -iwl_uefi_get_verified_variable(struct iwl_trans *trans, +iwl_uefi_get_verified_variable_guid(struct iwl_fw_runtime *fwrt, + efi_guid_t *guid, + efi_char16_t *uefi_var_name, + char *var_name, + unsigned int expected_size, + unsigned long *size) +{ + unsigned long var_size; + u32 attributes = 0; + void *var; + + if (fwrt->uefi_tables_lock_status == UEFI_CNV_GUID_UNLOCKED) + return ERR_PTR(-EINVAL); + + /* In x86 either GLUI or GLAI should exist */ + if ((IS_ENABLED(CONFIG_X86) || IS_ENABLED(CONFIG_X86_64) || + IS_ENABLED(CONFIG_X86_32)) && + fwrt->uefi_tables_lock_status == UEFI_CNV_GUID_UNKNOWN) + return ERR_PTR(-EINVAL); + + var = iwl_uefi_get_variable_guid(fwrt->trans, + guid, + uefi_var_name, var_name, + expected_size, &var_size, + &attributes); + if (IS_ERR(var)) + return var; + + if (fwrt->uefi_tables_lock_status != UEFI_CNV_GUID_UNKNOWN) + goto out; + + /* + * The lock status is unknown, so probe it: rewrite the variable + * with the data just read and trust it only if the firmware + * refuses the write. Treat a zero attributes value as untrusted, + * since a SetVariable() with no attributes would delete it. + */ + if (attributes) { + efi_status_t status; + + status = iwl_uefi_set_variable(uefi_var_name, guid, attributes, + var, var_size); + if (status == EFI_WRITE_PROTECTED || + status == EFI_SECURITY_VIOLATION || + status == EFI_ACCESS_DENIED) + goto out; + } + + /* unprobeable (e.g. EFI_UNSUPPORTED) or writable: not trusted */ + kfree(var); + return ERR_PTR(-EINVAL); + +out: + if (size) + *size = var_size; + return var; +} + +static void * +iwl_uefi_get_verified_wifi_var(struct iwl_fw_runtime *fwrt, efi_char16_t *uefi_var_name, char *var_name, unsigned int expected_size, unsigned long *size) { - return iwl_uefi_get_verified_variable_guid(trans, &IWL_EFI_WIFI_GUID, + return iwl_uefi_get_verified_variable_guid(fwrt, &IWL_EFI_WIFI_GUID, uefi_var_name, var_name, expected_size, size); } @@ -173,15 +251,24 @@ static int iwl_uefi_reduce_power_section(struct iwl_trans *trans, memset(pnvm_data, 0, sizeof(*pnvm_data)); while (len >= sizeof(*tlv)) { - u32 tlv_len, tlv_type; + u32 tlv_len, tlv_type, tlv_len_aligned; len -= sizeof(*tlv); tlv = (const void *)data; tlv_len = le32_to_cpu(tlv->length); tlv_type = le32_to_cpu(tlv->type); + tlv_len_aligned = ALIGN(tlv_len, 4); - if (len < tlv_len) { + /* Make sure ALIGN() did not overflow for a malformed TLV length. */ + if (tlv_len_aligned < tlv_len) { + IWL_ERR(trans, + "TLV len overflows on alignment: %u\n", + tlv_len); + return -EINVAL; + } + + if (len < tlv_len_aligned) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); return -EINVAL; @@ -200,13 +287,13 @@ static int iwl_uefi_reduce_power_section(struct iwl_trans *trans, "New REDUCE_POWER section started, stop parsing.\n"); goto done; default: - IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %d\n", + IWL_DEBUG_FW(trans, "Found TLV 0x%0x, len %u\n", tlv_type, tlv_len); break; } - len -= ALIGN(tlv_len, 4); - data += ALIGN(tlv_len, 4); + len -= tlv_len_aligned; + data += tlv_len_aligned; } done: @@ -227,15 +314,24 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, IWL_DEBUG_FW(trans, "Parsing REDUCE_POWER data\n"); while (len >= sizeof(*tlv)) { - u32 tlv_len, tlv_type; + u32 tlv_len, tlv_type, tlv_len_aligned; len -= sizeof(*tlv); tlv = (const void *)data; tlv_len = le32_to_cpu(tlv->length); tlv_type = le32_to_cpu(tlv->type); + tlv_len_aligned = ALIGN(tlv_len, 4); - if (len < tlv_len) { + /* Make sure ALIGN() did not overflow for a malformed TLV length. */ + if (tlv_len_aligned < tlv_len) { + IWL_ERR(trans, + "TLV len overflows on alignment: %u\n", + tlv_len); + return -EINVAL; + } + + if (len < tlv_len_aligned) { IWL_ERR(trans, "invalid TLV len: %zd/%u\n", len, tlv_len); return -EINVAL; @@ -245,22 +341,23 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, const struct iwl_sku_id *tlv_sku_id = (const void *)(data + sizeof(*tlv)); - IWL_DEBUG_FW(trans, - "Got IWL_UCODE_TLV_PNVM_SKU len %d\n", - tlv_len); if (tlv_len < sizeof(*tlv_sku_id)) { IWL_ERR(trans, "invalid PNVM SKU TLV len: %u\n", tlv_len); return -EINVAL; } + IWL_DEBUG_FW(trans, + "Got IWL_UCODE_TLV_PNVM_SKU len %u\n", + tlv_len); + IWL_DEBUG_FW(trans, "sku_id 0x%0x 0x%0x 0x%0x\n", le32_to_cpu(tlv_sku_id->data[0]), le32_to_cpu(tlv_sku_id->data[1]), le32_to_cpu(tlv_sku_id->data[2])); - data += sizeof(*tlv) + ALIGN(tlv_len, 4); - len -= ALIGN(tlv_len, 4); + data += sizeof(*tlv) + tlv_len_aligned; + len -= tlv_len_aligned; if (sku_id[0] == tlv_sku_id->data[0] && sku_id[1] == tlv_sku_id->data[1] && @@ -274,8 +371,8 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, IWL_DEBUG_FW(trans, "SKU ID didn't match!\n"); } } else { - data += sizeof(*tlv) + ALIGN(tlv_len, 4); - len -= ALIGN(tlv_len, 4); + data += sizeof(*tlv) + tlv_len_aligned; + len -= tlv_len_aligned; } } @@ -288,11 +385,12 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) unsigned long package_size; u8 *data; - package = iwl_uefi_get_verified_variable(trans, - IWL_UEFI_REDUCED_POWER_NAME, - "Reduced Power", - sizeof(*package), - &package_size); + package = + iwl_uefi_get_variable_guid(trans, &IWL_EFI_WIFI_GUID, + IWL_UEFI_REDUCED_POWER_NAME, + "Reduced Power", + sizeof(*package), + &package_size, NULL); if (IS_ERR(package)) return ERR_CAST(package); @@ -334,9 +432,9 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans) if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return; - data = iwl_uefi_get_verified_variable_guid(trans, &IWL_EFI_WIFI_BT_GUID, - IWL_UEFI_STEP_NAME, - "STEP", sizeof(*data), NULL); + data = iwl_uefi_get_variable_guid(trans, &IWL_EFI_WIFI_BT_GUID, + IWL_UEFI_STEP_NAME, "STEP", + sizeof(*data), NULL, NULL); if (IS_ERR(data)) return; @@ -389,8 +487,9 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, if (!fwrt->geo_enabled) return; - data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_SGOM_NAME, - "SGOM", sizeof(*data), NULL); + data = iwl_uefi_get_variable_guid(trans, &IWL_EFI_WIFI_GUID, + IWL_UEFI_SGOM_NAME, "SGOM", + sizeof(*data), NULL, NULL); if (IS_ERR(data)) return; @@ -423,8 +522,9 @@ void iwl_uefi_get_uats_table(struct iwl_trans *trans, struct uefi_cnv_wlan_uats_data *data; int ret; - data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UATS_NAME, - "UATS", sizeof(*data), NULL); + data = iwl_uefi_get_variable_guid(trans, &IWL_EFI_WIFI_GUID, + IWL_UEFI_UATS_NAME, "UATS", + sizeof(*data), NULL, NULL); if (IS_ERR(data)) return; @@ -440,8 +540,9 @@ void iwl_uefi_get_uneb_table(struct iwl_trans *trans, { struct uefi_cnv_wlan_uneb_data *data; - data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UNEB_NAME, - "UNEB", sizeof(*data), NULL); + data = iwl_uefi_get_variable_guid(trans, &IWL_EFI_WIFI_GUID, + IWL_UEFI_UNEB_NAME, "UNEB", + sizeof(*data), NULL, NULL); if (IS_ERR(data)) return; @@ -465,11 +566,11 @@ void iwl_uefi_get_uneb_table(struct iwl_trans *trans, } IWL_EXPORT_SYMBOL(iwl_uefi_get_uneb_table); -static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, +static void iwl_uefi_set_sar_profile(struct iwl_sar_profile *profiles, const u8 *vals, u8 prof_index, - u8 num_subbands, bool enabled) + u8 num_subbands, u32 mode) { - struct iwl_sar_profile *sar_prof = &fwrt->sar_profiles[prof_index]; + struct iwl_sar_profile *sar_prof = &profiles[prof_index]; /* * Make sure fwrt has enough room to hold the data @@ -491,7 +592,7 @@ static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, vals[chain * num_subbands + subband]; } - fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK; + sar_prof->enabled = mode & IWL_SAR_ENABLE_MSK; } int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) @@ -502,8 +603,8 @@ int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) int num_subbands; int ret = 0; - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME, - "WRDS", + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_WRDS_NAME, "WRDS", UEFI_SAR_WRDS_TABLE_SIZE_REV2, &size); @@ -535,8 +636,9 @@ int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) /* The profile from WRDS is officially profile 1, but goes * into sar_profiles[0] (because we don't have a profile 0). */ - iwl_uefi_set_sar_profile(fwrt, data->vals, 0, + iwl_uefi_set_sar_profile(fwrt->sar_profiles, data->vals, 0, num_subbands, data->mode); + fwrt->wrds_table_revision = data->revision; out: kfree(data); return ret; @@ -551,8 +653,8 @@ int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) int num_subbands; int profile_size; - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME, - "EWRD", + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_EWRD_NAME, "EWRD", UEFI_SAR_EWRD_TABLE_SIZE_REV2, &size); if (IS_ERR(data)) @@ -588,14 +690,136 @@ int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) * save them in sar_profiles[1-3] (because we don't * have profile 0). So in the array we start from 1. */ - iwl_uefi_set_sar_profile(fwrt, &data->vals[i * profile_size], + iwl_uefi_set_sar_profile(fwrt->sar_profiles, + &data->vals[i * profile_size], i + 1, num_subbands, data->mode); + fwrt->ewrd_table_revision = data->revision; + out: kfree(data); return ret; } +int iwl_uefi_get_wsss_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_wrds *data __free(kfree) = NULL; + unsigned long expected_size; + unsigned long size; + int num_subbands; + + if (fwrt->wrds_table_revision == IWL_BIOS_REVISION_UNSET) { + IWL_DEBUG_RADIO(fwrt, + "Skipping standalone SAR: WRDS table was not read\n"); + return -EINVAL; + } + + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_WSSS_NAME, + "WSSS", + UEFI_SAR_WRDS_TABLE_SIZE_REV2, + &size); + if (IS_ERR(data)) + return PTR_ERR(data); + + switch (data->revision) { + case 2: + expected_size = UEFI_SAR_WRDS_TABLE_SIZE_REV2; + num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV2; + break; + case 3: + expected_size = UEFI_SAR_WRDS_TABLE_SIZE_REV3; + num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV3; + break; + default: + IWL_DEBUG_RADIO(fwrt, + "Unsupported UEFI WSSS revision:%d\n", + data->revision); + return -EINVAL; + } + + if (size != expected_size) + return -EINVAL; + + if (fwrt->wrds_table_revision != data->revision) { + IWL_DEBUG_RADIO(fwrt, + "Skipping standalone SAR: WRDS/WSSS revision mismatch (WRDS rev %d, WSSS rev %d)\n", + fwrt->wrds_table_revision, + data->revision); + return -EINVAL; + } + + IWL_DEBUG_RADIO(fwrt, "Reading WSSS (WRDS Standalone) tbl_rev=%d\n", + data->revision); + iwl_uefi_set_sar_profile(fwrt->sar_standalone_profiles, + data->vals, 0, + num_subbands, + data->mode); + return 0; +} + +int iwl_uefi_get_ewss_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_ewrd *data __free(kfree) = NULL; + unsigned long expected_size; + unsigned long size; + int num_subbands; + int profile_size; + int i; + + if (fwrt->ewrd_table_revision == IWL_BIOS_REVISION_UNSET) { + IWL_DEBUG_RADIO(fwrt, + "Skipping standalone SAR: EWRD table was not read\n"); + return -EINVAL; + } + + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_EWSS_NAME, + "EWSS", + UEFI_SAR_EWRD_TABLE_SIZE_REV2, + &size); + if (IS_ERR(data)) + return PTR_ERR(data); + + switch (data->revision) { + case 3: + expected_size = UEFI_SAR_EWRD_TABLE_SIZE_REV3; + num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV3; + profile_size = UEFI_SAR_PROFILE_SIZE_REV3; + break; + case 2: + expected_size = UEFI_SAR_EWRD_TABLE_SIZE_REV2; + num_subbands = UEFI_SAR_SUB_BANDS_NUM_REV2; + profile_size = UEFI_SAR_PROFILE_SIZE_REV2; + break; + default: + IWL_DEBUG_RADIO(fwrt, + "Unsupported UEFI EWSS revision:%d\n", + data->revision); + return -EINVAL; + } + + if (size != expected_size || + data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) + return -EINVAL; + + if (fwrt->ewrd_table_revision != data->revision) { + IWL_DEBUG_RADIO(fwrt, + "Skipping standalone SAR: EWRD/EWSS revision mismatch (EWRD rev %d, EWSS rev %d)\n", + fwrt->ewrd_table_revision, + data->revision); + return -EINVAL; + } + + for (i = 0; i < data->num_profiles; i++) + iwl_uefi_set_sar_profile(fwrt->sar_standalone_profiles, + &data->vals[i * profile_size], + i + 1, num_subbands, + data->mode); + + return 0; +} + int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) { struct uefi_cnv_var_wgds *data; @@ -605,9 +829,9 @@ int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) int n_subbands; int ret = 0; - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME, - "WGDS", UEFI_WGDS_TABLE_SIZE_REV3, - &size); + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_WGDS_NAME, "WGDS", + UEFI_WGDS_TABLE_SIZE_REV3, &size); if (IS_ERR(data)) return -EINVAL; @@ -680,9 +904,9 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) u32 valid_rev; int ret = 0; - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME, - "PPAG", UEFI_PPAG_DATA_SIZE_V5, - NULL); + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_PPAG_NAME, "PPAG", + UEFI_PPAG_DATA_SIZE_V5, NULL); if (!IS_ERR(data)) { n_subbands = UEFI_PPAG_SUB_BANDS_NUM_REV5; valid_rev = BIT(5); @@ -690,7 +914,7 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) goto parse_table; } - data = iwl_uefi_get_verified_variable(fwrt->trans, + data = iwl_uefi_get_verified_wifi_var(fwrt, IWL_UEFI_PPAG_NAME, "PPAG", UEFI_PPAG_DATA_SIZE_V4, @@ -748,8 +972,9 @@ int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, struct uefi_cnv_var_wtas *uefi_tas; int ret, enabled; - uefi_tas = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WTAS_NAME, - "WTAS", sizeof(*uefi_tas), NULL); + uefi_tas = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_WTAS_NAME, "WTAS", + sizeof(*uefi_tas), NULL); if (IS_ERR(uefi_tas)) return -EINVAL; @@ -801,7 +1026,7 @@ int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, struct uefi_cnv_var_splc *data; int ret = 0; - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_SPLC_NAME, + data = iwl_uefi_get_verified_wifi_var(fwrt, IWL_UEFI_SPLC_NAME, "SPLC", sizeof(*data), NULL); if (IS_ERR(data)) return -EINVAL; @@ -823,8 +1048,9 @@ int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) struct uefi_cnv_var_wrdd *data; int ret = 0; - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDD_NAME, - "WRDD", sizeof(*data), NULL); + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_WRDD_NAME, "WRDD", + sizeof(*data), NULL); if (IS_ERR(data)) return -EINVAL; @@ -854,7 +1080,7 @@ int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) struct uefi_cnv_var_eckv *data; int ret = 0; - data = iwl_uefi_get_verified_variable_guid(fwrt->trans, + data = iwl_uefi_get_verified_variable_guid(fwrt, &IWL_EFI_WIFI_BT_GUID, IWL_UEFI_ECKV_NAME, "ECKV", sizeof(*data), NULL); @@ -878,8 +1104,9 @@ int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value) struct uefi_cnv_wlan_wbem_data *data; int ret = 0; - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WBEM_NAME, - "WBEM", sizeof(*data), NULL); + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_WBEM_NAME, "WBEM", + sizeof(*data), NULL); if (IS_ERR(data)) return -EINVAL; @@ -905,7 +1132,7 @@ static int iwl_uefi_load_dsm_values(struct iwl_fw_runtime *fwrt) BUILD_BUG_ON(ARRAY_SIZE(data->functions) < ARRAY_SIZE(fwrt->dsm_values)); - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME, + data = iwl_uefi_get_verified_wifi_var(fwrt, IWL_UEFI_DSM_NAME, "DSM", sizeof(*data), NULL); if (IS_ERR(data)) return -EINVAL; @@ -915,6 +1142,12 @@ static int iwl_uefi_load_dsm_values(struct iwl_fw_runtime *fwrt) data->revision); goto out; } + if (!data->functions[DSM_FUNC_QUERY]) { + IWL_DEBUG_RADIO(fwrt, + "UEFI DSM query bitmap is empty, revision:%d\n", + data->revision); + goto out; + } fwrt->dsm_revision = data->revision; fwrt->dsm_source = BIOS_SOURCE_UEFI; @@ -980,10 +1213,10 @@ int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt) struct uefi_cnv_var_puncturing_data *data; int ret = 0; - data = iwl_uefi_get_verified_variable(fwrt->trans, - IWL_UEFI_PUNCTURING_NAME, - "UefiCnvWlanPuncturing", - sizeof(*data), NULL); + data = iwl_uefi_get_variable_guid(fwrt->trans, &IWL_EFI_WIFI_GUID, + IWL_UEFI_PUNCTURING_NAME, + "UefiCnvWlanPuncturing", + sizeof(*data), NULL, NULL); if (IS_ERR(data)) return -EINVAL; @@ -1009,7 +1242,7 @@ int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value) struct uefi_cnv_wlan_dsbr_data *data; int ret = 0; - data = iwl_uefi_get_verified_variable_guid(fwrt->trans, + data = iwl_uefi_get_verified_variable_guid(fwrt, &IWL_EFI_WIFI_BT_GUID, IWL_UEFI_DSBR_NAME, "DSBR", sizeof(*data), NULL); @@ -1035,8 +1268,9 @@ int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt) struct uefi_cnv_wpfc_data *data __free(kfree); struct iwl_phy_specific_cfg *filters = &fwrt->phy_filters; - data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WPFC_NAME, - "WPFC", sizeof(*data), NULL); + data = iwl_uefi_get_verified_wifi_var(fwrt, + IWL_UEFI_WPFC_NAME, "WPFC", + sizeof(*data), NULL); if (IS_ERR(data)) return -EINVAL; @@ -1057,3 +1291,33 @@ int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt) IWL_DEBUG_RADIO(fwrt, "Loaded WPFC config from UEFI\n"); return 0; } + +void iwl_uefi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_glui *data __free(kfree) = + iwl_uefi_get_variable_guid(fwrt->trans, + &IWL_EFI_GLUI_GUID, + IWL_UEFI_GLUI_NAME, "GLUI", + sizeof(*data), NULL, NULL); + + if (IS_ERR(data)) + return; + + if (data->revision != IWL_UEFI_GLUI_REVISION) { + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI GLUI revision:%d\n", + data->revision); + return; + } + + /* UEFI_CNV_GUID_TEST_MODE is the max value the BIOS can report */ + if (data->guid_lock_status > UEFI_CNV_GUID_TEST_MODE) { + IWL_DEBUG_RADIO(fwrt, "Invalid UEFI GUID lock status:%d\n", + data->guid_lock_status); + return; + } + + fwrt->uefi_tables_lock_status = data->guid_lock_status; + + IWL_DEBUG_RADIO(fwrt, "Loaded UEFI WIFI GUID lock status: %d\n", + fwrt->uefi_tables_lock_status); +} diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h index 386ca3744408..f4f7a447e528 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h @@ -13,7 +13,10 @@ #define IWL_UEFI_STEP_NAME L"UefiCnvCommonSTEP" #define IWL_UEFI_UATS_NAME L"CnvUefiWlanUATS" #define IWL_UEFI_WRDS_NAME L"UefiCnvWlanWRDS" +#define IWL_UEFI_GLUI_NAME L"UefiCnvCommonGLUI" #define IWL_UEFI_EWRD_NAME L"UefiCnvWlanEWRD" +#define IWL_UEFI_WSSS_NAME L"UefiCnvWlanWSSS" +#define IWL_UEFI_EWSS_NAME L"UefiCnvWlanEWSS" #define IWL_UEFI_WGDS_NAME L"UefiCnvWlanWGDS" #define IWL_UEFI_PPAG_NAME L"UefiCnvWlanPPAG" #define IWL_UEFI_WTAS_NAME L"UefiCnvWlanWTAS" @@ -40,6 +43,7 @@ #define IWL_UEFI_DSM_REVISION 4 #define IWL_UEFI_PUNCTURING_REVISION 0 #define IWL_UEFI_DSBR_REVISION 1 +#define IWL_UEFI_GLUI_REVISION 0 struct pnvm_sku_package { u8 rev; @@ -54,6 +58,11 @@ struct uefi_cnv_wlan_sgom_data { u8 offset_map[IWL_SGOM_MAP_SIZE - 1]; } __packed; +struct uefi_cnv_var_glui { + u8 revision; + u8 guid_lock_status; +} __packed; + struct uefi_cnv_wlan_uats_data { u8 revision; u8 mcc_to_ap_type_map[IWL_UATS_MAP_SIZE - 1]; @@ -330,6 +339,8 @@ int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, u32 tlv_len, struct iwl_pnvm_image *pnvm_data); int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt); +int iwl_uefi_get_wsss_table(struct iwl_fw_runtime *fwrt); +int iwl_uefi_get_ewss_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, @@ -349,6 +360,7 @@ void iwl_uefi_get_uneb_table(struct iwl_trans *trans, int iwl_uefi_get_puncturing(struct iwl_fw_runtime *fwrt); int iwl_uefi_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *value); int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt); +void iwl_uefi_get_guid_lock_status(struct iwl_fw_runtime *fwrt); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -391,6 +403,16 @@ static inline int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) return -ENOENT; } +static inline int iwl_uefi_get_wsss_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_ewss_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + static inline int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; @@ -466,5 +488,9 @@ static inline int iwl_uefi_get_phy_filters(struct iwl_fw_runtime *fwrt) { return -ENOENT; } + +static inline void iwl_uefi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) +{ +} #endif /* CONFIG_EFI */ #endif /* __iwl_fw_uefi__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h index d2fa80a3dd04..11f2b31f6df7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h @@ -14,9 +14,9 @@ * low power states due to driver-invoked device resets * (e.g. CSR_RESET_REG_FLAG_SW_RESET) or uCode-driven power-saving modes. * - * Use iwl_write32() and iwl_read32() family to access these registers; + * Use iwl_trans_write32() and iwl_trans_read32() family to access these registers; * these provide simple PCI bus access, without waking up the MAC. - * Do not use iwl_write_direct32() family for these registers; + * Do not use iwl_trans_write_direct32() family for these registers; * no need to "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ. * The MAC (uCode processor, etc.) does not need to be powered up for accessing * the CSR registers. @@ -36,7 +36,7 @@ #define CSR_GP_CNTRL (CSR_BASE+0x024) #define CSR_FUNC_SCRATCH (CSR_BASE+0x02c) /* Scratch register - used for FW dbg */ -/* 2nd byte of CSR_INT_COALESCING, not accessible via iwl_write32()! */ +/* 2nd byte of CSR_INT_COALESCING, not accessible via iwl_trans_write32()! */ #define CSR_INT_PERIODIC_REG (CSR_BASE+0x005) /* @@ -474,7 +474,7 @@ enum { * indirect read/write via HEEP_CTRL_WRD_PCIEX_CTRL (0xEC) and * HEEP_CTRL_WRD_PCIEX_DATA (0xF4) registers. * - * Use iwl_write32()/iwl_read32() family to access these registers. The MAC HW + * Use iwl_trans_write32()/iwl_trans_read32() family to access these registers. The MAC HW * need not be powered up so no "grab inc access" is required. */ @@ -501,12 +501,13 @@ enum { * to indirectly access device's internal memory or registers that * may be powered-down. * - * Use iwl_write_direct32()/iwl_read_direct32() family for these registers; + * Use iwl_trans_write_direct32() family for writing to these registers; + * A read operation doesn't exist, can be added if needed. * host must "grab nic access" via CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ * to make sure the MAC (uCode processor, etc.) is powered up for accessing * internal resources. * - * Do not use iwl_write32()/iwl_read32() family to access these registers; + * Do not use iwl_trans_write32()/iwl_trans_read32() family to access these registers; * these provide only simple PCI bus access, without waking up the MAC. */ #define HBUS_BASE (0x400) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c index 11763dec77ec..cc6044222b5c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-dbg-tlv.c @@ -167,11 +167,13 @@ static int iwl_dbg_tlv_alloc_hcmd(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv) { const struct iwl_fw_ini_hcmd_tlv *hcmd = (const void *)tlv->data; - u32 tp = le32_to_cpu(hcmd->time_point); + u32 tp; if (le32_to_cpu(tlv->length) <= sizeof(*hcmd)) return -EINVAL; + tp = le32_to_cpu(hcmd->time_point); + /* Host commands can not be sent in early time point since the FW * is not ready */ @@ -194,9 +196,14 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, { const struct iwl_fw_ini_region_tlv *reg = (const void *)tlv->data; struct iwl_ucode_tlv **active_reg; - u32 id = le32_to_cpu(reg->id); - u8 type = reg->type; u32 tlv_len = sizeof(*tlv) + le32_to_cpu(tlv->length); + u32 id; + u8 type; + + if (le32_to_cpu(tlv->length) < sizeof(*reg)) + return -EINVAL; + + id = le32_to_cpu(reg->id); /* * The higher part of the ID from version 2 is debug policy. @@ -205,9 +212,6 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, if (le32_to_cpu(reg->hdr.version) >= 2) id &= IWL_FW_INI_REGION_ID_MASK; - if (le32_to_cpu(tlv->length) < sizeof(*reg)) - return -EINVAL; - /* for safe use of a string from FW, limit it to IWL_FW_INI_MAX_NAME */ IWL_DEBUG_FW(trans, "WRT: parsing region: %.*s\n", IWL_FW_INI_MAX_NAME, reg->name); @@ -217,12 +221,26 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, return -EINVAL; } + type = reg->type; + if (type <= IWL_FW_INI_REGION_INVALID || type >= IWL_FW_INI_REGION_NUM) { IWL_ERR(trans, "WRT: Invalid region type %u\n", type); return -EINVAL; } + if (type == IWL_FW_INI_REGION_DRAM_BUFFER) { + u32 alloc_id = le32_to_cpu(reg->dram_alloc_id); + + if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID || + alloc_id >= ARRAY_SIZE(trans->dbg.fw_mon_ini)) { + IWL_ERR(trans, + "WRT: Invalid dram_alloc_id %u for region %u\n", + alloc_id, id); + return -EINVAL; + } + } + if (type == IWL_FW_INI_REGION_INTERNAL_BUFFER) { trans->dbg.imr_data.sram_addr = le32_to_cpu(reg->internal_buffer.base_addr); @@ -251,13 +269,14 @@ static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv) { const struct iwl_fw_ini_trigger_tlv *trig = (const void *)tlv->data; - u32 tp = le32_to_cpu(trig->time_point); - u32 rf = le32_to_cpu(trig->reset_fw); + u32 tp, rf; struct iwl_ucode_tlv *new_tlv; if (le32_to_cpu(tlv->length) < sizeof(*trig)) return -EINVAL; + tp = le32_to_cpu(trig->time_point); + if (tp <= IWL_FW_INI_TIME_POINT_INVALID || tp >= IWL_FW_INI_TIME_POINT_NUM) { IWL_ERR(trans, @@ -266,6 +285,8 @@ static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans, return -EINVAL; } + rf = le32_to_cpu(trig->reset_fw); + IWL_DEBUG_FW(trans, "WRT: time point %u for trigger TLV with reset_fw %u\n", tp, rf); @@ -288,8 +309,13 @@ static int iwl_dbg_tlv_config_set(struct iwl_trans *trans, const struct iwl_ucode_tlv *tlv) { const struct iwl_fw_ini_conf_set_tlv *conf_set = (const void *)tlv->data; - u32 tp = le32_to_cpu(conf_set->time_point); - u32 type = le32_to_cpu(conf_set->set_type); + u32 tp, type; + + if (le32_to_cpu(tlv->length) < sizeof(*conf_set)) + return -EINVAL; + + tp = le32_to_cpu(conf_set->time_point); + type = le32_to_cpu(conf_set->set_type); if (tp <= IWL_FW_INI_TIME_POINT_INVALID || tp >= IWL_FW_INI_TIME_POINT_NUM) { @@ -593,7 +619,7 @@ static int iwl_dbg_tlv_alloc_fragments(struct iwl_fw_runtime *fwrt, u32 num_frags, remain_pages, frag_pages; int i; - if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID || + if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID || alloc_id >= IWL_FW_INI_ALLOCATION_NUM) return -EIO; @@ -676,7 +702,7 @@ static int iwl_dbg_tlv_apply_buffer(struct iwl_fw_runtime *fwrt, IWL_UCODE_TLV_CAPA_DBG_BUF_ALLOC_CMD_SUPP)) return 0; - if (alloc_id < IWL_FW_INI_ALLOCATION_INVALID || + if (alloc_id <= IWL_FW_INI_ALLOCATION_INVALID || alloc_id >= IWL_FW_INI_ALLOCATION_NUM) return -EIO; @@ -886,7 +912,7 @@ static void iwl_dbg_tlv_apply_config(struct iwl_fw_runtime *fwrt, for (count = 0; count < len; count++) { address = le32_to_cpu(config_list->addr_val[count].address); value = le32_to_cpu(config_list->addr_val[count].value); - iwl_trans_write_prph(fwrt->trans, address + offset, value); + iwl_trans_write_prph_no_grab(fwrt->trans, address + offset, value); } iwl_trans_release_nic_access(fwrt->trans); break; @@ -905,7 +931,7 @@ static void iwl_dbg_tlv_apply_config(struct iwl_fw_runtime *fwrt, for (count = 0; count < len; count++) { address = le32_to_cpu(config_list->addr_val[count].address); value = le32_to_cpu(config_list->addr_val[count].value); - iwl_write32(fwrt->trans, address + offset, value); + iwl_trans_write32(fwrt->trans, address + offset, value); IWL_DEBUG_FW(fwrt, "WRT: CSR: count %u, add: %u val: %u\n", count, address, value); } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h index 0af9d8362c5b..a0cc40119890 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-devtrace-io.h @@ -3,6 +3,7 @@ * * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2016-2017 Intel Deutschland GmbH + * Copyright (C) 2026 Intel Corporation *****************************************************************************/ #if !defined(__IWLWIFI_DEVICE_TRACE_IO) || defined(TRACE_HEADER_MULTI_READ) @@ -65,23 +66,6 @@ TRACE_EVENT(iwlwifi_dev_iowrite32, __get_str(dev), __entry->offs, __entry->val) ); -TRACE_EVENT(iwlwifi_dev_iowrite64, - TP_PROTO(const struct device *dev, u64 offs, u64 val), - TP_ARGS(dev, offs, val), - TP_STRUCT__entry( - DEV_ENTRY - __field(u64, offs) - __field(u64, val) - ), - TP_fast_assign( - DEV_ASSIGN; - __entry->offs = offs; - __entry->val = val; - ), - TP_printk("[%s] write io[%llu] = %llu)", - __get_str(dev), __entry->offs, __entry->val) -); - TRACE_EVENT(iwlwifi_dev_iowrite_prph32, TP_PROTO(const struct device *dev, u32 offs, u32 val), TP_ARGS(dev, offs, val), diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 7f1515dfc5bf..0982e60842b1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -1103,10 +1103,17 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, const struct iwl_fw_dbg_dest_tlv_v1 *dest_v1 = NULL; u8 mon_mode; + if (tlv_len < sizeof(*pieces->dbg_dest_ver)) + goto invalid_tlv_len; + pieces->dbg_dest_ver = (const u8 *)tlv_data; if (*pieces->dbg_dest_ver == 1) { + if (tlv_len < sizeof(*dest)) + goto invalid_tlv_len; dest = (const void *)tlv_data; } else if (*pieces->dbg_dest_ver == 0) { + if (tlv_len < sizeof(*dest_v1)) + goto invalid_tlv_len; dest_v1 = (const void *)tlv_data; } else { IWL_ERR(drv, @@ -2039,8 +2046,6 @@ void iwl_drv_stop(struct iwl_drv *drv) mutex_unlock(&iwlwifi_opmode_table_mtx); #ifdef CONFIG_IWLWIFI_DEBUGFS - iwl_trans_debugfs_cleanup(drv->trans); - debugfs_remove_recursive(drv->dbgfs_drv); #endif diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c deleted file mode 100644 index bb746112ddad..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ /dev/null @@ -1,448 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* - * Copyright (C) 2003-2014, 2018-2022, 2024-2026 Intel Corporation - * Copyright (C) 2015-2016 Intel Deutschland GmbH - */ -#include -#include - -#include "iwl-drv.h" -#include "iwl-io.h" -#include "iwl-csr.h" -#include "iwl-debug.h" -#include "iwl-prph.h" -#include "iwl-fh.h" - -void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val) -{ - trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val); - iwl_trans_write8(trans, ofs, val); -} -IWL_EXPORT_SYMBOL(iwl_write8); - -void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val) -{ - trace_iwlwifi_dev_iowrite32(trans->dev, ofs, val); - iwl_trans_write32(trans, ofs, val); -} -IWL_EXPORT_SYMBOL(iwl_write32); - -void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val) -{ - trace_iwlwifi_dev_iowrite64(trans->dev, ofs, val); - iwl_trans_write32(trans, ofs, lower_32_bits(val)); - iwl_trans_write32(trans, ofs + 4, upper_32_bits(val)); -} -IWL_EXPORT_SYMBOL(iwl_write64); - -u32 iwl_read32(struct iwl_trans *trans, u32 ofs) -{ - u32 val = iwl_trans_read32(trans, ofs); - - trace_iwlwifi_dev_ioread32(trans->dev, ofs, val); - return val; -} -IWL_EXPORT_SYMBOL(iwl_read32); - -#define IWL_POLL_INTERVAL 10 /* microseconds */ - -int iwl_poll_bits_mask(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int t = 0; - - do { - if ((iwl_read32(trans, addr) & mask) == (bits & mask)) - return 0; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} -IWL_EXPORT_SYMBOL(iwl_poll_bits_mask); - -u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) -{ - if (iwl_trans_grab_nic_access(trans)) { - u32 value = iwl_read32(trans, reg); - - iwl_trans_release_nic_access(trans); - return value; - } - - /* return as if we have a HW timeout/failure */ - return 0x5a5a5a5a; -} - -void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) -{ - if (iwl_trans_grab_nic_access(trans)) { - iwl_write32(trans, reg, value); - iwl_trans_release_nic_access(trans); - } -} -IWL_EXPORT_SYMBOL(iwl_write_direct32); - -void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value) -{ - if (iwl_trans_grab_nic_access(trans)) { - iwl_write64(trans, reg, value); - iwl_trans_release_nic_access(trans); - } -} - -int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, - int timeout) -{ - int t = 0; - - do { - if ((iwl_read_direct32(trans, addr) & mask) == mask) - return t; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} - -u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) -{ - u32 val = iwl_trans_read_prph(trans, ofs); - trace_iwlwifi_dev_ioread_prph32(trans->dev, ofs, val); - return val; -} - -void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) -{ - trace_iwlwifi_dev_iowrite_prph32(trans->dev, ofs, val); - iwl_trans_write_prph(trans, ofs, val); -} - -void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val) -{ - trace_iwlwifi_dev_iowrite_prph64(trans->dev, ofs, val); - iwl_write_prph_no_grab(trans, ofs, val & 0xffffffff); - iwl_write_prph_no_grab(trans, ofs + 4, val >> 32); -} - -u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs) -{ - if (iwl_trans_grab_nic_access(trans)) { - u32 val = iwl_read_prph_no_grab(trans, ofs); - - iwl_trans_release_nic_access(trans); - - return val; - } - - /* return as if we have a HW timeout/failure */ - return 0x5a5a5a5a; -} -IWL_EXPORT_SYMBOL(iwl_read_prph); - -void iwl_write_prph_delay(struct iwl_trans *trans, u32 ofs, u32 val, u32 delay_ms) -{ - if (iwl_trans_grab_nic_access(trans)) { - mdelay(delay_ms); - iwl_write_prph_no_grab(trans, ofs, val); - iwl_trans_release_nic_access(trans); - } -} -IWL_EXPORT_SYMBOL(iwl_write_prph_delay); - -int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int t = 0; - - do { - if ((iwl_read_prph(trans, addr) & mask) == (bits & mask)) - return 0; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} - -int iwl_poll_umac_prph_bits_no_grab(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout) -{ - int t = 0; - - do { - if ((iwl_read_umac_prph_no_grab(trans, addr) & mask) == - (bits & mask)) - return 0; - udelay(IWL_POLL_INTERVAL); - t += IWL_POLL_INTERVAL; - } while (t < timeout); - - return -ETIMEDOUT; -} - -void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) -{ - if (iwl_trans_grab_nic_access(trans)) { - iwl_write_prph_no_grab(trans, ofs, - iwl_read_prph_no_grab(trans, ofs) | - mask); - iwl_trans_release_nic_access(trans); - } -} -IWL_EXPORT_SYMBOL(iwl_set_bits_prph); - -void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, - u32 bits, u32 mask) -{ - if (iwl_trans_grab_nic_access(trans)) { - iwl_write_prph_no_grab(trans, ofs, - (iwl_read_prph_no_grab(trans, ofs) & - mask) | bits); - iwl_trans_release_nic_access(trans); - } -} -IWL_EXPORT_SYMBOL(iwl_set_bits_mask_prph); - -void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) -{ - u32 val; - - if (iwl_trans_grab_nic_access(trans)) { - val = iwl_read_prph_no_grab(trans, ofs); - iwl_write_prph_no_grab(trans, ofs, (val & ~mask)); - iwl_trans_release_nic_access(trans); - } -} -IWL_EXPORT_SYMBOL(iwl_clear_bits_prph); - -void iwl_force_nmi(struct iwl_trans *trans) -{ - if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_9000) - iwl_write_prph_delay(trans, DEVICE_SET_NMI_REG, - DEVICE_SET_NMI_VAL_DRV, 1); - else if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) - iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, - UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER); - else if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ) - iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, - UREG_DOORBELL_TO_ISR6_NMI_BIT); - else - iwl_write32(trans, CSR_DOORBELL_VECTOR, - UREG_DOORBELL_TO_ISR6_NMI_BIT); -} -IWL_EXPORT_SYMBOL(iwl_force_nmi); - -static const char *get_rfh_string(int cmd) -{ -#define IWL_CMD(x) case x: return #x -#define IWL_CMD_MQ(arg, reg, q) { if (arg == reg(q)) return #reg; } - - int i; - - for (i = 0; i < IWL_MAX_RX_HW_QUEUES; i++) { - IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_BA_LSB, i); - IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_WIDX, i); - IWL_CMD_MQ(cmd, RFH_Q_FRBDCB_RIDX, i); - IWL_CMD_MQ(cmd, RFH_Q_URBD_STTS_WPTR_LSB, i); - } - - switch (cmd) { - IWL_CMD(RFH_RXF_DMA_CFG); - IWL_CMD(RFH_GEN_CFG); - IWL_CMD(RFH_GEN_STATUS); - IWL_CMD(FH_TSSR_TX_STATUS_REG); - IWL_CMD(FH_TSSR_TX_ERROR_REG); - default: - return "UNKNOWN"; - } -#undef IWL_CMD_MQ -} - -struct reg { - u32 addr; - bool is64; -}; - -static int iwl_dump_rfh(struct iwl_trans *trans, char **buf) -{ - int i, q; - int num_q = trans->info.num_rxqs; - static const u32 rfh_tbl[] = { - RFH_RXF_DMA_CFG, - RFH_GEN_CFG, - RFH_GEN_STATUS, - FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_ERROR_REG, - }; - static const struct reg rfh_mq_tbl[] = { - { RFH_Q0_FRBDCB_BA_LSB, true }, - { RFH_Q0_FRBDCB_WIDX, false }, - { RFH_Q0_FRBDCB_RIDX, false }, - { RFH_Q0_URBD_STTS_WPTR_LSB, true }, - }; - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (buf) { - int pos = 0; - /* - * Register (up to 34 for name + 8 blank/q for MQ): 40 chars - * Colon + space: 2 characters - * 0X%08x: 10 characters - * New line: 1 character - * Total of 53 characters - */ - size_t bufsz = ARRAY_SIZE(rfh_tbl) * 53 + - ARRAY_SIZE(rfh_mq_tbl) * 53 * num_q + 40; - - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - - pos += scnprintf(*buf + pos, bufsz - pos, - "RFH register values:\n"); - - for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) - pos += scnprintf(*buf + pos, bufsz - pos, - "%40s: 0X%08x\n", - get_rfh_string(rfh_tbl[i]), - iwl_read_prph(trans, rfh_tbl[i])); - - for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) - for (q = 0; q < num_q; q++) { - u32 addr = rfh_mq_tbl[i].addr; - - addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); - pos += scnprintf(*buf + pos, bufsz - pos, - "%34s(q %2d): 0X%08x\n", - get_rfh_string(addr), q, - iwl_read_prph(trans, addr)); - } - - return pos; - } -#endif - - IWL_ERR(trans, "RFH register values:\n"); - for (i = 0; i < ARRAY_SIZE(rfh_tbl); i++) - IWL_ERR(trans, " %34s: 0X%08x\n", - get_rfh_string(rfh_tbl[i]), - iwl_read_prph(trans, rfh_tbl[i])); - - for (i = 0; i < ARRAY_SIZE(rfh_mq_tbl); i++) - for (q = 0; q < num_q; q++) { - u32 addr = rfh_mq_tbl[i].addr; - - addr += q * (rfh_mq_tbl[i].is64 ? 8 : 4); - IWL_ERR(trans, " %34s(q %d): 0X%08x\n", - get_rfh_string(addr), q, - iwl_read_prph(trans, addr)); - } - - return 0; -} - -static const char *get_fh_string(int cmd) -{ - switch (cmd) { - IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG); - IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG); - IWL_CMD(FH_RSCSR_CHNL0_WPTR); - IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG); - IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG); - IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG); - IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV); - IWL_CMD(FH_TSSR_TX_STATUS_REG); - IWL_CMD(FH_TSSR_TX_ERROR_REG); - default: - return "UNKNOWN"; - } -#undef IWL_CMD -} - -int iwl_dump_fh(struct iwl_trans *trans, char **buf) -{ - int i; - static const u32 fh_tbl[] = { - FH_RSCSR_CHNL0_STTS_WPTR_REG, - FH_RSCSR_CHNL0_RBDCB_BASE_REG, - FH_RSCSR_CHNL0_WPTR, - FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_MEM_RSSR_SHARED_CTRL_REG, - FH_MEM_RSSR_RX_STATUS_REG, - FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV, - FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_ERROR_REG - }; - - if (trans->mac_cfg->mq_rx_supported) - return iwl_dump_rfh(trans, buf); - -#ifdef CONFIG_IWLWIFI_DEBUGFS - if (buf) { - int pos = 0; - size_t bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40; - - *buf = kmalloc(bufsz, GFP_KERNEL); - if (!*buf) - return -ENOMEM; - - pos += scnprintf(*buf + pos, bufsz - pos, - "FH register values:\n"); - - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) - pos += scnprintf(*buf + pos, bufsz - pos, - " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(trans, fh_tbl[i])); - - return pos; - } -#endif - - IWL_ERR(trans, "FH register values:\n"); - for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) - IWL_ERR(trans, " %34s: 0X%08x\n", - get_fh_string(fh_tbl[i]), - iwl_read_direct32(trans, fh_tbl[i])); - - return 0; -} - -void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, - u32 sw_err_bit) -{ - unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT; - bool interrupts_enabled = test_bit(STATUS_INT_ENABLED, &trans->status); - - /* if the interrupts were already disabled, there is no point in - * calling iwl_disable_interrupts - */ - if (interrupts_enabled) - iwl_trans_interrupts(trans, false); - - iwl_force_nmi(trans); - while (time_after(timeout, jiffies)) { - u32 inta_hw = iwl_read32(trans, inta_addr); - - /* Error detected by uCode */ - if (inta_hw & sw_err_bit) { - /* Clear causes register */ - iwl_write32(trans, inta_addr, inta_hw & sw_err_bit); - break; - } - - mdelay(1); - } - - /* enable interrupts only if there were already enabled before this - * function to avoid a case were the driver enable interrupts before - * proper configurations were made - */ - if (interrupts_enabled) - iwl_trans_interrupts(trans, true); - - iwl_trans_fw_error(trans, IWL_ERR_TYPE_NMI_FORCED); -} diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h deleted file mode 100644 index 6dce2e5267a6..000000000000 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h +++ /dev/null @@ -1,107 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* - * Copyright (C) 2018-2021, 2025-2026 Intel Corporation - */ -#ifndef __iwl_io_h__ -#define __iwl_io_h__ - -#include "iwl-devtrace.h" -#include "iwl-trans.h" - -void iwl_write8(struct iwl_trans *trans, u32 ofs, u8 val); -void iwl_write32(struct iwl_trans *trans, u32 ofs, u32 val); -void iwl_write64(struct iwl_trans *trans, u64 ofs, u64 val); -u32 iwl_read32(struct iwl_trans *trans, u32 ofs); - -static inline void iwl_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) -{ - iwl_trans_set_bits_mask(trans, reg, mask, mask); -} - -static inline void iwl_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) -{ - iwl_trans_set_bits_mask(trans, reg, mask, 0); -} - -int iwl_poll_bits_mask(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout); -static inline int iwl_poll_bits(struct iwl_trans *trans, u32 addr, u32 bits, - int timeout) -{ - return iwl_poll_bits_mask(trans, addr, bits, bits, timeout); -} -int iwl_poll_direct_bit(struct iwl_trans *trans, u32 addr, u32 mask, - int timeout); - -u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg); -void iwl_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); -void iwl_write_direct64(struct iwl_trans *trans, u64 reg, u64 value); - - -u32 iwl_read_prph_no_grab(struct iwl_trans *trans, u32 ofs); -u32 iwl_read_prph(struct iwl_trans *trans, u32 ofs); -void iwl_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val); -void iwl_write_prph64_no_grab(struct iwl_trans *trans, u64 ofs, u64 val); -void iwl_write_prph_delay(struct iwl_trans *trans, u32 ofs, - u32 val, u32 delay_ms); -static inline void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) -{ - iwl_write_prph_delay(trans, ofs, val, 0); -} - -int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout); -int iwl_poll_umac_prph_bits_no_grab(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout); -void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); -void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, - u32 bits, u32 mask); -void iwl_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); -void iwl_force_nmi(struct iwl_trans *trans); - -/* Error handling */ -int iwl_dump_fh(struct iwl_trans *trans, char **buf); - -/* - * UMAC periphery address space changed from 0xA00000 to 0xD00000 starting from - * device family AX200. So peripheries used in families above and below AX200 - * should go through iwl_..._umac_..._prph. - */ -static inline u32 iwl_umac_prph(struct iwl_trans *trans, u32 ofs) -{ - return ofs + trans->mac_cfg->umac_prph_offset; -} - -static inline u32 iwl_read_umac_prph_no_grab(struct iwl_trans *trans, u32 ofs) -{ - return iwl_read_prph_no_grab(trans, ofs + - trans->mac_cfg->umac_prph_offset); -} - -static inline u32 iwl_read_umac_prph(struct iwl_trans *trans, u32 ofs) -{ - return iwl_read_prph(trans, ofs + trans->mac_cfg->umac_prph_offset); -} - -static inline void iwl_write_umac_prph_no_grab(struct iwl_trans *trans, u32 ofs, - u32 val) -{ - iwl_write_prph_no_grab(trans, ofs + trans->mac_cfg->umac_prph_offset, - val); -} - -static inline void iwl_write_umac_prph(struct iwl_trans *trans, u32 ofs, - u32 val) -{ - iwl_write_prph(trans, ofs + trans->mac_cfg->umac_prph_offset, val); -} - -static inline int iwl_poll_umac_prph_bit(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout) -{ - return iwl_poll_prph_bit(trans, addr + - trans->mac_cfg->umac_prph_offset, - bits, mask, timeout); -} - -#endif diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c index 863d5e358152..31badfa35f97 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c @@ -16,7 +16,7 @@ #include "iwl-modparams.h" #include "iwl-nvm-parse.h" #include "iwl-prph.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-csr.h" #include "fw/api/nvm-reg.h" #include "fw/api/commands.h" @@ -612,7 +612,6 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = { IEEE80211_HE_PHY_CAP7_POWER_BOOST_FACTOR_SUPP | IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, .phy_cap_info[8] = - IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G | IEEE80211_HE_PHY_CAP8_20MHZ_IN_160MHZ_HE_PPDU | IEEE80211_HE_PHY_CAP8_80MHZ_IN_160MHZ_HE_PPDU | @@ -710,12 +709,14 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = { .has_uhr = true, /* Note: asymmetry is fixed later */ .phy.cap = cpu_to_le32(IEEE80211_UHR_PHY_CAP_ELR_RX | - IEEE80211_UHR_PHY_CAP_ELR_TX), + IEEE80211_UHR_PHY_CAP_ELR_TX | + IEEE80211_UHR_PHY_CAP_2XLDPC_RX), .mac.mac_cap = { [0] = IEEE80211_UHR_MAC_CAP0_NPCA_SUPP | IEEE80211_UHR_MAC_CAP0_DPS_SUPP, [1] = IEEE80211_UHR_MAC_CAP1_DUO_SUPP | IEEE80211_UHR_MAC_CAP1_DBE_SUPP, + [4] = IEEE80211_UHR_MAC_CAP4_CO_BF_SUPP, }, }, }, @@ -746,7 +747,6 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = { .phy_cap_info[7] = IEEE80211_HE_PHY_CAP7_HE_SU_MU_PPDU_4XLTF_AND_08_US_GI, .phy_cap_info[8] = - IEEE80211_HE_PHY_CAP8_HE_ER_SU_PPDU_4XLTF_AND_08_US_GI | IEEE80211_HE_PHY_CAP8_DCM_MAX_RU_242, .phy_cap_info[9] = IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU | @@ -820,7 +820,8 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = { .has_uhr = true, /* Note: asymmetry is fixed later */ .phy.cap = cpu_to_le32(IEEE80211_UHR_PHY_CAP_ELR_RX | - IEEE80211_UHR_PHY_CAP_ELR_TX), + IEEE80211_UHR_PHY_CAP_ELR_TX | + IEEE80211_UHR_PHY_CAP_2XLDPC_RX), }, }, }; @@ -1312,10 +1313,10 @@ static void iwl_flip_hw_address(__le32 mac_addr0, __le32 mac_addr1, u8 *dest) static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, struct iwl_nvm_data *data) { - __le32 mac_addr0 = cpu_to_le32(iwl_read32(trans, - CSR_MAC_ADDR0_STRAP(trans))); - __le32 mac_addr1 = cpu_to_le32(iwl_read32(trans, - CSR_MAC_ADDR1_STRAP(trans))); + __le32 mac_addr0 = cpu_to_le32(iwl_trans_read32(trans, + CSR_MAC_ADDR0_STRAP(trans))); + __le32 mac_addr1 = cpu_to_le32(iwl_trans_read32(trans, + CSR_MAC_ADDR1_STRAP(trans))); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); /* @@ -1325,8 +1326,8 @@ static void iwl_set_hw_address_from_csr(struct iwl_trans *trans, if (is_valid_ether_addr(data->hw_addr)) return; - mac_addr0 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR0_OTP(trans))); - mac_addr1 = cpu_to_le32(iwl_read32(trans, CSR_MAC_ADDR1_OTP(trans))); + mac_addr0 = cpu_to_le32(iwl_trans_read32(trans, CSR_MAC_ADDR0_OTP(trans))); + mac_addr1 = cpu_to_le32(iwl_trans_read32(trans, CSR_MAC_ADDR1_OTP(trans))); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); } @@ -1367,10 +1368,10 @@ static void iwl_set_hw_address_family_8000(struct iwl_trans *trans, if (nvm_hw) { /* read the mac address from WFMP registers */ - __le32 mac_addr0 = cpu_to_le32(iwl_trans_read_prph(trans, - WFMP_MAC_ADDR_0)); - __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph(trans, - WFMP_MAC_ADDR_1)); + __le32 mac_addr0 = cpu_to_le32(iwl_trans_read_prph_no_grab(trans, + WFMP_MAC_ADDR_0)); + __le32 mac_addr1 = cpu_to_le32(iwl_trans_read_prph_no_grab(trans, + WFMP_MAC_ADDR_1)); iwl_flip_hw_address(mac_addr0, mac_addr1, data->hw_addr); @@ -1410,7 +1411,7 @@ static int iwl_set_hw_address(struct iwl_trans *trans, if (!trans->csme_own) IWL_INFO(trans, "base HW address: %pM, OTP minor version: 0x%x\n", - data->hw_addr, iwl_read_prph(trans, REG_OTP_MINOR)); + data->hw_addr, iwl_trans_read_prph(trans, REG_OTP_MINOR)); return 0; } diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-scd.h b/drivers/net/wireless/intel/iwlwifi/iwl-scd.h index 1eaff898ca3c..f13568d3094b 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-scd.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-scd.h @@ -1,52 +1,52 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2014 Intel Mobile Communications GmbH + * Copyright (C) 2026 Intel Corporation */ #ifndef __iwl_scd_h__ #define __iwl_scd_h__ #include "iwl-trans.h" -#include "iwl-io.h" #include "iwl-prph.h" static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans, u16 txq_id) { - iwl_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id)); + iwl_trans_set_bits_prph(trans, SCD_QUEUECHAIN_SEL, BIT(txq_id)); } static inline void iwl_scd_txq_enable_agg(struct iwl_trans *trans, u16 txq_id) { - iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); + iwl_trans_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); } static inline void iwl_scd_txq_disable_agg(struct iwl_trans *trans, u16 txq_id) { - iwl_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); + iwl_trans_clear_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id)); } static inline void iwl_scd_disable_agg(struct iwl_trans *trans) { - iwl_set_bits_prph(trans, SCD_AGGR_SEL, 0); + iwl_trans_set_bits_prph(trans, SCD_AGGR_SEL, 0); } static inline void iwl_scd_activate_fifos(struct iwl_trans *trans) { - iwl_write_prph(trans, SCD_TXFACT, IWL_MASK(0, 7)); + iwl_trans_write_prph(trans, SCD_TXFACT, IWL_MASK(0, 7)); } static inline void iwl_scd_deactivate_fifos(struct iwl_trans *trans) { - iwl_write_prph(trans, SCD_TXFACT, 0); + iwl_trans_write_prph(trans, SCD_TXFACT, 0); } static inline void iwl_scd_enable_set_active(struct iwl_trans *trans, u32 value) { - iwl_write_prph(trans, SCD_EN_CTRL, value); + iwl_trans_write_prph(trans, SCD_EN_CTRL, value); } static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl) @@ -76,9 +76,9 @@ static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl) static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans, u16 txq_id) { - iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), - (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| - (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); + iwl_trans_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), + (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)| + (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN)); } #endif diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 73aae1125042..6ddf4945ed1c 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -6,14 +6,14 @@ */ #include #include +#include #include #include "iwl-trans.h" #include "iwl-drv.h" +#include "iwl-prph.h" #include #include "fw/api/commands.h" -#include "pcie/gen1_2/internal.h" -#include "pcie/iwl-context-info-v2.h" struct iwl_trans_dev_restart_data { struct list_head list; @@ -259,13 +259,14 @@ static void iwl_trans_restart_wk(struct work_struct *wk) iwl_trans_schedule_reprobe(trans, 0); break; default: - iwl_trans_pcie_reset(trans, mode); + iwl_trans_reset(trans, mode); break; } } struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, + const struct iwl_trans_ops *ops, const struct iwl_mac_cfg *mac_cfg) { struct iwl_trans *trans; @@ -277,6 +278,7 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, if (!trans) return NULL; + trans->ops = ops; trans->mac_cfg = mac_cfg; #ifdef CONFIG_LOCKDEP @@ -300,6 +302,9 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) { int ret; + if (WARN_ON_ONCE(!trans->ops->send_cmd)) + return -EOPNOTSUPP; + if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) && test_bit(STATUS_RFKILL_OPMODE, &trans->status))) return -ERFKILL; @@ -319,7 +324,7 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) cmd->id = DEF_ID(cmd->id); } - ret = iwl_trans_pcie_send_hcmd(trans, cmd); + ret = trans->ops->send_cmd(trans, cmd); if (!(cmd->flags & CMD_ASYNC)) lock_map_release(&trans->sync_cmd_lockdep_map); @@ -333,14 +338,18 @@ IWL_EXPORT_SYMBOL(iwl_trans_send_cmd); struct iwl_device_tx_cmd *iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) { - return iwl_pcie_gen1_2_alloc_tx_cmd(trans); + if (WARN_ON_ONCE(!trans->ops->alloc_tx_cmd)) + return ERR_PTR(-EOPNOTSUPP); + return trans->ops->alloc_tx_cmd(trans); } IWL_EXPORT_SYMBOL(iwl_trans_alloc_tx_cmd); void iwl_trans_free_tx_cmd(struct iwl_trans *trans, struct iwl_device_tx_cmd *dev_cmd) { - iwl_pcie_gen1_2_free_tx_cmd(trans, dev_cmd); + if (WARN_ON_ONCE(!trans->ops->free_tx_cmd)) + return; + trans->ops->free_tx_cmd(trans, dev_cmd); } IWL_EXPORT_SYMBOL(iwl_trans_free_tx_cmd); @@ -395,7 +404,9 @@ void iwl_trans_op_mode_enter(struct iwl_trans *trans, WARN_ON_ONCE(!trans->conf.rx_mpdu_cmd); - iwl_pcie_gen1_2_op_mode_enter(trans); + if (WARN_ON_ONCE(!trans->ops->op_mode_enter)) + return; + trans->ops->op_mode_enter(trans); } IWL_EXPORT_SYMBOL(iwl_trans_op_mode_enter); @@ -405,7 +416,9 @@ int iwl_trans_start_hw(struct iwl_trans *trans) clear_bit(STATUS_TRANS_RESET_IN_PROGRESS, &trans->status); - return iwl_trans_pcie_start_hw(trans); + if (WARN_ON_ONCE(!trans->ops->start_hw)) + return -EOPNOTSUPP; + return trans->ops->start_hw(trans); } IWL_EXPORT_SYMBOL(iwl_trans_start_hw); @@ -413,10 +426,8 @@ void iwl_trans_op_mode_leave(struct iwl_trans *trans) { might_sleep(); - if (trans->mac_cfg->gen2) - iwl_trans_pcie_gen2_op_mode_leave(trans); - else - iwl_trans_pcie_op_mode_leave(trans); + if (!WARN_ON_ONCE(!trans->ops->op_mode_leave)) + trans->ops->op_mode_leave(trans); cancel_delayed_work_sync(&trans->restart.wk); @@ -427,42 +438,147 @@ void iwl_trans_op_mode_leave(struct iwl_trans *trans) } IWL_EXPORT_SYMBOL(iwl_trans_op_mode_leave); -void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) -{ - iwl_trans_pcie_write8(trans, ofs, val); -} - void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val) { - iwl_trans_pcie_write32(trans, ofs, val); + if (WARN_ON_ONCE(!trans->ops->write32)) + return; + trans->ops->write32(trans, ofs, val); } +IWL_EXPORT_SYMBOL(iwl_trans_write32); u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) { - return iwl_trans_pcie_read32(trans, ofs); + if (WARN_ON_ONCE(!trans->ops->read32)) + return 0; + return trans->ops->read32(trans, ofs); } +IWL_EXPORT_SYMBOL(iwl_trans_read32); + +u32 iwl_trans_read_prph_no_grab(struct iwl_trans *trans, u32 ofs) +{ + if (WARN_ON_ONCE(!trans->ops->read_prph)) + return 0; + return trans->ops->read_prph(trans, ofs); +} + +void iwl_trans_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val) +{ + if (WARN_ON_ONCE(!trans->ops->write_prph)) + return; + trans->ops->write_prph(trans, ofs, val); +} + +int iwl_trans_poll_bits_mask(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout) +{ + if (WARN_ON_ONCE(!trans->ops->poll_bits_mask)) + return -EOPNOTSUPP; + return trans->ops->poll_bits_mask(trans, addr, bits, mask, timeout); +} +IWL_EXPORT_SYMBOL(iwl_trans_poll_bits_mask); + +void iwl_trans_write_direct32(struct iwl_trans *trans, u32 reg, u32 value) +{ + if (iwl_trans_grab_nic_access(trans)) { + iwl_trans_write32(trans, reg, value); + iwl_trans_release_nic_access(trans); + } +} +IWL_EXPORT_SYMBOL(iwl_trans_write_direct32); u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs) { - return iwl_trans_pcie_read_prph(trans, ofs); -} + if (iwl_trans_grab_nic_access(trans)) { + u32 val = iwl_trans_read_prph_no_grab(trans, ofs); -void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) -{ - return iwl_trans_pcie_write_prph(trans, ofs, val); + iwl_trans_release_nic_access(trans); + + return val; + } + + /* return as if we have a HW timeout/failure */ + return 0x5a5a5a5a; } +IWL_EXPORT_SYMBOL(iwl_trans_read_prph); + +void iwl_trans_write_prph_delay(struct iwl_trans *trans, u32 ofs, u32 val, + u32 delay_ms) +{ + if (iwl_trans_grab_nic_access(trans)) { + mdelay(delay_ms); + iwl_trans_write_prph_no_grab(trans, ofs, val); + iwl_trans_release_nic_access(trans); + } +} +IWL_EXPORT_SYMBOL(iwl_trans_write_prph_delay); + +void iwl_trans_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) +{ + if (iwl_trans_grab_nic_access(trans)) { + iwl_trans_write_prph_no_grab(trans, ofs, + iwl_trans_read_prph_no_grab(trans, ofs) | + mask); + iwl_trans_release_nic_access(trans); + } +} +IWL_EXPORT_SYMBOL(iwl_trans_set_bits_prph); + +void iwl_trans_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, + u32 bits, u32 mask) +{ + if (iwl_trans_grab_nic_access(trans)) { + iwl_trans_write_prph_no_grab(trans, ofs, + (iwl_trans_read_prph_no_grab(trans, ofs) & + mask) | bits); + iwl_trans_release_nic_access(trans); + } +} +IWL_EXPORT_SYMBOL(iwl_trans_set_bits_mask_prph); + +void iwl_trans_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask) +{ + u32 val; + + if (iwl_trans_grab_nic_access(trans)) { + val = iwl_trans_read_prph_no_grab(trans, ofs); + iwl_trans_write_prph_no_grab(trans, ofs, (val & ~mask)); + iwl_trans_release_nic_access(trans); + } +} +IWL_EXPORT_SYMBOL(iwl_trans_clear_bits_prph); + +void iwl_trans_force_nmi(struct iwl_trans *trans) +{ + if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_9000) + iwl_trans_write_prph_delay(trans, DEVICE_SET_NMI_REG, + DEVICE_SET_NMI_VAL_DRV, 1); + else if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) + iwl_trans_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, + UREG_NIC_SET_NMI_DRIVER_NMI_FROM_DRIVER); + else if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ) + iwl_trans_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + UREG_DOORBELL_TO_ISR6_NMI_BIT); + else + iwl_trans_write32(trans, CSR_DOORBELL_VECTOR, + UREG_DOORBELL_TO_ISR6_NMI_BIT); +} +IWL_EXPORT_SYMBOL(iwl_trans_force_nmi); int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, void *buf, int dwords) { - return iwl_trans_pcie_read_mem(trans, addr, buf, dwords); + if (WARN_ON_ONCE(!trans->ops->read_mem)) + return -EOPNOTSUPP; + return trans->ops->read_mem(trans, addr, buf, dwords); } IWL_EXPORT_SYMBOL(iwl_trans_read_mem); int iwl_trans_read_mem_no_grab(struct iwl_trans *trans, u32 addr, void *buf, u32 dwords) { - return iwl_trans_pcie_read_mem_no_grab(trans, addr, buf, dwords); + if (WARN_ON_ONCE(!trans->ops->read_mem_no_grab)) + return -EOPNOTSUPP; + return trans->ops->read_mem_no_grab(trans, addr, buf, dwords); } int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, @@ -472,10 +588,10 @@ int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, const u32 *vals = buf; if (iwl_trans_grab_nic_access(trans)) { - iwl_write32(trans, HBUS_TARG_MEM_WADDR, addr); + iwl_trans_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_write32(trans, HBUS_TARG_MEM_WDAT, + vals ? vals[offs] : 0); iwl_trans_release_nic_access(trans); } else { ret = -EBUSY; @@ -495,7 +611,9 @@ IWL_EXPORT_SYMBOL(iwl_trans_set_pmi); int iwl_trans_sw_reset(struct iwl_trans *trans) { - return iwl_trans_pcie_sw_reset(trans, true); + if (WARN_ON_ONCE(!trans->ops->sw_reset)) + return -EOPNOTSUPP; + return trans->ops->sw_reset(trans, true); } struct iwl_trans_dump_data * @@ -503,15 +621,19 @@ iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, const struct iwl_dump_sanitize_ops *sanitize_ops, void *sanitize_ctx) { - return iwl_trans_pcie_dump_data(trans, dump_mask, - sanitize_ops, sanitize_ctx); + if (WARN_ON_ONCE(!trans->ops->dump_data)) + return NULL; + return trans->ops->dump_data(trans, dump_mask, + sanitize_ops, sanitize_ctx); } int iwl_trans_d3_suspend(struct iwl_trans *trans, bool reset) { might_sleep(); - return iwl_trans_pcie_d3_suspend(trans, reset); + if (WARN_ON_ONCE(!trans->ops->d3_suspend)) + return -EOPNOTSUPP; + return trans->ops->d3_suspend(trans, reset); } IWL_EXPORT_SYMBOL(iwl_trans_d3_suspend); @@ -519,54 +641,64 @@ int iwl_trans_d3_resume(struct iwl_trans *trans, bool reset) { might_sleep(); - return iwl_trans_pcie_d3_resume(trans, reset); + if (WARN_ON_ONCE(!trans->ops->d3_resume)) + return -EOPNOTSUPP; + return trans->ops->d3_resume(trans, reset); } IWL_EXPORT_SYMBOL(iwl_trans_d3_resume); -void iwl_trans_interrupts(struct iwl_trans *trans, bool enable) -{ - iwl_trans_pci_interrupts(trans, enable); -} - void iwl_trans_sync_nmi(struct iwl_trans *trans) { - iwl_trans_pcie_sync_nmi(trans); + if (WARN_ON_ONCE(!trans->ops->sync_nmi)) + return; + trans->ops->sync_nmi(trans); } int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr, u64 src_addr, u32 byte_cnt) { - return iwl_trans_pcie_copy_imr(trans, dst_addr, src_addr, byte_cnt); + if (WARN_ON_ONCE(!trans->ops->write_imr_mem)) + return -EOPNOTSUPP; + return trans->ops->write_imr_mem(trans, dst_addr, src_addr, byte_cnt); } void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) { - iwl_trans_pcie_set_bits_mask(trans, reg, mask, value); + if (WARN_ON_ONCE(!trans->ops->set_bits_mask)) + return; + trans->ops->set_bits_mask(trans, reg, mask, value); } IWL_EXPORT_SYMBOL(iwl_trans_set_bits_mask); int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs, u32 *val) { - return iwl_trans_pcie_read_config32(trans, ofs, val); + if (WARN_ON_ONCE(!trans->ops->read_config32)) + return -EOPNOTSUPP; + return trans->ops->read_config32(trans, ofs, val); } bool iwl_trans_grab_nic_access(struct iwl_trans *trans) { - return iwl_trans_pcie_grab_nic_access(trans); + if (WARN_ON_ONCE(!trans->ops->grab_nic_access)) + return false; + return trans->ops->grab_nic_access(trans); } IWL_EXPORT_SYMBOL(iwl_trans_grab_nic_access); void iwl_trans_resched_with_nic_access(struct iwl_trans *trans) { - iwl_trans_pcie_resched_with_nic_access(trans); + if (WARN_ON_ONCE(!trans->ops->resched_with_nic_access)) + return; + trans->ops->resched_with_nic_access(trans); } -void __releases(nic_access) -iwl_trans_release_nic_access(struct iwl_trans *trans) +void iwl_trans_release_nic_access(struct iwl_trans *trans) { - iwl_trans_pcie_release_nic_access(trans); + if (WARN_ON_ONCE(!trans->ops->release_nic_access)) + return; + trans->ops->release_nic_access(trans); } IWL_EXPORT_SYMBOL(iwl_trans_release_nic_access); @@ -576,10 +708,8 @@ void iwl_trans_fw_alive(struct iwl_trans *trans) trans->state = IWL_TRANS_FW_ALIVE; - if (trans->mac_cfg->gen2) - iwl_trans_pcie_gen2_fw_alive(trans); - else - iwl_trans_pcie_fw_alive(trans); + if (!WARN_ON_ONCE(!trans->ops->fw_alive)) + trans->ops->fw_alive(trans); } IWL_EXPORT_SYMBOL(iwl_trans_fw_alive); @@ -597,12 +727,10 @@ int iwl_trans_start_fw(struct iwl_trans *trans, const struct iwl_fw *fw, clear_bit(STATUS_FW_ERROR, &trans->status); - if (trans->mac_cfg->gen2) - ret = iwl_trans_pcie_gen2_start_fw(trans, fw, img, - run_in_rfkill); - else - ret = iwl_trans_pcie_start_fw(trans, fw, img, - run_in_rfkill); + if (WARN_ON_ONCE(!trans->ops->start_fw)) + return -EOPNOTSUPP; + + ret = trans->ops->start_fw(trans, fw, img, run_in_rfkill); if (ret == 0) trans->state = IWL_TRANS_FW_STARTED; @@ -643,10 +771,8 @@ void iwl_trans_stop_device(struct iwl_trans *trans) iwl_op_mode_dump_error(trans->op_mode, &mode); } - if (trans->mac_cfg->gen2) - iwl_trans_pcie_gen2_stop_device(trans); - else - iwl_trans_pcie_stop_device(trans); + if (!WARN_ON_ONCE(!trans->ops->stop_device)) + trans->ops->stop_device(trans); trans->state = IWL_TRANS_NO_FW; } @@ -662,10 +788,10 @@ int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, "bad state = %d\n", trans->state)) return -EIO; - if (trans->mac_cfg->gen2) - return iwl_txq_gen2_tx(trans, skb, dev_cmd, queue); + if (WARN_ON_ONCE(!trans->ops->tx)) + return -EOPNOTSUPP; - return iwl_trans_pcie_tx(trans, skb, dev_cmd, queue); + return trans->ops->tx(trans, skb, dev_cmd, queue); } IWL_EXPORT_SYMBOL(iwl_trans_tx); @@ -679,14 +805,18 @@ void iwl_trans_reclaim(struct iwl_trans *trans, int queue, int ssn, "bad state = %d\n", trans->state)) return; - iwl_pcie_reclaim(trans, queue, ssn, skbs, is_flush); + if (WARN_ON_ONCE(!trans->ops->reclaim)) + return; + trans->ops->reclaim(trans, queue, ssn, skbs, is_flush); } IWL_EXPORT_SYMBOL(iwl_trans_reclaim); void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, bool configure_scd) { - iwl_trans_pcie_txq_disable(trans, queue, configure_scd); + if (WARN_ON_ONCE(!trans->ops->txq_disable)) + return; + trans->ops->txq_disable(trans, queue, configure_scd); } IWL_EXPORT_SYMBOL(iwl_trans_txq_disable); @@ -700,8 +830,10 @@ bool iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, "bad state = %d\n", trans->state)) return false; - return iwl_trans_pcie_txq_enable(trans, queue, ssn, - cfg, queue_wdg_timeout); + if (WARN_ON_ONCE(!trans->ops->txq_enable)) + return false; + return trans->ops->txq_enable(trans, queue, ssn, + cfg, queue_wdg_timeout); } IWL_EXPORT_SYMBOL(iwl_trans_txq_enable_cfg); @@ -714,7 +846,9 @@ int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue) "bad state = %d\n", trans->state)) return -EIO; - return iwl_trans_pcie_wait_txq_empty(trans, queue); + if (WARN_ON_ONCE(!trans->ops->wait_txq_empty)) + return -EOPNOTSUPP; + return trans->ops->wait_txq_empty(trans, queue); } IWL_EXPORT_SYMBOL(iwl_trans_wait_txq_empty); @@ -724,7 +858,9 @@ int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, u32 txqs) "bad state = %d\n", trans->state)) return -EIO; - return iwl_trans_pcie_wait_txqs_empty(trans, txqs); + if (WARN_ON_ONCE(!trans->ops->wait_txqs_empty)) + return -EOPNOTSUPP; + return trans->ops->wait_txqs_empty(trans, txqs); } IWL_EXPORT_SYMBOL(iwl_trans_wait_tx_queues_empty); @@ -735,31 +871,30 @@ void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, "bad state = %d\n", trans->state)) return; - iwl_pcie_freeze_txq_timer(trans, txqs, freeze); + if (WARN_ON_ONCE(!trans->ops->freeze_txq_timer)) + return; + trans->ops->freeze_txq_timer(trans, txqs, freeze); } IWL_EXPORT_SYMBOL(iwl_trans_freeze_txq_timer); void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, int txq_id, bool shared_mode) { - iwl_trans_pcie_txq_set_shared_mode(trans, txq_id, shared_mode); + if (WARN_ON_ONCE(!trans->ops->txq_set_shared_mode)) + return; + trans->ops->txq_set_shared_mode(trans, txq_id, shared_mode); } IWL_EXPORT_SYMBOL(iwl_trans_txq_set_shared_mode); -#ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_trans_debugfs_cleanup(struct iwl_trans *trans) -{ - iwl_trans_pcie_debugfs_cleanup(trans); -} -#endif - void iwl_trans_set_q_ptrs(struct iwl_trans *trans, int queue, int ptr) { if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, "bad state = %d\n", trans->state)) return; - iwl_pcie_set_q_ptrs(trans, queue, ptr); + if (WARN_ON_ONCE(!trans->ops->set_q_ptrs)) + return; + trans->ops->set_q_ptrs(trans, queue, ptr); } IWL_EXPORT_SYMBOL(iwl_trans_set_q_ptrs); @@ -772,49 +907,62 @@ int iwl_trans_txq_alloc(struct iwl_trans *trans, u32 flags, u32 sta_mask, "bad state = %d\n", trans->state)) return -EIO; - return iwl_txq_dyn_alloc(trans, flags, sta_mask, tid, - size, wdg_timeout); + if (WARN_ON_ONCE(!trans->ops->txq_alloc)) + return -EOPNOTSUPP; + return trans->ops->txq_alloc(trans, flags, sta_mask, tid, + size, wdg_timeout); } IWL_EXPORT_SYMBOL(iwl_trans_txq_alloc); void iwl_trans_txq_free(struct iwl_trans *trans, int queue) { - iwl_txq_dyn_free(trans, queue); + if (WARN_ON_ONCE(!trans->ops->txq_free)) + return; + trans->ops->txq_free(trans, queue); } IWL_EXPORT_SYMBOL(iwl_trans_txq_free); int iwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue, struct iwl_trans_rxq_dma_data *data) { - return iwl_trans_pcie_rxq_dma_data(trans, queue, data); + if (WARN_ON_ONCE(!trans->ops->rxq_dma_data)) + return -EOPNOTSUPP; + return trans->ops->rxq_dma_data(trans, queue, data); } int iwl_trans_load_pnvm(struct iwl_trans *trans, const struct iwl_pnvm_image *pnvm_data, const struct iwl_ucode_capabilities *capa) { - return iwl_trans_pcie_ctx_info_v2_load_pnvm(trans, pnvm_data, capa); + if (WARN_ON_ONCE(!trans->ops->load_pnvm)) + return -EOPNOTSUPP; + return trans->ops->load_pnvm(trans, pnvm_data, capa); } IWL_EXPORT_SYMBOL(iwl_trans_load_pnvm); void iwl_trans_set_pnvm(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa) { - iwl_trans_pcie_ctx_info_v2_set_pnvm(trans, capa); + if (WARN_ON_ONCE(!trans->ops->set_pnvm)) + return; + trans->ops->set_pnvm(trans, capa); } int iwl_trans_load_reduce_power(struct iwl_trans *trans, const struct iwl_pnvm_image *payloads, const struct iwl_ucode_capabilities *capa) { - return iwl_trans_pcie_ctx_info_v2_load_reduce_power(trans, payloads, - capa); + if (WARN_ON_ONCE(!trans->ops->load_reduce_power)) + return -EOPNOTSUPP; + return trans->ops->load_reduce_power(trans, payloads, capa); } void iwl_trans_set_reduce_power(struct iwl_trans *trans, const struct iwl_ucode_capabilities *capa) { - iwl_trans_pcie_ctx_info_v2_set_reduce_power(trans, capa); + if (WARN_ON_ONCE(!trans->ops->set_reduce_power)) + return; + trans->ops->set_reduce_power(trans, capa); } bool iwl_trans_is_pm_supported(struct iwl_trans *trans) @@ -822,19 +970,39 @@ bool iwl_trans_is_pm_supported(struct iwl_trans *trans) if (WARN_ON(trans->mac_cfg->gen2)) return false; - return iwl_pcie_gen1_is_pm_supported(trans); + if (WARN_ON_ONCE(!trans->ops->is_pm_supported)) + return false; + return trans->ops->is_pm_supported(trans); } IWL_EXPORT_SYMBOL(iwl_trans_is_pm_supported); bool iwl_trans_is_ltr_enabled(struct iwl_trans *trans) { - return iwl_pcie_gen1_2_is_ltr_enabled(trans); + if (WARN_ON_ONCE(!trans->ops->is_ltr_enabled)) + return false; + return trans->ops->is_ltr_enabled(trans); } IWL_EXPORT_SYMBOL(iwl_trans_is_ltr_enabled); int iwl_trans_activate_nic(struct iwl_trans *trans) { - return iwl_pcie_gen1_2_activate_nic(trans); + if (WARN_ON_ONCE(!trans->ops->activate_nic)) + return -EOPNOTSUPP; + return trans->ops->activate_nic(trans); } IWL_EXPORT_SYMBOL(iwl_trans_activate_nic); + +void iwl_trans_reset(struct iwl_trans *trans, enum iwl_reset_mode mode) +{ + if (!WARN_ON_ONCE(!trans->ops->reset)) + trans->ops->reset(trans, mode); +} +IWL_EXPORT_SYMBOL(iwl_trans_reset); + +void iwl_trans_fw_reset_handshake(struct iwl_trans *trans) +{ + if (!WARN_ON_ONCE(!trans->ops->fw_reset_handshake)) + trans->ops->fw_reset_handshake(trans); +} + diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index c581cc8f5bcb..7a358daab584 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -734,12 +734,15 @@ struct iwl_trans_info { u8 num_rxqs; }; +struct iwl_trans_ops; + /** * struct iwl_trans - transport common data * * @csme_own: true if we couldn't get ownership on the device * @op_mode: pointer to the op_mode * @mac_cfg: the trans-specific configuration part + * @ops: bus-specific transport operations, see &struct iwl_trans_ops * @cfg: pointer to the configuration * @drv: pointer to iwl_drv * @conf: configuration set by the opmode before enter @@ -773,6 +776,7 @@ struct iwl_trans { bool csme_own; struct iwl_op_mode *op_mode; const struct iwl_mac_cfg *mac_cfg; + const struct iwl_trans_ops *ops; const struct iwl_rf_cfg *cfg; struct iwl_drv *drv; struct iwl_trans_config conf; @@ -910,15 +914,13 @@ int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, u32 txqs); int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue); -void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val); - void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val); u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs); -u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs); +u32 iwl_trans_read_prph_no_grab(struct iwl_trans *trans, u32 ofs); -void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); +void iwl_trans_write_prph_no_grab(struct iwl_trans *trans, u32 ofs, u32 val); int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, void *buf, int dwords); @@ -934,10 +936,6 @@ int iwl_trans_read_mem_no_grab(struct iwl_trans *trans, u32 addr, int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs, u32 *val); -#ifdef CONFIG_IWLWIFI_DEBUGFS -void iwl_trans_debugfs_cleanup(struct iwl_trans *trans); -#endif - #define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \ ({ \ if (__builtin_constant_p(bufsize)) \ @@ -983,6 +981,66 @@ int iwl_trans_sw_reset(struct iwl_trans *trans); void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); +static inline void iwl_trans_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) +{ + iwl_trans_set_bits_mask(trans, reg, mask, mask); +} + +static inline void iwl_trans_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) +{ + iwl_trans_set_bits_mask(trans, reg, mask, 0); +} + +int iwl_trans_poll_bits_mask(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout); +static inline int iwl_trans_poll_bits(struct iwl_trans *trans, u32 addr, u32 bits, + int timeout) +{ + return iwl_trans_poll_bits_mask(trans, addr, bits, bits, timeout); +} + +void iwl_trans_write_direct32(struct iwl_trans *trans, u32 reg, u32 value); + +u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs); +void iwl_trans_write_prph_delay(struct iwl_trans *trans, u32 ofs, + u32 val, u32 delay_ms); +static inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) +{ + iwl_trans_write_prph_delay(trans, ofs, val, 0); +} + +void iwl_trans_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); +void iwl_trans_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs, + u32 bits, u32 mask); +void iwl_trans_clear_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask); + +/* + * UMAC periphery address space changed from 0xA00000 to 0xD00000 starting from + * device family AX200. So peripheries used in families above and below AX200 + * should go through iwl_trans_..._umac_..._prph. + */ +static inline u32 iwl_trans_umac_prph(struct iwl_trans *trans, u32 ofs) +{ + return ofs + trans->mac_cfg->umac_prph_offset; +} + +static inline u32 iwl_trans_read_umac_prph_no_grab(struct iwl_trans *trans, u32 ofs) +{ + return iwl_trans_read_prph_no_grab(trans, ofs + + trans->mac_cfg->umac_prph_offset); +} + +static inline u32 iwl_trans_read_umac_prph(struct iwl_trans *trans, u32 ofs) +{ + return iwl_trans_read_prph(trans, ofs + trans->mac_cfg->umac_prph_offset); +} + +static inline void iwl_trans_write_umac_prph(struct iwl_trans *trans, u32 ofs, + u32 val) +{ + iwl_trans_write_prph(trans, ofs + trans->mac_cfg->umac_prph_offset, val); +} + bool iwl_trans_grab_nic_access(struct iwl_trans *trans); /** @@ -996,8 +1054,7 @@ bool iwl_trans_grab_nic_access(struct iwl_trans *trans); */ void iwl_trans_resched_with_nic_access(struct iwl_trans *trans); -void __releases(nic_access) -iwl_trans_release_nic_access(struct iwl_trans *trans); +void iwl_trans_release_nic_access(struct iwl_trans *trans); static inline void iwl_trans_schedule_reset(struct iwl_trans *trans, enum iwl_fw_error_type type) @@ -1059,8 +1116,7 @@ static inline bool iwl_trans_fw_running(struct iwl_trans *trans) void iwl_trans_sync_nmi(struct iwl_trans *trans); -void iwl_trans_sync_nmi_with_addr(struct iwl_trans *trans, u32 inta_addr, - u32 sw_err_bit); +void iwl_trans_force_nmi(struct iwl_trans *trans); int iwl_trans_load_pnvm(struct iwl_trans *trans, const struct iwl_pnvm_image *pnvm_data, @@ -1082,8 +1138,6 @@ static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans) trans->dbg.external_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED; } -void iwl_trans_interrupts(struct iwl_trans *trans, bool enable); - int iwl_trans_activate_nic(struct iwl_trans *trans); static inline void iwl_trans_finish_sw_reset(struct iwl_trans *trans) @@ -1096,6 +1150,7 @@ static inline void iwl_trans_finish_sw_reset(struct iwl_trans *trans) *****************************************************/ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, + const struct iwl_trans_ops *ops, const struct iwl_mac_cfg *mac_cfg); void iwl_trans_free(struct iwl_trans *trans); @@ -1166,8 +1221,149 @@ enum iwl_reset_mode { IWL_RESET_MODE_BACKOFF, }; -void iwl_trans_pcie_reset(struct iwl_trans *trans, enum iwl_reset_mode mode); -void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans); +void iwl_trans_reset(struct iwl_trans *trans, enum iwl_reset_mode mode); +void iwl_trans_fw_reset_handshake(struct iwl_trans *trans); + +/** + * struct iwl_trans_ops - bus-specific transport operations + * + * Function-pointer table filled in by the bus implementation. Unless noted + * otherwise, each callback implements the identically named iwl_trans_*() + * API, see its documentation. + * + * @op_mode_enter: the op_mode took ownership of the transport + * @start_hw: start the hardware + * @op_mode_leave: the op_mode released the transport + * @send_cmd: send a host command to the firmware + * @alloc_tx_cmd: allocate a device TX command + * @free_tx_cmd: free a device TX command + * @write32: write a dword to a device register + * @read32: read a dword from a device register + * @read_prph: read a peripheral register + * @write_prph: write a peripheral register + * @read_mem: read device memory, taking NIC access + * @read_mem_no_grab: read device memory, NIC access already taken + * @set_bits_mask: read-modify-write a device register + * @poll_bits_mask: poll a device register until the masked bits match + * @read_config32: read a dword from the bus configuration space + * @grab_nic_access: keep the NIC awake for register access + * @release_nic_access: release the NIC access taken by @grab_nic_access + * @resched_with_nic_access: reschedule while holding NIC access + * @sw_reset: perform a software reset of the device + * @reset: reset the device, see &enum iwl_reset_mode + * @fw_reset_handshake: do a firmware reset handshake. + * @dump_data: collect a firmware error dump + * @d3_suspend: prepare the device for D3 (WoWLAN) + * @d3_resume: resume the device from D3 (WoWLAN) + * @sync_nmi: trigger an NMI and wait for it to be handled + * @write_imr_mem: write to the IMR memory region + * @fw_alive: Notify trans that the firmware sent the ALIVE notification + * @start_fw: download firmware code to the device and and start the firmware + * @stop_device: stop the device and the firmware + * @tx: transmit an MPDU + * @reclaim: free TX MPDUs up to the given sequence number + * @txq_disable: disable a TX queue (gen1) + * @txq_enable: enable a TX queue (gen1) + * @wait_txq_empty: wait for a single TX queue to become empty + * @wait_txqs_empty: wait for the given TX queues to become empty + * @freeze_txq_timer: freeze/unfreeze the watchdog of the given TX queues + * @txq_set_shared_mode: mark a TX queue as shared between TIDs + * @set_q_ptrs: set the write pointer of a TX queue + * @txq_alloc: allocate a TX queue (gen2) + * @txq_free: free a TX queue allocated by @txq_alloc + * @rxq_dma_data: get the DMA addresses of an RX queue + * @load_pnvm: load the PNVM image + * @set_pnvm: tell the firmware to use the loaded PNVM + * @load_reduce_power: load the reduced power table + * @set_reduce_power: tell the firmware to use the reduced power table + * @is_pm_supported: whether bus power management is supported + * @is_ltr_enabled: whether LTR is enabled on the bus + * @activate_nic: bring the NIC out of low power and make it accessible + */ +struct iwl_trans_ops { + void (*op_mode_enter)(struct iwl_trans *trans); + int (*start_hw)(struct iwl_trans *trans); + void (*op_mode_leave)(struct iwl_trans *trans); + + int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); + struct iwl_device_tx_cmd *(*alloc_tx_cmd)(struct iwl_trans *trans); + void (*free_tx_cmd)(struct iwl_trans *trans, + struct iwl_device_tx_cmd *dev_cmd); + + void (*write32)(struct iwl_trans *trans, u32 ofs, u32 val); + u32 (*read32)(struct iwl_trans *trans, u32 ofs); + u32 (*read_prph)(struct iwl_trans *trans, u32 ofs); + void (*write_prph)(struct iwl_trans *trans, u32 ofs, u32 val); + int (*read_mem)(struct iwl_trans *trans, u32 addr, + void *buf, int dwords); + int (*read_mem_no_grab)(struct iwl_trans *trans, u32 addr, + void *buf, u32 dwords); + void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, + u32 mask, u32 value); + int (*poll_bits_mask)(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout); + int (*read_config32)(struct iwl_trans *trans, u32 ofs, u32 *val); + bool (*grab_nic_access)(struct iwl_trans *trans); + void (*release_nic_access)(struct iwl_trans *trans); + void (*resched_with_nic_access)(struct iwl_trans *trans); + + int (*sw_reset)(struct iwl_trans *trans, bool retake_ownership); + void (*reset)(struct iwl_trans *trans, enum iwl_reset_mode mode); + void (*fw_reset_handshake)(struct iwl_trans *trans); + + struct iwl_trans_dump_data *(*dump_data)(struct iwl_trans *trans, + u32 dump_mask, + const struct iwl_dump_sanitize_ops *sanitize_ops, + void *sanitize_ctx); + int (*d3_suspend)(struct iwl_trans *trans, bool reset); + int (*d3_resume)(struct iwl_trans *trans, bool reset); + + void (*sync_nmi)(struct iwl_trans *trans); + int (*write_imr_mem)(struct iwl_trans *trans, u32 dst_addr, + u64 src_addr, u32 byte_cnt); + + void (*fw_alive)(struct iwl_trans *trans); + int (*start_fw)(struct iwl_trans *trans, const struct iwl_fw *fw, + const struct fw_img *img, bool run_in_rfkill); + void (*stop_device)(struct iwl_trans *trans); + + int (*tx)(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_tx_cmd *dev_cmd, int queue); + void (*reclaim)(struct iwl_trans *trans, int queue, int ssn, + struct sk_buff_head *skbs, bool is_flush); + void (*txq_disable)(struct iwl_trans *trans, int queue, + bool configure_scd); + bool (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int queue_wdg_timeout); + int (*wait_txq_empty)(struct iwl_trans *trans, int queue); + int (*wait_txqs_empty)(struct iwl_trans *trans, u32 txqs); + void (*freeze_txq_timer)(struct iwl_trans *trans, + unsigned long txqs, bool freeze); + void (*txq_set_shared_mode)(struct iwl_trans *trans, u32 txq_id, + bool shared_mode); + void (*set_q_ptrs)(struct iwl_trans *trans, int queue, int ptr); + int (*txq_alloc)(struct iwl_trans *trans, u32 flags, u32 sta_mask, + u8 tid, int size, unsigned int wdg_timeout); + void (*txq_free)(struct iwl_trans *trans, int queue); + int (*rxq_dma_data)(struct iwl_trans *trans, int queue, + struct iwl_trans_rxq_dma_data *data); + + int (*load_pnvm)(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_data, + const struct iwl_ucode_capabilities *capa); + void (*set_pnvm)(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa); + int (*load_reduce_power)(struct iwl_trans *trans, + const struct iwl_pnvm_image *payloads, + const struct iwl_ucode_capabilities *capa); + void (*set_reduce_power)(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa); + + bool (*is_pm_supported)(struct iwl_trans *trans); + bool (*is_ltr_enabled)(struct iwl_trans *trans); + int (*activate_nic)(struct iwl_trans *trans); +}; /* Internal helper */ static inline void iwl_trans_set_info(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/agg.c b/drivers/net/wireless/intel/iwlwifi/mld/agg.c index c45c47337509..ea1f02380ad4 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/agg.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/agg.c @@ -660,6 +660,7 @@ int iwl_mld_update_sta_baids(struct iwl_mld *mld, .modify.new_sta_id_mask = cpu_to_le32(new_sta_mask), }; u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 2); int baid; /* mac80211 will remove sessions later, but we ignore all that */ @@ -667,6 +668,7 @@ int iwl_mld_update_sta_baids(struct iwl_mld *mld, return 0; BUILD_BUG_ON(sizeof(struct iwl_rx_baid_cfg_resp) != sizeof(baid)); + BUILD_BUG_ON(sizeof(cmd.modify) != sizeof(cmd.modify_v2)); for (baid = 0; baid < ARRAY_SIZE(mld->fw_id_to_ba); baid++) { struct iwl_mld_baid_data *data; @@ -683,7 +685,10 @@ int iwl_mld_update_sta_baids(struct iwl_mld *mld, "BAID data for %d corrupted - expected 0x%x found 0x%x\n", baid, old_sta_mask, data->sta_mask); - cmd.modify.tid = cpu_to_le32(data->tid); + if (cmd_ver >= 3) + cmd.modify.tid = data->tid; + else + cmd.modify_v2.tid = cpu_to_le32(data->tid); ret = iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd); if (ret) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/constants.h b/drivers/net/wireless/intel/iwlwifi/mld/constants.h index 890abcab3837..bfd5398510ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/constants.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/constants.h @@ -39,6 +39,10 @@ #define IWL_MLD_TPT_COUNT_WINDOW (5 * HZ) +#define IWL_MLD_TX_GP2_VALID_PERIOD (10 * HZ) +#define IWL_MLD_TX_GP2_REFRESH_MARGIN (5 * HZ) +#define IWL_MLD_TX_GP2_RETRY_PERIOD HZ + #define IWL_MLD_DIS_RANDOM_FW_ID false #define IWL_MLD_D3_DEBUG false #define IWL_MLD_NON_TRANSMITTING_AP false diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c index 6d8ede336d59..ce959363f62c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c @@ -5,6 +5,7 @@ #include "mld.h" #include "d3.h" +#include "tx.h" #include "power.h" #include "hcmd.h" #include "iface.h" @@ -597,6 +598,37 @@ iwl_mld_convert_wowlan_notif_v5(const struct iwl_wowlan_info_notif_v5 *notif_v5, } } +static void +iwl_mld_convert_wowlan_notif_v6(const struct iwl_wowlan_info_notif_v6 *notif_v6, + struct iwl_wowlan_info_notif *notif) +{ + /* v6 is identical to the new format, except that it has no CIGTK */ + BUILD_BUG_ON(sizeof(notif->gtk) != sizeof(notif_v6->gtk)); + BUILD_BUG_ON(sizeof(notif->igtk) != sizeof(notif_v6->igtk)); + BUILD_BUG_ON(sizeof(notif->bigtk) != sizeof(notif_v6->bigtk)); + + memcpy(notif->gtk, notif_v6->gtk, sizeof(notif_v6->gtk)); + memcpy(notif->igtk, notif_v6->igtk, sizeof(notif_v6->igtk)); + memcpy(notif->bigtk, notif_v6->bigtk, sizeof(notif_v6->bigtk)); + + notif->replay_ctr = notif_v6->replay_ctr; + notif->pattern_number = notif_v6->pattern_number; + notif->qos_seq_ctr = notif_v6->qos_seq_ctr; + notif->wakeup_reasons = notif_v6->wakeup_reasons; + notif->num_of_gtk_rekeys = notif_v6->num_of_gtk_rekeys; + notif->transmitted_ndps = notif_v6->transmitted_ndps; + notif->received_beacons = notif_v6->received_beacons; + notif->tid_tear_down = notif_v6->tid_tear_down; + notif->station_id = notif_v6->station_id; + notif->num_mlo_link_keys = notif_v6->num_mlo_link_keys; + notif->tid_offloaded_tx = notif_v6->tid_offloaded_tx; + + if (notif_v6->num_mlo_link_keys) + memcpy(notif->mlo_gtks, notif_v6->mlo_gtks, + notif_v6->num_mlo_link_keys * + sizeof(struct iwl_wowlan_mlo_gtk)); +} + static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld, u32 len, const void *notif_data, int version) @@ -618,12 +650,23 @@ static bool iwl_mld_validate_wowlan_notif_size(struct iwl_mld *mld, u32 len, num_mlo_keys = notif_v5->num_mlo_link_keys; } else if (version == 6) { + const struct iwl_wowlan_info_notif_v6 *notif_v6 = notif_data; + + expected_len = sizeof(*notif_v6); + + if (IWL_FW_CHECK(mld, len < expected_len, + "Invalid wowlan_info_notif v6 (expected=%u got=%u)\n", + expected_len, len)) + return false; + + num_mlo_keys = notif_v6->num_mlo_link_keys; + } else if (version == 7) { const struct iwl_wowlan_info_notif *notif = notif_data; expected_len = sizeof(*notif); if (IWL_FW_CHECK(mld, len < expected_len, - "Invalid wowlan_info_notif v6 (expected=%u got=%u)\n", + "Invalid wowlan_info_notif v7 (expected=%u got=%u)\n", expected_len, len)) return false; @@ -682,9 +725,27 @@ iwl_mld_handle_wowlan_info_notif(struct iwl_mld *mld, iwl_mld_convert_wowlan_notif_v5(_notif, converted_notif); notif = converted_notif; } else if (wowlan_info_ver == 6) { + const struct iwl_wowlan_info_notif_v6 *_notif = + (void *)pkt->data; + + if (!iwl_mld_validate_wowlan_notif_size(mld, len, _notif, 6)) + return true; + + converted_notif = kzalloc_flex(*converted_notif, mlo_gtks, + _notif->num_mlo_link_keys, + GFP_ATOMIC); + if (!converted_notif) { + IWL_ERR(mld, + "Failed to allocate memory for converted wowlan_info_notif\n"); + return true; + } + + iwl_mld_convert_wowlan_notif_v6(_notif, converted_notif); + notif = converted_notif; + } else if (wowlan_info_ver == 7) { notif = (void *)pkt->data; - if (!iwl_mld_validate_wowlan_notif_size(mld, len, notif, 6)) + if (!iwl_mld_validate_wowlan_notif_size(mld, len, notif, 7)) return true; } else { /* smaller versions are not supported */ @@ -1610,6 +1671,8 @@ int iwl_mld_no_wowlan_suspend(struct iwl_mld *mld) iwl_mld_low_latency_stop(mld); + iwl_mld_tx_gp2_stop(mld); + ret = iwl_mld_update_device_power(mld, true); if (ret) { IWL_ERR(mld, @@ -1663,6 +1726,8 @@ int iwl_mld_no_wowlan_resume(struct iwl_mld *mld) iwl_mld_low_latency_restart(mld); + iwl_mld_tx_gp2_start(mld); + return iwl_mld_update_device_power(mld, false); } @@ -1829,9 +1894,12 @@ iwl_mld_send_kek_kck_cmd(struct iwl_mld *mld, struct iwl_mld_suspend_key_iter_data data, int ap_sta_id) { - struct iwl_wowlan_kek_kck_material_cmd_v4 kek_kck_cmd = {}; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, WOWLAN_KEK_KCK_MATERIAL, 4); + struct iwl_wowlan_kek_kck_material_cmd kek_kck_cmd = {}; struct iwl_mld_rekey_data *rekey_data = &mld_vif->wowlan_data.rekey_data; + u32 cmd_size = cmd_ver == 5 ? sizeof(kek_kck_cmd) : + sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4); memcpy(kek_kck_cmd.kck, rekey_data->kck, rekey_data->kck_len); @@ -1850,7 +1918,7 @@ iwl_mld_send_kek_kck_cmd(struct iwl_mld *mld, rekey_data->akm); return iwl_mld_send_cmd_pdu(mld, WOWLAN_KEK_KCK_MATERIAL, - &kek_kck_cmd); + &kek_kck_cmd, cmd_size); } static int diff --git a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c index 351a4f177e92..b8793b71494d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c @@ -5,7 +5,7 @@ #include "mld.h" #include "debugfs.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "hcmd.h" #include "iface.h" #include "sta.h" @@ -69,7 +69,7 @@ static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mld *mld, char *buf, if (count == 6 && !strcmp(buf, "nolog\n")) mld->fw_status.do_not_dump_once = true; - iwl_force_nmi(mld->trans); + iwl_trans_force_nmi(mld->trans); return count; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c index a4b8037b5c76..a6a4f9672e4f 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ftm-initiator.c @@ -8,7 +8,7 @@ #include "mld.h" #include "iface.h" #include "phy.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "constants.h" #include "fw/api/location.h" diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c index 7b1fb84a641c..c33a553488ee 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2024-2025 Intel Corporation + * Copyright (C) 2024-2026 Intel Corporation */ #include "mld.h" +#include "tx.h" #include "fw/api/alive.h" #include "fw/api/scan.h" @@ -46,6 +47,9 @@ static int iwl_mld_send_rss_cfg_cmd(struct iwl_mld *mld) lockdep_assert_wiphy(mld->wiphy); + if (mld->trans->info.num_rxqs == 1) + return 0; + /* Do not direct RSS traffic to Q 0 which is our fallback queue */ for (int i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++) cmd.indirection_table[i] = @@ -206,11 +210,11 @@ static void iwl_mld_print_alive_notif_timeout(struct iwl_mld *mld) IWL_ERR(mld, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", - iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS), - iwl_read_umac_prph(trans, - UMAG_SB_CPU_2_STATUS)); + iwl_trans_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS), + iwl_trans_read_umac_prph(trans, + UMAG_SB_CPU_2_STATUS)); #define IWL_FW_PRINT_REG_INFO(reg_name) \ - IWL_ERR(mld, #reg_name ": 0x%x\n", iwl_read_umac_prph(trans, reg_name)) + IWL_ERR(mld, #reg_name ": 0x%x\n", iwl_trans_read_umac_prph(trans, reg_name)) IWL_FW_PRINT_REG_INFO(WFPM_LMAC1_PD_NOTIFICATION); @@ -355,6 +359,8 @@ void iwl_mld_stop_fw(struct iwl_mld *mld) { lockdep_assert_wiphy(mld->wiphy); + iwl_mld_tx_gp2_stop(mld); + iwl_abort_notification_waits(&mld->notif_wait); iwl_fw_dbg_stop_sync(&mld->fwrt); @@ -396,8 +402,10 @@ void iwl_mld_send_recovery_cmd(struct iwl_mld *mld, u32 flags) if (flags & ERROR_RECOVERY_UPDATE_DB) { /* no buf was allocated upon NIC error */ - if (!mld->error_recovery_buf) + if (!mld->error_recovery_buf) { + IWL_ERR(mld, "Recovering without recovery buffer. Expect bugs\n"); return; + } cmd.data[1] = mld->error_recovery_buf; cmd.len[1] = error_log_size; @@ -540,6 +548,8 @@ int iwl_mld_start_fw(struct iwl_mld *mld) if (ret) goto error; + iwl_mld_tx_gp2_start(mld); + return 0; error: diff --git a/drivers/net/wireless/intel/iwlwifi/mld/hcmd.h b/drivers/net/wireless/intel/iwlwifi/mld/hcmd.h index 19e1c9e509cf..761ef73dd9a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/hcmd.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/hcmd.h @@ -5,6 +5,8 @@ #ifndef __iwl_mld_hcmd_h__ #define __iwl_mld_hcmd_h__ +#include "mld.h" + static inline int iwl_mld_send_cmd(struct iwl_mld *mld, struct iwl_host_cmd *cmd) { /* No commands, including the d3 related commands, should be sent diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.c b/drivers/net/wireless/intel/iwlwifi/mld/key.c index bf80b4770b5a..f2c87f830ba3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/key.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/key.c @@ -37,6 +37,12 @@ static u32 iwl_mld_get_key_flags(struct iwl_mld *mld, break; } + /* Note that sta->mfp might not be set yet, as it is set only + * after association. + */ + if (sta && pairwise && sta->epp_peer) + flags |= IWL_SEC_KEY_FLAG_ASSOC_ENC | IWL_SEC_KEY_FLAG_MFP; + /* If we are installing an iGTK (in AP or STA mode), we need to tell * the firmware this key will en/decrypt MGMT frames. * Same goes if we are installing a pairwise key for an MFP station. diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c index 96e06940b34c..c7d50ba30b36 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/link.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c @@ -361,13 +361,6 @@ iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link, flags |= LINK_FLG_MLPM; } - cmd.htc_trig_based_pkt_ext = link->htc_trig_based_pkt_ext; - - if (link->uora_exists) { - cmd.rand_alloc_ecwmin = link->uora_ocw_range & 0x7; - cmd.rand_alloc_ecwmax = (link->uora_ocw_range >> 3) & 0x7; - } - if (iwl_mld_fill_mu_edca(mld, mld_link, cmd.trig_based_txf)) flags |= LINK_FLG_MU_EDCA_CW; @@ -376,8 +369,6 @@ iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link, if (!link->he_bss_color.enabled) flags |= LINK_FLG_BSS_COLOR_DIS; - cmd.frame_time_rts_th = cpu_to_le16(link->frame_time_rts_th); - /* Block 26-tone RU OFDMA transmissions */ if (mld_link->he_ru_2mhz_block) flags |= LINK_FLG_RU_2MHZ_BLOCK; @@ -387,6 +378,11 @@ iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link, cmd.bssid_index = link->bssid_index; } + if (iwl_fw_lookup_cmd_ver(mld->fw, + WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD), + 0) >= 9) + cmd.max_bssid_indicator = link->bssid_indicator; + /* The only EHT parameter is puncturing, and starting from PHY cmd * version 6 - it is sent there. For older versions of the PHY cmd, * puncturing is not needed at all. diff --git a/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c b/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c index a4ddc32e2860..e7482623111c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/low_latency.c @@ -257,7 +257,8 @@ static bool iwl_mld_is_vo_vi_pkt(struct ieee80211_hdr *hdr) if (tid >= IWL_MAX_TID_COUNT) return false; - return tid_to_mac80211_ac[tid] < IEEE80211_AC_VI; + return tid_to_mac80211_ac[tid] == IEEE80211_AC_VI || + tid_to_mac80211_ac[tid] == IEEE80211_AC_VO; } void iwl_mld_low_latency_update_counters(struct iwl_mld *mld, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c index 3a4c8fda68d0..e05bdbd3e1a9 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c @@ -395,6 +395,10 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld) if (fw_has_capa(ucode_capa, IWL_UCODE_TLV_CAPA_PROTECTED_TWT)) wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PROTECTED_TWT); + if (fw_has_capa(ucode_capa, IWL_UCODE_TLV_CAPA_ASSOC_ENC_SUPPORT)) + wiphy_ext_feature_set(wiphy, + NL80211_EXT_FEATURE_ASSOC_FRAME_ENCRYPTION); + if (iwlmld_mod_params.power_scheme != IWL_POWER_SCHEME_CAM) wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT; else @@ -2164,6 +2168,8 @@ static int iwl_mld_resume(struct ieee80211_hw *hw) iwl_mld_low_latency_restart(mld); + iwl_mld_tx_gp2_start(mld); + return 0; } #endif diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c index 6e991fb99ff3..71832d92024d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c @@ -35,6 +35,17 @@ MODULE_IMPORT_NS("IWLWIFI"); static const struct iwl_op_mode_ops iwl_mld_ops; +int iwl_mld_get_systime(struct iwl_mld *mld, u32 *gp2) +{ + *gp2 = iwl_trans_read_prph(mld->trans, + mld->trans->mac_cfg->base->gp2_reg_addr); + + if (*gp2 == 0x5a5a5a5a) + return -EINVAL; + + return 0; +} + static int __init iwl_mld_init(void) { int ret = iwl_opmode_register("iwlmld", &iwl_mld_ops); @@ -425,6 +436,8 @@ iwl_op_mode_mld_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg, /* Configure transport layer with the opmode specific params */ iwl_mld_configure_trans(op_mode); + iwl_mld_tx_gp2_init(mld); + /* needed for regulatory init */ rtnl_lock(); /* Needed for sending commands */ @@ -621,6 +634,13 @@ static void iwl_mld_read_error_recovery_buffer(struct iwl_mld *mld) if (!src_size) return; + /* + * If we have a the recovery buffer from a previous (failing) recovery - + * free it here + */ + kfree(mld->error_recovery_buf); + mld->error_recovery_buf = NULL; + recovery_buf = kzalloc(src_size, GFP_ATOMIC); if (!recovery_buf) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h index 37f41b504b54..a9e65b216fd3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h @@ -29,6 +29,7 @@ #include "notif.h" #include "scan.h" #include "rx.h" +#include "tx.h" #include "thermal.h" #include "low_latency.h" #include "constants.h" @@ -196,6 +197,7 @@ * being IBSS manager for that time and needing to respond to probe * requests * @ptp_data: data of the PTP clock + * @tx_gp2: gp2 timestamping state for TX commands * @time_sync: time sync data. * @ftm_initiator: FTM initiator data * @nan_device_vif: points to the NAN device vif if exists @@ -306,6 +308,8 @@ struct iwl_mld { struct ptp_data ptp_data; + struct iwl_mld_tx_gp2 tx_gp2; + struct iwl_mld_time_sync_data __rcu *time_sync; struct ftm_initiator_data ftm_initiator; @@ -572,6 +576,8 @@ iwl_mld_fw_id_to_link_conf(struct iwl_mld *mld, u8 fw_link_id) #define MSEC_TO_TU(_msec) ((_msec) * 1000 / 1024) +int iwl_mld_get_systime(struct iwl_mld *mld, u32 *gp2); + void iwl_mld_add_vif_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif); void iwl_mld_add_link_debugfs(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c index a2f8a6957535..34273d4731ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c @@ -1076,9 +1076,9 @@ static void iwl_mld_chan_load_update_iter(void *_data, u8 *mac, struct ieee80211_vif *vif) { struct iwl_mld_chan_load_data *data = _data; - const struct iwl_mld_phy *phy = data->phy; + struct iwl_mld_phy *phy = data->phy; struct ieee80211_chanctx_conf *chanctx = - container_of((const void *)phy, struct ieee80211_chanctx_conf, + container_of((void *)phy, struct ieee80211_chanctx_conf, drv_priv); struct iwl_mld *mld = iwl_mld_vif_from_mac80211(vif)->mld; u32 new_chan_load = phy->avg_channel_load_not_by_us; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c index dbe7a54a38b7..10df33a238d1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c @@ -5,6 +5,7 @@ #include "mld.h" #include "iface.h" +#include "key.h" #include "link.h" #include "mlo.h" #include "tlc.h" @@ -107,6 +108,20 @@ static void iwl_mld_nan_flush(struct iwl_mld *mld, struct ieee80211_vif *vif) iwl_mld_flush_link_sta_txqs(mld, sta->sta_id); } +static void iwl_mld_remove_nan_keys_iter(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *data) +{ + struct iwl_mld *mld = data; + + if (sta || key->hw_key_idx == STA_KEY_IDX_INVALID) + return; + + iwl_mld_remove_key(mld, vif, NULL, key); +} + static void iwl_mld_nan_remove_stations(struct iwl_mld *mld, struct ieee80211_vif *vif) { @@ -296,6 +311,8 @@ int iwl_mld_stop_nan(struct ieee80211_hw *hw, if (ret) IWL_ERR(mld, "NAN: Failed to stop NAN. ret=%d\n", ret); + ieee80211_iter_keys(mld->hw, vif, iwl_mld_remove_nan_keys_iter, mld); + /* assume that higher layer guarantees that no additional frames are * added before calling this callback */ @@ -576,21 +593,11 @@ static int iwl_mld_nan_link_set_active(struct iwl_mld *mld, bool active) { struct iwl_link_config_cmd cmd; - struct ieee80211_sta *sta; int ret; if (nan_link->active == active) return 0; - if (active) { - for_each_station(sta, mld->hw) { - struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); - - if (mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI) - iwl_mld_config_tlc(mld, mld_sta->vif, sta); - } - } - nan_link->active = active; iwl_mld_nan_link_prep_cmd(mld, nan_link, &cmd, @@ -602,10 +609,8 @@ static int iwl_mld_nan_link_set_active(struct iwl_mld *mld, return ret; } - if (!active) { + if (!active) nan_link->chanctx = NULL; - /* TODO: when FW is ready, Update phy in TLC to invalid after */ - } return 0; } @@ -847,6 +852,10 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld, if (mld_sta->sta_type == STATION_TYPE_NAN_PEER_NMI || mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI) iwl_mld_add_modify_sta_cmd(mld, &sta->deflink); + + if (added_links && + mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI) + iwl_mld_config_tlc(mld, mld_sta->vif, sta); } /* diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c index 90733bbaf733..7d9416ecbf92 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c @@ -159,8 +159,8 @@ static void iwl_mld_mu_mimo_iface_iterator(void *_data, u8 *mac, * action frame, so no conversion is needed. */ ieee80211_update_mu_groups(vif, link_id, - (u8 *)¬if->membership_status, - (u8 *)¬if->user_position); + (const u8 *)¬if->membership_status, + (const u8 *)¬if->user_position); } } @@ -292,7 +292,8 @@ CMD_VERSIONS(scan_start_notif, CMD_VERSIONS(scan_complete_notif, CMD_VER_ENTRY(1, iwl_umac_scan_complete)) CMD_VERSIONS(scan_iter_complete_notif, - CMD_VER_ENTRY(2, iwl_umac_scan_iter_complete_notif)) + CMD_VER_ENTRY(2, iwl_umac_scan_iter_complete_notif_v2) + CMD_VER_ENTRY(3, iwl_umac_scan_iter_complete_notif)) CMD_VERSIONS(channel_survey_notif, CMD_VER_ENTRY(1, iwl_umac_scan_channel_survey_notif)) CMD_VERSIONS(mfuart_notif, @@ -329,7 +330,8 @@ CMD_VERSIONS(datapath_monitor_notif, CMD_VER_ENTRY(1, iwl_datapath_monitor_notif)) CMD_VERSIONS(stats_oper_notif, CMD_VER_ENTRY(3, iwl_system_statistics_notif_oper_v3) - CMD_VER_ENTRY(4, iwl_system_statistics_notif_oper)) + CMD_VER_ENTRY(4, iwl_system_statistics_notif_oper_v4) + CMD_VER_ENTRY(5, iwl_system_statistics_notif_oper)) CMD_VERSIONS(stats_oper_part1_notif, CMD_VER_ENTRY(4, iwl_system_statistics_part1_notif_oper)) CMD_VERSIONS(bt_coex_notif, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/power.c b/drivers/net/wireless/intel/iwlwifi/mld/power.c index 2387f3da5185..6fcbb1a2e8a8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/power.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/power.c @@ -525,7 +525,7 @@ int iwl_mld_set_tx_power(struct iwl_mld *mld, .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_LINK), .common.pwr_restriction = cpu_to_le16(u_tx_power), }; - int len = sizeof(cmd.common) + sizeof(cmd.v11); + int len = sizeof(cmd.common) + sizeof(cmd.v12); if (iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 10) == 10) len = sizeof(cmd.common) + sizeof(cmd.v10); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c index 1ac85d6ce1d7..9f7d17dbdee1 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2025 Intel Corporation + * Copyright (C) 2025 - 2026 Intel Corporation */ #include "mld.h" @@ -19,16 +19,6 @@ #define IWL_PTP_WRAP_TIME (3600 * HZ) #define IWL_PTP_WRAP_THRESHOLD_USEC (5000) -static int iwl_mld_get_systime(struct iwl_mld *mld, u32 *gp2) -{ - *gp2 = iwl_read_prph(mld->trans, mld->trans->mac_cfg->base->gp2_reg_addr); - - if (*gp2 == 0x5a5a5a5a) - return -EINVAL; - - return 0; -} - static void iwl_mld_ptp_update_new_read(struct iwl_mld *mld, u32 gp2) { IWL_DEBUG_PTP(mld, "PTP: last_gp2=%u, new gp2 read=%u\n", diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c index 6db84c2117f2..8a20d7622329 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c @@ -6,7 +6,6 @@ #include #include "fw/regulatory.h" -#include "fw/acpi.h" #include "fw/uefi.h" #include "regulatory.h" @@ -37,7 +36,7 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld) { int ret; - iwl_acpi_get_guid_lock_status(&mld->fwrt); + iwl_bios_get_guid_lock_status(&mld->fwrt); ret = iwl_bios_get_ppag_table(&mld->fwrt); if (ret < 0) { @@ -75,6 +74,21 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld) "EWRD SAR BIOS table invalid or unavailable. (%d)\n", ret); + ret = iwl_bios_get_wsss_table(&mld->fwrt); + if (ret < 0) + IWL_DEBUG_RADIO(mld, + "WSSS (WRDS Standalone) SAR BIOS table invalid or unavailable. (%d)\n", + ret); + + if (!ret) { + /* EWSS only extends the standalone SAR profiles from WSSS. */ + ret = iwl_bios_get_ewss_table(&mld->fwrt); + if (ret < 0) + IWL_DEBUG_RADIO(mld, + "EWSS (EWRD Standalone) SAR BIOS table invalid or unavailable. (%d)\n", + ret); + } + ret = iwl_bios_get_wgds_table(&mld->fwrt); if (ret < 0) IWL_DEBUG_RADIO(mld, @@ -136,7 +150,9 @@ static int iwl_mld_geo_sar_init(struct iwl_mld *mld) return iwl_mld_send_cmd_pdu(mld, cmd_id, &cmd, cmd_size); } -int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b) +static int +iwl_mld_config_sar_concurrent_profile(struct iwl_mld *mld, int prof_a, + int prof_b) { struct iwl_dev_tx_power_cmd cmd = { .common.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_CHAINS), @@ -153,8 +169,9 @@ int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b) num_subbands = IWL_NUM_SUB_BANDS_V2; break; case 11: - cmd.v11.flags = cpu_to_le32(mld->fwrt.reduced_power_flags); - cmd_size = sizeof(cmd.common) + sizeof(cmd.v11); + case 12: + cmd.v12.flags = cpu_to_le32(mld->fwrt.reduced_power_flags); + cmd_size = sizeof(cmd.common) + sizeof(cmd.v12); num_subbands = IWL_NUM_SUB_BANDS_V3; break; default: @@ -164,12 +181,13 @@ int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b) } /* TODO: CDB - support IWL_NUM_CHAIN_TABLES_V2 */ - /* v10 and v11 have the same position for per_chain */ - BUILD_BUG_ON(offsetof(typeof(cmd), v11.per_chain) != + /* v10 and v12 have the same position for per_chain */ + BUILD_BUG_ON(offsetof(typeof(cmd), v12.per_chain) != offsetof(typeof(cmd), v10.per_chain)); - ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v11.per_chain[0][0][0], + ret = iwl_sar_fill_profile(&mld->fwrt, &cmd.v12.per_chain[0][0][0], IWL_NUM_CHAIN_TABLES, num_subbands, - prof_a, prof_b); + prof_a, prof_b, + mld->fwrt.sar_profiles, false); /* return on error or if the profile is disabled (positive number) */ if (ret) return ret; @@ -177,6 +195,51 @@ int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b) return iwl_mld_send_cmd_pdu(mld, REDUCE_TX_POWER_CMD, &cmd, cmd_size); } +static int iwl_mld_config_sar_standalone_profile(struct iwl_mld *mld, + int prof_a, int prof_b) +{ + struct iwl_dev_tx_power_cmd cmd = { + .common.set_mode = + cpu_to_le32(IWL_TX_POWER_MODE_SET_STANDALONE_CHAINS), + }; + int ret; + + /* standalone per-chain SAR limits require cmd version 12 */ + if (iwl_fw_lookup_cmd_ver(mld->fw, REDUCE_TX_POWER_CMD, 10) != 12) + return 0; + + ret = iwl_sar_fill_profile(&mld->fwrt, + &cmd.v12.per_chain[0][0][0], + IWL_NUM_CHAIN_TABLES, + IWL_NUM_SUB_BANDS_V3, + prof_a, prof_b, + mld->fwrt.sar_standalone_profiles, + true); + /* return on error or if the standalone profile is disabled */ + if (ret) + return ret; + + return iwl_mld_send_cmd_pdu(mld, REDUCE_TX_POWER_CMD, &cmd, + sizeof(cmd.common) + sizeof(cmd.v12)); +} + +int iwl_mld_config_sar_profiles(struct iwl_mld *mld, int prof_a, int prof_b) +{ + int ret; + + ret = iwl_mld_config_sar_concurrent_profile(mld, prof_a, prof_b); + /* return on error or if the profile is disabled (positive number) */ + if (ret) + return ret; + + ret = iwl_mld_config_sar_standalone_profile(mld, prof_a, prof_b); + /* standalone profile is optional and may be disabled (positive number) */ + if (ret < 0) + return ret; + + return 0; +} + int iwl_mld_init_sar(struct iwl_mld *mld) { int chain_a_prof = 1; @@ -191,7 +254,7 @@ int iwl_mld_init_sar(struct iwl_mld *mld) chain_b_prof = mld->fwrt.sar_chain_b_profile; } - ret = iwl_mld_config_sar_profile(mld, chain_a_prof, chain_b_prof); + ret = iwl_mld_config_sar_profiles(mld, chain_a_prof, chain_b_prof); if (ret < 0) return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h index 5498c19789f4..0877b951f2e2 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2024-2025 Intel Corporation + * Copyright (C) 2024-2026 Intel Corporation */ #ifndef __iwl_mld_regulatory_h__ #define __iwl_mld_regulatory_h__ @@ -18,6 +18,6 @@ int iwl_mld_init_sgom(struct iwl_mld *mld); int iwl_mld_init_sar(struct iwl_mld *mld); -int iwl_mld_config_sar_profile(struct iwl_mld *mld, int prof_a, int prof_b); +int iwl_mld_config_sar_profiles(struct iwl_mld *mld, int prof_a, int prof_b); #endif /* __iwl_mld_regulatory_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c index 02bdf6ccbcdc..e1964e570012 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c @@ -553,7 +553,10 @@ iwl_mld_decode_he_tb_phy_data(struct iwl_mld_rx_phy_data *phy_data, nsts = le32_get_bits(phy_data->ntfy->sigs.he_tb.tb_rx1, OFDM_UCODE_TRIG_BASE_RX_NSTS) + 1; - rx_status->nss = nsts >> !!(rate_n_flags & RATE_MCS_STBC_MSK); + + rx_status->nss = nsts; + if (rate_n_flags & RATE_MCS_STBC_MSK) + rx_status->nss = 1; } static void @@ -589,7 +592,9 @@ iwl_mld_decode_he_phy_data(struct iwl_mld_rx_phy_data *phy_data, break; } - rx_status->nss = nsts >> !!(rate_n_flags & RATE_MCS_STBC_MSK); + rx_status->nss = nsts; + if (rate_n_flags & RATE_MCS_STBC_MSK) + rx_status->nss = 1; he->data1 |= cpu_to_le16(IEEE80211_RADIOTAP_HE_DATA1_LDPC_XSYMSEG_KNOWN | IEEE80211_RADIOTAP_HE_DATA1_DOPPLER_KNOWN); @@ -811,6 +816,14 @@ iwl_mld_radiotap_put_tlv(struct sk_buff *skb, u16 type, u16 len) (_usig)->value |= LE32_DEC_ENC(in_value, dec_bits, _enc_bits); \ } while (0) +static void +iwl_mld_check_bad_usig_crc(struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_eht_usig *usig) +{ + if (usig->common & cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC)) + rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; +} + static void iwl_mld_decode_eht_usig_tb(struct iwl_mld_rx_phy_data *phy_data, struct ieee80211_radiotap_eht_usig *usig) { @@ -818,7 +831,8 @@ static void iwl_mld_decode_eht_usig_tb(struct iwl_mld_rx_phy_data *phy_data, __le32 usig_a2 = phy_data->ntfy->sigs.eht_tb.usig_a2_eht; IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, - OFDM_RX_FRAME_EHT_USIG1_DISREGARD, + OFDM_RX_FRAME_EHT_USIG1_DISREGARD | + OFDM_RX_FRAME_EHT_USIG1_VALIDATE, IEEE80211_RADIOTAP_EHT_USIG1_TB_B20_B25_DISREGARD); IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, OFDM_RX_FRAME_EHT_PPDU_TYPE, @@ -872,6 +886,7 @@ static void iwl_mld_decode_eht_usig_non_tb(struct iwl_mld_rx_phy_data *phy_data, static void iwl_mld_decode_eht_usig(struct iwl_mld_rx_phy_data *phy_data, struct sk_buff *skb) { + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); u32 he_type = phy_data->rate_n_flags & RATE_MCS_HE_TYPE_MSK; __le32 usig_a1 = phy_data->ntfy->sigs.eht.usig_a1; __le32 usig_a2 = phy_data->ntfy->sigs.eht.usig_a2_eht; @@ -935,11 +950,13 @@ static void iwl_mld_decode_eht_usig(struct iwl_mld_rx_phy_data *phy_data, iwl_mld_decode_eht_usig_tb(phy_data, usig); else iwl_mld_decode_eht_usig_non_tb(phy_data, usig); + + iwl_mld_check_bad_usig_crc(rx_status, usig); } static void -iwl_mld_eht_set_ru_alloc(struct ieee80211_rx_status *rx_status, - u32 ru_with_p80) +iwl_mld_eht_uhr_set_ru_alloc(struct ieee80211_rx_status *rx_status, + u32 ru_with_p80, bool uhr) { enum nl80211_eht_ru_alloc nl_ru; u32 ru = ru_with_p80 >> 1; @@ -1005,7 +1022,15 @@ iwl_mld_eht_set_ru_alloc(struct ieee80211_rx_status *rx_status, } rx_status->bw = RATE_INFO_BW_EHT_RU; - rx_status->eht.ru = nl_ru; + + /* + * This should get optimised away, but since it's bitfields, + * we can't ensure uhr.ru and eht.ru overlap in the union. + */ + if (uhr) + rx_status->uhr.ru = nl_ru; + else + rx_status->eht.ru = nl_ru; } static void iwl_mld_decode_eht_tb(struct iwl_mld_rx_phy_data *phy_data, @@ -1045,9 +1070,10 @@ static void iwl_mld_decode_eht_tb(struct iwl_mld_rx_phy_data *phy_data, OFDM_UCODE_TRIG_BASE_RX_RU_P80, IEEE80211_RADIOTAP_EHT_DATA1_PRIMARY_80); - iwl_mld_eht_set_ru_alloc(rx_status, - le32_get_bits(phy_data->ntfy->sigs.eht_tb.tb_rx1, - OFDM_UCODE_TRIG_BASE_RX_RU)); + iwl_mld_eht_uhr_set_ru_alloc(rx_status, + le32_get_bits(phy_data->ntfy->sigs.eht_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU), + false); } static void iwl_mld_eht_decode_user_ru(struct iwl_mld_rx_phy_data *phy_data, @@ -1203,9 +1229,10 @@ static void iwl_mld_decode_eht_non_tb(struct iwl_mld_rx_phy_data *phy_data, iwl_mld_eht_decode_user_ru(phy_data, eht); - iwl_mld_eht_set_ru_alloc(rx_status, - le32_get_bits(phy_data->ntfy->sigs.eht.b2, - OFDM_RX_FRAME_EHT_STA_RU)); + iwl_mld_eht_uhr_set_ru_alloc(rx_status, + le32_get_bits(phy_data->ntfy->sigs.eht.b2, + OFDM_RX_FRAME_EHT_STA_RU), + false); if (phy_data->with_data) eht->user_info[0] |= @@ -1227,48 +1254,30 @@ static void iwl_mld_decode_eht_phy_data(struct iwl_mld_rx_phy_data *phy_data, iwl_mld_decode_eht_non_tb(phy_data, rx_status, eht); } -static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, - struct iwl_mld_rx_phy_data *phy_data) +static u8 iwl_mld_decode_eht_uhr_gi_ltf(u32 rate_n_flags, u8 *gi) { - struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_radiotap_eht *eht; - size_t eht_len = sizeof(*eht); - u32 rate_n_flags = phy_data->rate_n_flags; u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; - /* EHT and HE have the same values for LTF */ - u8 ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN; - /* u32 for 1 user_info */ - if (phy_data->with_data) - eht_len += sizeof(u32); - - eht = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT, eht_len); + *gi = NL80211_RATE_INFO_EHT_GI_0_8; switch (u32_get_bits(rate_n_flags, RATE_MCS_HE_GI_LTF_MSK)) { case 0: if (he_type == RATE_MCS_HE_TYPE_TRIG) { - rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_1_6; - ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X; - } else { - rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_0_8; - ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; + *gi = NL80211_RATE_INFO_EHT_GI_1_6; + return IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_1X; } - break; + return IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; case 1: - rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_1_6; - ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; - break; + *gi = NL80211_RATE_INFO_EHT_GI_1_6; + return IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_2X; case 2: - ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; if (he_type == RATE_MCS_HE_TYPE_TRIG) - rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_3_2; - else - rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_0_8; - break; + *gi = NL80211_RATE_INFO_EHT_GI_3_2; + return IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; case 3: if (he_type != RATE_MCS_HE_TYPE_TRIG) { - ltf = IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; - rx_status->eht.gi = NL80211_RATE_INFO_EHT_GI_3_2; + *gi = NL80211_RATE_INFO_EHT_GI_3_2; + return IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_4X; } break; default: @@ -1276,7 +1285,29 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, break; } + return IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN; +} + +static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, + struct iwl_mld_rx_phy_data *phy_data) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + struct ieee80211_radiotap_eht *eht; + size_t eht_len = sizeof(*eht); + u32 rate_n_flags = phy_data->rate_n_flags; + u8 gi, ltf; + + /* u32 for 1 user_info */ + if (phy_data->with_data) + eht_len += sizeof(u32); + + eht = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT, eht_len); + + ltf = iwl_mld_decode_eht_uhr_gi_ltf(rate_n_flags, &gi); + if (ltf != IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN) { + rx_status->eht.gi = gi; + eht->known |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_KNOWN_GI); eht->data[0] |= le32_encode_bits(ltf, IEEE80211_RADIOTAP_EHT_DATA0_LTF) | @@ -1311,7 +1342,7 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, eht->user_info[0] |= le32_encode_bits(u32_get_bits(rate_n_flags, - RATE_VHT_MCS_RATE_CODE_MSK), + RATE_MCS_CODE_MSK), IEEE80211_RADIOTAP_EHT_USER_INFO_MCS) | le32_encode_bits(u32_get_bits(rate_n_flags, RATE_MCS_NSS_MSK), @@ -1325,6 +1356,558 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb, iwl_mld_decode_eht_phy_data(phy_data, rx_status, eht); } +static void iwl_mld_decode_uhr_usig_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht_usig *usig) +{ + __le32 usig_a1 = phy_data->ntfy->sigs.uhr_tb.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.uhr_tb.usig_a2_uhr; + + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_DISREGARD | + OFDM_RX_FRAME_EHT_USIG1_VALIDATE, + IEEE80211_RADIOTAP_UHR_USIG1_TB_B20_B25_DISREGARD); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_PPDU_TYPE, + IEEE80211_RADIOTAP_UHR_USIG2_TB_B0_B1_PPDU_TYPE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_1, + IEEE80211_RADIOTAP_UHR_USIG2_TB_B3_B6_SPATIAL_REUSE_1); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_2, + IEEE80211_RADIOTAP_UHR_USIG2_TB_B7_B10_SPATIAL_REUSE_2); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_TRIG_USIG2_DISREGARD, + IEEE80211_RADIOTAP_UHR_USIG2_TB_B11_B15_DISREGARD); + + if (le32_get_bits(usig_a1, OFDM_RX_FRAME_EHT_USIG1_VALIDATE) && + le32_get_bits(usig_a2, OFDM_RX_FRAME_UHR_USIG2_VALIDATE_B8)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); + + if (!le32_get_bits(usig_a2, OFDM_RX_FRAME_UHR_USIG_CRC_OK)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC); +} + +static void iwl_mld_decode_uhr_usig_elr(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht_usig *usig) +{ + __le32 usig_a1 = phy_data->ntfy->sigs.uhr_elr.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.uhr_elr.usig_a2_uhr_elr; + + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_DISREGARD, + IEEE80211_RADIOTAP_UHR_USIG1_ELR_B20_B24_DISREGARD); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_VALIDATE, + IEEE80211_RADIOTAP_UHR_USIG1_ELR_B25_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_VECTOR_UHR_ELR_PPDU_TYPE, + IEEE80211_RADIOTAP_UHR_USIG2_ELR_B0_B1_PPDU_TYPE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_VECTOR_UHR_ELR_USIG_STA_ID, + IEEE80211_RADIOTAP_UHR_USIG2_ELR_B2_B12_STA_ID); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_VECTOR_UHR_ELR_VALIDATE, + IEEE80211_RADIOTAP_UHR_USIG2_ELR_B13_B15_VALIDATE); + + if (le32_get_bits(usig_a1, OFDM_RX_FRAME_EHT_USIG1_VALIDATE) && + le32_get_bits(usig_a2, OFDM_RX_VECTOR_UHR_ELR_VALIDATE) == 0xe) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); + + if (!le32_get_bits(usig_a2, OFDM_RX_VECTOR_UHR_ELR_CRC_OK)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC); +} + +static void iwl_mld_decode_uhr_usig_non_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_eht_usig *usig) +{ + __le32 usig_a1 = phy_data->ntfy->sigs.uhr.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.uhr.usig_a2_uhr; + + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_DISREGARD, + IEEE80211_RADIOTAP_UHR_USIG1_MU_B20_B24_DISREGARD); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a1, + OFDM_RX_FRAME_EHT_USIG1_VALIDATE, + IEEE80211_RADIOTAP_UHR_USIG1_MU_B25_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_PPDU_TYPE, + IEEE80211_RADIOTAP_UHR_USIG2_MU_B0_B1_PPDU_TYPE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_COBF_CSR_DISABLE, + IEEE80211_RADIOTAP_UHR_USIG2_MU_B2_COBF_COSR); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_PUNC_CHANNEL, + IEEE80211_RADIOTAP_UHR_USIG2_MU_B3_B7_PUNCTURED_INFO); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_USIG2_VALIDATE_B8, + IEEE80211_RADIOTAP_UHR_USIG2_MU_B8_VALIDATE); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_SIG_MCS, + IEEE80211_RADIOTAP_UHR_USIG2_MU_B9_B10_SIG_MCS); + IWL_MLD_ENC_USIG_VALUE_MASK(usig, usig_a2, + OFDM_RX_FRAME_UHR_SIG_SYM_NUM, + IEEE80211_RADIOTAP_UHR_USIG2_MU_B11_B15_UHR_SIG_SYMBOLS); + + if (le32_get_bits(usig_a1, OFDM_RX_FRAME_EHT_USIG1_VALIDATE) && + le32_get_bits(usig_a2, OFDM_RX_FRAME_UHR_USIG2_VALIDATE_B8)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_OK); + + if (!le32_get_bits(usig_a2, OFDM_RX_FRAME_UHR_USIG_CRC_OK)) + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BAD_USIG_CRC); +} + +static void iwl_mld_decode_uhr_usig(struct iwl_mld_rx_phy_data *phy_data, + struct sk_buff *skb) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u32 he_type = phy_data->rate_n_flags & RATE_MCS_HE_TYPE_MSK; + struct ieee80211_radiotap_eht_usig *usig; + __le32 usig_a1 = phy_data->ntfy->sigs.uhr.usig_a1; + u32 bw; + + usig = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_EHT_USIG, + sizeof(*usig)); + + BUILD_BUG_ON(offsetof(typeof(phy_data->ntfy->sigs.uhr), usig_a1) != + offsetof(typeof(phy_data->ntfy->sigs.uhr_elr), usig_a1)); + BUILD_BUG_ON(offsetof(typeof(phy_data->ntfy->sigs.uhr), usig_a1) != + offsetof(typeof(phy_data->ntfy->sigs.uhr_tb), usig_a1)); + + usig->common |= cpu_to_le32(IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_VALIDATE_BITS_CHECKED | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP_KNOWN | + IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER_KNOWN); + +#define CHECK_BW(bw) \ + BUILD_BUG_ON(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_ ## bw ## MHZ != \ + RATE_MCS_CHAN_WIDTH_ ## bw ## _VAL) + CHECK_BW(20); + CHECK_BW(40); + CHECK_BW(80); + CHECK_BW(160); +#undef CHECK_BW + BUILD_BUG_ON(IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW_320MHZ_1 != + RATE_MCS_CHAN_WIDTH_320_VAL); + bw = u32_get_bits(phy_data->rate_n_flags, RATE_MCS_CHAN_WIDTH_MSK); + /* specific handling for 320MHz-1/320MHz-2 */ + if (bw == RATE_MCS_CHAN_WIDTH_320_VAL) + bw += le32_get_bits(usig_a1, OFDM_RX_FRAME_EHT_BW320_SLOT); + usig->common |= le32_encode_bits(bw, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BW); + + usig->common |= LE32_DEC_ENC(usig_a1, OFDM_RX_FRAME_ENHANCED_WIFI_UL_FLAG, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_UL_DL); + usig->common |= LE32_DEC_ENC(usig_a1, OFDM_RX_FRAME_ENHANCED_WIFI_BSS_COLOR, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_BSS_COLOR); + usig->common |= LE32_DEC_ENC(usig_a1, + OFDM_RX_FRAME_ENHANCED_WIFI_TXOP_DURATION, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_TXOP); + usig->common |= LE32_DEC_ENC(usig_a1, + OFDM_RX_FRAME_ENHANCED_WIFI_VER_ID, + IEEE80211_RADIOTAP_EHT_USIG_COMMON_PHY_VER); + + switch (he_type) { + case RATE_MCS_HE_TYPE_TRIG: + iwl_mld_decode_uhr_usig_tb(phy_data, usig); + break; + case RATE_MCS_HE_TYPE_UHR_ELR: + iwl_mld_decode_uhr_usig_elr(phy_data, usig); + break; + default: + iwl_mld_decode_uhr_usig_non_tb(phy_data, usig); + break; + } + + iwl_mld_check_bad_usig_crc(rx_status, usig); +} + +static void iwl_mld_decode_uhr_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_uhr *uhr) +{ + if (!(phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_TB_RX)) + return; + + uhr->known |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_KNOWN_DRU_RRU_ALLOC_TB_FMT | + IEEE80211_RADIOTAP_UHR_KNOWN_LDPC_EXTRA_SYMBOL_SEGMENT | + IEEE80211_RADIOTAP_UHR_KNOWN_PRE_FEC_PADDING_FACTOR | + IEEE80211_RADIOTAP_UHR_KNOWN_PE_DISAMBIGUITY | + IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_UHR_LTF_SYMBOLS | + IEEE80211_RADIOTAP_UHR_KNOWN_PRI80_CHAN_POS); + + uhr->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr_tb.tb_rx0, + OFDM_UCODE_TRIG_BASE_PS160, + IEEE80211_RADIOTAP_UHR_DATA8_DRU_RRU_ALLOC_TB_FMT_PS_160); + uhr->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU, + IEEE80211_RADIOTAP_UHR_DATA8_DRU_RRU_ALLOC_TB_FMT_B0 | + IEEE80211_RADIOTAP_UHR_DATA8_DRU_RRU_ALLOC_TB_FMT_B7_B1); + uhr->data[8] |= le32_encode_bits(!le32_get_bits(phy_data->ntfy->sigs.uhr_tb.tb_rx0, + OFDM_UCODE_RX_IS_DRU), + IEEE80211_RADIOTAP_UHR_DATA8_DRU_RRU_INDICATION); + + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_UHR_DATA0_LDPC_EXTRA_SYMBOL_SEGMENT); + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PRE_FEC_PAD_FACTOR, + IEEE80211_RADIOTAP_UHR_DATA0_PRE_FEC_PADDING_FACTOR); + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_PE_DISAMBIG, + IEEE80211_RADIOTAP_UHR_DATA0_PE_DISAMBIGUITY); + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_NUM_OF_LTF_SYM, + IEEE80211_RADIOTAP_UHR_DATA0_NUMBER_OF_LTF_SYMBOLS); + uhr->data[1] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr_tb.tb_rx0, + OFDM_UCODE_TRIG_BASE_RX_RU_P80, + IEEE80211_RADIOTAP_UHR_DATA1_PRI80_CHAN_POS); + + iwl_mld_eht_uhr_set_ru_alloc(rx_status, + le32_get_bits(phy_data->ntfy->sigs.uhr_tb.tb_rx1, + OFDM_UCODE_TRIG_BASE_RX_RU), + true); +} + +static void iwl_mld_uhr_decode_user_ru(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_radiotap_uhr *uhr) +{ + u32 phy_bw = phy_data->rate_n_flags & RATE_MCS_CHAN_WIDTH_MSK; + + if (!(phy_data->ntfy->flags & IWL_SNIF_FLAG_VALID_RU)) + return; + +#define __IWL_MLD_ENC_UHR_RU(rt_data, rt_ru, fw_data, fw_ru) \ + uhr->data[(rt_data)] |= \ + (cpu_to_le32(IEEE80211_RADIOTAP_UHR_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru ## _KNOWN) | \ + LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.cmn[fw_data], \ + OFDM_RX_FRAME_EHT_RU_ALLOC_ ## fw_data ## _ ## fw_ru, \ + IEEE80211_RADIOTAP_UHR_DATA ## rt_data ## _RU_ALLOC_CC_ ## rt_ru)) + +#define _IWL_MLD_ENC_UHR_RU(rt_data, rt_ru, fw_data, fw_ru) \ + __IWL_MLD_ENC_UHR_RU(rt_data, rt_ru, fw_data, fw_ru) + +#define IEEE80211_RADIOTAP_RU_DATA_1_1_1 1 +#define IEEE80211_RADIOTAP_RU_DATA_2_1_1 2 +#define IEEE80211_RADIOTAP_RU_DATA_1_1_2 2 +#define IEEE80211_RADIOTAP_RU_DATA_2_1_2 2 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_1 3 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_1 3 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_2 3 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_2 4 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_3 4 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_3 4 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_4 5 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_4 5 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_5 5 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_5 6 +#define IEEE80211_RADIOTAP_RU_DATA_1_2_6 6 +#define IEEE80211_RADIOTAP_RU_DATA_2_2_6 6 + +#define IWL_RX_RU_DATA_A1 0 +#define IWL_RX_RU_DATA_A2 0 +#define IWL_RX_RU_DATA_A3 0 +#define IWL_RX_RU_DATA_A4 4 +#define IWL_RX_RU_DATA_B1 1 +#define IWL_RX_RU_DATA_B2 1 +#define IWL_RX_RU_DATA_B3 1 +#define IWL_RX_RU_DATA_B4 4 +#define IWL_RX_RU_DATA_C1 2 +#define IWL_RX_RU_DATA_C2 2 +#define IWL_RX_RU_DATA_C3 2 +#define IWL_RX_RU_DATA_C4 5 +#define IWL_RX_RU_DATA_D1 3 +#define IWL_RX_RU_DATA_D2 3 +#define IWL_RX_RU_DATA_D3 3 +#define IWL_RX_RU_DATA_D4 5 + +#define IWL_MLD_ENC_UHR_RU(rt_ru, fw_ru) \ + _IWL_MLD_ENC_UHR_RU(IEEE80211_RADIOTAP_RU_DATA_ ## rt_ru, \ + rt_ru, \ + IWL_RX_RU_DATA_ ## fw_ru, \ + fw_ru) + + /* + * Hardware labels the content channels/RU allocation values + * as follows: + * + * Content Channel 1 Content Channel 2 + * 20 MHz: A1 + * 40 MHz: A1 B1 + * 80 MHz: A1 C1 B1 D1 + * 160 MHz: A1 C1 A2 C2 B1 D1 B2 D2 + * 320 MHz: A1 C1 A2 C2 A3 C3 A4 C4 B1 D1 B2 D2 B3 D3 B4 D4 + */ + + switch (phy_bw) { + case RATE_MCS_CHAN_WIDTH_320: + /* content channel 1 */ + IWL_MLD_ENC_UHR_RU(1_2_3, A3); + IWL_MLD_ENC_UHR_RU(1_2_4, C3); + IWL_MLD_ENC_UHR_RU(1_2_5, A4); + IWL_MLD_ENC_UHR_RU(1_2_6, C4); + /* content channel 2 */ + IWL_MLD_ENC_UHR_RU(2_2_3, B3); + IWL_MLD_ENC_UHR_RU(2_2_4, D3); + IWL_MLD_ENC_UHR_RU(2_2_5, B4); + IWL_MLD_ENC_UHR_RU(2_2_6, D4); + fallthrough; + case RATE_MCS_CHAN_WIDTH_160: + /* content channel 1 */ + IWL_MLD_ENC_UHR_RU(1_2_1, A2); + IWL_MLD_ENC_UHR_RU(1_2_2, C2); + /* content channel 2 */ + IWL_MLD_ENC_UHR_RU(2_2_1, B2); + IWL_MLD_ENC_UHR_RU(2_2_2, D2); + fallthrough; + case RATE_MCS_CHAN_WIDTH_80: + /* content channel 1 */ + IWL_MLD_ENC_UHR_RU(1_1_2, C1); + /* content channel 2 */ + IWL_MLD_ENC_UHR_RU(2_1_2, D1); + fallthrough; + case RATE_MCS_CHAN_WIDTH_40: + /* content channel 2 */ + IWL_MLD_ENC_UHR_RU(2_1_1, B1); + fallthrough; + case RATE_MCS_CHAN_WIDTH_20: + /* content channel 1 */ + IWL_MLD_ENC_UHR_RU(1_1_1, A1); + break; + } +} + +static void iwl_mld_decode_uhr_non_tb(struct iwl_mld_rx_phy_data *phy_data, + struct ieee80211_rx_status *rx_status, + struct ieee80211_radiotap_uhr *uhr) +{ + __le32 usig_a1 = phy_data->ntfy->sigs.uhr.usig_a1; + __le32 usig_a2 = phy_data->ntfy->sigs.uhr.usig_a2_uhr; + bool ofdma; + + uhr->known |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_KNOWN_SPATIAL_REUSE | + IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_UHR_LTF_SYMBOLS | + IEEE80211_RADIOTAP_UHR_KNOWN_LDPC_EXTRA_SYMBOL_SEGMENT | + IEEE80211_RADIOTAP_UHR_KNOWN_PRE_FEC_PADDING_FACTOR | + IEEE80211_RADIOTAP_UHR_KNOWN_PE_DISAMBIGUITY | + IEEE80211_RADIOTAP_UHR_KNOWN_PRI80_CHAN_POS); + + /* + * TB isn't handled here, so uplink can't be OFDMA. + * Downlink OFDMA is PPDU type 0. + */ + ofdma = !(usig_a1 & cpu_to_le32(OFDM_RX_FRAME_ENHANCED_WIFI_UL_FLAG)) && + le32_get_bits(usig_a2, OFDM_RX_FRAME_UHR_PPDU_TYPE) == 0; + + if (ofdma) { + /* All RU allocation size/index is in TB format */ + uhr->known |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_KNOWN_DRU_RRU_ALLOC_TB_FMT); + /* downlink is never DRU */ + uhr->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b2, + OFDM_RX_FRAME_UHR_STA_RU_PS160, + IEEE80211_RADIOTAP_UHR_DATA8_DRU_RRU_ALLOC_TB_FMT_PS_160); + uhr->data[8] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b2, + OFDM_RX_FRAME_UHR_STA_RU, + IEEE80211_RADIOTAP_UHR_DATA8_DRU_RRU_ALLOC_TB_FMT_B0 | + IEEE80211_RADIOTAP_UHR_DATA8_DRU_RRU_ALLOC_TB_FMT_B7_B1); + uhr->data[8] |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_DATA8_DRU_RRU_INDICATION); + } else { + uhr->known |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_KNOWN_NUMBER_OF_NON_OFDMA_USERS | + IEEE80211_RADIOTAP_UHR_KNOWN_INTERFERENCE_MITIGATION); + uhr->data[7] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b1, + OFDM_RX_FRAME_UHR_NUM_OF_USERS, + IEEE80211_RADIOTAP_UHR_DATA7_NUMBER_OF_NON_OFDMA_USERS); + if (!(phy_data->ntfy->sigs.uhr.b1 & cpu_to_le32(OFDM_RX_FRAME_UHR_IM_DISABLE))) + uhr->data[7] |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_DATA7_INTERFERENCE_MITIGATION); + } + + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b1, + OFDM_RX_FRAME_UHR_SPATIAL_REUSE, + IEEE80211_RADIOTAP_UHR_DATA0_SPATIAL_REUSE); + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b1, + OFDM_RX_FRAME_UHR_NUM_OF_LTF_SYM, + IEEE80211_RADIOTAP_UHR_DATA0_NUMBER_OF_LTF_SYMBOLS); + + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b1, + OFDM_RX_FRAME_UHR_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_UHR_DATA0_LDPC_EXTRA_SYMBOL_SEGMENT); + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b1, + OFDM_RX_FRAME_UHR_PE_A_FACTOR, + IEEE80211_RADIOTAP_UHR_DATA0_PRE_FEC_PADDING_FACTOR); + uhr->data[0] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b1, + OFDM_RX_FRAME_UHR_PE_DISAMBIGUITY, + IEEE80211_RADIOTAP_UHR_DATA0_PE_DISAMBIGUITY); + uhr->data[1] |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b2, + OFDM_RX_FRAME_UHR_STA_RU_P80, + IEEE80211_RADIOTAP_UHR_DATA1_PRI80_CHAN_POS); + + iwl_mld_uhr_decode_user_ru(phy_data, uhr); + + iwl_mld_eht_uhr_set_ru_alloc(rx_status, + le32_get_bits(phy_data->ntfy->sigs.uhr.b2, + OFDM_RX_FRAME_UHR_STA_RU), + true); + + if (!phy_data->with_data) + return; + + uhr->user[0].known |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_USER_KNOWN_STA_ID); + uhr->user[0].info |= LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.user_id, + OFDM_RX_FRAME_UHR_USER_FIELD_ID, + IEEE80211_RADIOTAP_UHR_USER_INFO_STA_ID); + + /* don't report UEQM for downlink non-OFDMA MU-MIMO allocations */ + if (!(usig_a1 & cpu_to_le32(OFDM_RX_FRAME_ENHANCED_WIFI_UL_FLAG)) && + le32_get_bits(usig_a2, OFDM_RX_FRAME_UHR_PPDU_TYPE) == 2) + return; + + uhr->user[0].known |= + cpu_to_le32(IEEE80211_RADIOTAP_UHR_USER_KNOWN_UEQM); + uhr->user[0].info |= + LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b2, + OFDM_RX_FRAME_UHR_UEQM, + IEEE80211_RADIOTAP_UHR_USER_INFO_UEQM); + + if (uhr->user[0].info & cpu_to_le32(IEEE80211_RADIOTAP_UHR_USER_INFO_UEQM)) { + uhr->user[0].known |= + cpu_to_le32(IEEE80211_RADIOTAP_UHR_USER_KNOWN_UEQM_PATTERN); + uhr->user[0].info |= + LE32_DEC_ENC(phy_data->ntfy->sigs.uhr.b2, + OFDM_RX_FRAME_UHR_UEQM_PATTERN, + IEEE80211_RADIOTAP_UHR_USER_INFO_UEQM_PATTERN); + } +} + +static void +iwl_mld_decode_uhr_elr_phy_data(struct iwl_mld_rx_phy_data *phy_data, + struct sk_buff *skb, + struct ieee80211_rx_status *rx_status) +{ + struct ieee80211_radiotap_uhr_elr *elr; + __le32 elr1 = phy_data->ntfy->sigs.uhr_elr.uhr_sig_elr1; + __le32 elr2 = phy_data->ntfy->sigs.uhr_elr.uhr_sig_elr2; + + elr = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_UHR_ELR, + sizeof(*elr)); + + elr->known |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_ELR_KNOWN_VERSION_ID | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_UL_DL | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_MCS | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_CODING | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_LENGTH | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_LDPC_EXTRA_OFDM_SYM | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_STA_ID | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_DISREGARD | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_SIG_1_CRC_CHECKED | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_SIG_2_CRC_CHECKED | + IEEE80211_RADIOTAP_UHR_ELR_KNOWN_MARK_BSS_COLOR); + elr->sig1 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_VER_ID, + IEEE80211_RADIOTAP_UHR_ELR_SIG1_VERSION_ID); + elr->sig1 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_UPLINK_FLAG, + IEEE80211_RADIOTAP_UHR_ELR_SIG1_UL_DL); + elr->sig1 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_MCS, + IEEE80211_RADIOTAP_UHR_ELR_SIG1_MCS); + elr->sig1 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_CODING, + IEEE80211_RADIOTAP_UHR_ELR_SIG1_CODING); + elr->sig1 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_LENGTH_IN_SYM, + IEEE80211_RADIOTAP_UHR_ELR_SIG1_LENGTH); + elr->sig1 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_CODING_EXTRA_SYM, + IEEE80211_RADIOTAP_UHR_ELR_SIG1_LDPC_EXTRA_OFDM_SYM); + elr->sig1 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_SIG1_CRC_OK, + IEEE80211_RADIOTAP_UHR_ELR_SIG1_CRC_VALID); + + elr->sig2 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_STA_ID, + IEEE80211_RADIOTAP_UHR_ELR_SIG2_STA_ID); + elr->sig2 |= LE32_DEC_ENC(elr1, OFDM_RX_VECTOR_UHR_ELR_DISREGARD, + IEEE80211_RADIOTAP_UHR_ELR_SIG2_DISREGARD); + + elr->sig2 |= LE32_DEC_ENC(elr2, OFDM_RX_VECTOR_UHR_ELR_SIG2_CRC_OK, + IEEE80211_RADIOTAP_UHR_ELR_SIG2_CRC_VALID); + + elr->mark |= LE32_DEC_ENC(elr2, OFDM_RX_VECTOR_UHR_ELR_MARK_BSS_COLOR, + IEEE80211_RADIOTAP_UHR_ELR_MARK_BSS_COLOR); +} + +static void iwl_mld_decode_uhr_phy_data(struct iwl_mld_rx_phy_data *phy_data, + struct sk_buff *skb) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u32 rate_n_flags = phy_data->rate_n_flags; + u32 he_type = rate_n_flags & RATE_MCS_HE_TYPE_MSK; + struct ieee80211_radiotap_uhr *uhr; + size_t uhr_len; + + if (he_type == RATE_MCS_HE_TYPE_UHR_ELR) { + iwl_mld_decode_uhr_elr_phy_data(phy_data, skb, rx_status); + return; + } + + /* space for one user_info if we captured data */ + uhr_len = struct_size(uhr, user, (phy_data->with_data ? 1 : 0)); + + uhr = iwl_mld_radiotap_put_tlv(skb, IEEE80211_RADIOTAP_UHR, uhr_len); + + uhr->known |= cpu_to_le32(IEEE80211_RADIOTAP_UHR_KNOWN_GI_LTF_SIZE); + uhr->data[0] |= le32_encode_bits(u32_get_bits(rate_n_flags, + RATE_MCS_HE_GI_LTF_MSK), + IEEE80211_RADIOTAP_UHR_DATA0_GI_LTF_SIZE); + + if (phy_data->with_data) { + uhr->user[0].known |= + cpu_to_le32(IEEE80211_RADIOTAP_UHR_USER_KNOWN_MCS | + IEEE80211_RADIOTAP_UHR_USER_KNOWN_NSS | + IEEE80211_RADIOTAP_UHR_USER_KNOWN_BF | + IEEE80211_RADIOTAP_UHR_USER_KNOWN_2X_LDPC | + IEEE80211_RADIOTAP_UHR_USER_KNOWN_CODING | + IEEE80211_RADIOTAP_UHR_USER_KNOWN_USER_CAPTURED); + + uhr->user[0].info |= + le32_encode_bits(u32_get_bits(rate_n_flags, + RATE_MCS_CODE_MSK), + IEEE80211_RADIOTAP_UHR_USER_INFO_MCS); + uhr->user[0].info |= + le32_encode_bits(u32_get_bits(rate_n_flags, + RATE_MCS_NSS_MSK), + IEEE80211_RADIOTAP_UHR_USER_INFO_NSS); + + if (phy_data->phy_info & IWL_RX_MPDU_PHY_2X_LDPC) + uhr->user[0].info |= + cpu_to_le32(IEEE80211_RADIOTAP_UHR_USER_INFO_2X_LDPC); + + if (rate_n_flags & RATE_MCS_BF_MSK) + uhr->user[0].info |= + cpu_to_le32(IEEE80211_RADIOTAP_UHR_USER_INFO_BF); + + if (rate_n_flags & RATE_MCS_LDPC_MSK) + uhr->user[0].info |= + cpu_to_le32(IEEE80211_RADIOTAP_UHR_USER_INFO_CODING); + } + + if (he_type == RATE_MCS_HE_TYPE_TRIG) + iwl_mld_decode_uhr_tb(phy_data, rx_status, uhr); + else + iwl_mld_decode_uhr_non_tb(phy_data, rx_status, uhr); +} + +static void iwl_mld_rx_uhr(struct iwl_mld *mld, struct sk_buff *skb, + struct iwl_mld_rx_phy_data *phy_data) +{ + struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); + u8 gi, ltf; + + /* the LTF size is reported from the PHY data, only the GI is needed */ + ltf = iwl_mld_decode_eht_uhr_gi_ltf(phy_data->rate_n_flags, &gi); + if (ltf != IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE_UNKNOWN) + rx_status->uhr.gi = gi; + + if (likely(!phy_data->ntfy)) + return; + + iwl_mld_decode_uhr_usig(phy_data, skb); + iwl_mld_decode_uhr_phy_data(phy_data, skb); +} + #ifdef CONFIG_IWLWIFI_DEBUGFS static void iwl_mld_add_rtap_sniffer_config(struct iwl_mld *mld, struct sk_buff *skb) @@ -1506,19 +2089,42 @@ static void iwl_mld_rx_fill_status(struct iwl_mld *mld, int link_id, iwl_mld_set_rx_rate(mld, phy_data, rx_status); - /* must be before HE data (radiotap field order) */ - if (format == RATE_MCS_MOD_TYPE_VHT) + switch (format) { + case RATE_MCS_MOD_TYPE_CCK: + /* nothing to see here, see note below */ + break; + case RATE_MCS_MOD_TYPE_LEGACY_OFDM: + /* + * Technically legacy CCK/OFDM frames don't have an L-SIG + * since that's the compat format for HT (non-greenfield) + * and up. However, it's meant to be compatible with the + * LENGTH and RATE fields in Clause 17 and 18 OFDM frames + * so include the field for any non-CCK frame. For CCK it + * cannot work, since the LENGTH field for them is 16-bit + * and the radiotap field only has 12 bits. + */ + iwl_mld_decode_lsig(skb, phy_data); + break; + case RATE_MCS_MOD_TYPE_HT: + iwl_mld_decode_lsig(skb, phy_data); + break; + case RATE_MCS_MOD_TYPE_VHT: iwl_mld_rx_vht(skb, phy_data); - - /* must be before L-SIG data (radiotap field order) */ - if (format == RATE_MCS_MOD_TYPE_HE) + iwl_mld_decode_lsig(skb, phy_data); + break; + case RATE_MCS_MOD_TYPE_HE: iwl_mld_rx_he(skb, phy_data); - - iwl_mld_decode_lsig(skb, phy_data); - - /* TLVs - must be after radiotap fixed fields */ - if (format == RATE_MCS_MOD_TYPE_EHT) + iwl_mld_decode_lsig(skb, phy_data); + break; + case RATE_MCS_MOD_TYPE_EHT: + iwl_mld_decode_lsig(skb, phy_data); iwl_mld_rx_eht(mld, skb, phy_data); + break; + case RATE_MCS_MOD_TYPE_UHR: + iwl_mld_decode_lsig(skb, phy_data); + iwl_mld_rx_uhr(mld, skb, phy_data); + break; + } #ifdef CONFIG_IWLWIFI_DEBUGFS if (unlikely(mld->monitor.on)) { @@ -2281,7 +2887,7 @@ void iwl_mld_handle_rsc_notif(struct iwl_mld *mld, #endif /* CONFIG_PM_SLEEP */ static void iwl_mld_no_data_rx(struct iwl_mld *mld, - struct napi_struct *napi, + struct napi_struct *napi, bool no_mpdu, struct iwl_rx_phy_air_sniffer_ntfy *ntfy) { struct ieee80211_rx_status *rx_status; @@ -2308,9 +2914,24 @@ static void iwl_mld_no_data_rx(struct iwl_mld *mld, switch (ntfy->status) { case IWL_SNIF_STAT_PLCP_RX_OK: - /* we only get here with sounding PPDUs */ - rx_status->zero_length_psdu_type = - IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING; + /* + * For trigger-based PPDUs, the firmware decodes the PHY header + * and releases with a good status only if the frame was for the + * configured AID (the bad status depends on the version), and + * also only sets IWL_SNIF_FLAG_VALID_TB_RX if receiving for the + * configured AID. + * + * So trigger-based PHY notifications without MPDU are sounding + * PPDUs, while other releases without MPDU are some kind of + * error after a good PHY header - don't flag failed PLCP in + * this case, but release as unspecified zero-len reason. + */ + if (no_mpdu && !(ntfy->flags & IWL_SNIF_FLAG_VALID_TB_RX)) + rx_status->zero_length_psdu_type = + IEEE80211_RADIOTAP_ZERO_LEN_PSDU_VENDOR; + else + rx_status->zero_length_psdu_type = + IEEE80211_RADIOTAP_ZERO_LEN_PSDU_SOUNDING; break; case IWL_SNIF_STAT_AID_NOT_FOR_US: rx_status->zero_length_psdu_type = @@ -2321,6 +2942,7 @@ static void iwl_mld_no_data_rx(struct iwl_mld *mld, case IWL_SNIF_STAT_PLCP_RX_SIGB_ERR: case IWL_SNIF_STAT_UNKNOWN_ERROR: default: + /* some kind of PLCP error - no details from FW */ rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC; fallthrough; case IWL_SNIF_STAT_UNEXPECTED_TB: @@ -2364,12 +2986,9 @@ void iwl_mld_handle_phy_air_sniffer_notif(struct iwl_mld *mld, "invalid air sniffer notification size\n")) return; - /* check if there's an old one to release as errored */ - if (mld->monitor.phy.valid && !mld->monitor.phy.used) { - /* didn't capture data, so override status */ - mld->monitor.phy.data.status = IWL_SNIF_STAT_AID_NOT_FOR_US; - iwl_mld_no_data_rx(mld, napi, &mld->monitor.phy.data); - } + /* check if there's an old one to release */ + if (mld->monitor.phy.valid && !mld->monitor.phy.used) + iwl_mld_no_data_rx(mld, napi, true, &mld->monitor.phy.data); /* old data is no longer valid now */ mld->monitor.phy.valid = false; @@ -2403,10 +3022,17 @@ void iwl_mld_handle_phy_air_sniffer_notif(struct iwl_mld *mld, !le32_get_bits(ntfy->sigs.eht.sig2, OFDM_RX_FRAME_EHT_NUM_OF_DATA_SYM); break; + case RATE_MCS_MOD_TYPE_UHR: + if (he_type == RATE_MCS_HE_TYPE_TRIG || + he_type == RATE_MCS_HE_TYPE_UHR_ELR) + break; + is_ndp = !le32_get_bits(ntfy->sigs.uhr.sig2, + OFDM_RX_UHR_NUM_OF_DATA_SYM); + break; } if (ntfy->status != IWL_SNIF_STAT_PLCP_RX_OK || is_ndp) { - iwl_mld_no_data_rx(mld, napi, ntfy); + iwl_mld_no_data_rx(mld, napi, false, ntfy); return; } diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c index 0faca402bc14..b942ac1e7ccc 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c @@ -1992,7 +1992,14 @@ void iwl_mld_int_mlo_scan(struct iwl_mld *mld, struct ieee80211_vif *vif) void iwl_mld_handle_scan_iter_complete_notif(struct iwl_mld *mld, struct iwl_rx_packet *pkt) { - struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data; + /* + * The v3 notification is a superset of v2, so the fields that are + * common to both versions can always be read from the v3 layout. + */ + const struct iwl_umac_scan_iter_complete_notif *notif = + (const void *)pkt->data; + u8 notif_ver = iwl_fw_lookup_notif_ver(mld->fw, LEGACY_GROUP, + SCAN_ITERATION_COMPLETE_UMAC, 2); u32 uid = __le32_to_cpu(notif->uid); if (IWL_FW_CHECK(mld, uid >= ARRAY_SIZE(mld->scan.uid_status), @@ -2006,6 +2013,12 @@ void iwl_mld_handle_scan_iter_complete_notif(struct iwl_mld *mld, "UMAC Scan iteration complete: status=0x%x scanned_channels=%d\n", notif->status, notif->scanned_channels); + if (notif_ver >= 3) + IWL_DEBUG_SCAN(mld, + "UMAC Scan iteration complete: EBS=%s, EBS channel status=0x%llx\n", + iwl_mld_scan_ebs_status_str(notif->ebs_status), + le64_to_cpu(notif->ebs_channel_status)); + if (mld->scan.pass_all_sched_res == SCHED_SCAN_PASS_ALL_STATE_FOUND) { IWL_DEBUG_SCAN(mld, "Pass all scheduled scan results found\n"); ieee80211_sched_scan_results(mld->hw); @@ -2260,6 +2273,7 @@ void iwl_mld_handle_channel_survey_notif(struct iwl_mld *mld, /* Times are all in ms */ info->time = le32_to_cpu(notif->active_time); info->time_busy = le32_to_cpu(notif->busy_time); + info->time_rx = le32_to_cpu(notif->rx_time); info->noise = iwl_average_neg_dbm(notif->noise, ARRAY_SIZE(notif->noise)); } @@ -2308,9 +2322,11 @@ int iwl_mld_mac80211_get_survey(struct ieee80211_hw *hw, int idx, /* Found (the next) channel to report */ survey->channel = &sband->channels[per_band_idx]; survey->filled = SURVEY_INFO_TIME | - SURVEY_INFO_TIME_BUSY; + SURVEY_INFO_TIME_BUSY | + SURVEY_INFO_TIME_RX; survey->time = info->time; survey->time_busy = info->time_busy; + survey->time_rx = info->time_rx; survey->noise = info->noise; if (survey->noise < 0) survey->filled |= SURVEY_INFO_NOISE_DBM; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h index dc299fe2f999..74ebe8296693 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2024-2025 Intel Corporation + * Copyright (C) 2024-2026 Intel Corporation */ #ifndef __iwl_mld_scan_h__ #define __iwl_mld_scan_h__ @@ -151,11 +151,13 @@ struct iwl_mld_scan { * * @time: time in ms the radio was on the channel * @time_busy: time in ms the channel was sensed busy + * @time_rx: time in ms the channel was sensed to carry Wi-Fi frames * @noise: channel noise in dBm */ struct iwl_mld_survey_channel { u32 time; u32 time_busy; + u32 time_rx; s8 noise; }; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c index 7957ac11b0cd..97f013330f06 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c @@ -465,8 +465,8 @@ int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld, struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta); struct iwl_sta_cfg_cmd cmd = {}; int fw_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta); - bool is_6ghz, uora_exists; u32 link_mask; + bool is_6ghz; lockdep_assert_wiphy(mld->wiphy); @@ -479,7 +479,6 @@ int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld, return -EINVAL; is_6ghz = false; - uora_exists = false; link_mask = iwl_mld_get_nan_link_mask(mld); } else { @@ -495,7 +494,6 @@ int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld, link_mask = BIT(mld_link->fw_id); is_6ghz = link->chanreq.oper.chan->band == NL80211_BAND_6GHZ; - uora_exists = link->uora_exists; } cmd.sta_id = cpu_to_le32(fw_id); @@ -554,9 +552,6 @@ int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld, } if (link_sta->he_cap.has_he) { - cmd.trig_rnd_alloc = - cpu_to_le32(uora_exists ? 1 : 0); - /* PPE Thresholds */ iwl_mld_fill_pkt_ext(mld, link_sta, &cmd.pkt_ext); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/stats.c b/drivers/net/wireless/intel/iwlwifi/mld/stats.c index e7b283cbe199..3b6cd4f382f6 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/stats.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/stats.c @@ -43,12 +43,17 @@ iwl_mld_fill_stats_from_oper_notif(struct iwl_mld *mld, const struct iwl_stats_ntfy_per_sta *per_sta; struct ieee80211_link_sta *link_sta; struct iwl_mld_link_sta *mld_link_sta; + u8 notif_ver = iwl_fw_lookup_notif_ver(mld->fw, STATISTICS_GROUP, + STATISTICS_OPER_NOTIF, 3); - if (iwl_fw_lookup_notif_ver(mld->fw, STATISTICS_GROUP, - STATISTICS_OPER_NOTIF, 3) >= 4) { + if (notif_ver >= 5) { const struct iwl_system_statistics_notif_oper *notif = (void *)&pkt->data; per_sta = ¬if->per_sta[fw_sta_id]; + } else if (notif_ver == 4) { + const struct iwl_system_statistics_notif_oper_v4 *notif = + (void *)&pkt->data; + per_sta = ¬if->per_sta[fw_sta_id]; } else { const struct iwl_system_statistics_notif_oper_v3 *notif = (void *)&pkt->data; @@ -581,17 +586,39 @@ void iwl_mld_handle_stats_oper_notif(struct iwl_mld *mld, struct iwl_system_statistics_notif_oper *_notif __free(kfree) = NULL; const struct iwl_system_statistics_notif_oper *notif = (void *)&pkt->data; + u8 notif_ver = iwl_fw_lookup_notif_ver(mld->fw, STATISTICS_GROUP, + STATISTICS_OPER_NOTIF, 3); BUILD_BUG_ON(ARRAY_SIZE(notif->per_sta) != IWL_STATION_COUNT_MAX); BUILD_BUG_ON(ARRAY_SIZE(notif->per_link) < ARRAY_SIZE(mld->fw_id_to_bss_conf)); - if (iwl_fw_lookup_notif_ver(mld->fw, STATISTICS_GROUP, - STATISTICS_OPER_NOTIF, 3) == 3) { + if (notif_ver == 3) { const struct iwl_system_statistics_notif_oper_v3 *stats = (void *)&pkt->data; _notif = kzalloc_obj(*_notif); + if (!_notif) + return; + + _notif->time_stamp = stats->time_stamp; + for (int i = 0; i < ARRAY_SIZE(_notif->per_link); i++) + _notif->per_link[i] = stats->per_link[i]; + + BUILD_BUG_ON(sizeof(_notif->per_phy[0]) < + sizeof(stats->per_phy[0])); + for (int i = 0; i < ARRAY_SIZE(_notif->per_phy); i++) + memcpy(&_notif->per_phy[i], &stats->per_phy[i], + sizeof(stats->per_phy[i])); + for (int i = 0; i < ARRAY_SIZE(_notif->per_sta); i++) + _notif->per_sta[i] = stats->per_sta[i]; + + notif = _notif; + } else if (notif_ver == 4) { + const struct iwl_system_statistics_notif_oper_v4 *stats = + (void *)&pkt->data; + _notif = kzalloc_obj(*_notif); + if (!_notif) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/Makefile b/drivers/net/wireless/intel/iwlwifi/mld/tests/Makefile index efa61638b8ee..730185be3fa8 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tests/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause iwlmld-tests-y += module.o hcmd.o utils.o link.o rx.o agg.o link-selection.o -iwlmld-tests-y += chan_load_thresh.o +iwlmld-tests-y += chan_load_thresh.o tx-gp2.o ccflags-y += -I$(src)/../ obj-$(CONFIG_IWLWIFI_KUNIT_TESTS) += iwlmld-tests.o diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/tx-gp2.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/tx-gp2.c new file mode 100644 index 000000000000..535140eb17c4 --- /dev/null +++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/tx-gp2.c @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * KUnit tests for TX gp2 timestamp handling + * + * Copyright (C) 2026 Intel Corporation + */ +#include + +#include "mld.h" +#include "tx.h" + +MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); + +static const struct tx_gp2_case { + const char *desc; + u32 est_gp2_us; + u32 est_host_us; + u32 tx_host_us; + long valid_for; + u32 expected_gp2_us; + bool expected_refresh; +} tx_gp2_cases[] = { + { + .desc = "zero offset is valid", + .est_gp2_us = 2000, + .est_host_us = 2000, + .tx_host_us = 3500, + .valid_for = IWL_MLD_TX_GP2_VALID_PERIOD, + .expected_gp2_us = 3500, + }, + { + .desc = "gp2 behind host", + .est_gp2_us = 2000, + .est_host_us = 10000, + .tx_host_us = 11500, + .valid_for = IWL_MLD_TX_GP2_VALID_PERIOD, + .expected_gp2_us = 3500, + }, + { + .desc = "gp2 ahead of host", + .est_gp2_us = 10000, + .est_host_us = 2000, + .tx_host_us = 3500, + .valid_for = IWL_MLD_TX_GP2_VALID_PERIOD, + .expected_gp2_us = 11500, + }, + { + .desc = "gp2 wraps after the estimate", + .est_gp2_us = U32_MAX - 999, + .est_host_us = 1000, + .tx_host_us = 2500, + .valid_for = IWL_MLD_TX_GP2_VALID_PERIOD, + .expected_gp2_us = 500, + }, + { + .desc = "host time wraps after the estimate", + .est_gp2_us = 5000, + .est_host_us = U32_MAX - 999, + .tx_host_us = 500, + .valid_for = IWL_MLD_TX_GP2_VALID_PERIOD, + .expected_gp2_us = 6500, + }, + { + .desc = "gp2 landing on 0 is reported as 1", + .est_gp2_us = U32_MAX - 1499, + .est_host_us = 1000, + .tx_host_us = 2500, + .valid_for = IWL_MLD_TX_GP2_VALID_PERIOD, + .expected_gp2_us = 1, + }, + { + .desc = "within the refresh margin: still timestamped", + .est_gp2_us = 2000, + .est_host_us = 10000, + .tx_host_us = 11500, + .valid_for = IWL_MLD_TX_GP2_REFRESH_MARGIN - 1, + .expected_gp2_us = 3500, + .expected_refresh = true, + }, + { + .desc = "outside the refresh margin: no refresh", + .est_gp2_us = 2000, + .est_host_us = 10000, + .tx_host_us = 11500, + .valid_for = IWL_MLD_TX_GP2_REFRESH_MARGIN + 1, + .expected_gp2_us = 3500, + }, + { + .desc = "at the refresh threshold", + .est_gp2_us = 2000, + .est_host_us = 10000, + .tx_host_us = 11500, + .valid_for = IWL_MLD_TX_GP2_REFRESH_MARGIN, + .expected_gp2_us = 3500, + .expected_refresh = true, + }, + { + .desc = "last valid tick", + .est_gp2_us = 2000, + .est_host_us = 10000, + .tx_host_us = 11500, + .valid_for = 1, + .expected_gp2_us = 3500, + .expected_refresh = true, + }, + { + .desc = "validity reached: leave the frame unstamped", + .est_gp2_us = 2000, + .est_host_us = 10000, + .tx_host_us = 11500, + .valid_for = 0, + .expected_refresh = true, + }, + { + .desc = "validity passed: leave the frame unstamped", + .est_gp2_us = 2000, + .est_host_us = 10000, + .tx_host_us = 11500, + .valid_for = -1, + .expected_refresh = true, + }, +}; + +KUNIT_ARRAY_PARAM_DESC(tx_gp2, tx_gp2_cases, desc); + +static void test_tx_gp2(struct kunit *test) +{ + /* Pin time near wraparound to exercise wrapped validity deadlines. */ + const unsigned long now = + ULONG_MAX - IWL_MLD_TX_GP2_REFRESH_MARGIN - 1; + const struct tx_gp2_case *test_case = test->param_value; + u32 delta_us = test_case->est_gp2_us - test_case->est_host_us; + unsigned long valid_until = now + test_case->valid_for; + bool refresh = !test_case->expected_refresh; + u32 timestamp; + + timestamp = iwl_mld_tx_gp2_from_est(delta_us, valid_until, + test_case->tx_host_us, now, + &refresh); + KUNIT_EXPECT_EQ(test, timestamp, test_case->expected_gp2_us); + KUNIT_EXPECT_EQ(test, refresh, test_case->expected_refresh); +} + +static struct kunit_case tx_gp2_test_cases[] = { + KUNIT_CASE_PARAM(test_tx_gp2, tx_gp2_gen_params), + {} +}; + +static struct kunit_suite tx_gp2_test_suite = { + .name = "iwl_mld_tx_gp2", + .test_cases = tx_gp2_test_cases, +}; + +kunit_test_suite(tx_gp2_test_suite); diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c index b6c2fa3664cb..0e448b24a6a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c @@ -49,9 +49,60 @@ struct iwl_mld_tlc_sta_capa { const struct ieee80211_sta_uhr_cap *own_uhr_cap; }; +static bool iwl_mld_eht_ldpc_support(const struct ieee80211_sta_he_cap *he_cap, + const struct ieee80211_sta_eht_cap *eht_cap, + bool from_ap) +{ + u8 nss; + + /* higher bandwidth implies LDPC */ + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G) + return true; + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G) + return true; + if (he_cap->he_cap_elem.phy_cap_info[0] & + IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G) + return true; + if (eht_cap->eht_cap_elem.phy_cap_info[0] & + IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ) + return true; + + /* MCS 10-14 imply LDPC support, we only check 10-13 here */ + if (!from_ap) { + const struct ieee80211_eht_mcs_nss_supp_20mhz_only *mcs_nss; + + mcs_nss = &eht_cap->eht_mcs_nss_supp.only_20mhz; + + if (mcs_nss->rx_tx_mcs11_max_nss || + mcs_nss->rx_tx_mcs13_max_nss) + return true; + + nss = mcs_nss->rx_tx_mcs7_max_nss; + } else { + const struct ieee80211_eht_mcs_nss_supp_bw *mcs_nss; + + mcs_nss = &eht_cap->eht_mcs_nss_supp.bw._80; + + if (mcs_nss->rx_tx_mcs11_max_nss || + mcs_nss->rx_tx_mcs13_max_nss) + return true; + + nss = mcs_nss->rx_tx_mcs9_max_nss; + } + + /* NSS > 4 implies LDPC support */ + return u8_get_bits(nss, IEEE80211_EHT_MCS_NSS_RX) > 4 || + u8_get_bits(nss, IEEE80211_EHT_MCS_NSS_TX) > 4; +} + static __le16 iwl_mld_get_tlc_cmd_flags(struct iwl_mld *mld, - struct iwl_mld_tlc_sta_capa *capa) + struct ieee80211_vif *vif, + struct iwl_mld_tlc_sta_capa *capa, + enum iwl_tlc_mng_cfg_mode mode, + enum iwl_tlc_mng_cfg_cw max_bw) { const struct ieee80211_sta_ht_cap *ht_cap = capa->ht_cap; const struct ieee80211_sta_vht_cap *vht_cap = capa->vht_cap; @@ -61,64 +112,79 @@ iwl_mld_get_tlc_cmd_flags(struct iwl_mld *mld, const struct ieee80211_sta_he_cap *own_he_cap = capa->own_he_cap; const struct ieee80211_sta_eht_cap *own_eht_cap = capa->own_eht_cap; const struct ieee80211_sta_uhr_cap *own_uhr_cap = capa->own_uhr_cap; - bool has_vht = vht_cap && vht_cap->vht_supported; + bool stbc_possible = mld->cfg->ht_params.stbc && + hweight8(iwl_mld_get_valid_tx_ant(mld)) > 1; u16 flags = 0; - /* STBC flags */ - if (mld->cfg->ht_params.stbc && - (hweight8(iwl_mld_get_valid_tx_ant(mld)) > 1)) { - if (he_cap && he_cap->has_he && + switch (mode) { + case IWL_TLC_MNG_MODE_NON_HT: + break; + case IWL_TLC_MNG_MODE_HT: + if (WARN_ON(!ht_cap || !ht_cap->ht_supported)) + return 0; + if (stbc_possible && + ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) + flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; + if (mld->cfg->ht_params.ldpc && + ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) + flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; + break; + case IWL_TLC_MNG_MODE_VHT: + if (WARN_ON(!vht_cap || !vht_cap->vht_supported)) + return 0; + if (stbc_possible && + vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK) + flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; + if (mld->cfg->ht_params.ldpc && + vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC) + flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; + break; + case IWL_TLC_MNG_MODE_HE: + if (WARN_ON(!he_cap || !he_cap->has_he || !own_he_cap)) + return 0; + if (stbc_possible && he_cap->he_cap_elem.phy_cap_info[2] & - IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ) - flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; - else if (vht_cap && - vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK) - flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; - else if (ht_cap && ht_cap->cap & IEEE80211_HT_CAP_RX_STBC) + IEEE80211_HE_PHY_CAP2_STBC_RX_UNDER_80MHZ && + (max_bw <= IWL_TLC_MNG_CH_WIDTH_80MHZ || + he_cap->he_cap_elem.phy_cap_info[7] & + IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ)) flags |= IWL_TLC_MNG_CFG_FLAGS_STBC_MSK; + if (he_cap->he_cap_elem.phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD && + own_he_cap->he_cap_elem.phy_cap_info[1] & + IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD) + flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; + if (he_cap->he_cap_elem.phy_cap_info[3] & + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK && + own_he_cap->he_cap_elem.phy_cap_info[3] & + IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK) + flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK; + break; + case IWL_TLC_MNG_MODE_UHR: + if (WARN_ON(!uhr_cap || !uhr_cap->has_uhr || !own_uhr_cap)) + return 0; + if (uhr_cap->phy.cap & cpu_to_le32(IEEE80211_UHR_PHY_CAP_ELR_RX) && + own_uhr_cap->phy.cap & cpu_to_le32(IEEE80211_UHR_PHY_CAP_ELR_TX)) + flags |= IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_1_5_MBPS_MSK | + IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_3_MBPS_MSK; + /* uses most config from EHT */ + fallthrough; + case IWL_TLC_MNG_MODE_EHT: + if (WARN_ON(!own_he_cap || !he_cap || !he_cap->has_he || + !own_eht_cap || !eht_cap || !eht_cap->has_eht)) + return 0; + if (own_eht_cap->eht_cap_elem.phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF && + eht_cap->eht_cap_elem.phy_cap_info[5] & + IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF) + flags |= IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK; + /* no STBC in EHT */ + if (iwl_mld_eht_ldpc_support(he_cap, eht_cap, + vif->type == NL80211_IFTYPE_STATION)) + flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; + break; } - /* LDPC */ - if (mld->cfg->ht_params.ldpc && - ((ht_cap && ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING) || - (has_vht && (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC)))) - flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; - - if (he_cap && he_cap->has_he && - (he_cap->he_cap_elem.phy_cap_info[1] & - IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) - flags |= IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; - - if (own_he_cap && - !(own_he_cap->he_cap_elem.phy_cap_info[1] & - IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD)) - flags &= ~IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK; - - /* DCM */ - if (he_cap && he_cap->has_he && - (he_cap->he_cap_elem.phy_cap_info[3] & - IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_RX_MASK && - own_he_cap && - own_he_cap->he_cap_elem.phy_cap_info[3] & - IEEE80211_HE_PHY_CAP3_DCM_MAX_CONST_TX_MASK)) - flags |= IWL_TLC_MNG_CFG_FLAGS_HE_DCM_NSS_1_MSK; - - /* Extra EHT LTF */ - if (own_eht_cap && - own_eht_cap->eht_cap_elem.phy_cap_info[5] & - IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF && - eht_cap && eht_cap->has_eht && - eht_cap->eht_cap_elem.phy_cap_info[5] & - IEEE80211_EHT_PHY_CAP5_SUPP_EXTRA_EHT_LTF) { - flags |= IWL_TLC_MNG_CFG_FLAGS_EHT_EXTRA_LTF_MSK; - } - - if (uhr_cap && uhr_cap->has_uhr && own_uhr_cap && - uhr_cap->phy.cap & cpu_to_le32(IEEE80211_UHR_PHY_CAP_ELR_RX) && - own_uhr_cap->phy.cap & cpu_to_le32(IEEE80211_UHR_PHY_CAP_ELR_TX)) - flags |= IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_1_5_MBPS_MSK | - IWL_TLC_MNG_CFG_FLAGS_UHR_ELR_3_MBPS_MSK; - return cpu_to_le16(flags); } @@ -478,7 +544,6 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, .max_ch_width = mld_sta->sta_state > IEEE80211_STA_ASSOC ? iwl_mld_fw_bw_from_sta_bw(capa->bandwidth) : IWL_TLC_MNG_CH_WIDTH_20MHZ, - .flags = iwl_mld_get_tlc_cmd_flags(mld, capa), .chains = iwl_mld_get_fw_chains(mld), .sgi_ch_width_supp = iwl_mld_get_fw_sgi(capa), .max_mpdu_len = cpu_to_le16(capa->max_amsdu_len), @@ -493,6 +558,8 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld, cmd.phy_id = cpu_to_le32(phy_id); iwl_mld_fill_supp_rates(mld, vif, capa, &cmd); + cmd.flags = iwl_mld_get_tlc_cmd_flags(mld, vif, capa, cmd.mode, + cmd.max_ch_width); if (cmd_ver == 6) { cmd_ptr = &cmd; @@ -824,8 +891,13 @@ iwl_mld_get_amsdu_size_of_tid(struct iwl_mld *mld, txf = iwl_mld_mac80211_ac_to_fw_tx_fifo(ac); - /* Only one link: take the lmac according to the band */ - if (hweight16(sta->valid_links) <= 1) { + /* + * Only one link: take the lmac according to the band + * In NAN, we don't have a link_conf. + * TODO: once we have a TLC object, we can know better the band. + */ + if (hweight16(sta->valid_links) <= 1 && + vif->type != NL80211_IFTYPE_NAN_DATA) { enum nl80211_band band; struct ieee80211_bss_conf *link = wiphy_dereference(mld->wiphy, diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c index 2df6643a5aa8..44aa317b8e7d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c @@ -2,6 +2,7 @@ /* * Copyright (C) 2024 - 2026 Intel Corporation */ +#include #include #include "tx.h" @@ -20,6 +21,133 @@ #define MAX_ANT_NUM 2 +static u32 iwl_mld_tx_gp2_host_us(void) +{ + return div_u64(ktime_get_boottime_ns(), NSEC_PER_USEC); +} + +/* Returns the gp2 for the TX command, or 0 to leave the frame unstamped. + * Sets @refresh when the estimate expired or is about to. + */ +VISIBLE_IF_IWLWIFI_KUNIT u32 +iwl_mld_tx_gp2_from_est(u32 delta_us, unsigned long valid_until, u32 host_us, + unsigned long now, bool *refresh) +{ + u32 gp2; + + *refresh = time_after_eq(now, valid_until - + IWL_MLD_TX_GP2_REFRESH_MARGIN); + + if (time_after_eq(now, valid_until)) + return 0; + + gp2 = host_us + delta_us; + + /* 0 means no timestamp; use 1 for a valid wrapped value. */ + return gp2 ?: 1; +} +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mld_tx_gp2_from_est); + +static u32 +iwl_mld_tx_gp2_timestamp(struct iwl_mld *mld) +{ + unsigned long valid_until = + atomic_long_read_acquire(&mld->tx_gp2.valid_until); + bool refresh = false; + u32 gp2; + + if (!valid_until) + return 0; + + gp2 = iwl_mld_tx_gp2_from_est(atomic_read(&mld->tx_gp2.delta_us), + valid_until, iwl_mld_tx_gp2_host_us(), + jiffies, &refresh); + + if (refresh) + wiphy_delayed_work_queue(mld->wiphy, &mld->tx_gp2.wk, 0); + + return gp2; +} + +static void iwl_mld_tx_gp2_refresh(struct iwl_mld *mld) +{ + unsigned long valid_until, delay; + u32 gp2, host_us; + + lockdep_assert_wiphy(mld->wiphy); + + if (!mld->fw_status.running) + return; + +#ifdef CONFIG_PM_SLEEP + if (mld->fw_status.in_d3) + return; +#endif + + if (iwl_mld_get_systime(mld, &gp2)) + goto retry; + + host_us = iwl_mld_tx_gp2_host_us(); + valid_until = jiffies + IWL_MLD_TX_GP2_VALID_PERIOD; + + /* Keep arithmetic in u32 to match firmware wraparound semantics. */ + atomic_set(&mld->tx_gp2.delta_us, gp2 - host_us); + atomic_long_set_release(&mld->tx_gp2.valid_until, valid_until ?: 1); + + IWL_DEBUG_TX(mld, "gp2 sync: gp2=%u host_us=%u delta_us=%u\n", + gp2, host_us, gp2 - host_us); + return; + +retry: + /* Stop new TX readers from requesting immediate retries. */ + atomic_long_set(&mld->tx_gp2.valid_until, 0); + delay = round_jiffies_relative(IWL_MLD_TX_GP2_RETRY_PERIOD); + wiphy_delayed_work_queue(mld->wiphy, &mld->tx_gp2.wk, delay); +} + +static void iwl_mld_tx_gp2_wk(struct wiphy *wiphy, struct wiphy_work *wk) +{ + struct iwl_mld *mld = container_of(wk, struct iwl_mld, tx_gp2.wk.work); + unsigned long valid_until = atomic_long_read(&mld->tx_gp2.valid_until); + + /* TX may have queued this work using an older estimate. */ + if (valid_until && + time_before(jiffies, valid_until - IWL_MLD_TX_GP2_REFRESH_MARGIN)) + return; + + iwl_mld_tx_gp2_refresh(mld); +} + +void iwl_mld_tx_gp2_init(struct iwl_mld *mld) +{ + atomic_set(&mld->tx_gp2.delta_us, 0); + atomic_long_set(&mld->tx_gp2.valid_until, 0); + wiphy_delayed_work_init(&mld->tx_gp2.wk, iwl_mld_tx_gp2_wk); +} + +void iwl_mld_tx_gp2_start(struct iwl_mld *mld) +{ + lockdep_assert_wiphy(mld->wiphy); + + if (iwl_fw_lookup_cmd_ver(mld->fw, TX_CMD, 0) < 12) + return; + + iwl_mld_tx_gp2_refresh(mld); +} + +/* TX is quiesced before stopping the refresh work. */ +void iwl_mld_tx_gp2_stop(struct iwl_mld *mld) +{ + lockdep_assert_wiphy(mld->wiphy); + + if (iwl_fw_lookup_cmd_ver(mld->fw, TX_CMD, 0) < 12) + return; + + wiphy_delayed_work_cancel(mld->wiphy, &mld->tx_gp2.wk); + + atomic_long_set(&mld->tx_gp2.valid_until, 0); +} + /* Toggles between TX antennas. Receives the bitmask of valid TX antennas and * the *index* used for the last TX, and returns the next valid *index* to use. * In order to set it in the tx_cmd, must do BIT(idx). @@ -588,6 +716,9 @@ iwl_mld_fill_tx_cmd(struct iwl_mld *mld, struct sk_buff *skb, tx_cmd->flags = cpu_to_le16(flags); tx_cmd->rate_n_flags = rate_n_flags; + + tx_cmd->driver_timestamp = + cpu_to_le32(iwl_mld_tx_gp2_timestamp(mld)); } /* Caller of this need to check that info->control.vif is not NULL */ @@ -1353,6 +1484,10 @@ int iwl_mld_update_sta_txqs(struct iwl_mld *mld, lockdep_assert_wiphy(mld->wiphy); + if (mld->trans->conf.queue_alloc_cmd_ver >= 4) + cmd.u.modify.flags = + cpu_to_le16(IWL_SCD_QUEUE_MODIFY_FLAG_STA_MSK); + for (int tid = 0; tid <= IWL_MAX_TID_COUNT; tid++) { struct ieee80211_txq *txq = sta->txq[tid != IWL_MAX_TID_COUNT ? diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.h b/drivers/net/wireless/intel/iwlwifi/mld/tx.h index 520f15f9d33c..a376e8c9c500 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/tx.h +++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.h @@ -1,11 +1,15 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2024 Intel Corporation + * Copyright (C) 2024, 2026 Intel Corporation */ #ifndef __iwl_mld_tx_h__ #define __iwl_mld_tx_h__ -#include "mld.h" +#include +#include + +struct iwl_mld; +struct iwl_rx_packet; #define IWL_MLD_INVALID_QUEUE 0xFFFF #define IWL_MLD_INVALID_DROP_TX 0xFFFE @@ -74,4 +78,37 @@ u8 iwl_mld_get_lowest_rate(struct iwl_mld *mld, void iwl_mld_tx_skb(struct iwl_mld *mld, struct sk_buff *skb, struct ieee80211_txq *txq); +/** + * struct iwl_mld_tx_gp2 - gp2 timestamping state for TX commands + * + * Reading gp2 directly in the TX path is too costly. Instead, TX lazily + * schedules @wk to refresh gp2 in process context and adds @delta_us to the + * host clock to timestamp queued frames. + * + * A zero @valid_until leaves frames unstamped, including on older firmware + * without TX_CMD v12. A deadline that wraps to zero is published as one. + * Failed refreshes clear @valid_until, leaving @delta_us for old readers, and + * schedule a retry with %IWL_MLD_TX_GP2_RETRY_PERIOD rounded for timer + * coalescing, even without further TX traffic. Old readers may retry sooner. + * + * @delta_us: gp2 minus host time, in microseconds, modulo 2^32; + * valid while @valid_until is nonzero and has not expired + * @valid_until: jiffies deadline for the offset, or zero when disabled + * @wk: worker that refreshes the offset and retries failures + */ +struct iwl_mld_tx_gp2 { + atomic_t delta_us; + atomic_long_t valid_until; + struct wiphy_delayed_work wk; +}; + +void iwl_mld_tx_gp2_init(struct iwl_mld *mld); +void iwl_mld_tx_gp2_start(struct iwl_mld *mld); +void iwl_mld_tx_gp2_stop(struct iwl_mld *mld); + +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +u32 iwl_mld_tx_gp2_from_est(u32 delta_us, unsigned long valid_until, + u32 host_us, unsigned long now, bool *refresh); +#endif + #endif /* __iwl_mld_tx_h__ */ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index bd52f2ebd3ba..2abc4bc3eb34 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2440,6 +2440,12 @@ struct iwl_mvm_nd_results { u8 matches[ND_QUERY_BUF_LEN]; }; +static bool iwl_mvm_nd_match_info_v3(struct iwl_mvm *mvm) +{ + return iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + SCAN_OFFLOAD_PROFILES_QUERY_CMD, 0) >= 4; +} + static int iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, struct iwl_mvm_nd_results *results) @@ -2459,12 +2465,17 @@ iwl_mvm_netdetect_query_results(struct iwl_mvm *mvm, return ret; } - if (fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + if (iwl_mvm_nd_match_info_v3(mvm)) { matches_len = sizeof(struct iwl_scan_offload_profile_match) * max_profiles; query_len = offsetof(struct iwl_scan_offload_match_info, matches) + matches_len; + } else if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + matches_len = sizeof(struct iwl_scan_offload_profile_match_v2) * + max_profiles; + query_len = offsetof(struct iwl_scan_offload_match_info, + matches) + matches_len; } else { matches_len = sizeof(struct iwl_scan_offload_profile_match_v1) * max_profiles; @@ -2499,13 +2510,19 @@ static int iwl_mvm_query_num_match_chans(struct iwl_mvm *mvm, { int n_chans = 0, i; - if (fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + if (iwl_mvm_nd_match_info_v3(mvm)) { struct iwl_scan_offload_profile_match *matches = (void *)results->matches; for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN; i++) n_chans += hweight8(matches[idx].matching_channels[i]); + } else if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + struct iwl_scan_offload_profile_match_v2 *matches = + (void *)results->matches; + + for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V2; i++) + n_chans += hweight8(matches[idx].matching_channels[i]); } else { struct iwl_scan_offload_profile_match_v1 *matches = (void *)results->matches; @@ -2517,34 +2534,58 @@ static int iwl_mvm_query_num_match_chans(struct iwl_mvm *mvm, return n_chans; } +static void iwl_mvm_set_matching_freqs(struct iwl_mvm *mvm, + const u8 *matching_channels, + size_t num_bytes, + struct cfg80211_wowlan_nd_match *match) +{ + int n_channels = 0; + + for (int i = 0; i < num_bytes * 8; i++) { + if (!(matching_channels[i / 8] & BIT(i % 8))) + continue; + if (IWL_FW_CHECK(mvm, i >= mvm->n_nd_channels, + "FW matched channel bit %d beyond n_nd_channels %d\n", + i, mvm->n_nd_channels)) + break; + match->channels[n_channels++] = + mvm->nd_channels[i]->center_freq; + } + /* We may have ended up with fewer channels than we allocated. */ + match->n_channels = n_channels; +} + static void iwl_mvm_query_set_freqs(struct iwl_mvm *mvm, struct iwl_mvm_nd_results *results, struct cfg80211_wowlan_nd_match *match, int idx) { - int i; - int n_channels = 0; - - if (fw_has_api(&mvm->fw->ucode_capa, - IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + if (iwl_mvm_nd_match_info_v3(mvm)) { struct iwl_scan_offload_profile_match *matches = (void *)results->matches; - for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN * 8; i++) - if (matches[idx].matching_channels[i / 8] & (BIT(i % 8))) - match->channels[n_channels++] = - mvm->nd_channels[i]->center_freq; + iwl_mvm_set_matching_freqs(mvm, + matches[idx].matching_channels, + sizeof(matches[idx].matching_channels), + match); + } else if (fw_has_api(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_API_SCAN_OFFLOAD_CHANS)) { + struct iwl_scan_offload_profile_match_v2 *matches = + (void *)results->matches; + + iwl_mvm_set_matching_freqs(mvm, + matches[idx].matching_channels, + sizeof(matches[idx].matching_channels), + match); } else { struct iwl_scan_offload_profile_match_v1 *matches = (void *)results->matches; - for (i = 0; i < SCAN_OFFLOAD_MATCHING_CHANNELS_LEN_V1 * 8; i++) - if (matches[idx].matching_channels[i / 8] & (BIT(i % 8))) - match->channels[n_channels++] = - mvm->nd_channels[i]->center_freq; + iwl_mvm_set_matching_freqs(mvm, + matches[idx].matching_channels, + sizeof(matches[idx].matching_channels), + match); } - /* We may have ended up with fewer channels than we allocated. */ - match->n_channels = n_channels; } /** @@ -2817,8 +2858,14 @@ static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm, struct iwl_wowlan_status_data *status = d3_data->status; struct ieee80211_vif *vif = iwl_mvm_get_bss_vif(mvm); struct iwl_mvm_nd_results *results = d3_data->nd_results; - size_t i, matches_len = sizeof(struct iwl_scan_offload_profile_match) * - iwl_umac_scan_get_max_profiles(mvm->fw); + size_t i, matches_len; + + if (iwl_mvm_nd_match_info_v3(mvm)) + matches_len = sizeof(struct iwl_scan_offload_profile_match) * + iwl_umac_scan_get_max_profiles(mvm->fw); + else + matches_len = sizeof(struct iwl_scan_offload_profile_match_v2) * + iwl_umac_scan_get_max_profiles(mvm->fw); if (IS_ERR_OR_NULL(vif)) return; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c index e6b9896dc4ac..90175307a7db 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c @@ -13,7 +13,7 @@ #include "mvm.h" #include "sta.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "debugfs.h" #include "iwl-modparams.h" #include "iwl-drv.h" @@ -153,72 +153,6 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, return ret; } -static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - const struct fw_img *img; - unsigned int ofs, len; - size_t ret; - u8 *ptr; - - if (!iwl_mvm_firmware_running(mvm)) - return -EINVAL; - - /* default is to dump the entire data segment */ - img = &mvm->fw->img[mvm->fwrt.cur_fw_img]; - ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; - len = img->sec[IWL_UCODE_SECTION_DATA].len; - - if (mvm->dbgfs_sram_len) { - ofs = mvm->dbgfs_sram_offset; - len = mvm->dbgfs_sram_len; - } - - ptr = kzalloc(len, GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len); - - ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len); - - kfree(ptr); - - return ret; -} - -static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - const struct fw_img *img; - u32 offset, len; - u32 img_offset, img_len; - - if (!iwl_mvm_firmware_running(mvm)) - return -EINVAL; - - img = &mvm->fw->img[mvm->fwrt.cur_fw_img]; - img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset; - img_len = img->sec[IWL_UCODE_SECTION_DATA].len; - - if (sscanf(buf, "%x,%x", &offset, &len) == 2) { - if ((offset & 0x3) || (len & 0x3)) - return -EINVAL; - - if (offset + len > img_offset + img_len) - return -EINVAL; - - mvm->dbgfs_sram_offset = offset; - mvm->dbgfs_sram_len = len; - } else { - mvm->dbgfs_sram_offset = 0; - mvm->dbgfs_sram_len = 0; - } - - return count; -} - static ssize_t iwl_dbgfs_set_nic_temperature_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -591,16 +525,24 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file, if (ret < 0) return ret; + if (iwl_rx_packet_payload_len(hcmd.resp_pkt) != sizeof(*rsp)) { + iwl_free_resp(&hcmd); + return -EIO; + } + buff = kzalloc(bufsz, GFP_KERNEL); - if (!buff) + if (!buff) { + iwl_free_resp(&hcmd); return -ENOMEM; + } pos = buff; endpos = pos + bufsz; rsp = (void *)hcmd.resp_pkt->data; pos += scnprintf(pos, endpos - pos, "TAS Conclusion:\n"); - for (i = 0; i < rsp->in_dual_radio + 1; i++) { + for (i = 0; i < min_t(int, rsp->in_dual_radio + 1, + ARRAY_SIZE(rsp->tas_status_mac)); i++) { if (rsp->tas_status_mac[i].dynamic_status & BIT(TAS_DYNA_ACTIVE)) { pos += scnprintf(pos, endpos - pos, "\tON for "); @@ -655,7 +597,8 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file, "\tDo TAS Support Dual Radio?: %s\n", rsp->in_dual_radio ? "TRUE" : "FALSE"); - for (i = 0; i < rsp->in_dual_radio + 1; i++) { + for (i = 0; i < min_t(int, rsp->in_dual_radio + 1, + ARRAY_SIZE(rsp->tas_status_mac)); i++) { if (rsp->tas_status_mac[i].static_status == 0) { pos += scnprintf(pos, endpos - pos, "Static status: disabled\n"); @@ -1159,7 +1102,7 @@ static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, if (count == 6 && !strcmp(buf, "nolog\n")) set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); - iwl_force_nmi(mvm->trans); + iwl_trans_force_nmi(mvm->trans); return count; } @@ -1211,53 +1154,6 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf, return count; } -static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm, - char *buf, size_t count, - loff_t *ppos) -{ - struct iwl_rss_config_cmd cmd = { - .flags = cpu_to_le32(IWL_RSS_ENABLE), - .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP | - IWL_RSS_HASH_TYPE_IPV4_UDP | - IWL_RSS_HASH_TYPE_IPV4_PAYLOAD | - IWL_RSS_HASH_TYPE_IPV6_TCP | - IWL_RSS_HASH_TYPE_IPV6_UDP | - IWL_RSS_HASH_TYPE_IPV6_PAYLOAD, - }; - int ret, i, num_repeats, nbytes = count / 2; - - ret = hex2bin(cmd.indirection_table, buf, nbytes); - if (ret) - return ret; - - /* - * The input is the redirection table, partial or full. - * Repeat the pattern if needed. - * For example, input of 01020F will be repeated 42 times, - * indirecting RSS hash results to queues 1, 2, 15 (skipping - * queues 3 - 14). - */ - num_repeats = ARRAY_SIZE(cmd.indirection_table) / nbytes; - for (i = 1; i < num_repeats; i++) - memcpy(&cmd.indirection_table[i * nbytes], - cmd.indirection_table, nbytes); - /* handle cut in the middle pattern for the last places */ - memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table, - ARRAY_SIZE(cmd.indirection_table) % nbytes); - - netdev_rss_key_fill(cmd.secret_key, sizeof(cmd.secret_key)); - - mutex_lock(&mvm->mutex); - if (iwl_mvm_firmware_running(mvm)) - ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, - sizeof(cmd), &cmd); - else - ret = 0; - mutex_unlock(&mvm->mutex); - - return ret ?: count; -} - static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) @@ -1652,7 +1548,7 @@ iwl_dbgfs_prph_reg_read(struct file *file, pos += scnprintf(buf + pos, bufsz - pos, "Reg 0x%x: (0x%x)\n", mvm->dbgfs_prph_reg_addr, - iwl_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); + iwl_trans_read_prph(mvm->trans, mvm->dbgfs_prph_reg_addr)); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); } @@ -1673,7 +1569,7 @@ iwl_dbgfs_prph_reg_write(struct iwl_mvm *mvm, char *buf, if (args != 2) return -EINVAL; - iwl_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); + iwl_trans_write_prph(mvm->trans, mvm->dbgfs_prph_reg_addr, value); out: return count; @@ -1916,7 +1812,6 @@ MVM_DEBUGFS_WRITE_FILE_OPS(start_ctdp, 8); MVM_DEBUGFS_WRITE_FILE_OPS(force_ctkill, 8); MVM_DEBUGFS_WRITE_FILE_OPS(tx_flush, 16); MVM_DEBUGFS_WRITE_FILE_OPS(send_echo_cmd, 8); -MVM_DEBUGFS_READ_WRITE_FILE_OPS(sram, 64); MVM_DEBUGFS_READ_WRITE_FILE_OPS(set_nic_temperature, 64); MVM_DEBUGFS_READ_FILE_OPS(nic_temp); MVM_DEBUGFS_READ_FILE_OPS(stations); @@ -1933,8 +1828,6 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8); MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8); MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_clear, 64); MVM_DEBUGFS_WRITE_FILE_OPS(dbg_time_point, 64); -MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, - (IWL_RSS_INDIRECTION_TABLE_SIZE * 2)); MVM_DEBUGFS_WRITE_FILE_OPS(inject_packet, 512); MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie, 512); MVM_DEBUGFS_WRITE_FILE_OPS(inject_beacon_ie_restore, 512); @@ -2114,7 +2007,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) spin_lock_init(&mvm->drv_stats_lock); MVM_DEBUGFS_ADD_FILE(tx_flush, mvm->debugfs_dir, 0200); - MVM_DEBUGFS_ADD_FILE(sram, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(set_nic_temperature, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(nic_temp, mvm->debugfs_dir, 0400); MVM_DEBUGFS_ADD_FILE(ctdp_budget, mvm->debugfs_dir, 0400); @@ -2134,7 +2026,6 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) MVM_DEBUGFS_ADD_FILE(fw_dbg_clear, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(dbg_time_point, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, 0200); - MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(inject_packet, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(inject_beacon_ie, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(inject_beacon_ie_restore, mvm->debugfs_dir, 0200); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c index 8d7f60dcd027..dd1b80561f8c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ftm-initiator.c @@ -7,7 +7,7 @@ #include #include #include "mvm.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "constants.h" @@ -519,8 +519,9 @@ static int iwl_mvm_ftm_send_cmd(struct iwl_mvm *mvm, struct iwl_host_cmd *hcmd) return err; } -static int iwl_mvm_ftm_start_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *req) +static int noinline_for_stack +iwl_mvm_ftm_start_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd_v5 cmd_v5; struct iwl_host_cmd hcmd = { @@ -545,8 +546,9 @@ static int iwl_mvm_ftm_start_v5(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_ftm_send_cmd(mvm, &hcmd); } -static int iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *req) +static int noinline_for_stack +iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd_v7 cmd_v7; struct iwl_host_cmd hcmd = { @@ -575,8 +577,9 @@ static int iwl_mvm_ftm_start_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_ftm_send_cmd(mvm, &hcmd); } -static int iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *req) +static int noinline_for_stack +iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd_v8 cmd; struct iwl_host_cmd hcmd = { @@ -601,8 +604,10 @@ static int iwl_mvm_ftm_start_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return iwl_mvm_ftm_send_cmd(mvm, &hcmd); } -static int iwl_mvm_ftm_start_v9(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *req) + +static int noinline_for_stack +iwl_mvm_ftm_start_v9(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd_v9 cmd; struct iwl_host_cmd hcmd = { @@ -735,9 +740,10 @@ iwl_mvm_ftm_put_target_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, &target->initiator_ap_flags); } -static int iwl_mvm_ftm_start_v11(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *req) +static int noinline_for_stack +iwl_mvm_ftm_start_v11(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd_v11 cmd; struct iwl_host_cmd hcmd = { @@ -807,9 +813,10 @@ iwl_mvm_ftm_put_target_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } -static int iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *req) +static int noinline_for_stack +iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd_v12 cmd; struct iwl_host_cmd hcmd = { @@ -835,9 +842,10 @@ static int iwl_mvm_ftm_start_v12(struct iwl_mvm *mvm, return iwl_mvm_ftm_send_cmd(mvm, &hcmd); } -static int iwl_mvm_ftm_start_v13(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *req) +static int noinline_for_stack +iwl_mvm_ftm_start_v13(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd_v13 cmd; struct iwl_host_cmd hcmd = { @@ -951,9 +959,10 @@ iwl_mvm_ftm_put_target_v10(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return 0; } -static int iwl_mvm_ftm_start_v14(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, - struct cfg80211_pmsr_request *req) +static int noinline_for_stack +iwl_mvm_ftm_start_v14(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) { struct iwl_tof_range_req_cmd cmd; struct iwl_host_cmd hcmd = { diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 43a7230f1ab4..ae109e3ea141 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -263,7 +263,7 @@ static bool iwl_wait_phy_db_entry(struct iwl_notif_wait_data *notif_wait, static void iwl_mvm_print_pd_notification(struct iwl_mvm *mvm) { #define IWL_FW_PRINT_REG_INFO(reg_name) \ - IWL_ERR(mvm, #reg_name ": 0x%x\n", iwl_read_umac_prph(trans, reg_name)) + IWL_ERR(mvm, #reg_name ": 0x%x\n", iwl_trans_read_umac_prph(trans, reg_name)) struct iwl_trans *trans = mvm->trans; enum iwl_device_family device_family = trans->mac_cfg->device_family; @@ -332,13 +332,13 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, IWL_DEVICE_FAMILY_AX210) { /* print these registers regardless of alive fail/success */ IWL_INFO(mvm, "WFPM_UMAC_PD_NOTIFICATION: 0x%x\n", - iwl_read_umac_prph(mvm->trans, WFPM_ARC1_PD_NOTIFICATION)); + iwl_trans_read_umac_prph(mvm->trans, WFPM_ARC1_PD_NOTIFICATION)); IWL_INFO(mvm, "WFPM_LMAC2_PD_NOTIFICATION: 0x%x\n", - iwl_read_umac_prph(mvm->trans, WFPM_LMAC2_PD_NOTIFICATION)); + iwl_trans_read_umac_prph(mvm->trans, WFPM_LMAC2_PD_NOTIFICATION)); IWL_INFO(mvm, "WFPM_AUTH_KEY_0: 0x%x\n", - iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG)); + iwl_trans_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG)); IWL_INFO(mvm, "CNVI_SCU_SEQ_DATA_DW9: 0x%x\n", - iwl_read_prph(mvm->trans, CNVI_SCU_SEQ_DATA_DW9)); + iwl_trans_read_prph(mvm->trans, CNVI_SCU_SEQ_DATA_DW9)); } if (ret) { @@ -349,15 +349,15 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, IWL_DEVICE_FAMILY_22000) { IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", - iwl_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS), - iwl_read_umac_prph(trans, - UMAG_SB_CPU_2_STATUS)); + iwl_trans_read_umac_prph(trans, UMAG_SB_CPU_1_STATUS), + iwl_trans_read_umac_prph(trans, + UMAG_SB_CPU_2_STATUS)); } else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_8000) { IWL_ERR(mvm, "SecBoot CPU1 Status: 0x%x, CPU2 Status: 0x%x\n", - iwl_read_prph(trans, SB_CPU_1_STATUS), - iwl_read_prph(trans, SB_CPU_2_STATUS)); + iwl_trans_read_prph(trans, SB_CPU_1_STATUS), + iwl_trans_read_prph(trans, SB_CPU_2_STATUS)); } iwl_mvm_print_pd_notification(mvm); @@ -374,15 +374,15 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, } else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000) { IWL_ERR(mvm, "UMAC PC: 0x%x\n", - iwl_read_umac_prph(trans, - UREG_UMAC_CURRENT_PC)); + iwl_trans_read_umac_prph(trans, + UREG_UMAC_CURRENT_PC)); IWL_ERR(mvm, "LMAC PC: 0x%x\n", - iwl_read_umac_prph(trans, - UREG_LMAC1_CURRENT_PC)); + iwl_trans_read_umac_prph(trans, + UREG_LMAC1_CURRENT_PC)); if (iwl_mvm_is_cdb_supported(mvm)) IWL_ERR(mvm, "LMAC2 PC: 0x%x\n", - iwl_read_umac_prph(trans, - UREG_LMAC2_CURRENT_PC)); + iwl_trans_read_umac_prph(trans, + UREG_LMAC2_CURRENT_PC)); } if (ret == -ETIMEDOUT && !mvm->fw_product_reset) @@ -616,7 +616,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) mvm->rfkill_safe_init_done = false; if (mvm->trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_AX210) { - sb_cfg = iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG); + sb_cfg = iwl_trans_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG); /* if needed, we'll reset this on our way out later */ mvm->fw_product_reset = sb_cfg == SB_CFG_RESIDES_IN_ROM; if (mvm->fw_product_reset && iwl_mei_pldr_req()) @@ -640,8 +640,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) /* if we needed reset then fail here, but notify and remove */ if (mvm->fw_product_reset) { iwl_mei_alive_notif(false); - iwl_trans_pcie_reset(mvm->trans, - IWL_RESET_MODE_RESCAN); + iwl_trans_reset(mvm->trans, IWL_RESET_MODE_RESCAN); } goto error; @@ -911,7 +910,8 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) ret = iwl_sar_fill_profile(&mvm->fwrt, per_chain, IWL_NUM_CHAIN_TABLES, - n_subbands, prof_a, prof_b); + n_subbands, prof_a, prof_b, + mvm->fwrt.sar_profiles, false); /* return on error or if the profile is disabled (positive number) */ if (ret) @@ -1526,7 +1526,7 @@ static void iwl_mvm_send_lari_cfg_extension(struct iwl_mvm *mvm) u32 value; int ret; - if (iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) < 1) + if (iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) != 1) return; ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, &value); @@ -1576,7 +1576,7 @@ void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm) { int ret; - iwl_acpi_get_guid_lock_status(&mvm->fwrt); + iwl_bios_get_guid_lock_status(&mvm->fwrt); /* read PPAG table */ ret = iwl_bios_get_ppag_table(&mvm->fwrt); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/led.c b/drivers/net/wireless/intel/iwlwifi/mvm/led.c index c3cc1ea3ccc9..ac238c963855 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/led.c @@ -1,10 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2019, 2025 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2025-2026 Intel Corporation * Copyright (C) 2017 Intel Deutschland GmbH */ #include -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-csr.h" #include "mvm.h" @@ -38,8 +38,8 @@ static void iwl_mvm_led_set(struct iwl_mvm *mvm, bool on) return; } - iwl_write32(mvm->trans, CSR_LED_REG, - on ? CSR_LED_REG_TURN_ON : CSR_LED_REG_TURN_OFF); + iwl_trans_write32(mvm->trans, CSR_LED_REG, + on ? CSR_LED_REG_TURN_ON : CSR_LED_REG_TURN_OFF); } static void iwl_led_brightness_set(struct led_classdev *led_cdev, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c index b41b4bbf0049..18372ddcc0e0 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c @@ -7,7 +7,7 @@ #include #include #include -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "fw-api.h" #include "mvm.h" @@ -932,8 +932,8 @@ u16 iwl_mvm_mac_ctxt_get_beacon_flags(const struct iwl_fw *fw, u8 rate_idx) u16 flags = 0; if (rate_idx <= IWL_LAST_CCK_RATE) - flags |= is_new_rate ? IWL_MAC_BEACON_CCK - : IWL_MAC_BEACON_CCK_V1; + flags |= is_new_rate ? (u16)IWL_MAC_BEACON_CCK + : (u16)IWL_MAC_BEACON_CCK_V1; if (iwl_fw_lookup_cmd_ver(fw, TX_CMD, 0) > 8) flags |= iwl_mvm_rate_idx_to_fw_idx(fw, rate_idx); @@ -1109,8 +1109,8 @@ static int iwl_mvm_mac_ctxt_send_beacon_v9(struct iwl_mvm *mvm, if (iwl_mvm_enable_fils(mvm, vif, ctx)) { flags |= iwl_fw_lookup_cmd_ver(mvm->fw, BEACON_TEMPLATE_CMD, 0) > 10 ? - IWL_MAC_BEACON_FILS : - IWL_MAC_BEACON_FILS_V1; + (u16)IWL_MAC_BEACON_FILS : + (u16)IWL_MAC_BEACON_FILS_V1; beacon_cmd.short_ssid = cpu_to_le32(~crc32_le(~0, vif->cfg.ssid, vif->cfg.ssid_len)); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c index 5bd246e37943..daa05339e3fb 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c @@ -19,7 +19,7 @@ #include "iwl-drv.h" #include "iwl-op-mode.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "mvm.h" #include "sta.h" #include "time-event.h" @@ -5258,7 +5258,7 @@ iwl_mvm_switch_vif_chanctx_swap(struct iwl_mvm *mvm, out_restart: /* things keep failing, better restart the hw */ - iwl_force_nmi(mvm->trans); + iwl_trans_force_nmi(mvm->trans); return ret; } @@ -5294,7 +5294,7 @@ iwl_mvm_switch_vif_chanctx_reassign(struct iwl_mvm *mvm, out_restart: /* things keep failing, better restart the hw */ - iwl_force_nmi(mvm->trans); + iwl_trans_force_nmi(mvm->trans); return ret; } diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h index c64e4ed00986..ae2ee8771f16 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h @@ -42,7 +42,7 @@ #define IWL_MVM_MAX_ADDRESSES 5 /* RSSI offset for WkP */ #define IWL_RSSI_OFFSET 50 -#define IWL_MVM_MISSED_BEACONS_SINCE_RX_THOLD 4 +#define IWL_MVM_MISSED_BEACONS_SINCE_RX_THOLD 6 #define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 #define IWL_MVM_MISSED_BEACONS_THRESHOLD_LONG 19 @@ -1053,7 +1053,6 @@ struct iwl_mvm { */ struct dentry *debugfs_dir; #ifdef CONFIG_IWLWIFI_DEBUGFS - u32 dbgfs_sram_offset, dbgfs_sram_len; u32 dbgfs_prph_reg_addr; bool disable_power_off; bool disable_power_off_d3; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c index f76e57399c1f..54006d5e15a5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/nvm.c @@ -86,6 +86,7 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, .data = { &nvm_access_cmd, }, }; int ret, bytes_read, offset_read; + unsigned int pkt_len; u8 *resp_data; cmd.len[0] = sizeof(struct iwl_nvm_access_cmd); @@ -95,6 +96,12 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, return ret; pkt = cmd.resp_pkt; + pkt_len = iwl_rx_packet_payload_len(pkt); + if (pkt_len < sizeof(*nvm_resp)) { + IWL_ERR(mvm, "NVM ACCESS response too short: %u\n", pkt_len); + ret = -EINVAL; + goto exit; + } /* Extract NVM response */ nvm_resp = (void *)pkt->data; @@ -133,6 +140,14 @@ static int iwl_nvm_read_chunk(struct iwl_mvm *mvm, u16 section, goto exit; } + if (bytes_read > length || + pkt_len < struct_size(nvm_resp, data, bytes_read)) { + IWL_ERR(mvm, "NVM ACCESS response with invalid length %d\n", + bytes_read); + ret = -EINVAL; + goto exit; + } + /* Write data to NVM */ memcpy(data + offset, resp_data, bytes_read); ret = bytes_read; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c index 1dd27292af9b..183251457361 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ops.c @@ -20,7 +20,6 @@ #include "iwl-phy-db.h" #include "iwl-nvm-utils.h" #include "iwl-csr.h" -#include "iwl-io.h" #include "iwl-prph.h" #include "rs.h" #include "fw/api/scan.h" @@ -138,9 +137,9 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode) * to lose ownership and not being able to obtain it back. */ if (!mvm->trans->mac_cfg->base->apmg_not_supported) - iwl_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, - ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); + iwl_trans_set_bits_mask_prph(mvm->trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS, + ~APMG_PS_CTRL_EARLY_PWR_OFF_RESET_DIS); } static void iwl_mvm_rx_monitor_notif(struct iwl_mvm *mvm, @@ -374,7 +373,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { struct iwl_umac_scan_complete), RX_HANDLER(SCAN_ITERATION_COMPLETE_UMAC, iwl_mvm_rx_umac_scan_iter_complete_notif, RX_HANDLER_SYNC, - struct iwl_umac_scan_iter_complete_notif), + struct iwl_umac_scan_iter_complete_notif_v2), RX_HANDLER(MISSED_BEACONS_NOTIFICATION, iwl_mvm_rx_missed_beacons_notif_legacy, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c index 8c4009d3a00c..77a3d8dcab57 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c @@ -99,10 +99,14 @@ static int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb, u8 mic_crc_len = u8_get_bits(desc->mac_flags1, IWL_RX_MPDU_MFLG1_MIC_CRC_LEN_MASK) << 1; - if (desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD) { - len -= 2; - pad_len = 2; - } + pad_len = desc->mac_flags2 & IWL_RX_MPDU_MFLG2_PAD ? 2 : 0; + + if (IWL_FW_CHECK(mvm, len < hdrlen + crypt_len + pad_len + mic_crc_len, + "invalid len (%d): hdrlen=%u, crypt_len=%u, pad_len=%u, mic_crc_len=%u\n", + len, hdrlen, crypt_len, pad_len, mic_crc_len)) + return -EINVAL; + + len -= pad_len; /* * For non monitor interface strip the bytes the RADA might not have @@ -110,7 +114,7 @@ static int iwl_mvm_create_skb(struct iwl_mvm *mvm, struct sk_buff *skb, * interface cannot exist with other interfaces, this removal is safe * and sufficient, in monitor mode there's no decryption being done. */ - if (len > mic_crc_len && !ieee80211_hw_check(mvm->hw, RX_INCLUDES_FCS)) + if (!ieee80211_hw_check(mvm->hw, RX_INCLUDES_FCS)) len -= mic_crc_len; /* If frame is small enough to fit in skb->head, pull it completely. @@ -2164,7 +2168,17 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, phy_data.phy_info = le16_to_cpu(desc->phy_info); phy_data.d4 = desc->phy_data4; + if (IWL_FW_CHECK(mvm, len < sizeof(hdr->frame_control), + "MPDU len (%u) is smaller than frame control\n", + len)) + return; + hdr = (void *)(pkt->data + desc_size); + if (IWL_FW_CHECK(mvm, len < ieee80211_hdrlen(hdr->frame_control), + "MPDU len (%u) is smaller than header length (%u)\n", + len, ieee80211_hdrlen(hdr->frame_control))) + return; + /* Dont use dev_alloc_skb(), we'll have enough headroom once * ieee80211_hdr pulled. */ @@ -2285,7 +2299,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_fw_dbg_trigger_tlv *trig; struct ieee80211_vif *vif = mvmsta->vif; - if (!mvm->tcm.paused && len >= sizeof(*hdr) && + if (!mvm->tcm.paused && !is_multicast_ether_addr(hdr->addr1) && ieee80211_is_data(hdr->frame_control) && time_after(jiffies, mvm->tcm.ts + MVM_TCM_PERIOD)) @@ -2413,7 +2427,6 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_rx_no_data_ver_3 *desc = (void *)pkt->data; u32 rssi; - struct ieee80211_sta *sta = NULL; struct sk_buff *skb; struct iwl_mvm_rx_phy_data phy_data; u32 format; @@ -2527,9 +2540,7 @@ void iwl_mvm_rx_monitor_no_data(struct iwl_mvm *mvm, struct napi_struct *napi, RX_NO_DATA_RX_VEC2_EHT_NSTS_MSK) + 1; } - rcu_read_lock(); - ieee80211_rx_napi(mvm->hw, sta ? &sta->deflink : NULL, skb, napi); - rcu_read_unlock(); + ieee80211_rx_napi(mvm->hw, NULL, skb, napi); } void iwl_mvm_rx_frame_release(struct iwl_mvm *mvm, struct napi_struct *napi, diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c index 3831b3c27e0f..c12eda75317d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/scan.c @@ -10,7 +10,7 @@ #include "mvm.h" #include "fw/api/scan.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-utils.h" #define IWL_DENSE_EBS_SCAN_RATIO 5 @@ -2703,7 +2703,7 @@ void iwl_mvm_scan_timeout_wk(struct work_struct *work) IWL_ERR(mvm, "regular scan timed out\n"); - iwl_force_nmi(mvm->trans); + iwl_trans_force_nmi(mvm->trans); } static void iwl_mvm_fill_scan_type(struct iwl_mvm *mvm, @@ -3282,7 +3282,7 @@ void iwl_mvm_rx_umac_scan_iter_complete_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_umac_scan_iter_complete_notif *notif = (void *)pkt->data; + struct iwl_umac_scan_iter_complete_notif_v2 *notif = (void *)pkt->data; mvm->scan_start = le64_to_cpu(notif->start_tsf); diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 2d0811be7346..a66128a62546 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2015, 2018-2025 Intel Corporation + * Copyright (C) 2012-2015, 2018-2026 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -2792,7 +2792,11 @@ static int iwl_mvm_fw_baid_op_sta(struct iwl_mvm *mvm, if (WARN_ON(start && iwl_mvm_has_new_rx_api(mvm) && !(status & IWL_ADD_STA_BAID_VALID_MASK))) return -EINVAL; - return u32_get_bits(status, IWL_ADD_STA_BAID_MASK); + ret = u32_get_bits(status, IWL_ADD_STA_BAID_MASK); + if (IWL_FW_CHECK(mvm, start && ret >= ARRAY_SIZE(mvm->baid_map), + "invalid BAID %d from FW\n", ret)) + return -EINVAL; + return ret; case ADD_STA_IMMEDIATE_BA_FAILURE: IWL_WARN(mvm, "RX BA Session refused by fw\n"); return -ENOSPC; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c index a7cd2e4ba1ae..6aac71cfccb3 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/tdls.c @@ -2,12 +2,12 @@ /* * Copyright (C) 2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020, 2022-2025 Intel Corporation + * Copyright (C) 2018-2020, 2022-2026 Intel Corporation */ #include #include "mvm.h" #include "time-event.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #define TU_TO_US(x) (x * 1024) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c index 93b46c9e2333..5a800d3f2a98 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/time-event.c @@ -12,7 +12,6 @@ #include "fw-api.h" #include "time-event.h" #include "mvm.h" -#include "iwl-io.h" #include "iwl-prph.h" /* diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c index 2fd4a9961145..b2f34d1f2c48 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/utils.c @@ -7,7 +7,7 @@ #include #include "iwl-debug.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-prph.h" #include "iwl-csr.h" #include "mvm.h" @@ -1159,7 +1159,7 @@ u32 iwl_mvm_get_systime(struct iwl_mvm *mvm) mvm->trans->mac_cfg->base->gp2_reg_addr) reg_addr = mvm->trans->mac_cfg->base->gp2_reg_addr; - return iwl_read_prph(mvm->trans, reg_addr); + return iwl_trans_read_prph(mvm->trans, reg_addr); } void iwl_mvm_get_sync_time(struct iwl_mvm *mvm, int clock_type, @@ -1356,8 +1356,8 @@ __le32 iwl_mvm_v3_rate_to_fw(u32 rate, u8 rate_ver) case RATE_MCS_MOD_TYPE_VHT: result = RATE_MCS_VHT_MSK_V1; result |= u32_encode_bits(u32_get_bits(rate, - RATE_VHT_MCS_NSS_MSK), - RATE_MCS_CODE_MSK); + RATE_MCS_CODE_MSK), + RATE_VHT_MCS_RATE_CODE_MSK); result |= u32_encode_bits(u32_get_bits(rate, RATE_MCS_NSS_MSK), RATE_VHT_MCS_NSS_MSK); break; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-v2.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-v2.c index 06be929a3ca5..0009a05511af 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-v2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info-v2.c @@ -1,12 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2018-2025 Intel Corporation + * Copyright (C) 2018-2026 Intel Corporation */ #include #include "iwl-trans.h" #include "iwl-fh.h" #include "iwl-context-info-v2.h" -#include "gen1_2/internal.h" +#include "internal.h" +#include "pcie/utils.h" #include "iwl-prph.h" static const struct dmi_system_id dmi_force_scu_active_approved_list[] = { @@ -112,6 +113,14 @@ int iwl_pcie_ctxt_info_v2_alloc(struct iwl_trans *trans, int cmdq_size = max_t(u32, IWL_CMD_QUEUE_SIZE, trans->mac_cfg->base->min_txq_size); + if (WARN_ON_ONCE(trans_pcie->ctxt_info_v2 || trans_pcie->prph_info || + trans_pcie->prph_scratch || trans_pcie->iml || + trans_pcie->ctxt_info_dma_addr || + trans_pcie->prph_info_dma_addr || + trans_pcie->prph_scratch_dma_addr || + trans_pcie->iml_dma_addr || trans_pcie->iml_len)) + return -EBUSY; + switch (trans->conf.rx_buf_size) { case IWL_AMSDU_DEF: return -EINVAL; @@ -263,7 +272,6 @@ int iwl_pcie_ctxt_info_v2_alloc(struct iwl_trans *trans, trans_pcie->prph_scratch = prph_scratch; /* Allocate IML */ - trans_pcie->iml_len = fw->iml_len; trans_pcie->iml = dma_alloc_coherent(trans->dev, fw->iml_len, &trans_pcie->iml_dma_addr, GFP_KERNEL); @@ -271,6 +279,7 @@ int iwl_pcie_ctxt_info_v2_alloc(struct iwl_trans *trans, ret = -ENOMEM; goto err_free_ctxt_info; } + trans_pcie->iml_len = fw->iml_len; memcpy(trans_pcie->iml, fw->iml, fw->iml_len); @@ -280,16 +289,21 @@ int iwl_pcie_ctxt_info_v2_alloc(struct iwl_trans *trans, dma_free_coherent(trans->dev, sizeof(*trans_pcie->ctxt_info_v2), trans_pcie->ctxt_info_v2, trans_pcie->ctxt_info_dma_addr); + trans_pcie->ctxt_info_dma_addr = 0; trans_pcie->ctxt_info_v2 = NULL; err_free_prph_info: dma_free_coherent(trans->dev, PAGE_SIZE, prph_info, trans_pcie->prph_info_dma_addr); + trans_pcie->prph_info_dma_addr = 0; + trans_pcie->prph_info = NULL; err_free_prph_scratch: dma_free_coherent(trans->dev, sizeof(*prph_scratch), prph_scratch, trans_pcie->prph_scratch_dma_addr); + trans_pcie->prph_scratch_dma_addr = 0; + trans_pcie->prph_scratch = NULL; return ret; } @@ -301,12 +315,12 @@ void iwl_pcie_ctxt_info_v2_kick(struct iwl_trans *trans) iwl_enable_fw_load_int_ctx_info(trans, trans->do_top_reset); /* kick FW self load */ - iwl_write64(trans, CSR_CTXT_INFO_ADDR, trans_pcie->ctxt_info_dma_addr); - iwl_write64(trans, CSR_IML_DATA_ADDR, trans_pcie->iml_dma_addr); - iwl_write32(trans, CSR_IML_SIZE_ADDR, trans_pcie->iml_len); + iwl_pcie_write64(trans, CSR_CTXT_INFO_ADDR, trans_pcie->ctxt_info_dma_addr); + iwl_pcie_write64(trans, CSR_IML_DATA_ADDR, trans_pcie->iml_dma_addr); + iwl_trans_pcie_write32(trans, CSR_IML_SIZE_ADDR, trans_pcie->iml_len); - iwl_set_bit(trans, CSR_CTXT_INFO_BOOT_CTRL, - CSR_AUTO_FUNC_BOOT_ENA); + iwl_trans_set_bit(trans, CSR_CTXT_INFO_BOOT_CTRL, + CSR_AUTO_FUNC_BOOT_ENA); } void iwl_pcie_ctxt_info_v2_free(struct iwl_trans *trans, bool alive) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c index 7f886200d693..bc90a2714251 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/ctxt-info.c @@ -6,7 +6,8 @@ #include "iwl-trans.h" #include "iwl-fh.h" #include "iwl-context-info.h" -#include "gen1_2/internal.h" +#include "internal.h" +#include "utils.h" #include "iwl-prph.h" static void *_iwl_pcie_ctxt_info_dma_alloc_coherent(struct iwl_trans *trans, @@ -245,7 +246,7 @@ int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, iwl_pcie_apply_destination(trans); /* kick FW self load */ - iwl_write64(trans, CSR_CTXT_INFO_BA, trans_pcie->ctxt_info_dma_addr); + iwl_pcie_write64(trans, CSR_CTXT_INFO_BA, trans_pcie->ctxt_info_dma_addr); /* Context info will be released upon alive or failure to get one */ diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index a3e6c9e09a3b..24012005ccb8 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -15,7 +15,7 @@ #include "iwl-trans.h" #include "iwl-drv.h" #include "iwl-prph.h" -#include "gen1_2/internal.h" +#include "internal.h" #define _IS_A(cfg, _struct) __builtin_types_compatible_p(typeof(cfg), \ struct _struct) @@ -1018,6 +1018,7 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { /* GF RF */ IWL_DEV_INFO(iwl_rf_gf, iwl_ax211_name, RF_TYPE(GF)), IWL_DEV_INFO(iwl_rf_ot, iwl_ax231_name, RF_TYPE(GF), SUBDEV(0x0294)), + IWL_DEV_INFO(iwl_rf_ot, iwl_ax231_name, RF_TYPE(GF), SUBDEV(0x4294)), IWL_DEV_INFO(iwl_rf_gf, iwl_ax411_name, RF_TYPE(GF), CDB), IWL_DEV_INFO(iwl_rf_gf, iwl_ax210_name, DEVICE(0x2725)), @@ -1187,17 +1188,22 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return -EIO; } - return iwl_pci_gen1_2_probe(pdev, ent, mac_cfg, hw_base, hw_rev); + return _iwl_pci_probe(pdev, ent, mac_cfg, hw_base, hw_rev); } static void iwl_pci_remove(struct pci_dev *pdev) { struct iwl_trans *trans = pci_get_drvdata(pdev); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); if (!trans) return; - iwl_pcie_gen1_2_remove(trans); + cancel_delayed_work_sync(&trans_pcie->me_recheck_wk); + + iwl_drv_stop(trans->drv); + + iwl_trans_pcie_free(trans); } #ifdef CONFIG_PM_SLEEP @@ -1246,7 +1252,7 @@ static int _iwl_pci_resume(struct device *device, bool restore) * For older devices, just try silently to grab the NIC. */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - u32 scratch = iwl_read32(trans, CSR_FUNC_SCRATCH); + u32 scratch = iwl_trans_pcie_read32(trans, CSR_FUNC_SCRATCH); if (!(scratch & CSR_FUNC_SCRATCH_POWER_OFF_MASK) || scratch == ~0U) { diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h similarity index 92% rename from drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h rename to drivers/net/wireless/intel/iwlwifi/pcie/internal.h index d84c7c1efee1..01bfc1492c84 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -18,11 +18,21 @@ #include "iwl-fh.h" #include "iwl-csr.h" #include "iwl-trans.h" +#include "iwl-devtrace.h" #include "iwl-debug.h" -#include "iwl-io.h" #include "iwl-op-mode.h" #include "iwl-drv.h" -#include "pcie/iwl-context-info.h" +#include "iwl-context-info.h" + +/* transport-specific register accessors (bus implementation) */ +void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val); +void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val); +u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs); +u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg); +void iwl_pcie_write_prph_no_grab(struct iwl_trans *trans, u32 addr, u32 val); + +/* bus-specific transport operations table */ +extern const struct iwl_trans_ops iwl_trans_pcie_ops; /* * RX related structures and functions @@ -206,23 +216,6 @@ static inline u16 iwl_get_closed_rb_stts(struct iwl_trans *trans, } } -#ifdef CONFIG_IWLWIFI_DEBUGFS -/** - * enum iwl_fw_mon_dbgfs_state - the different states of the monitor_data - * debugfs file - * - * @IWL_FW_MON_DBGFS_STATE_CLOSED: the file is closed. - * @IWL_FW_MON_DBGFS_STATE_OPEN: the file is open. - * @IWL_FW_MON_DBGFS_STATE_DISABLED: the file is disabled, once this state is - * set the file can no longer be used. - */ -enum iwl_fw_mon_dbgfs_state { - IWL_FW_MON_DBGFS_STATE_CLOSED, - IWL_FW_MON_DBGFS_STATE_OPEN, - IWL_FW_MON_DBGFS_STATE_DISABLED, -}; -#endif - /** * enum iwl_shared_irq_flags - level of sharing for irq * @IWL_SHARED_IRQ_NON_RX: interrupt vector serves non rx causes. @@ -245,26 +238,6 @@ enum iwl_image_response_code { IWL_IMAGE_RESP_FAIL = 2, }; -#ifdef CONFIG_IWLWIFI_DEBUGFS -/** - * struct cont_rec: continuous recording data structure - * @prev_wr_ptr: the last address that was read in monitor_data - * debugfs file - * @prev_wrap_cnt: the wrap count that was used during the last read in - * monitor_data debugfs file - * @state: the state of monitor_data debugfs file as described - * in &iwl_fw_mon_dbgfs_state enum - * @mutex: locked while reading from monitor_data debugfs file - */ -struct cont_rec { - u32 prev_wr_ptr; - u32 prev_wrap_cnt; - u8 state; - /* Used to sync monitor_data debugfs file with driver unload flow */ - struct mutex mutex; -}; -#endif - enum iwl_pcie_fw_reset_state { FW_RESET_IDLE, FW_RESET_REQUESTED, @@ -451,7 +424,6 @@ struct iwl_pcie_txqs { * @rx_buf_bytes: RX buffer (RB) size in bytes * @reg_lock: protect hw register access * @mutex: to protect stop_device / start_fw / start_hw - * @fw_mon_data: fw continuous recording data * @cmd_hold_nic_awake: indicates NIC is held awake for APMG workaround * during commands in flight * @msix_entries: array of MSI-X entries @@ -577,10 +549,6 @@ struct iwl_trans_pcie { spinlock_t reg_lock; bool cmd_hold_nic_awake; -#ifdef CONFIG_IWLWIFI_DEBUGFS - struct cont_rec fw_mon_data; -#endif - struct msix_entry msix_entries[IWL_MAX_RX_HW_QUEUES]; bool msix_enabled; u8 shared_vec_mask; @@ -635,7 +603,7 @@ static inline void iwl_pcie_clear_irq(struct iwl_trans *trans, int queue) * write 1 clear (W1C) register, meaning that it's being clear * by writing 1 to the bit. */ - iwl_write32(trans, CSR_MSIX_AUTOMASK_ST_AD, BIT(queue)); + iwl_trans_pcie_write32(trans, CSR_MSIX_AUTOMASK_ST_AD, BIT(queue)); } static inline struct iwl_trans * @@ -892,7 +860,7 @@ static inline u16 iwl_txq_gen1_tfd_tb_get_len(struct iwl_trans *trans, } static inline struct iwl_device_tx_cmd * -iwl_pcie_gen1_2_alloc_tx_cmd(struct iwl_trans *trans) +iwl_pcie_alloc_tx_cmd(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -900,8 +868,8 @@ iwl_pcie_gen1_2_alloc_tx_cmd(struct iwl_trans *trans) } static inline void -iwl_pcie_gen1_2_free_tx_cmd(struct iwl_trans *trans, - struct iwl_device_tx_cmd *dev_cmd) +iwl_pcie_free_tx_cmd(struct iwl_trans *trans, + struct iwl_device_tx_cmd *dev_cmd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -931,18 +899,18 @@ static inline void _iwl_disable_interrupts(struct iwl_trans *trans) clear_bit(STATUS_INT_ENABLED, &trans->status); if (!trans_pcie->msix_enabled) { /* disable interrupts from uCode/NIC to host */ - iwl_write32(trans, CSR_INT_MASK, 0x00000000); + iwl_trans_pcie_write32(trans, CSR_INT_MASK, 0x00000000); /* acknowledge/clear/reset any interrupts still pending * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(trans, CSR_INT, 0xffffffff); - iwl_write32(trans, CSR_FH_INT_STATUS, 0xffffffff); + iwl_trans_pcie_write32(trans, CSR_INT, 0xffffffff); + iwl_trans_pcie_write32(trans, CSR_FH_INT_STATUS, 0xffffffff); } else { /* disable all the interrupt we might use */ - iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, - trans_pcie->fh_init_mask); - iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, - trans_pcie->hw_init_mask); + iwl_trans_pcie_write32(trans, CSR_MSIX_FH_INT_MASK_AD, + trans_pcie->fh_init_mask); + iwl_trans_pcie_write32(trans, CSR_MSIX_HW_INT_MASK_AD, + trans_pcie->hw_init_mask); trans_pcie->fh_mask = 0; trans_pcie->hw_mask = 0; } @@ -1000,7 +968,7 @@ static inline void _iwl_enable_interrupts(struct iwl_trans *trans) set_bit(STATUS_INT_ENABLED, &trans->status); if (!trans_pcie->msix_enabled) { trans_pcie->inta_mask = CSR_INI_SET_MASK; - iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + iwl_trans_pcie_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); } else { /* * fh/hw_mask keeps all the unmasked causes. @@ -1008,10 +976,10 @@ static inline void _iwl_enable_interrupts(struct iwl_trans *trans) */ trans_pcie->hw_mask = trans_pcie->hw_init_mask; trans_pcie->fh_mask = trans_pcie->fh_init_mask; - iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, - ~trans_pcie->fh_mask); - iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, - ~trans_pcie->hw_mask); + iwl_trans_pcie_write32(trans, CSR_MSIX_FH_INT_MASK_AD, + ~trans_pcie->fh_mask); + iwl_trans_pcie_write32(trans, CSR_MSIX_HW_INT_MASK_AD, + ~trans_pcie->hw_mask); } } @@ -1027,7 +995,7 @@ static inline void iwl_enable_hw_int_msk_msix(struct iwl_trans *trans, u32 msk) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, ~msk); + iwl_trans_pcie_write32(trans, CSR_MSIX_HW_INT_MASK_AD, ~msk); trans_pcie->hw_mask = msk; } @@ -1035,7 +1003,7 @@ static inline void iwl_enable_fh_int_msk_msix(struct iwl_trans *trans, u32 msk) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~msk); + iwl_trans_pcie_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~msk); trans_pcie->fh_mask = msk; } @@ -1046,10 +1014,10 @@ static inline void iwl_enable_fw_load_int(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Enabling FW load interrupt\n"); if (!trans_pcie->msix_enabled) { trans_pcie->inta_mask = CSR_INT_BIT_FH_TX; - iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + iwl_trans_pcie_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); } else { - iwl_write32(trans, CSR_MSIX_HW_INT_MASK_AD, - trans_pcie->hw_init_mask); + iwl_trans_pcie_write32(trans, CSR_MSIX_HW_INT_MASK_AD, + trans_pcie->hw_init_mask); iwl_enable_fh_int_msk_msix(trans, MSIX_FH_INT_CAUSES_D2S_CH0_NUM); } @@ -1076,7 +1044,7 @@ static inline void iwl_enable_fw_load_int_ctx_info(struct iwl_trans *trans, else trans_pcie->inta_mask = CSR_INT_BIT_ALIVE | CSR_INT_BIT_FH_RX; - iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + iwl_trans_pcie_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); } else { u32 val = top_reset ? MSIX_HW_INT_CAUSES_REG_RESET_DONE : MSIX_HW_INT_CAUSES_REG_ALIVE; @@ -1123,10 +1091,10 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n"); if (!trans_pcie->msix_enabled) { trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL; - iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); + iwl_trans_pcie_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); } else { - iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, - trans_pcie->fh_init_mask); + iwl_trans_pcie_write32(trans, CSR_MSIX_FH_INT_MASK_AD, + trans_pcie->fh_init_mask); trans_pcie->fh_mask = 0; iwl_enable_hw_int_msk_msix(trans, MSIX_HW_INT_CAUSES_REG_RF_KILL); @@ -1138,8 +1106,8 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) * when we power down the device we need set the bit to allow it * to wake up the PCI-E bus for RF-kill interrupts. */ - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_RFKILL_WAKE_L1A_EN); } } @@ -1154,7 +1122,7 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) if (trans_pcie->debug_rfkill == 1) return true; - return !(iwl_read32(trans, CSR_GP_CNTRL) & + return !(iwl_trans_pcie_read32(trans, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); } @@ -1167,7 +1135,6 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state, bool from_irq); #ifdef CONFIG_IWLWIFI_DEBUGFS void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans); -void iwl_trans_pcie_debugfs_cleanup(struct iwl_trans *trans); #else static inline void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) { } #endif @@ -1175,20 +1142,16 @@ static inline void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) { } void iwl_pcie_rx_allocator_work(struct work_struct *data); /* common trans ops for all generations transports */ -void iwl_pcie_gen1_2_op_mode_enter(struct iwl_trans *trans); +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); -void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val); -u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs); -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_read_mem_no_grab(struct iwl_trans *trans, u32 addr, void *buf, u32 dwords); int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership); +void iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans); struct iwl_trans_dump_data * iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask, const struct iwl_dump_sanitize_ops *sanitize_ops, @@ -1204,14 +1167,11 @@ int iwl_trans_pcie_read_config32(struct iwl_trans *trans, u32 ofs, u32 *val); bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans); -void __releases(nic_access_nobh) -iwl_trans_pcie_release_nic_access(struct iwl_trans *trans); +void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans); void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power); -int iwl_pci_gen1_2_probe(struct pci_dev *pdev, - const struct pci_device_id *ent, - const struct iwl_mac_cfg *mac_cfg, - u8 __iomem *hw_base, u32 hw_rev); -void iwl_pcie_gen1_2_remove(struct iwl_trans *trans); +int _iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent, + const struct iwl_mac_cfg *mac_cfg, + u8 __iomem *hw_base, u32 hw_rev); /* transport gen 1 exported functions */ void iwl_trans_pcie_fw_alive(struct iwl_trans *trans); @@ -1236,7 +1196,7 @@ int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr, size_t size); void iwl_pcie_free_dma_ptr(struct iwl_trans *trans, struct iwl_dma_ptr *ptr); void iwl_pcie_apply_destination(struct iwl_trans *trans); -int iwl_pcie_gen1_2_activate_nic(struct iwl_trans *trans); +int iwl_pcie_activate_nic(struct iwl_trans *trans); /* transport gen 2 exported functions */ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, @@ -1266,7 +1226,7 @@ static inline bool iwl_pcie_gen1_is_pm_supported(struct iwl_trans *trans) return trans_pcie->pm_support; } -static inline bool iwl_pcie_gen1_2_is_ltr_enabled(struct iwl_trans *trans) +static inline bool iwl_pcie_is_ltr_enabled(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info-v2.h b/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info-v2.h index 416baadc5017..a50e80cccadb 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info-v2.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info-v2.h @@ -1,327 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018, 2020-2025 Intel Corporation + * Copyright (C) 2018, 2020-2026 Intel Corporation */ #ifndef __iwl_context_info_file_v2_h__ #define __iwl_context_info_file_v2_h__ -#include "iwl-context-info.h" - -#define CSR_CTXT_INFO_BOOT_CTRL 0x0 -#define CSR_CTXT_INFO_ADDR 0x118 -#define CSR_IML_DATA_ADDR 0x120 -#define CSR_IML_SIZE_ADDR 0x128 -#define CSR_IML_RESP_ADDR 0x12c - -#define UNFRAGMENTED_PNVM_PAYLOADS_NUMBER 2 - -/* Set bit for enabling automatic function boot */ -#define CSR_AUTO_FUNC_BOOT_ENA BIT(1) -/* Set bit for initiating function boot */ -#define CSR_AUTO_FUNC_INIT BIT(7) - -/** - * enum iwl_prph_scratch_mtr_format - tfd size configuration - * @IWL_PRPH_MTR_FORMAT_16B: 16 bit tfd - * @IWL_PRPH_MTR_FORMAT_32B: 32 bit tfd - * @IWL_PRPH_MTR_FORMAT_64B: 64 bit tfd - * @IWL_PRPH_MTR_FORMAT_256B: 256 bit tfd - */ -enum iwl_prph_scratch_mtr_format { - IWL_PRPH_MTR_FORMAT_16B = 0x0, - IWL_PRPH_MTR_FORMAT_32B = 0x40000, - IWL_PRPH_MTR_FORMAT_64B = 0x80000, - IWL_PRPH_MTR_FORMAT_256B = 0xC0000, -}; - -/** - * enum iwl_prph_scratch_flags - PRPH scratch control flags - * @IWL_PRPH_SCRATCH_IMR_DEBUG_EN: IMR support for debug - * @IWL_PRPH_SCRATCH_EARLY_DEBUG_EN: enable early debug conf - * @IWL_PRPH_SCRATCH_EDBG_DEST_DRAM: use DRAM, with size allocated - * in hwm config. - * @IWL_PRPH_SCRATCH_EDBG_DEST_INTERNAL: use buffer on SRAM - * @IWL_PRPH_SCRATCH_EDBG_DEST_ST_ARBITER: use st arbiter, mainly for - * multicomm. - * @IWL_PRPH_SCRATCH_EDBG_DEST_TB22DTF: route debug data to SoC HW - * @IWL_PRPH_SCRATCH_RB_SIZE_4K: Use 4K RB size (the default is 2K) - * @IWL_PRPH_SCRATCH_MTR_MODE: format used for completion - 0: for - * completion descriptor, 1 for responses (legacy) - * @IWL_PRPH_SCRATCH_MTR_FORMAT: a mask for the size of the tfd. - * There are 4 optional values: 0: 16 bit, 1: 32 bit, 2: 64 bit, - * 3: 256 bit. - * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_MASK: RB size full information, ignored - * by older firmware versions, so set IWL_PRPH_SCRATCH_RB_SIZE_4K - * appropriately; use the below values for this. - * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_8K: 8kB RB size - * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_12K: 12kB RB size - * @IWL_PRPH_SCRATCH_RB_SIZE_EXT_16K: 16kB RB size - * @IWL_PRPH_SCRATCH_SCU_FORCE_ACTIVE: Indicate fw to set SCU_FORCE_ACTIVE - * upon reset. - * @IWL_PRPH_SCRATCH_TOP_RESET: request TOP reset - */ -enum iwl_prph_scratch_flags { - IWL_PRPH_SCRATCH_IMR_DEBUG_EN = BIT(1), - IWL_PRPH_SCRATCH_EARLY_DEBUG_EN = BIT(4), - IWL_PRPH_SCRATCH_EDBG_DEST_DRAM = BIT(8), - IWL_PRPH_SCRATCH_EDBG_DEST_INTERNAL = BIT(9), - IWL_PRPH_SCRATCH_EDBG_DEST_ST_ARBITER = BIT(10), - IWL_PRPH_SCRATCH_EDBG_DEST_TB22DTF = BIT(11), - IWL_PRPH_SCRATCH_RB_SIZE_4K = BIT(16), - IWL_PRPH_SCRATCH_MTR_MODE = BIT(17), - IWL_PRPH_SCRATCH_MTR_FORMAT = BIT(18) | BIT(19), - IWL_PRPH_SCRATCH_RB_SIZE_EXT_MASK = 0xf << 20, - IWL_PRPH_SCRATCH_RB_SIZE_EXT_8K = 8 << 20, - IWL_PRPH_SCRATCH_RB_SIZE_EXT_12K = 9 << 20, - IWL_PRPH_SCRATCH_RB_SIZE_EXT_16K = 10 << 20, - IWL_PRPH_SCRATCH_SCU_FORCE_ACTIVE = BIT(29), - IWL_PRPH_SCRATCH_TOP_RESET = BIT(30), -}; - -/** - * enum iwl_prph_scratch_ext_flags - PRPH scratch control ext flags - * @IWL_PRPH_SCRATCH_EXT_EXT_FSEQ: external FSEQ image provided - * @IWL_PRPH_SCRATCH_EXT_URM_FW: switch to URM mode based on fw setting - * @IWL_PRPH_SCRATCH_EXT_URM_PERM: switch to permanent URM mode - * @IWL_PRPH_SCRATCH_EXT_32KHZ_CLK_VALID: use external 32 KHz clock - */ -enum iwl_prph_scratch_ext_flags { - IWL_PRPH_SCRATCH_EXT_EXT_FSEQ = BIT(0), - IWL_PRPH_SCRATCH_EXT_URM_FW = BIT(4), - IWL_PRPH_SCRATCH_EXT_URM_PERM = BIT(5), - IWL_PRPH_SCRATCH_EXT_32KHZ_CLK_VALID = BIT(8), -}; - -/** - * struct iwl_prph_scratch_version - version structure - * @mac_id: SKU and revision id - * @version: prph scratch information version id - * @size: the size of the context information in DWs - * @reserved: reserved - */ -struct iwl_prph_scratch_version { - __le16 mac_id; - __le16 version; - __le16 size; - __le16 reserved; -} __packed; /* PERIPH_SCRATCH_VERSION_S */ - -/** - * struct iwl_prph_scratch_control - control structure - * @control_flags: context information flags see &enum iwl_prph_scratch_flags - * @control_flags_ext: context information for extended flags, - * see &enum iwl_prph_scratch_ext_flags - */ -struct iwl_prph_scratch_control { - __le32 control_flags; - __le32 control_flags_ext; -} __packed; /* PERIPH_SCRATCH_CONTROL_S */ - -/** - * struct iwl_prph_scratch_pnvm_cfg - PNVM scratch - * @pnvm_base_addr: PNVM start address - * @pnvm_size: the size of the PNVM image in bytes - * @reserved: reserved - */ -struct iwl_prph_scratch_pnvm_cfg { - __le64 pnvm_base_addr; - __le32 pnvm_size; - __le32 reserved; -} __packed; /* PERIPH_SCRATCH_PNVM_CFG_S */ - -/** - * struct iwl_prph_scratch_mem_desc_addr_array - DRAM - * @mem_descs: array of dram addresses. - * Each address is the beginning of a PNVM payload. - */ -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 */ - -/** - * struct iwl_prph_scratch_hwm_cfg - hwm config - * @hwm_base_addr: hwm start address - * @hwm_size: hwm size in DWs - * @debug_token_config: debug preset - */ -struct iwl_prph_scratch_hwm_cfg { - __le64 hwm_base_addr; - __le32 hwm_size; - __le32 debug_token_config; -} __packed; /* PERIPH_SCRATCH_HWM_CFG_S */ - -/** - * struct iwl_prph_scratch_rbd_cfg - RBDs configuration - * @free_rbd_addr: default queue free RB CB base address - * @reserved: reserved - */ -struct iwl_prph_scratch_rbd_cfg { - __le64 free_rbd_addr; - __le32 reserved; -} __packed; /* PERIPH_SCRATCH_RBD_CFG_S */ - -/** - * struct iwl_prph_scratch_uefi_cfg - prph scratch reduce power table - * @base_addr: reduce power table address - * @size: the size of the entire power table image - * @reserved: (reserved) - */ -struct iwl_prph_scratch_uefi_cfg { - __le64 base_addr; - __le32 size; - __le32 reserved; -} __packed; /* PERIPH_SCRATCH_UEFI_CFG_S */ - -/** - * struct iwl_prph_scratch_step_cfg - prph scratch step configuration - * @mbx_addr_0: [0:7] revision, - * [8:15] cnvi_to_cnvr length, - * [16:23] cnvr_to_cnvi channel length, - * [24:31] radio1 reserved - * @mbx_addr_1: [0:7] radio2 reserved - */ - -struct iwl_prph_scratch_step_cfg { - __le32 mbx_addr_0; - __le32 mbx_addr_1; -} __packed; - -/** - * struct iwl_prph_scratch_ctrl_cfg - prph scratch ctrl and config - * @version: version information of context info and HW - * @control: control flags of FH configurations - * @pnvm_cfg: ror configuration - * @hwm_cfg: hwm configuration - * @rbd_cfg: default RX queue configuration - * @reduce_power_cfg: UEFI power reduction table - * @step_cfg: step configuration - */ -struct iwl_prph_scratch_ctrl_cfg { - struct iwl_prph_scratch_version version; - struct iwl_prph_scratch_control control; - struct iwl_prph_scratch_pnvm_cfg pnvm_cfg; - struct iwl_prph_scratch_hwm_cfg hwm_cfg; - struct iwl_prph_scratch_rbd_cfg rbd_cfg; - struct iwl_prph_scratch_uefi_cfg reduce_power_cfg; - struct iwl_prph_scratch_step_cfg step_cfg; -} __packed; /* PERIPH_SCRATCH_CTRL_CFG_S */ - -#define IWL_NUM_DRAM_FSEQ_ENTRIES 8 - -/** - * struct iwl_context_info_dram_fseq - images DRAM map (with fseq) - * each entry in the map represents a DRAM chunk of up to 32 KB - * @common: UMAC/LMAC/virtual images - * @fseq_img: FSEQ image DRAM map - */ -struct iwl_context_info_dram_fseq { - struct iwl_context_info_dram_nonfseq common; - __le64 fseq_img[IWL_NUM_DRAM_FSEQ_ENTRIES]; -} __packed; /* PERIPH_SCRATCH_DRAM_MAP_S */ - -/** - * struct iwl_prph_scratch - peripheral scratch mapping - * @ctrl_cfg: control and configuration of prph scratch - * @dram: firmware images addresses in DRAM - * @fseq_override: FSEQ override parameters - * @step_analog_params: STEP analog calibration values - * @reserved: reserved - */ -struct iwl_prph_scratch { - struct iwl_prph_scratch_ctrl_cfg ctrl_cfg; - __le32 fseq_override; - __le32 step_analog_params; - __le32 reserved[8]; - struct iwl_context_info_dram_fseq dram; -} __packed; /* PERIPH_SCRATCH_S */ - -/** - * struct iwl_prph_info - peripheral information - * @boot_stage_mirror: reflects the value in the Boot Stage CSR register - * @ipc_status_mirror: reflects the value in the IPC Status CSR register - * @sleep_notif: indicates the peripheral sleep status - * @reserved: reserved - */ -struct iwl_prph_info { - __le32 boot_stage_mirror; - __le32 ipc_status_mirror; - __le32 sleep_notif; - __le32 reserved; -} __packed; /* PERIPH_INFO_S */ - -/** - * struct iwl_context_info_v2 - device INIT configuration - * @version: version of the context information - * @size: size of context information in DWs - * @config: context in which the peripheral would execute - a subset of - * capability csr register published by the peripheral - * @prph_info_base_addr: the peripheral information structure start address - * @cr_head_idx_arr_base_addr: the completion ring head index array - * start address - * @tr_tail_idx_arr_base_addr: the transfer ring tail index array - * start address - * @cr_tail_idx_arr_base_addr: the completion ring tail index array - * start address - * @tr_head_idx_arr_base_addr: the transfer ring head index array - * start address - * @cr_idx_arr_size: number of entries in the completion ring index array - * @tr_idx_arr_size: number of entries in the transfer ring index array - * @mtr_base_addr: the message transfer ring start address - * @mcr_base_addr: the message completion ring start address - * @mtr_size: number of entries which the message transfer ring can hold - * @mcr_size: number of entries which the message completion ring can hold - * @mtr_doorbell_vec: the doorbell vector associated with the message - * transfer ring - * @mcr_doorbell_vec: the doorbell vector associated with the message - * completion ring - * @mtr_msi_vec: the MSI which shall be generated by the peripheral after - * completing a transfer descriptor in the message transfer ring - * @mcr_msi_vec: the MSI which shall be generated by the peripheral after - * completing a completion descriptor in the message completion ring - * @mtr_opt_header_size: the size of the optional header in the transfer - * descriptor associated with the message transfer ring in DWs - * @mtr_opt_footer_size: the size of the optional footer in the transfer - * descriptor associated with the message transfer ring in DWs - * @mcr_opt_header_size: the size of the optional header in the completion - * descriptor associated with the message completion ring in DWs - * @mcr_opt_footer_size: the size of the optional footer in the completion - * descriptor associated with the message completion ring in DWs - * @msg_rings_ctrl_flags: message rings control flags - * @prph_info_msi_vec: the MSI which shall be generated by the peripheral - * after updating the Peripheral Information structure - * @prph_scratch_base_addr: the peripheral scratch structure start address - * @prph_scratch_size: the size of the peripheral scratch structure in DWs - * @reserved: reserved - */ -struct iwl_context_info_v2 { - __le16 version; - __le16 size; - __le32 config; - __le64 prph_info_base_addr; - __le64 cr_head_idx_arr_base_addr; - __le64 tr_tail_idx_arr_base_addr; - __le64 cr_tail_idx_arr_base_addr; - __le64 tr_head_idx_arr_base_addr; - __le16 cr_idx_arr_size; - __le16 tr_idx_arr_size; - __le64 mtr_base_addr; - __le64 mcr_base_addr; - __le16 mtr_size; - __le16 mcr_size; - __le16 mtr_doorbell_vec; - __le16 mcr_doorbell_vec; - __le16 mtr_msi_vec; - __le16 mcr_msi_vec; - u8 mtr_opt_header_size; - u8 mtr_opt_footer_size; - u8 mcr_opt_header_size; - u8 mcr_opt_footer_size; - __le16 msg_rings_ctrl_flags; - __le16 prph_info_msi_vec; - __le64 prph_scratch_base_addr; - __le32 prph_scratch_size; - __le32 reserved; -} __packed; /* IPC_CONTEXT_INFO_S */ +#include "fw/api/ctxt-info-v2.h" int iwl_pcie_ctxt_info_v2_alloc(struct iwl_trans *trans, const struct iwl_fw *fw, diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info.h b/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info.h index 7ae0fbdef208..562c023cbf2c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/iwl-context-info.h @@ -1,185 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020, 2022, 2024-2025 Intel Corporation + * Copyright (C) 2018-2020, 2022, 2024-2026 Intel Corporation */ #ifndef __iwl_context_info_file_h__ #define __iwl_context_info_file_h__ -/* maximum number of DRAM map entries supported by FW */ -#define IWL_MAX_DRAM_ENTRY 64 -#define CSR_CTXT_INFO_BA 0x40 - -/** - * enum iwl_context_info_flags - Context information control flags - * @IWL_CTXT_INFO_AUTO_FUNC_INIT: If set, FW will not wait before interrupting - * the init done for driver command that configures several system modes - * @IWL_CTXT_INFO_EARLY_DEBUG: enable early debug - * @IWL_CTXT_INFO_ENABLE_CDMP: enable core dump - * @IWL_CTXT_INFO_RB_CB_SIZE: mask of the RBD Cyclic Buffer Size - * exponent, the actual size is 2**value, valid sizes are 8-2048. - * The value is four bits long. Maximum valid exponent is 12 - * @IWL_CTXT_INFO_TFD_FORMAT_LONG: use long TFD Format (the - * default is short format - not supported by the driver) - * @IWL_CTXT_INFO_RB_SIZE: RB size mask - * (values are IWL_CTXT_INFO_RB_SIZE_*K) - * @IWL_CTXT_INFO_RB_SIZE_1K: Value for 1K RB size - * @IWL_CTXT_INFO_RB_SIZE_2K: Value for 2K RB size - * @IWL_CTXT_INFO_RB_SIZE_4K: Value for 4K RB size - * @IWL_CTXT_INFO_RB_SIZE_8K: Value for 8K RB size - * @IWL_CTXT_INFO_RB_SIZE_12K: Value for 12K RB size - * @IWL_CTXT_INFO_RB_SIZE_16K: Value for 16K RB size - * @IWL_CTXT_INFO_RB_SIZE_20K: Value for 20K RB size - * @IWL_CTXT_INFO_RB_SIZE_24K: Value for 24K RB size - * @IWL_CTXT_INFO_RB_SIZE_28K: Value for 28K RB size - * @IWL_CTXT_INFO_RB_SIZE_32K: Value for 32K RB size - */ -enum iwl_context_info_flags { - IWL_CTXT_INFO_AUTO_FUNC_INIT = 0x0001, - IWL_CTXT_INFO_EARLY_DEBUG = 0x0002, - IWL_CTXT_INFO_ENABLE_CDMP = 0x0004, - IWL_CTXT_INFO_RB_CB_SIZE = 0x00f0, - IWL_CTXT_INFO_TFD_FORMAT_LONG = 0x0100, - IWL_CTXT_INFO_RB_SIZE = 0x1e00, - IWL_CTXT_INFO_RB_SIZE_1K = 0x1, - IWL_CTXT_INFO_RB_SIZE_2K = 0x2, - IWL_CTXT_INFO_RB_SIZE_4K = 0x4, - IWL_CTXT_INFO_RB_SIZE_8K = 0x8, - IWL_CTXT_INFO_RB_SIZE_12K = 0x9, - IWL_CTXT_INFO_RB_SIZE_16K = 0xa, - IWL_CTXT_INFO_RB_SIZE_20K = 0xb, - IWL_CTXT_INFO_RB_SIZE_24K = 0xc, - IWL_CTXT_INFO_RB_SIZE_28K = 0xd, - IWL_CTXT_INFO_RB_SIZE_32K = 0xe, -}; - -/** - * struct iwl_context_info_version - version structure - * @mac_id: SKU and revision id - * @version: context information version id - * @size: the size of the context information in DWs - * @reserved: (reserved) - */ -struct iwl_context_info_version { - __le16 mac_id; - __le16 version; - __le16 size; - __le16 reserved; -} __packed; - -/** - * struct iwl_context_info_control - version structure - * @control_flags: context information flags see &enum iwl_context_info_flags - * @reserved: (reserved) - */ -struct iwl_context_info_control { - __le32 control_flags; - __le32 reserved; -} __packed; - -/** - * struct iwl_context_info_dram_nonfseq - images DRAM map - * each entry in the map represents a DRAM chunk of up to 32 KB - * @umac_img: UMAC image DRAM map - * @lmac_img: LMAC image DRAM map - * @virtual_img: paged image DRAM map - */ -struct iwl_context_info_dram_nonfseq { - __le64 umac_img[IWL_MAX_DRAM_ENTRY]; - __le64 lmac_img[IWL_MAX_DRAM_ENTRY]; - __le64 virtual_img[IWL_MAX_DRAM_ENTRY]; -} __packed; - -/** - * struct iwl_context_info_rbd_cfg - RBDs configuration - * @free_rbd_addr: default queue free RB CB base address - * @used_rbd_addr: default queue used RB CB base address - * @status_wr_ptr: default queue used RB status write pointer - */ -struct iwl_context_info_rbd_cfg { - __le64 free_rbd_addr; - __le64 used_rbd_addr; - __le64 status_wr_ptr; -} __packed; - -/** - * struct iwl_context_info_hcmd_cfg - command queue configuration - * @cmd_queue_addr: address of command queue - * @cmd_queue_size: number of entries - * @reserved: (reserved) - */ -struct iwl_context_info_hcmd_cfg { - __le64 cmd_queue_addr; - u8 cmd_queue_size; - u8 reserved[7]; -} __packed; - -/** - * struct iwl_context_info_dump_cfg - Core Dump configuration - * @core_dump_addr: core dump (debug DRAM address) start address - * @core_dump_size: size, in DWs - * @reserved: (reserved) - */ -struct iwl_context_info_dump_cfg { - __le64 core_dump_addr; - __le32 core_dump_size; - __le32 reserved; -} __packed; - -/** - * struct iwl_context_info_pnvm_cfg - platform NVM data configuration - * @platform_nvm_addr: Platform NVM data start address - * @platform_nvm_size: size in DWs - * @reserved: (reserved) - */ -struct iwl_context_info_pnvm_cfg { - __le64 platform_nvm_addr; - __le32 platform_nvm_size; - __le32 reserved; -} __packed; - -/** - * struct iwl_context_info_early_dbg_cfg - early debug configuration for - * dumping DRAM addresses - * @early_debug_addr: early debug start address - * @early_debug_size: size in DWs - * @reserved: (reserved) - */ -struct iwl_context_info_early_dbg_cfg { - __le64 early_debug_addr; - __le32 early_debug_size; - __le32 reserved; -} __packed; - -/** - * struct iwl_context_info - device INIT configuration - * @version: version information of context info and HW - * @control: control flags of FH configurations - * @reserved0: (reserved) - * @rbd_cfg: default RX queue configuration - * @hcmd_cfg: command queue configuration - * @reserved1: (reserved) - * @dump_cfg: core dump data - * @edbg_cfg: early debug configuration - * @pnvm_cfg: platform nvm configuration - * @reserved2: (reserved) - * @dram: firmware image addresses in DRAM - * @reserved3: (reserved) - */ -struct iwl_context_info { - struct iwl_context_info_version version; - struct iwl_context_info_control control; - __le64 reserved0; - struct iwl_context_info_rbd_cfg rbd_cfg; - struct iwl_context_info_hcmd_cfg hcmd_cfg; - __le32 reserved1[4]; - struct iwl_context_info_dump_cfg dump_cfg; - struct iwl_context_info_early_dbg_cfg edbg_cfg; - struct iwl_context_info_pnvm_cfg pnvm_cfg; - __le32 reserved2[16]; - struct iwl_context_info_dram_nonfseq dram; - __le32 reserved3[16]; -} __packed; /* BOOT_LOADER_CONTEXT_INFO_S */ +#include "fw/api/ctxt-info.h" int iwl_pcie_ctxt_info_init(struct iwl_trans *trans, const struct fw_img *img); void iwl_pcie_ctxt_info_free(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/rx.c b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c similarity index 93% rename from drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/rx.c rename to drivers/net/wireless/intel/iwlwifi/pcie/rx.c index 4631e11f2a96..f033bb51dcca 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/rx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/rx.c @@ -9,10 +9,11 @@ #include #include "iwl-prph.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "internal.h" +#include "pcie/utils.h" #include "iwl-op-mode.h" -#include "pcie/iwl-context-info-v2.h" +#include "iwl-context-info-v2.h" #include "fw/dbg.h" /****************************************************************************** @@ -146,18 +147,18 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans) { if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { /* TODO: remove this once fw does it */ - iwl_write_umac_prph(trans, RFH_RXF_DMA_CFG_AX210, 0); - return iwl_poll_umac_prph_bit(trans, RFH_GEN_STATUS_AX210, - RXF_DMA_IDLE, RXF_DMA_IDLE, 1000); + iwl_trans_write_umac_prph(trans, RFH_RXF_DMA_CFG_AX210, 0); + return iwl_pcie_poll_umac_prph_bit(trans, RFH_GEN_STATUS_AX210, + RXF_DMA_IDLE, RXF_DMA_IDLE, 1000); } else if (trans->mac_cfg->mq_rx_supported) { - iwl_write_prph(trans, RFH_RXF_DMA_CFG, 0); - return iwl_poll_prph_bit(trans, RFH_GEN_STATUS, - RXF_DMA_IDLE, RXF_DMA_IDLE, 1000); + iwl_trans_write_prph(trans, RFH_RXF_DMA_CFG, 0); + return iwl_pcie_poll_prph_bit(trans, RFH_GEN_STATUS, + RXF_DMA_IDLE, RXF_DMA_IDLE, 1000); } else { - iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG, - FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, - 1000); + iwl_trans_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + return iwl_pcie_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, + 1000); } } @@ -178,13 +179,13 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, */ if (!trans->mac_cfg->base->shadow_reg_enable && test_bit(STATUS_TPOWER_PMI, &trans->status)) { - reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); + reg = iwl_trans_pcie_read32(trans, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { IWL_DEBUG_INFO(trans, "Rx queue requesting wakeup, GP1 = 0x%x\n", reg); - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); rxq->need_update = true; return; } @@ -192,13 +193,13 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, rxq->write_actual = round_down(rxq->write, 8); if (!trans->mac_cfg->mq_rx_supported) - iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); + iwl_trans_pcie_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual); else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) - iwl_write32(trans, HBUS_TARG_WRPTR, rxq->write_actual | - HBUS_TARG_WRPTR_RX_Q(rxq->id)); + iwl_trans_pcie_write32(trans, HBUS_TARG_WRPTR, rxq->write_actual | + HBUS_TARG_WRPTR_RX_Q(rxq->id)); else - iwl_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id), - rxq->write_actual); + iwl_trans_pcie_write32(trans, RFH_Q_FRBDCB_WIDX_TRG(rxq->id), + rxq->write_actual); } static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans) @@ -854,22 +855,22 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) return; /* Stop Rx DMA */ - iwl_write32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); + iwl_trans_pcie_write32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); /* reset and flush pointers */ - iwl_write32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0); - iwl_write32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0); - iwl_write32(trans, FH_RSCSR_CHNL0_RDPTR, 0); + iwl_trans_pcie_write32(trans, FH_MEM_RCSR_CHNL0_RBDCB_WPTR, 0); + iwl_trans_pcie_write32(trans, FH_MEM_RCSR_CHNL0_FLUSH_RB_REQ, 0); + iwl_trans_pcie_write32(trans, FH_RSCSR_CHNL0_RDPTR, 0); /* Reset driver's Rx queue write index */ - iwl_write32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); + iwl_trans_pcie_write32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0); /* Tell device where to find RBD circular buffer in DRAM */ - iwl_write32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG, - (u32)(rxq->bd_dma >> 8)); + iwl_trans_pcie_write32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG, + (u32)(rxq->bd_dma >> 8)); /* Tell device where in DRAM to update its Rx status */ - iwl_write32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG, - rxq->rb_stts_dma >> 4); + iwl_trans_pcie_write32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG, + rxq->rb_stts_dma >> 4); /* Enable Rx DMA * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in @@ -879,22 +880,22 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq) * RB timeout 0x10 * 256 RBDs */ - iwl_write32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, - FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | - FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | - FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | - rb_size | - (RX_RB_TIMEOUT << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) | - (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); + iwl_trans_pcie_write32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, + FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | + FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | + FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + rb_size | + (RX_RB_TIMEOUT << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS) | + (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); iwl_trans_release_nic_access(trans); /* Set interrupt coalescing timer to default (2048 usecs) */ - iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); + iwl_trans_pcie_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); /* W/A for interrupt coalescing bug in 7260 and 3160 */ if (trans->cfg->host_interrupt_operation_mode) - iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE); + iwl_trans_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE); } static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) @@ -925,27 +926,27 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) return; /* Stop Rx DMA */ - iwl_write_prph_no_grab(trans, RFH_RXF_DMA_CFG, 0); + iwl_pcie_write_prph_no_grab(trans, RFH_RXF_DMA_CFG, 0); /* disable free amd used rx queue operation */ - iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, 0); + iwl_pcie_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, 0); for (i = 0; i < trans->info.num_rxqs; i++) { /* Tell device where to find RBD free table in DRAM */ - iwl_write_prph64_no_grab(trans, - RFH_Q_FRBDCB_BA_LSB(i), - trans_pcie->rxq[i].bd_dma); + iwl_pcie_write_prph64_no_grab(trans, + RFH_Q_FRBDCB_BA_LSB(i), + trans_pcie->rxq[i].bd_dma); /* Tell device where to find RBD used table in DRAM */ - iwl_write_prph64_no_grab(trans, - RFH_Q_URBDCB_BA_LSB(i), - trans_pcie->rxq[i].used_bd_dma); + iwl_pcie_write_prph64_no_grab(trans, + RFH_Q_URBDCB_BA_LSB(i), + trans_pcie->rxq[i].used_bd_dma); /* Tell device where in DRAM to update its Rx status */ - iwl_write_prph64_no_grab(trans, - RFH_Q_URBD_STTS_WPTR_LSB(i), - trans_pcie->rxq[i].rb_stts_dma); + iwl_pcie_write_prph64_no_grab(trans, + RFH_Q_URBD_STTS_WPTR_LSB(i), + trans_pcie->rxq[i].rb_stts_dma); /* Reset device indice tables */ - iwl_write_prph_no_grab(trans, RFH_Q_FRBDCB_WIDX(i), 0); - iwl_write_prph_no_grab(trans, RFH_Q_FRBDCB_RIDX(i), 0); - iwl_write_prph_no_grab(trans, RFH_Q_URBDCB_WIDX(i), 0); + iwl_pcie_write_prph_no_grab(trans, RFH_Q_FRBDCB_WIDX(i), 0); + iwl_pcie_write_prph_no_grab(trans, RFH_Q_FRBDCB_RIDX(i), 0); + iwl_pcie_write_prph_no_grab(trans, RFH_Q_URBDCB_WIDX(i), 0); enabled |= BIT(i) | BIT(i + 16); } @@ -957,32 +958,32 @@ static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans) * Drop frames that exceed RB size * 512 RBDs */ - iwl_write_prph_no_grab(trans, RFH_RXF_DMA_CFG, - RFH_DMA_EN_ENABLE_VAL | rb_size | - RFH_RXF_DMA_MIN_RB_4_8 | - RFH_RXF_DMA_DROP_TOO_LARGE_MASK | - RFH_RXF_DMA_RBDCB_SIZE_512); + iwl_pcie_write_prph_no_grab(trans, RFH_RXF_DMA_CFG, + RFH_DMA_EN_ENABLE_VAL | rb_size | + RFH_RXF_DMA_MIN_RB_4_8 | + RFH_RXF_DMA_DROP_TOO_LARGE_MASK | + RFH_RXF_DMA_RBDCB_SIZE_512); /* * Activate DMA snooping. * Set RX DMA chunk size to 64B for IOSF and 128B for PCIe * Default queue is 0 */ - iwl_write_prph_no_grab(trans, RFH_GEN_CFG, - RFH_GEN_CFG_RFH_DMA_SNOOP | - RFH_GEN_CFG_VAL(DEFAULT_RXQ_NUM, 0) | - RFH_GEN_CFG_SERVICE_DMA_SNOOP | - RFH_GEN_CFG_VAL(RB_CHUNK_SIZE, - trans->mac_cfg->integrated ? - RFH_GEN_CFG_RB_CHUNK_SIZE_64 : - RFH_GEN_CFG_RB_CHUNK_SIZE_128)); + iwl_pcie_write_prph_no_grab(trans, RFH_GEN_CFG, + RFH_GEN_CFG_RFH_DMA_SNOOP | + RFH_GEN_CFG_VAL(DEFAULT_RXQ_NUM, 0) | + RFH_GEN_CFG_SERVICE_DMA_SNOOP | + RFH_GEN_CFG_VAL(RB_CHUNK_SIZE, + trans->mac_cfg->integrated ? + RFH_GEN_CFG_RB_CHUNK_SIZE_64 : + RFH_GEN_CFG_RB_CHUNK_SIZE_128)); /* Enable the relevant rx queues */ - iwl_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled); + iwl_pcie_write_prph_no_grab(trans, RFH_RXF_RXQ_ACTIVE, enabled); iwl_trans_release_nic_access(trans); /* Set interrupt coalescing timer to default (2048 usecs) */ - iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); + iwl_trans_pcie_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); } void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq) @@ -1189,7 +1190,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) int iwl_pcie_gen2_rx_init(struct iwl_trans *trans) { /* Set interrupt coalescing timer to default (2048 usecs) */ - iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); + iwl_trans_pcie_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF); /* * We don't configure the RFH. @@ -1493,7 +1494,7 @@ static struct iwl_rx_mem_buffer *iwl_pcie_get_rxb(struct iwl_trans *trans, out_err: WARN(1, "Invalid rxb from HW %u\n", (u32)vid); - iwl_force_nmi(trans); + iwl_trans_force_nmi(trans); return NULL; } @@ -1519,6 +1520,11 @@ static int iwl_pcie_rx_handle(struct iwl_trans *trans, int queue, int budget) r = iwl_get_closed_rb_stts(trans, rxq); i = rxq->read; + /* Order the read of the write pointer before any read of the + * completion descriptors and of the RB contents it makes visible. + */ + dma_rmb(); + /* W/A 9000 device step A0 wrap-around bug */ r &= (rxq->queue_size - 1); @@ -1686,9 +1692,9 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) /* W/A for WiFi/WiMAX coex and WiMAX own the RF */ if (trans->cfg->internal_wimax_coex && !trans->mac_cfg->base->apmg_not_supported && - (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) & + (!(iwl_trans_read_prph(trans, APMG_CLK_CTRL_REG) & APMS_CLK_VAL_MRB_FUNC_MODE) || - (iwl_read_prph(trans, APMG_PS_CTRL_REG) & + (iwl_trans_read_prph(trans, APMG_PS_CTRL_REG) & APMG_PS_CTRL_VAL_RESET_REQ))) { clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status); iwl_op_mode_wimax_active(trans->op_mode); @@ -1703,7 +1709,7 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) } if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) { - u32 val = iwl_read32(trans, CSR_IPC_STATE); + u32 val = iwl_trans_pcie_read32(trans, CSR_IPC_STATE); if (val & CSR_IPC_STATE_TOP_RESET_REQ) { IWL_ERR(trans, "FW requested TOP reset for FSEQ\n"); @@ -1728,7 +1734,7 @@ static u32 iwl_pcie_int_cause_non_ict(struct iwl_trans *trans) trace_iwlwifi_dev_irq(trans->dev); /* Discover which interrupts are active/pending */ - inta = iwl_read32(trans, CSR_INT); + inta = iwl_trans_pcie_read32(trans, CSR_INT); /* the thread will service interrupts and re-enable them */ return inta; @@ -1845,7 +1851,7 @@ static void iwl_trans_pcie_handle_reset_interrupt(struct iwl_trans *trans) u32 state; if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC) { - u32 val = iwl_read32(trans, CSR_IPC_STATE); + u32 val = iwl_trans_pcie_read32(trans, CSR_IPC_STATE); state = u32_get_bits(val, CSR_IPC_STATE_RESET); IWL_DEBUG_ISR(trans, "IPC state = 0x%x/%d\n", val, state); @@ -1917,8 +1923,8 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled 0x%08x(sw), enabled(hw) 0x%08x, fh 0x%08x\n", inta, trans_pcie->inta_mask, - iwl_read32(trans, CSR_INT_MASK), - iwl_read32(trans, CSR_FH_INT_STATUS)); + iwl_trans_pcie_read32(trans, CSR_INT_MASK), + iwl_trans_pcie_read32(trans, CSR_FH_INT_STATUS)); if (inta & (~trans_pcie->inta_mask)) IWL_DEBUG_ISR(trans, "We got a masked interrupt (0x%08x)\n", @@ -1966,11 +1972,11 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) * hardware bugs here by ACKing all the possible interrupts so that * interrupt coalescing can still be achieved. */ - iwl_write32(trans, CSR_INT, inta | ~trans_pcie->inta_mask); + iwl_trans_pcie_write32(trans, CSR_INT, inta | ~trans_pcie->inta_mask); if (iwl_have_debug_level(IWL_DL_ISR)) IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n", - inta, iwl_read32(trans, CSR_INT_MASK)); + inta, iwl_trans_pcie_read32(trans, CSR_INT_MASK)); spin_unlock_bh(&trans_pcie->irq_lock); @@ -2065,13 +2071,13 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) IWL_DEBUG_ISR(trans, "Rx interrupt\n"); if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) { handled |= (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX); - iwl_write32(trans, CSR_FH_INT_STATUS, - CSR_FH_INT_RX_MASK); + iwl_trans_pcie_write32(trans, CSR_FH_INT_STATUS, + CSR_FH_INT_RX_MASK); } if (inta & CSR_INT_BIT_RX_PERIODIC) { handled |= CSR_INT_BIT_RX_PERIODIC; - iwl_write32(trans, - CSR_INT, CSR_INT_BIT_RX_PERIODIC); + iwl_trans_pcie_write32(trans, + CSR_INT, CSR_INT_BIT_RX_PERIODIC); } /* Sending RX interrupt require many steps to be done in the * device: @@ -2085,8 +2091,8 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) */ /* Disable periodic interrupt; we use it as just a one-shot. */ - iwl_write8(trans, CSR_INT_PERIODIC_REG, - CSR_INT_PERIODIC_DIS); + iwl_trans_pcie_write8(trans, CSR_INT_PERIODIC_REG, + CSR_INT_PERIODIC_DIS); /* * Enable periodic interrupt in 8 msec only if we received @@ -2096,8 +2102,8 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) * to extend the periodic interrupt; one-shot is enough. */ if (inta & (CSR_INT_BIT_FH_RX | CSR_INT_BIT_SW_RX)) - iwl_write8(trans, CSR_INT_PERIODIC_REG, - CSR_INT_PERIODIC_ENA); + iwl_trans_pcie_write8(trans, CSR_INT_PERIODIC_REG, + CSR_INT_PERIODIC_ENA); isr_stats->rx++; @@ -2111,7 +2117,7 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) /* This "Tx" DMA channel is used only for loading uCode */ if (inta & CSR_INT_BIT_FH_TX) { - iwl_write32(trans, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); + iwl_trans_pcie_write32(trans, CSR_FH_INT_STATUS, CSR_FH_INT_TX_MASK); IWL_DEBUG_ISR(trans, "uCode load interrupt\n"); isr_stats->tx++; handled |= CSR_INT_BIT_FH_TX; @@ -2225,10 +2231,10 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "CSR_DRAM_INT_TBL_REG =0x%x\n", val); - iwl_write32(trans, CSR_DRAM_INT_TBL_REG, val); + iwl_trans_pcie_write32(trans, CSR_DRAM_INT_TBL_REG, val); trans_pcie->use_ict = true; trans_pcie->ict_index = 0; - iwl_write32(trans, CSR_INT, trans_pcie->inta_mask); + iwl_trans_pcie_write32(trans, CSR_INT, trans_pcie->inta_mask); _iwl_enable_interrupts(trans); spin_unlock_bh(&trans_pcie->irq_lock); } @@ -2255,7 +2261,7 @@ irqreturn_t iwl_pcie_isr(int irq, void *data) * If we have something to service, the tasklet will re-enable ints. * If we *don't* have something, we'll re-enable before leaving here. */ - iwl_write32(trans, CSR_INT_MASK, 0x00000000); + iwl_trans_pcie_write32(trans, CSR_INT_MASK, 0x00000000); return IRQ_WAKE_THREAD; } @@ -2285,13 +2291,13 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) lock_map_acquire(&trans->sync_cmd_lockdep_map); spin_lock_bh(&trans_pcie->irq_lock); - inta_fh = iwl_read32(trans, CSR_MSIX_FH_INT_CAUSES_AD); - inta_hw = iwl_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD); + inta_fh = iwl_trans_pcie_read32(trans, CSR_MSIX_FH_INT_CAUSES_AD); + inta_hw = iwl_trans_pcie_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD); /* * Clear causes registers to avoid being handling the same cause. */ - iwl_write32(trans, CSR_MSIX_FH_INT_CAUSES_AD, inta_fh & inta_fh_msk); - iwl_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD, inta_hw); + iwl_trans_pcie_write32(trans, CSR_MSIX_FH_INT_CAUSES_AD, inta_fh & inta_fh_msk); + iwl_trans_pcie_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD, inta_hw); spin_unlock_bh(&trans_pcie->irq_lock); trace_iwlwifi_dev_irq_msix(trans->dev, entry, true, inta_fh, inta_hw); @@ -2306,7 +2312,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) IWL_DEBUG_ISR(trans, "ISR[%d] inta_fh 0x%08x, enabled (sw) 0x%08x (hw) 0x%08x\n", entry->entry, inta_fh, trans_pcie->fh_mask, - iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD)); + iwl_trans_pcie_read32(trans, CSR_MSIX_FH_INT_MASK_AD)); if (inta_fh & ~trans_pcie->fh_mask) IWL_DEBUG_ISR(trans, "We got a masked interrupt (0x%08x)\n", @@ -2408,7 +2414,7 @@ irqreturn_t iwl_pcie_irq_msix_handler(int irq, void *dev_id) IWL_DEBUG_ISR(trans, "ISR[%d] inta_hw 0x%08x, enabled (sw) 0x%08x (hw) 0x%08x\n", entry->entry, inta_hw, trans_pcie->hw_mask, - iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD)); + iwl_trans_pcie_read32(trans, CSR_MSIX_HW_INT_MASK_AD)); if (inta_hw & ~trans_pcie->hw_mask) IWL_DEBUG_ISR(trans, "We got a masked interrupt 0x%08x\n", diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c similarity index 87% rename from drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c rename to drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c index f41cbe62e7aa..dce6043fe962 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans-gen2.c @@ -5,8 +5,8 @@ */ #include "iwl-trans.h" #include "iwl-prph.h" -#include "pcie/iwl-context-info.h" -#include "pcie/iwl-context-info-v2.h" +#include "iwl-context-info.h" +#include "iwl-context-info-v2.h" #include "internal.h" #include "fw/dbg.h" @@ -32,18 +32,18 @@ int iwl_pcie_gen2_apm_init(struct iwl_trans *trans) * Disable L0s without affecting L1; * don't wait for ICH L0s (ICH bug W/A) */ - iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + iwl_trans_set_bit(trans, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); /* Set FH wait threshold to maximum (HW error during stress W/A) */ - iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + iwl_trans_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s */ - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_HAP_WAKE); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_HAP_WAKE); iwl_pcie_apm_config(trans); @@ -65,14 +65,14 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) iwl_pcie_gen2_apm_init(trans); /* inform ME that we are leaving */ - iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, - CSR_RESET_LINK_PWR_MGMT_DISABLED); - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_WAKE_ME | - CSR_HW_IF_CONFIG_REG_WAKE_ME_PCIE_OWNER_EN); + iwl_trans_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_WAKE_ME | + CSR_HW_IF_CONFIG_REG_WAKE_ME_PCIE_OWNER_EN); mdelay(1); - iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, - CSR_RESET_LINK_PWR_MGMT_DISABLED); + iwl_trans_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); mdelay(5); } @@ -88,11 +88,11 @@ static void iwl_pcie_gen2_apm_stop(struct iwl_trans *trans, bool op_mode_leave) * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) - iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_INIT); else - iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } static void @@ -105,14 +105,14 @@ _iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans, trans_pcie->fw_reset_state = FW_RESET_REQUESTED; if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) - iwl_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, - UREG_NIC_SET_NMI_DRIVER_RESET_HANDSHAKE); + iwl_trans_write_umac_prph(trans, UREG_NIC_SET_NMI_DRIVER, + UREG_NIC_SET_NMI_DRIVER_RESET_HANDSHAKE); else if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_AX210) - iwl_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, - UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); + iwl_trans_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); else - iwl_write32(trans, CSR_DOORBELL_VECTOR, - UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); + iwl_trans_pcie_write32(trans, CSR_DOORBELL_VECTOR, + UREG_DOORBELL_TO_ISR6_RESET_HANDSHAKE); /* wait 200ms */ ret = wait_event_timeout(trans_pcie->fw_reset_waitq, @@ -123,11 +123,11 @@ _iwl_trans_pcie_fw_reset_handshake(struct iwl_trans *trans, u32 inta_hw; if (trans_pcie->msix_enabled) { - inta_hw = iwl_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD); + inta_hw = iwl_trans_pcie_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD); reset_done = inta_hw & MSIX_HW_INT_CAUSES_REG_RESET_DONE; } else { - inta_hw = iwl_read32(trans, CSR_INT); + inta_hw = iwl_trans_pcie_read32(trans, CSR_INT); reset_done = inta_hw & CSR_INT_BIT_RESET_DONE; } @@ -281,7 +281,7 @@ static int iwl_pcie_gen2_nic_init(struct iwl_trans *trans) return -ENOMEM; /* enable shadow regs in HW */ - iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); + iwl_trans_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n"); return 0; @@ -342,7 +342,7 @@ static void iwl_pcie_get_rf_name(struct iwl_trans *trans) case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR): case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HR1): case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_HRCDB): - version = iwl_read_prph(trans, CNVI_MBOX_C); + version = iwl_trans_read_prph(trans, CNVI_MBOX_C); switch (version) { case 0x20000: pos += scnprintf(buf + pos, buflen - pos, " B3"); @@ -410,7 +410,7 @@ void iwl_trans_pcie_gen2_fw_alive(struct iwl_trans *trans) step_reg = trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_SC ? CNVI_PMU_STEP_FLOW_SC : CNVI_PMU_STEP_FLOW_BZ; - trans->step_urm = !!(iwl_read_prph(trans, step_reg) & + trans->step_urm = !!(iwl_trans_read_prph(trans, step_reg) & CNVI_PMU_STEP_FLOW_FORCE_URM); } @@ -434,21 +434,21 @@ static bool iwl_pcie_set_ltr(struct iwl_trans *trans) if ((trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_AX210 || trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_22000) && !trans->mac_cfg->integrated) { - iwl_write32(trans, CSR_LTR_LONG_VAL_AD, ltr_val); + iwl_trans_pcie_write32(trans, CSR_LTR_LONG_VAL_AD, ltr_val); return true; } if (trans->mac_cfg->integrated && trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_22000) { - iwl_write_prph(trans, HPM_MAC_LTR_CSR, HPM_MAC_LRT_ENABLE_ALL); - iwl_write_prph(trans, HPM_UMAC_LTR, ltr_val); + iwl_trans_write_prph(trans, HPM_MAC_LTR_CSR, HPM_MAC_LRT_ENABLE_ALL); + iwl_trans_write_prph(trans, HPM_UMAC_LTR, ltr_val); return true; } if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_AX210) { /* First clear the interrupt, just in case */ - iwl_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD, - MSIX_HW_INT_CAUSES_REG_IML); + iwl_trans_pcie_write32(trans, CSR_MSIX_HW_INT_CAUSES_AD, + MSIX_HW_INT_CAUSES_REG_IML); /* In this case, unfortunately the same ROM bug exists in the * device (not setting LTR correctly), but we don't have control * over the settings from the host due to some hardware security @@ -475,18 +475,18 @@ static void iwl_pcie_spin_for_iml(struct iwl_trans *trans) if (WARN_ON(!trans_pcie->iml)) return; - value = iwl_read32(trans, CSR_LTR_LAST_MSG); + value = iwl_trans_pcie_read32(trans, CSR_LTR_LAST_MSG); IWL_DEBUG_INFO(trans, "Polling for IML load - CSR_LTR_LAST_MSG=0x%x\n", value); while (time_before(jiffies, end_time)) { - if (iwl_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD) & + if (iwl_trans_pcie_read32(trans, CSR_MSIX_HW_INT_CAUSES_AD) & MSIX_HW_INT_CAUSES_REG_IML) { irq = true; break; } /* Keep the CPU and device busy. */ - value = iwl_read32(trans, CSR_LTR_LAST_MSG); + value = iwl_trans_pcie_read32(trans, CSR_LTR_LAST_MSG); loops++; } @@ -522,7 +522,7 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, iwl_enable_rfkill_int(trans); - iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + iwl_trans_pcie_write32(trans, CSR_INT, 0xFFFFFFFF); /* * We enabled the RF-Kill interrupt and the handler may very @@ -550,12 +550,12 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, } /* make sure rfkill handshake bits are cleared */ - iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_trans_pcie_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_trans_pcie_write32(trans, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); /* clear (again), then enable host interrupts */ - iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + iwl_trans_pcie_write32(trans, CSR_INT, 0xFFFFFFFF); ret = iwl_pcie_gen2_nic_init(trans); if (ret) { @@ -591,14 +591,14 @@ int iwl_trans_pcie_gen2_start_fw(struct iwl_trans *trans, if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { IWL_DEBUG_POWER(trans, "function scratch register value is 0x%08x\n", - iwl_read32(trans, CSR_FUNC_SCRATCH)); - iwl_write32(trans, CSR_FUNC_SCRATCH, CSR_FUNC_SCRATCH_INIT_VALUE); - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_ROM_START); + iwl_trans_pcie_read32(trans, CSR_FUNC_SCRATCH)); + iwl_trans_pcie_write32(trans, CSR_FUNC_SCRATCH, CSR_FUNC_SCRATCH_INIT_VALUE); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_ROM_START); } else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { - iwl_write_umac_prph(trans, UREG_CPU_INIT_RUN, 1); + iwl_trans_write_umac_prph(trans, UREG_CPU_INIT_RUN, 1); } else { - iwl_write_prph(trans, UREG_CPU_INIT_RUN, 1); + iwl_trans_write_prph(trans, UREG_CPU_INIT_RUN, 1); } if (keep_ram_busy) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c similarity index 84% rename from drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c rename to drivers/net/wireless/intel/iwlwifi/pcie/trans.c index 28b276c65952..0f4e309fe32b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -28,7 +28,7 @@ #include "mei/iwl-mei.h" #include "internal.h" #include "iwl-fh.h" -#include "pcie/iwl-context-info-v2.h" +#include "iwl-context-info-v2.h" #include "pcie/utils.h" #define IWL_HOST_MON_BLOCK_PEMON 0x00 @@ -44,10 +44,10 @@ static void iwl_dump_host_monitor_block(struct iwl_trans *trans, int i; IWL_ERR(trans, "Host monitor block 0x%x vector 0x%x\n", block, vec); - iwl_write32(trans, CSR_MONITOR_CFG_REG, (block << 8) | vec); + iwl_trans_pcie_write32(trans, CSR_MONITOR_CFG_REG, (block << 8) | vec); for (i = 0; i < iter; i++) IWL_ERR(trans, " value [iter %d]: 0x%08x\n", - i, iwl_read32(trans, CSR_MONITOR_STATUS_REG)); + i, iwl_trans_pcie_read32(trans, CSR_MONITOR_STATUS_REG)); } static void iwl_pcie_dump_host_monitor(struct iwl_trans *trans) @@ -56,7 +56,7 @@ static void iwl_pcie_dump_host_monitor(struct iwl_trans *trans) case IWL_DEVICE_FAMILY_22000: case IWL_DEVICE_FAMILY_AX210: IWL_ERR(trans, "CSR_RESET = 0x%x\n", - iwl_read32(trans, CSR_RESET)); + iwl_trans_pcie_read32(trans, CSR_RESET)); iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, IWL_HOST_MON_BLOCK_PEMON_VEC0, 15); iwl_dump_host_monitor_block(trans, IWL_HOST_MON_BLOCK_PEMON, @@ -79,12 +79,12 @@ int iwl_trans_pcie_sw_reset(struct iwl_trans *trans, bool retake_ownership) { /* Reset entire device - do controller reset (results in SHRD_HW_RST) */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_SW_RESET); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_SW_RESET); usleep_range(10000, 20000); } else { - iwl_set_bit(trans, CSR_RESET, - CSR_RESET_REG_FLAG_SW_RESET); + iwl_trans_set_bit(trans, CSR_RESET, + CSR_RESET_REG_FLAG_SW_RESET); usleep_range(5000, 6000); } @@ -170,16 +170,16 @@ void iwl_pcie_alloc_fw_monitor(struct iwl_trans *trans, u8 max_power) static u32 iwl_trans_pcie_read_shr(struct iwl_trans *trans, u32 reg) { - iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, - ((reg & 0x0000ffff) | (2 << 28))); - return iwl_read32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG); + iwl_trans_pcie_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, + ((reg & 0x0000ffff) | (2 << 28))); + return iwl_trans_pcie_read32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG); } static void iwl_trans_pcie_write_shr(struct iwl_trans *trans, u32 reg, u32 val) { - iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG, val); - iwl_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, - ((reg & 0x0000ffff) | (3 << 28))); + iwl_trans_pcie_write32(trans, HEEP_CTRL_WRD_PCIEX_DATA_REG, val); + iwl_trans_pcie_write32(trans, HEEP_CTRL_WRD_PCIEX_CTRL_REG, + ((reg & 0x0000ffff) | (3 << 28))); } static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) @@ -188,13 +188,13 @@ static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) return; if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) - iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VAUX, - ~APMG_PS_CTRL_MSK_PWR_SRC); + iwl_trans_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VAUX, + ~APMG_PS_CTRL_MSK_PWR_SRC); else - iwl_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, - APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, - ~APMG_PS_CTRL_MSK_PWR_SRC); + iwl_trans_set_bits_mask_prph(trans, APMG_PS_CTRL_REG, + APMG_PS_CTRL_VAL_PWR_SRC_VMAIN, + ~APMG_PS_CTRL_MSK_PWR_SRC); } /* PCI registers */ @@ -211,7 +211,7 @@ void iwl_pcie_apm_config(struct iwl_trans *trans) * and in newer hardware they are not officially supported at * all, so we must always set the L0S_DISABLED bit. */ - iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_DISABLED); + iwl_trans_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_DISABLED); pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl); trans_pcie->pm_support = !(lctl & PCI_EXP_LNKCTL_ASPM_L0S); @@ -241,31 +241,31 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) /* Disable L0S exit timer (platform NMI Work/Around) */ if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_8000) - iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); + iwl_trans_set_bit(trans, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); /* * Disable L0s without affecting L1; * don't wait for ICH L0s (ICH bug W/A) */ - iwl_set_bit(trans, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); + iwl_trans_set_bit(trans, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); /* Set FH wait threshold to maximum (HW error during stress W/A) */ - iwl_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); + iwl_trans_set_bit(trans, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); /* * Enable HAP INTA (interrupt from management bus) to * wake device's PCI Express link L1a -> L0s */ - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_HAP_WAKE); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_HAP_WAKE); iwl_pcie_apm_config(trans); /* Configure analog phase-lock-loop before activating to D0A */ if (trans->mac_cfg->base->pll_cfg) - iwl_set_bit(trans, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); + iwl_trans_set_bit(trans, CSR_ANA_PLL_CFG, CSR50_ANA_PLL_CFG_VAL); ret = iwl_trans_activate_nic(trans); if (ret) @@ -286,11 +286,11 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) * just to discard the value. But that's the way the hardware * seems to like it. */ - iwl_read_prph(trans, OSC_CLK); - iwl_read_prph(trans, OSC_CLK); - iwl_set_bits_prph(trans, OSC_CLK, OSC_CLK_FORCE_CONTROL); - iwl_read_prph(trans, OSC_CLK); - iwl_read_prph(trans, OSC_CLK); + iwl_trans_read_prph(trans, OSC_CLK); + iwl_trans_read_prph(trans, OSC_CLK); + iwl_trans_set_bits_prph(trans, OSC_CLK, OSC_CLK_FORCE_CONTROL); + iwl_trans_read_prph(trans, OSC_CLK); + iwl_trans_read_prph(trans, OSC_CLK); } /* @@ -301,17 +301,17 @@ static int iwl_pcie_apm_init(struct iwl_trans *trans) * bits already set by default in "CLK_CTRL_REG" after reset. */ if (!trans->mac_cfg->base->apmg_not_supported) { - iwl_write_prph(trans, APMG_CLK_EN_REG, - APMG_CLK_VAL_DMA_CLK_RQT); + iwl_trans_write_prph(trans, APMG_CLK_EN_REG, + APMG_CLK_VAL_DMA_CLK_RQT); udelay(20); /* Disable L1-Active */ - iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + iwl_trans_set_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); /* Clear the interrupt in APMG if the NIC is in RFKILL */ - iwl_write_prph(trans, APMG_RTC_INT_STT_REG, - APMG_RTC_INT_STT_RFKILL); + iwl_trans_write_prph(trans, APMG_RTC_INT_STT_REG, + APMG_RTC_INT_STT_RFKILL); } set_bit(STATUS_DEVICE_ENABLED, &trans->status); @@ -334,8 +334,8 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) u32 dl_cfg_reg; /* Force XTAL ON */ - iwl_trans_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + iwl_pcie_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); ret = iwl_trans_pcie_sw_reset(trans, true); @@ -344,8 +344,8 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) if (WARN_ON(ret)) { /* Release XTAL ON request */ - iwl_trans_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + iwl_pcie_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); return; } @@ -353,8 +353,8 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) * Clear "disable persistence" to avoid LP XTAL resetting when * SHRD_HW_RST is applied in S3. */ - iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_PERSIST_DIS); + iwl_trans_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_PERSIST_DIS); /* * Force APMG XTAL to be active to prevent its disabling by HW @@ -386,22 +386,22 @@ static void iwl_pcie_apm_lp_xtal_enable(struct iwl_trans *trans) * Enable persistence mode to avoid LP XTAL resetting when * SHRD_HW_RST is applied in S3. */ - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_PERSISTENCE); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PERSISTENCE); /* * Clear "initialization complete" bit to move adapter from * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ - iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* Activates XTAL resources monitor */ - iwl_trans_set_bit(trans, CSR_MONITOR_CFG_REG, - CSR_MONITOR_XTAL_RESOURCES); + iwl_pcie_set_bit(trans, CSR_MONITOR_CFG_REG, + CSR_MONITOR_XTAL_RESOURCES); /* Release XTAL ON request */ - iwl_trans_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_XTAL_ON); + iwl_pcie_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_XTAL_ON); udelay(10); /* Release APMG XTAL */ @@ -417,18 +417,18 @@ void iwl_pcie_apm_stop_master(struct iwl_trans *trans) /* stop device's busmaster DMA activity */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ); - ret = iwl_poll_bits(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, - 100); + ret = iwl_trans_poll_bits(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, + 100); usleep_range(10000, 20000); } else { - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); + iwl_trans_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bits(trans, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + ret = iwl_trans_poll_bits(trans, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); } if (ret) @@ -447,18 +447,18 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) /* inform ME that we are leaving */ if (trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_7000) - iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_WAKE_ME); + iwl_trans_set_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_WAKE_ME); else if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_8000) { - iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, - CSR_RESET_LINK_PWR_MGMT_DISABLED); - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_WAKE_ME | - CSR_HW_IF_CONFIG_REG_WAKE_ME_PCIE_OWNER_EN); + iwl_trans_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_WAKE_ME | + CSR_HW_IF_CONFIG_REG_WAKE_ME_PCIE_OWNER_EN); mdelay(1); - iwl_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, - CSR_RESET_LINK_PWR_MGMT_DISABLED); + iwl_trans_clear_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); } mdelay(5); } @@ -479,7 +479,7 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave) * Clear "initialization complete" bit to move adapter from * D0A* (powered-up Active) --> D0U* (Uninitialized) state. */ - iwl_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_trans_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); } static int iwl_pcie_nic_init(struct iwl_trans *trans) @@ -512,7 +512,7 @@ static int iwl_pcie_nic_init(struct iwl_trans *trans) if (trans->mac_cfg->base->shadow_reg_enable) { /* enable shadow regs in HW */ - iwl_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); + iwl_trans_set_bit(trans, CSR_MAC_SHADOW_REG_CTRL, 0x800FFFFF); IWL_DEBUG_INFO(trans, "Enabling shadow registers in device\n"); } @@ -525,16 +525,16 @@ static int iwl_pcie_set_hw_ready(struct iwl_trans *trans) { int ret; - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_PCI_OWN_SET); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PCI_OWN_SET); /* See if we got it */ - ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_PCI_OWN_SET, - HW_READY_TIMEOUT); + ret = iwl_trans_poll_bits(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PCI_OWN_SET, + HW_READY_TIMEOUT); if (!ret) - iwl_set_bit(trans, CSR_MBOX_SET_REG, CSR_MBOX_SET_REG_OS_ALIVE); + iwl_trans_set_bit(trans, CSR_MBOX_SET_REG, CSR_MBOX_SET_REG_OS_ALIVE); IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret ? " not" : ""); return ret; @@ -555,16 +555,16 @@ int iwl_pcie_prepare_card_hw(struct iwl_trans *trans) return 0; } - iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, - CSR_RESET_LINK_PWR_MGMT_DISABLED); + iwl_trans_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, + CSR_RESET_LINK_PWR_MGMT_DISABLED); usleep_range(1000, 2000); for (iter = 0; iter < 10; iter++) { int t = 0; /* If HW is not ready, prepare the conditions to check again */ - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_WAKE_ME); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_WAKE_ME); do { ret = iwl_pcie_set_hw_ready(trans); @@ -603,28 +603,28 @@ static void iwl_pcie_load_firmware_chunk_fh(struct iwl_trans *trans, u32 dst_addr, dma_addr_t phy_addr, u32 byte_cnt) { - iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); + iwl_trans_pcie_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE); - iwl_write32(trans, FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), - dst_addr); + iwl_trans_pcie_write32(trans, FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), + dst_addr); - iwl_write32(trans, FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), - phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); + iwl_trans_pcie_write32(trans, FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL), + phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK); - iwl_write32(trans, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), - (iwl_get_dma_hi_addr(phy_addr) - << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); + iwl_trans_pcie_write32(trans, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), + (iwl_get_dma_hi_addr(phy_addr) + << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); - iwl_write32(trans, FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), - BIT(FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) | - BIT(FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) | - FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); + iwl_trans_pcie_write32(trans, FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL), + BIT(FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM) | + BIT(FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX) | + FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID); - iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | - FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); + iwl_trans_pcie_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | + FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); } static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, @@ -688,16 +688,16 @@ static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num, extended_addr = true; if (extended_addr) - iwl_set_bits_prph(trans, LMPM_CHICK, - LMPM_CHICK_EXTENDED_ADDR_SPACE); + iwl_trans_set_bits_prph(trans, LMPM_CHICK, + LMPM_CHICK_EXTENDED_ADDR_SPACE); memcpy(v_addr, (const u8 *)section->data + offset, copy_size); ret = iwl_pcie_load_firmware_chunk(trans, dst_addr, p_addr, copy_size); if (extended_addr) - iwl_clear_bits_prph(trans, LMPM_CHICK, - LMPM_CHICK_EXTENDED_ADDR_SPACE); + iwl_trans_clear_bits_prph(trans, LMPM_CHICK, + LMPM_CHICK_EXTENDED_ADDR_SPACE); if (ret) { IWL_ERR(trans, @@ -751,9 +751,9 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, return ret; /* Notify ucode of loaded section number and status */ - val = iwl_read_direct32(trans, FH_UCODE_LOAD_STATUS); + val = iwl_pcie_read_direct32(trans, FH_UCODE_LOAD_STATUS); val = val | (sec_num << shift_param); - iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, val); + iwl_trans_write_direct32(trans, FH_UCODE_LOAD_STATUS, val); sec_num = (sec_num << 1) | 0x1; } @@ -764,18 +764,18 @@ static int iwl_pcie_load_cpu_sections_8000(struct iwl_trans *trans, if (trans->mac_cfg->gen2) { if (cpu == 1) - iwl_write_prph(trans, UREG_UCODE_LOAD_STATUS, - 0xFFFF); + iwl_trans_write_prph(trans, UREG_UCODE_LOAD_STATUS, + 0xFFFF); else - iwl_write_prph(trans, UREG_UCODE_LOAD_STATUS, - 0xFFFFFFFF); + iwl_trans_write_prph(trans, UREG_UCODE_LOAD_STATUS, + 0xFFFFFFFF); } else { if (cpu == 1) - iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, - 0xFFFF); + iwl_trans_write_direct32(trans, FH_UCODE_LOAD_STATUS, + 0xFFFF); else - iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, - 0xFFFFFFFF); + iwl_trans_write_direct32(trans, FH_UCODE_LOAD_STATUS, + 0xFFFFFFFF); } return 0; @@ -836,8 +836,8 @@ static void iwl_pcie_apply_destination_ini(struct iwl_trans *trans) IWL_FW_INI_LOCATION_SRAM_PATH) { IWL_DEBUG_FW(trans, "WRT: Applying SMEM buffer destination\n"); /* set sram monitor by enabling bit 7 */ - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_BIT_MONITOR_SRAM); return; } @@ -852,11 +852,11 @@ static void iwl_pcie_apply_destination_ini(struct iwl_trans *trans) IWL_DEBUG_FW(trans, "WRT: Applying DRAM destination (alloc_id=%u)\n", alloc_id); - iwl_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2, - frag->physical >> MON_BUFF_SHIFT_VER2); - iwl_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2, - (frag->physical + frag->size - 256) >> - MON_BUFF_SHIFT_VER2); + iwl_trans_write_umac_prph(trans, MON_BUFF_BASE_ADDR_VER2, + frag->physical >> MON_BUFF_SHIFT_VER2); + iwl_trans_write_umac_prph(trans, MON_BUFF_END_ADDR_VER2, + (frag->physical + frag->size - 256) >> + MON_BUFF_SHIFT_VER2); } void iwl_pcie_apply_destination(struct iwl_trans *trans) @@ -884,25 +884,25 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans) switch (dest->reg_ops[i].op) { case CSR_ASSIGN: - iwl_write32(trans, addr, val); + iwl_trans_pcie_write32(trans, addr, val); break; case CSR_SETBIT: - iwl_set_bit(trans, addr, BIT(val)); + iwl_trans_set_bit(trans, addr, BIT(val)); break; case CSR_CLEARBIT: - iwl_clear_bit(trans, addr, BIT(val)); + iwl_trans_clear_bit(trans, addr, BIT(val)); break; case PRPH_ASSIGN: - iwl_write_prph(trans, addr, val); + iwl_trans_write_prph(trans, addr, val); break; case PRPH_SETBIT: - iwl_set_bits_prph(trans, addr, BIT(val)); + iwl_trans_set_bits_prph(trans, addr, BIT(val)); break; case PRPH_CLEARBIT: - iwl_clear_bits_prph(trans, addr, BIT(val)); + iwl_trans_clear_bits_prph(trans, addr, BIT(val)); break; case PRPH_BLOCKBIT: - if (iwl_read_prph(trans, addr) & BIT(val)) { + if (iwl_trans_read_prph(trans, addr) & BIT(val)) { IWL_ERR(trans, "BIT(%u) in address 0x%x is 1, stopping FW configuration\n", val, addr); @@ -918,16 +918,16 @@ void iwl_pcie_apply_destination(struct iwl_trans *trans) monitor: if (dest->monitor_mode == EXTERNAL_MODE && fw_mon->size) { - iwl_write_prph(trans, le32_to_cpu(dest->base_reg), - fw_mon->physical >> dest->base_shift); + iwl_trans_write_prph(trans, le32_to_cpu(dest->base_reg), + fw_mon->physical >> dest->base_shift); if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_8000) - iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (fw_mon->physical + fw_mon->size - - 256) >> dest->end_shift); + iwl_trans_write_prph(trans, le32_to_cpu(dest->end_reg), + (fw_mon->physical + fw_mon->size - + 256) >> dest->end_shift); else - iwl_write_prph(trans, le32_to_cpu(dest->end_reg), - (fw_mon->physical + fw_mon->size) >> - dest->end_shift); + iwl_trans_write_prph(trans, le32_to_cpu(dest->end_reg), + (fw_mon->physical + fw_mon->size) >> + dest->end_shift); } } @@ -947,9 +947,9 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, if (image->is_dual_cpus) { /* set CPU2 header address */ - iwl_write_prph(trans, - LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR, - LMPM_SECURE_CPU2_HDR_MEM_SPACE); + iwl_trans_write_prph(trans, + LMPM_SECURE_UCODE_LOAD_CPU2_HDR_ADDR, + LMPM_SECURE_CPU2_HDR_MEM_SPACE); /* load to FW the binary sections of CPU2 */ ret = iwl_pcie_load_cpu_sections(trans, image, 2, @@ -964,7 +964,7 @@ static int iwl_pcie_load_given_ucode(struct iwl_trans *trans, iwl_enable_interrupts(trans); /* release CPU reset */ - iwl_write32(trans, CSR_RESET, 0); + iwl_trans_pcie_write32(trans, CSR_RESET, 0); return 0; } @@ -982,18 +982,18 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, iwl_pcie_apply_destination(trans); IWL_DEBUG_POWER(trans, "Original WFPM value = 0x%08X\n", - iwl_read_prph(trans, WFPM_GP2)); + iwl_trans_read_prph(trans, WFPM_GP2)); /* * Set default value. On resume reading the values that were * zeored can provide debug data on the resume flow. * This is for debugging only and has no functional impact. */ - iwl_write_prph(trans, WFPM_GP2, 0x01010101); + iwl_trans_write_prph(trans, WFPM_GP2, 0x01010101); /* configure the ucode to be ready to get the secured image */ /* release CPU reset */ - iwl_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); + iwl_trans_write_prph(trans, RELEASE_CPU_RESET, RELEASE_CPU_RESET_BIT); /* load to FW the binary Secured sections of CPU1 */ ret = iwl_pcie_load_cpu_sections_8000(trans, image, 1, @@ -1079,9 +1079,9 @@ static void iwl_pcie_map_list(struct iwl_trans *trans, int i; for (i = 0; i < arr_size; i++) { - iwl_write8(trans, CSR_MSIX_IVAR(causes[i].addr), val); - iwl_clear_bit(trans, causes[i].mask_reg, - BIT(causes[i].bit)); + iwl_trans_pcie_write8(trans, CSR_MSIX_IVAR(causes[i].addr), val); + iwl_trans_clear_bit(trans, causes[i].mask_reg, + BIT(causes[i].bit)); } } @@ -1119,19 +1119,19 @@ static void iwl_pcie_map_rx_causes(struct iwl_trans *trans) */ val = BIT(MSIX_FH_INT_CAUSES_Q(0)); for (idx = 1; idx < trans->info.num_rxqs; idx++) { - iwl_write8(trans, CSR_MSIX_RX_IVAR(idx), - MSIX_FH_INT_CAUSES_Q(idx - offset)); + iwl_trans_pcie_write8(trans, CSR_MSIX_RX_IVAR(idx), + MSIX_FH_INT_CAUSES_Q(idx - offset)); val |= BIT(MSIX_FH_INT_CAUSES_Q(idx)); } - iwl_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~val); + iwl_trans_pcie_write32(trans, CSR_MSIX_FH_INT_MASK_AD, ~val); val = MSIX_FH_INT_CAUSES_Q(0); if (trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_NON_RX) val |= MSIX_NON_AUTO_CLEAR_CAUSE; - iwl_write8(trans, CSR_MSIX_RX_IVAR(0), val); + iwl_trans_pcie_write8(trans, CSR_MSIX_RX_IVAR(0), val); if (trans_pcie->shared_vec_mask & IWL_SHARED_IRQ_FIRST_RSS) - iwl_write8(trans, CSR_MSIX_RX_IVAR(1), val); + iwl_trans_pcie_write8(trans, CSR_MSIX_RX_IVAR(1), val); } void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie) @@ -1141,8 +1141,8 @@ void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie) if (!trans_pcie->msix_enabled) { if (trans->mac_cfg->mq_rx_supported && test_bit(STATUS_DEVICE_ENABLED, &trans->status)) - iwl_write_umac_prph(trans, UREG_CHICK, - UREG_CHICK_MSI_ENABLE); + iwl_trans_write_umac_prph(trans, UREG_CHICK, + UREG_CHICK_MSI_ENABLE); return; } /* @@ -1151,7 +1151,7 @@ void iwl_pcie_conf_msix_hw(struct iwl_trans_pcie *trans_pcie) * prph. */ if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) - iwl_write_umac_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE); + iwl_trans_write_umac_prph(trans, UREG_CHICK, UREG_CHICK_MSIX_ENABLE); /* * Each cause from the causes list above and the RX causes is @@ -1174,9 +1174,9 @@ static void iwl_pcie_init_msix(struct iwl_trans_pcie *trans_pcie) if (!trans_pcie->msix_enabled) return; - trans_pcie->fh_init_mask = ~iwl_read32(trans, CSR_MSIX_FH_INT_MASK_AD); + trans_pcie->fh_init_mask = ~iwl_trans_pcie_read32(trans, CSR_MSIX_FH_INT_MASK_AD); trans_pcie->fh_mask = trans_pcie->fh_init_mask; - trans_pcie->hw_init_mask = ~iwl_read32(trans, CSR_MSIX_HW_INT_MASK_AD); + trans_pcie->hw_init_mask = ~iwl_trans_pcie_read32(trans, CSR_MSIX_HW_INT_MASK_AD); trans_pcie->hw_mask = trans_pcie->hw_init_mask; } @@ -1215,19 +1215,19 @@ static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool from_irq) /* Power-down device's busmaster DMA clocks */ if (!trans->mac_cfg->base->apmg_not_supported) { - iwl_write_prph(trans, APMG_CLK_DIS_REG, - APMG_CLK_VAL_DMA_CLK_RQT); + iwl_trans_write_prph(trans, APMG_CLK_DIS_REG, + APMG_CLK_VAL_DMA_CLK_RQT); udelay(5); } } /* Make sure (redundant) we've released our request to stay awake */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) - iwl_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_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); /* Stop the device, and put it in low power state */ iwl_pcie_apm_stop(trans, false); @@ -1288,6 +1288,10 @@ int iwl_trans_pcie_start_fw(struct iwl_trans *trans, bool hw_rfkill; int ret; + if (trans->mac_cfg->gen2) + return iwl_trans_pcie_gen2_start_fw(trans, fw, img, + run_in_rfkill); + /* This may fail if AMT took ownership of the device */ if (iwl_pcie_prepare_card_hw(trans)) { IWL_WARN(trans, "Exit HW not ready\n"); @@ -1296,7 +1300,7 @@ int iwl_trans_pcie_start_fw(struct iwl_trans *trans, iwl_enable_rfkill_int(trans); - iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + iwl_trans_pcie_write32(trans, CSR_INT, 0xFFFFFFFF); /* * We enabled the RF-Kill interrupt and the handler may very @@ -1326,12 +1330,12 @@ int iwl_trans_pcie_start_fw(struct iwl_trans *trans, } /* make sure rfkill handshake bits are cleared */ - iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, - CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); + iwl_trans_pcie_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_trans_pcie_write32(trans, CSR_UCODE_DRV_GP1_CLR, + CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED); /* clear (again), then enable host interrupts */ - iwl_write32(trans, CSR_INT, 0xFFFFFFFF); + iwl_trans_pcie_write32(trans, CSR_INT, 0xFFFFFFFF); ret = iwl_pcie_nic_init(trans); if (ret) { @@ -1349,8 +1353,8 @@ int iwl_trans_pcie_start_fw(struct iwl_trans *trans, iwl_enable_fw_load_int(trans); /* really make sure rfkill handshake bits are cleared */ - iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); - iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_trans_pcie_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); + iwl_trans_pcie_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); /* Load the given image to the HW */ if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_8000) @@ -1370,6 +1374,11 @@ int iwl_trans_pcie_start_fw(struct iwl_trans *trans, void iwl_trans_pcie_fw_alive(struct iwl_trans *trans) { + if (trans->mac_cfg->gen2) { + iwl_trans_pcie_gen2_fw_alive(trans); + return; + } + iwl_pcie_reset_ict(trans); iwl_pcie_tx_start(trans); } @@ -1408,6 +1417,11 @@ void iwl_trans_pcie_stop_device(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool was_in_rfkill; + if (trans->mac_cfg->gen2) { + iwl_trans_pcie_gen2_stop_device(trans); + return; + } + iwl_op_mode_time_point(trans->op_mode, IWL_FW_INI_TIME_POINT_HOST_DEVICE_DISABLE, NULL); @@ -1444,15 +1458,15 @@ static void iwl_pcie_d3_complete_suspend(struct iwl_trans *trans, iwl_pcie_synchronize_irqs(trans); if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); - iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + iwl_trans_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_MAC_INIT); } else { - iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); - iwl_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_trans_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_INIT_DONE); } if (reset) { @@ -1478,13 +1492,13 @@ static int iwl_pcie_d3_handshake(struct iwl_trans *trans, bool suspend) 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); + iwl_trans_write_umac_prph(trans, UREG_DOORBELL_TO_ISR6, + suspend ? UREG_DOORBELL_TO_ISR6_SUSPEND : + UREG_DOORBELL_TO_ISR6_RESUME); else - iwl_write32(trans, CSR_IPC_SLEEP_CONTROL, - suspend ? CSR_IPC_SLEEP_CONTROL_SUSPEND : - CSR_IPC_SLEEP_CONTROL_RESUME); + iwl_trans_pcie_write32(trans, CSR_IPC_SLEEP_CONTROL, + suspend ? CSR_IPC_SLEEP_CONTROL_SUSPEND : + CSR_IPC_SLEEP_CONTROL_RESUME); ret = wait_event_timeout(trans_pcie->sx_waitq, trans_pcie->sx_state != IWL_SX_WAITING, @@ -1515,8 +1529,8 @@ int iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool reset) if (!reset) /* Enable persistence mode to avoid reset */ - iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_PERSISTENCE); + iwl_trans_set_bit(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PERSISTENCE); ret = iwl_pcie_d3_handshake(trans, true); if (ret) @@ -1535,11 +1549,11 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, int ret; if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); else - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); ret = iwl_trans_activate_nic(trans); if (ret) { @@ -1563,8 +1577,8 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, iwl_pcie_set_pwr(trans, false); if (!reset) { - iwl_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); } else { iwl_trans_pcie_tx_reset(trans); @@ -1577,9 +1591,9 @@ int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, } IWL_DEBUG_POWER(trans, "WFPM value upon resume = 0x%08X\n", - iwl_read_umac_prph(trans, WFPM_GP2)); + iwl_trans_read_umac_prph(trans, WFPM_GP2)); - val = iwl_read32(trans, CSR_RESET); + val = iwl_trans_pcie_read32(trans, CSR_RESET); if (val & CSR_RESET_REG_FLAG_NEVO_RESET) { IWL_INFO(trans, "Device was reset during suspend\n"); trans->state = IWL_TRANS_NO_FW; @@ -1745,17 +1759,17 @@ static int iwl_trans_pcie_clear_persistence_bit(struct iwl_trans *trans) return 0; } - hpm = iwl_read_umac_prph_no_grab(trans, HPM_DEBUG); + hpm = iwl_trans_read_umac_prph_no_grab(trans, HPM_DEBUG); if (!iwl_trans_is_hw_error_value(hpm) && (hpm & PERSISTENCE_BIT)) { - u32 wprot_val = iwl_read_umac_prph_no_grab(trans, wprot); + u32 wprot_val = iwl_trans_read_umac_prph_no_grab(trans, wprot); if (wprot_val & PREG_WFPM_ACCESS) { IWL_ERR(trans, "Error, can not clear persistence bit\n"); return -EPERM; } - iwl_write_umac_prph_no_grab(trans, HPM_DEBUG, - hpm & ~PERSISTENCE_BIT); + iwl_pcie_write_umac_prph_no_grab(trans, HPM_DEBUG, + hpm & ~PERSISTENCE_BIT); } return 0; @@ -1769,15 +1783,15 @@ static int iwl_pcie_gen2_force_power_gating(struct iwl_trans *trans) if (ret < 0) return ret; - iwl_set_bits_prph(trans, HPM_HIPM_GEN_CFG, - HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE); + iwl_trans_set_bits_prph(trans, HPM_HIPM_GEN_CFG, + HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE); udelay(20); - iwl_set_bits_prph(trans, HPM_HIPM_GEN_CFG, - HPM_HIPM_GEN_CFG_CR_PG_EN | - HPM_HIPM_GEN_CFG_CR_SLP_EN); + iwl_trans_set_bits_prph(trans, HPM_HIPM_GEN_CFG, + HPM_HIPM_GEN_CFG_CR_PG_EN | + HPM_HIPM_GEN_CFG_CR_SLP_EN); udelay(20); - iwl_clear_bits_prph(trans, HPM_HIPM_GEN_CFG, - HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE); + iwl_trans_clear_bits_prph(trans, HPM_HIPM_GEN_CFG, + HPM_HIPM_GEN_CFG_CR_FORCE_ACTIVE); return iwl_trans_pcie_sw_reset(trans, true); } @@ -1846,6 +1860,11 @@ void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + if (trans->mac_cfg->gen2) { + iwl_trans_pcie_gen2_op_mode_leave(trans); + return; + } + mutex_lock(&trans_pcie->mutex); /* disable interrupts - don't enable HW RF kill interrupt */ @@ -1864,17 +1883,22 @@ void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) { + trace_iwlwifi_dev_iowrite8(trans->dev, ofs, val); writeb(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); } void iwl_trans_pcie_write32(struct iwl_trans *trans, u32 ofs, u32 val) { + trace_iwlwifi_dev_iowrite32(trans->dev, ofs, val); writel(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); } u32 iwl_trans_pcie_read32(struct iwl_trans *trans, u32 ofs) { - return readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); + u32 val = readl(IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs); + + trace_iwlwifi_dev_ioread32(trans->dev, ofs, val); + return val; } static u32 iwl_trans_pcie_prph_msk(struct iwl_trans *trans) @@ -1888,22 +1912,26 @@ static u32 iwl_trans_pcie_prph_msk(struct iwl_trans *trans) u32 iwl_trans_pcie_read_prph(struct iwl_trans *trans, u32 reg) { u32 mask = iwl_trans_pcie_prph_msk(trans); + u32 val; iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_RADDR, ((reg & mask) | (3 << 24))); - return iwl_trans_pcie_read32(trans, HBUS_TARG_PRPH_RDAT); + val = iwl_trans_pcie_read32(trans, HBUS_TARG_PRPH_RDAT); + trace_iwlwifi_dev_ioread_prph32(trans->dev, reg, val); + return val; } -void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr, u32 val) +void iwl_pcie_write_prph_no_grab(struct iwl_trans *trans, u32 addr, u32 val) { u32 mask = iwl_trans_pcie_prph_msk(trans); + trace_iwlwifi_dev_iowrite_prph32(trans->dev, addr, val); iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WADDR, ((addr & mask) | (3 << 24))); iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val); } -void iwl_pcie_gen1_2_op_mode_enter(struct iwl_trans *trans) +void iwl_trans_pcie_op_mode_enter(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); @@ -2265,7 +2293,7 @@ static void iwl_trans_pcie_removal_wk(struct work_struct *wk) module_put(THIS_MODULE); } -void iwl_trans_pcie_reset(struct iwl_trans *trans, enum iwl_reset_mode mode) +static void iwl_trans_pcie_reset(struct iwl_trans *trans, enum iwl_reset_mode mode) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_trans_pcie_removal *removal; @@ -2320,7 +2348,6 @@ void iwl_trans_pcie_reset(struct iwl_trans *trans, enum iwl_reset_mode mode) pci_dev_get(removal->pdev); schedule_work(&removal->work); } -EXPORT_SYMBOL(iwl_trans_pcie_reset); /* * This version doesn't disable BHs but rather assumes they're @@ -2350,7 +2377,7 @@ bool _iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) } /* this bit wakes up the NIC */ - iwl_trans_set_bit(trans, CSR_GP_CNTRL, write); + iwl_pcie_set_bit(trans, CSR_GP_CNTRL, write); if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_8000) udelay(2); @@ -2374,9 +2401,9 @@ bool _iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) * 5000 series and later (including 1000 series) have non-volatile SRAM, * and do not save/restore SRAM when power cycling. */ - ret = iwl_poll_bits_mask(trans, CSR_GP_CNTRL, poll, mask, 15000); + ret = iwl_trans_poll_bits_mask(trans, CSR_GP_CNTRL, poll, mask, 15000); if (unlikely(ret)) { - u32 cntrl = iwl_read32(trans, CSR_GP_CNTRL); + u32 cntrl = iwl_trans_pcie_read32(trans, CSR_GP_CNTRL); if (silent) { spin_unlock(&trans_pcie->reg_lock); @@ -2393,8 +2420,8 @@ bool _iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) iwl_trans_pcie_reset(trans, IWL_RESET_MODE_REMOVE_ONLY); else - iwl_write32(trans, CSR_RESET, - CSR_RESET_REG_FLAG_FORCE_NMI); + iwl_trans_pcie_write32(trans, CSR_RESET, + CSR_RESET_REG_FLAG_FORCE_NMI); spin_unlock(&trans_pcie->reg_lock); return false; @@ -2402,10 +2429,10 @@ bool _iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent) out: /* - * Fool sparse by faking we release the lock - sparse will - * track nic_access anyway. + * Deliberately return with reg_lock held; the caller must drop it via + * iwl_trans_pcie_release_nic_access(), or explicitly if it wants to + * keep the NIC awake past the critical section (cmd_hold_nic_awake). */ - __release(&trans_pcie->reg_lock); return true; } @@ -2427,32 +2454,27 @@ void iwl_trans_pcie_resched_with_nic_access(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + lockdep_assert_held(&trans_pcie->reg_lock); + spin_unlock_bh(&trans_pcie->reg_lock); cond_resched(); spin_lock_bh(&trans_pcie->reg_lock); } -void __releases(nic_access_nobh) -iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) +void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); lockdep_assert_held(&trans_pcie->reg_lock); - /* - * Fool sparse by faking we acquiring the lock - sparse will - * track nic_access anyway. - */ - __acquire(&trans_pcie->reg_lock); - if (trans_pcie->cmd_hold_nic_awake) goto out; if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) - iwl_trans_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); + iwl_pcie_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ); else - iwl_trans_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_pcie_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 @@ -2460,7 +2482,6 @@ iwl_trans_pcie_release_nic_access(struct iwl_trans *trans) * scheduled on different CPUs (after we drop reg_lock). */ out: - __release(nic_access_nobh); spin_unlock_bh(&trans_pcie->reg_lock); } @@ -2478,12 +2499,12 @@ int iwl_trans_pcie_read_mem(struct iwl_trans *trans, u32 addr, bool resched = false; if (iwl_trans_grab_nic_access(trans)) { - iwl_write32(trans, HBUS_TARG_MEM_RADDR, - addr + 4 * offs); + iwl_trans_pcie_write32(trans, HBUS_TARG_MEM_RADDR, + addr + 4 * offs); while (offs < dwords) { - vals[offs] = iwl_read32(trans, - HBUS_TARG_MEM_RDAT); + vals[offs] = iwl_trans_pcie_read32(trans, + HBUS_TARG_MEM_RDAT); if (iwl_trans_is_hw_error_value(vals[offs])) num_consec_hw_errors++; @@ -2530,11 +2551,11 @@ int iwl_trans_pcie_read_mem_no_grab(struct iwl_trans *trans, u32 addr, unsigned long end = jiffies + HZ / 2; bool resched = false; - iwl_write32(trans, HBUS_TARG_MEM_RADDR, - addr + 4 * offs); + iwl_trans_pcie_write32(trans, HBUS_TARG_MEM_RADDR, + addr + 4 * offs); while (offs < dwords) { - vals[offs] = iwl_read32(trans, HBUS_TARG_MEM_RDAT); + vals[offs] = iwl_trans_pcie_read32(trans, HBUS_TARG_MEM_RDAT); if (iwl_trans_is_hw_error_value(vals[offs])) num_consec_hw_errors++; @@ -2678,10 +2699,27 @@ 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_set_bits_mask(trans, reg, mask, value); + iwl_pcie_set_bits_mask(trans, reg, mask, value); spin_unlock_bh(&trans_pcie->reg_lock); } +#define IWL_POLL_INTERVAL 10 /* microseconds */ + +static int iwl_trans_pcie_poll_bits_mask(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_trans_pcie_read32(trans, addr) & mask) == (bits & mask)) + return 0; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + static const char *get_csr_string(int cmd) { #define IWL_CMD(x) case x: return #x @@ -2751,7 +2789,7 @@ void iwl_pcie_dump_csr(struct iwl_trans *trans) for (i = 0; i < ARRAY_SIZE(csr_tbl); i++) { IWL_ERR(trans, " %25s: 0X%08x\n", get_csr_string(csr_tbl[i]), - iwl_read32(trans, csr_tbl[i])); + iwl_trans_pcie_read32(trans, csr_tbl[i])); } } @@ -3016,24 +3054,6 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file, return count; } -static ssize_t iwl_dbgfs_fh_reg_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_trans *trans = file->private_data; - char *buf = NULL; - ssize_t ret; - - ret = iwl_dump_fh(trans, &buf); - if (ret < 0) - return ret; - if (!buf) - return -EINVAL; - ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); - kfree(buf); - return ret; -} - static ssize_t iwl_dbgfs_rfkill_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -3045,7 +3065,7 @@ static ssize_t iwl_dbgfs_rfkill_read(struct file *file, pos = scnprintf(buf, sizeof(buf), "debug: %d\nhw: %d\n", trans_pcie->debug_rfkill, - !(iwl_read32(trans, CSR_GP_CNTRL) & + !(iwl_trans_pcie_read32(trans, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)); return simple_read_from_buffer(user_buf, count, ppos, buf, pos); @@ -3073,137 +3093,6 @@ static ssize_t iwl_dbgfs_rfkill_write(struct file *file, return count; } -static int iwl_dbgfs_monitor_data_open(struct inode *inode, - struct file *file) -{ - struct iwl_trans *trans = inode->i_private; - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - if (!trans->dbg.dest_tlv || - trans->dbg.dest_tlv->monitor_mode != EXTERNAL_MODE) { - IWL_ERR(trans, "Debug destination is not set to DRAM\n"); - return -ENOENT; - } - - if (trans_pcie->fw_mon_data.state != IWL_FW_MON_DBGFS_STATE_CLOSED) - return -EBUSY; - - trans_pcie->fw_mon_data.state = IWL_FW_MON_DBGFS_STATE_OPEN; - return simple_open(inode, file); -} - -static int iwl_dbgfs_monitor_data_release(struct inode *inode, - struct file *file) -{ - struct iwl_trans_pcie *trans_pcie = - IWL_TRANS_GET_PCIE_TRANS(inode->i_private); - - if (trans_pcie->fw_mon_data.state == IWL_FW_MON_DBGFS_STATE_OPEN) - trans_pcie->fw_mon_data.state = IWL_FW_MON_DBGFS_STATE_CLOSED; - return 0; -} - -static bool iwl_write_to_user_buf(char __user *user_buf, ssize_t count, - void *buf, ssize_t *size, - ssize_t *bytes_copied) -{ - ssize_t buf_size_left = count - *bytes_copied; - - buf_size_left = buf_size_left - (buf_size_left % sizeof(u32)); - if (*size > buf_size_left) - *size = buf_size_left; - - *size -= copy_to_user(user_buf, buf, *size); - *bytes_copied += *size; - - if (buf_size_left == *size) - return true; - return false; -} - -static ssize_t iwl_dbgfs_monitor_data_read(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_trans *trans = file->private_data; - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u8 *cpu_addr = (void *)trans->dbg.fw_mon.block, *curr_buf; - struct cont_rec *data = &trans_pcie->fw_mon_data; - u32 write_ptr_addr, wrap_cnt_addr, write_ptr, wrap_cnt; - ssize_t size, bytes_copied = 0; - bool b_full; - - if (trans->dbg.dest_tlv) { - write_ptr_addr = - le32_to_cpu(trans->dbg.dest_tlv->write_ptr_reg); - wrap_cnt_addr = le32_to_cpu(trans->dbg.dest_tlv->wrap_count); - } else { - write_ptr_addr = MON_BUFF_WRPTR; - wrap_cnt_addr = MON_BUFF_CYCLE_CNT; - } - - if (unlikely(!trans->dbg.rec_on)) - return 0; - - mutex_lock(&data->mutex); - if (data->state == - IWL_FW_MON_DBGFS_STATE_DISABLED) { - mutex_unlock(&data->mutex); - return 0; - } - - /* write_ptr position in bytes rather then DW */ - write_ptr = iwl_read_prph(trans, write_ptr_addr) * sizeof(u32); - wrap_cnt = iwl_read_prph(trans, wrap_cnt_addr); - - if (data->prev_wrap_cnt == wrap_cnt) { - size = write_ptr - data->prev_wr_ptr; - curr_buf = cpu_addr + data->prev_wr_ptr; - b_full = iwl_write_to_user_buf(user_buf, count, - curr_buf, &size, - &bytes_copied); - data->prev_wr_ptr += size; - - } else if (data->prev_wrap_cnt == wrap_cnt - 1 && - write_ptr < data->prev_wr_ptr) { - size = trans->dbg.fw_mon.size - data->prev_wr_ptr; - curr_buf = cpu_addr + data->prev_wr_ptr; - b_full = iwl_write_to_user_buf(user_buf, count, - curr_buf, &size, - &bytes_copied); - data->prev_wr_ptr += size; - - if (!b_full) { - size = write_ptr; - b_full = iwl_write_to_user_buf(user_buf, count, - cpu_addr, &size, - &bytes_copied); - data->prev_wr_ptr = size; - data->prev_wrap_cnt++; - } - } else { - if (data->prev_wrap_cnt == wrap_cnt - 1 && - write_ptr > data->prev_wr_ptr) - IWL_WARN(trans, - "write pointer passed previous write pointer, start copying from the beginning\n"); - else if (!unlikely(data->prev_wrap_cnt == 0 && - data->prev_wr_ptr == 0)) - IWL_WARN(trans, - "monitor data is out of sync, start copying from the beginning\n"); - - size = write_ptr; - b_full = iwl_write_to_user_buf(user_buf, count, - cpu_addr, &size, - &bytes_copied); - data->prev_wr_ptr = size; - data->prev_wrap_cnt = wrap_cnt; - } - - mutex_unlock(&data->mutex); - - return bytes_copied; -} - static ssize_t iwl_dbgfs_rf_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -3264,7 +3153,6 @@ static ssize_t iwl_dbgfs_reset_write(struct file *file, } DEBUGFS_READ_WRITE_FILE_OPS(interrupt); -DEBUGFS_READ_FILE_OPS(fh_reg); DEBUGFS_READ_FILE_OPS(rx_queue); DEBUGFS_WRITE_FILE_OPS(csr); DEBUGFS_READ_WRITE_FILE_OPS(rfkill); @@ -3279,12 +3167,6 @@ static const struct file_operations iwl_dbgfs_tx_queue_ops = { .release = seq_release_private, }; -static const struct file_operations iwl_dbgfs_monitor_data_ops = { - .read = iwl_dbgfs_monitor_data_read, - .open = iwl_dbgfs_monitor_data_open, - .release = iwl_dbgfs_monitor_data_release, -}; - /* Create the debugfs files and directories */ void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) { @@ -3294,22 +3176,10 @@ void iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans) DEBUGFS_ADD_FILE(tx_queue, dir, 0400); DEBUGFS_ADD_FILE(interrupt, dir, 0600); DEBUGFS_ADD_FILE(csr, dir, 0200); - DEBUGFS_ADD_FILE(fh_reg, dir, 0400); DEBUGFS_ADD_FILE(rfkill, dir, 0600); - DEBUGFS_ADD_FILE(monitor_data, dir, 0400); DEBUGFS_ADD_FILE(rf, dir, 0400); DEBUGFS_ADD_FILE(reset, dir, 0200); } - -void iwl_trans_pcie_debugfs_cleanup(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - struct cont_rec *data = &trans_pcie->fw_mon_data; - - mutex_lock(&data->mutex); - data->state = IWL_FW_MON_DBGFS_STATE_DISABLED; - mutex_unlock(&data->mutex); -} #endif /*CONFIG_IWLWIFI_DEBUGFS */ static u32 iwl_trans_pcie_get_cmdlen(struct iwl_trans *trans, void *tfd) @@ -3402,8 +3272,8 @@ static u32 iwl_trans_pcie_fh_regs_dump(struct iwl_trans *trans, i += sizeof(u32)) *val++ = cpu_to_le32(iwl_trans_pcie_read32(trans, i)); else - for (i = iwl_umac_prph(trans, FH_MEM_LOWER_BOUND_GEN2); - i < iwl_umac_prph(trans, FH_MEM_UPPER_BOUND_GEN2); + for (i = iwl_trans_umac_prph(trans, FH_MEM_LOWER_BOUND_GEN2); + i < iwl_trans_umac_prph(trans, FH_MEM_UPPER_BOUND_GEN2); i += sizeof(u32)) *val++ = cpu_to_le32(iwl_trans_pcie_read_prph(trans, i)); @@ -3427,11 +3297,11 @@ iwl_trans_pci_dump_marbh_monitor(struct iwl_trans *trans, if (!iwl_trans_grab_nic_access(trans)) return 0; - iwl_write_umac_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x1); + iwl_pcie_write_umac_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x1); for (i = 0; i < buf_size_in_dwords; i++) - buffer[i] = iwl_read_umac_prph_no_grab(trans, - MON_DMARB_RD_DATA_ADDR); - iwl_write_umac_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x0); + buffer[i] = iwl_trans_read_umac_prph_no_grab(trans, + MON_DMARB_RD_DATA_ADDR); + iwl_pcie_write_umac_prph_no_grab(trans, MON_DMARB_RD_CTL_ADDR, 0x0); iwl_trans_release_nic_access(trans); @@ -3459,14 +3329,14 @@ iwl_trans_pcie_dump_pointers(struct iwl_trans *trans, wrap_cnt = MON_BUFF_CYCLE_CNT; } - write_ptr_val = iwl_read_prph(trans, write_ptr); + write_ptr_val = iwl_trans_read_prph(trans, write_ptr); fw_mon_data->fw_mon_cycle_cnt = - cpu_to_le32(iwl_read_prph(trans, wrap_cnt)); + cpu_to_le32(iwl_trans_read_prph(trans, wrap_cnt)); fw_mon_data->fw_mon_base_ptr = - cpu_to_le32(iwl_read_prph(trans, base)); + cpu_to_le32(iwl_trans_read_prph(trans, base)); if (trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { fw_mon_data->fw_mon_base_high_ptr = - cpu_to_le32(iwl_read_prph(trans, base_high)); + cpu_to_le32(iwl_trans_read_prph(trans, base_high)); write_ptr_val &= DBGC_CUR_DBGBUF_STATUS_OFFSET_MSK; /* convert wrtPtr to DWs, to align with all HWs */ write_ptr_val >>= 2; @@ -3504,13 +3374,13 @@ iwl_trans_pcie_dump_monitor(struct iwl_trans *trans, * shifting */ if (trans->dbg.dest_tlv->version) { - base = (iwl_read_prph(trans, base) & + base = (iwl_trans_read_prph(trans, base) & IWL_LDBG_M2S_BUF_BA_MSK) << trans->dbg.dest_tlv->base_shift; base *= IWL_M2S_UNIT_SIZE; base += trans->mac_cfg->base->smem_offset; } else { - base = iwl_read_prph(trans, base) << + base = iwl_trans_read_prph(trans, base) << trans->dbg.dest_tlv->base_shift; } @@ -3545,7 +3415,7 @@ static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, u32 *len) if (trans->dbg.dest_tlv->version == 1) { cfg_reg = le32_to_cpu(trans->dbg.dest_tlv->base_reg); - cfg_reg = iwl_read_prph(trans, cfg_reg); + cfg_reg = iwl_trans_read_prph(trans, cfg_reg); base = (cfg_reg & IWL_LDBG_M2S_BUF_BA_MSK) << trans->dbg.dest_tlv->base_shift; base *= IWL_M2S_UNIT_SIZE; @@ -3559,9 +3429,9 @@ static int iwl_trans_get_fw_monitor_len(struct iwl_trans *trans, u32 *len) base = le32_to_cpu(trans->dbg.dest_tlv->base_reg); end = le32_to_cpu(trans->dbg.dest_tlv->end_reg); - base = iwl_read_prph(trans, base) << + base = iwl_trans_read_prph(trans, base) << trans->dbg.dest_tlv->base_shift; - end = iwl_read_prph(trans, end) << + end = iwl_trans_read_prph(trans, end) << trans->dbg.dest_tlv->end_shift; /* Make "end" point to the actual end */ @@ -3619,8 +3489,8 @@ iwl_trans_pcie_dump_data(struct iwl_trans *trans, u32 dump_mask, if (dump_mask & BIT(IWL_FW_ERROR_DUMP_FH_REGS)) { if (trans->mac_cfg->gen2) len += sizeof(*data) + - (iwl_umac_prph(trans, FH_MEM_UPPER_BOUND_GEN2) - - iwl_umac_prph(trans, FH_MEM_LOWER_BOUND_GEN2)); + (iwl_trans_umac_prph(trans, FH_MEM_UPPER_BOUND_GEN2) - + iwl_trans_umac_prph(trans, FH_MEM_LOWER_BOUND_GEN2)); else len += sizeof(*data) + (FH_MEM_UPPER_BOUND - @@ -3742,8 +3612,10 @@ void iwl_trans_pci_interrupts(struct iwl_trans *trans, bool enable) void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans) { - u32 inta_addr, sw_err_bit; + bool interrupts_enabled = test_bit(STATUS_INT_ENABLED, &trans->status); struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + unsigned long timeout = jiffies + IWL_TRANS_NMI_TIMEOUT; + u32 inta_addr, sw_err_bit; if (trans_pcie->msix_enabled) { inta_addr = CSR_MSIX_HW_INT_CAUSES_AD; @@ -3756,7 +3628,34 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans) sw_err_bit = CSR_INT_BIT_SW_ERR; } - iwl_trans_sync_nmi_with_addr(trans, inta_addr, sw_err_bit); + /* if the interrupts were already disabled, there is no point in + * calling iwl_disable_interrupts + */ + if (interrupts_enabled) + iwl_trans_pci_interrupts(trans, false); + + iwl_trans_force_nmi(trans); + while (time_after(timeout, jiffies)) { + u32 inta_hw = iwl_trans_pcie_read32(trans, inta_addr); + + /* Error detected by uCode */ + if (inta_hw & sw_err_bit) { + /* Clear causes register */ + iwl_trans_pcie_write32(trans, inta_addr, inta_hw & sw_err_bit); + break; + } + + mdelay(1); + } + + /* enable interrupts only if there were already enabled before this + * function to avoid a case were the driver enable interrupts before + * proper configurations were made + */ + if (interrupts_enabled) + iwl_trans_pci_interrupts(trans, true); + + iwl_trans_fw_error(trans, IWL_ERR_TYPE_NMI_FORCED); } static int iwl_trans_pcie_alloc_txcmd_pool(struct iwl_trans *trans) @@ -3796,6 +3695,66 @@ static int iwl_trans_pcie_alloc_txcmd_pool(struct iwl_trans *trans) return 0; } +const struct iwl_trans_ops iwl_trans_pcie_ops = { + .op_mode_enter = iwl_trans_pcie_op_mode_enter, + .start_hw = iwl_trans_pcie_start_hw, + .op_mode_leave = iwl_trans_pcie_op_mode_leave, + + .send_cmd = iwl_trans_pcie_send_hcmd, + .alloc_tx_cmd = iwl_pcie_alloc_tx_cmd, + .free_tx_cmd = iwl_pcie_free_tx_cmd, + + .write32 = iwl_trans_pcie_write32, + .read32 = iwl_trans_pcie_read32, + .read_prph = iwl_trans_pcie_read_prph, + .write_prph = iwl_pcie_write_prph_no_grab, + .read_mem = iwl_trans_pcie_read_mem, + .read_mem_no_grab = iwl_trans_pcie_read_mem_no_grab, + .set_bits_mask = iwl_trans_pcie_set_bits_mask, + .poll_bits_mask = iwl_trans_pcie_poll_bits_mask, + .read_config32 = iwl_trans_pcie_read_config32, + .grab_nic_access = iwl_trans_pcie_grab_nic_access, + .release_nic_access = iwl_trans_pcie_release_nic_access, + .resched_with_nic_access = iwl_trans_pcie_resched_with_nic_access, + + .sw_reset = iwl_trans_pcie_sw_reset, + .reset = iwl_trans_pcie_reset, + .fw_reset_handshake = iwl_trans_pcie_fw_reset_handshake, + + .dump_data = iwl_trans_pcie_dump_data, + .d3_suspend = iwl_trans_pcie_d3_suspend, + .d3_resume = iwl_trans_pcie_d3_resume, + + .sync_nmi = iwl_trans_pcie_sync_nmi, + .write_imr_mem = iwl_trans_pcie_copy_imr, + + .fw_alive = iwl_trans_pcie_fw_alive, + .start_fw = iwl_trans_pcie_start_fw, + .stop_device = iwl_trans_pcie_stop_device, + + .tx = iwl_trans_pcie_tx, + .reclaim = iwl_pcie_reclaim, + .txq_disable = iwl_trans_pcie_txq_disable, + .txq_enable = iwl_trans_pcie_txq_enable, + .wait_txq_empty = iwl_trans_pcie_wait_txq_empty, + .wait_txqs_empty = iwl_trans_pcie_wait_txqs_empty, + .freeze_txq_timer = iwl_pcie_freeze_txq_timer, + .txq_set_shared_mode = iwl_trans_pcie_txq_set_shared_mode, + .set_q_ptrs = iwl_pcie_set_q_ptrs, + .txq_alloc = iwl_txq_dyn_alloc, + .txq_free = iwl_txq_dyn_free, + .rxq_dma_data = iwl_trans_pcie_rxq_dma_data, + + .load_pnvm = iwl_trans_pcie_ctx_info_v2_load_pnvm, + .set_pnvm = iwl_trans_pcie_ctx_info_v2_set_pnvm, + .load_reduce_power = iwl_trans_pcie_ctx_info_v2_load_reduce_power, + .set_reduce_power = iwl_trans_pcie_ctx_info_v2_set_reduce_power, + + .is_pm_supported = iwl_pcie_gen1_is_pm_supported, + .is_ltr_enabled = iwl_pcie_is_ltr_enabled, + .activate_nic = iwl_pcie_activate_nic, +}; + static struct iwl_trans * iwl_trans_pcie_alloc(struct pci_dev *pdev, const struct iwl_mac_cfg *mac_cfg, @@ -3807,7 +3766,7 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, int ret, addr_size; trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev, - mac_cfg); + &iwl_trans_pcie_ops, mac_cfg); if (!trans) return ERR_PTR(-ENOMEM); @@ -3974,11 +3933,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, } } -#ifdef CONFIG_IWLWIFI_DEBUGFS - trans_pcie->fw_mon_data.state = IWL_FW_MON_DBGFS_STATE_CLOSED; - mutex_init(&trans_pcie->fw_mon_data.mutex); -#endif - iwl_dbg_tlv_init(trans); return trans; @@ -4001,19 +3955,19 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, void iwl_trans_pcie_copy_imr_fh(struct iwl_trans *trans, u32 dst_addr, u64 src_addr, u32 byte_cnt) { - iwl_write_prph(trans, IMR_UREG_CHICK, - iwl_read_prph(trans, IMR_UREG_CHICK) | - IMR_UREG_CHICK_HALT_UMAC_PERMANENTLY_MSK); - iwl_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_SRAM_ADDR, dst_addr); - iwl_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_DRAM_ADDR_LSB, - (u32)(src_addr & 0xFFFFFFFF)); - iwl_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_DRAM_ADDR_MSB, - iwl_get_dma_hi_addr(src_addr)); - iwl_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_BC, byte_cnt); - iwl_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_CTRL, - IMR_TFH_SRV_DMA_CHNL0_CTRL_D2S_IRQ_TARGET_POS | - IMR_TFH_SRV_DMA_CHNL0_CTRL_D2S_DMA_EN_POS | - IMR_TFH_SRV_DMA_CHNL0_CTRL_D2S_RS_MSK); + iwl_trans_write_prph(trans, IMR_UREG_CHICK, + iwl_trans_read_prph(trans, IMR_UREG_CHICK) | + IMR_UREG_CHICK_HALT_UMAC_PERMANENTLY_MSK); + iwl_trans_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_SRAM_ADDR, dst_addr); + iwl_trans_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_DRAM_ADDR_LSB, + (u32)(src_addr & 0xFFFFFFFF)); + iwl_trans_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_DRAM_ADDR_MSB, + iwl_get_dma_hi_addr(src_addr)); + iwl_trans_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_BC, byte_cnt); + iwl_trans_write_prph(trans, IMR_TFH_SRV_DMA_CHNL0_CTRL, + IMR_TFH_SRV_DMA_CHNL0_CTRL_D2S_IRQ_TARGET_POS | + IMR_TFH_SRV_DMA_CHNL0_CTRL_D2S_DMA_EN_POS | + IMR_TFH_SRV_DMA_CHNL0_CTRL_D2S_RS_MSK); } int iwl_trans_pcie_copy_imr(struct iwl_trans *trans, @@ -4040,10 +3994,10 @@ int iwl_trans_pcie_copy_imr(struct iwl_trans *trans, * Read rf id and cdb info from prph register and store it */ static void get_crf_id(struct iwl_trans *iwl_trans, - struct iwl_trans_info *info) + struct iwl_trans_info *info, + u32 *hw_wfpm_id) { u32 sd_reg_ver_addr; - u32 hw_wfpm_id; u32 val = 0; u8 step; @@ -4055,8 +4009,8 @@ static void get_crf_id(struct iwl_trans *iwl_trans, /* wait until the device is ready to access the prph registers */ if (iwl_trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_DR || iwl_trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_SC) { - u32 req = iwl_read_umac_prph_no_grab(iwl_trans, - WFPM_RSRCS_4PHS_REQ_STTS); + u32 req = iwl_trans_read_umac_prph_no_grab(iwl_trans, + WFPM_RSRCS_4PHS_REQ_STTS); int ret; if (!(req & RSRC_REQ_CNVR_TOP)) { @@ -4066,26 +4020,26 @@ static void get_crf_id(struct iwl_trans *iwl_trans, return; } - ret = iwl_poll_umac_prph_bits_no_grab(iwl_trans, - WFPM_RSRCS_4PHS_ACK_STTS, - RSRC_ACK_CNVR_TOP, - RSRC_ACK_CNVR_TOP, - 50 * 1000); + ret = iwl_pcie_poll_umac_prph_bits_no_grab(iwl_trans, + WFPM_RSRCS_4PHS_ACK_STTS, + RSRC_ACK_CNVR_TOP, + RSRC_ACK_CNVR_TOP, + 50 * 1000); if (ret < 0) IWL_ERR(iwl_trans, "WFPM_RSRCS_4PHS_ACK_STTS bit 6 is clear\n"); } /* Enable access to peripheral registers */ - val = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG); + val = iwl_trans_read_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG); val |= WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK; - iwl_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val); + iwl_pcie_write_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG, val); /* Read crf info */ - info->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr); + info->hw_crf_id = iwl_trans_pcie_read_prph(iwl_trans, sd_reg_ver_addr); /* Read cnv info */ - info->hw_cnv_id = iwl_read_prph_no_grab(iwl_trans, CNVI_AUX_MISC_CHIP); + info->hw_cnv_id = iwl_trans_pcie_read_prph(iwl_trans, CNVI_AUX_MISC_CHIP); /* For BZ-W, take B step also when A step is indicated */ if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) @@ -4109,10 +4063,10 @@ static void get_crf_id(struct iwl_trans *iwl_trans, } /* Read cdb info (also contains the jacket info if needed in the future */ - hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); + *hw_wfpm_id = iwl_trans_read_umac_prph_no_grab(iwl_trans, WFPM_OTP_CFG1_ADDR); IWL_INFO(iwl_trans, "Detected crf-id 0x%x, cnv-id 0x%x wfpm id 0x%x\n", - info->hw_crf_id, info->hw_cnv_id, hw_wfpm_id); + info->hw_crf_id, info->hw_cnv_id, *hw_wfpm_id); } /* @@ -4120,14 +4074,13 @@ static void get_crf_id(struct iwl_trans *iwl_trans, * from the prph registers. */ static int map_crf_id(struct iwl_trans *iwl_trans, - struct iwl_trans_info *info) + struct iwl_trans_info *info, + u32 hw_wfpm_id) { int ret = 0; u32 val = info->hw_crf_id; u32 step_id = REG_CRF_ID_STEP(val); u32 slave_id = REG_CRF_ID_SLAVE(val); - u32 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, - WFPM_OTP_CFG1_ADDR); u32 cdb_id_wfpm = WFPM_OTP_CFG1_IS_CDB(hw_wfpm_id); /* Map between crf id to rf id */ @@ -4193,7 +4146,7 @@ static void iwl_pcie_recheck_me_status(struct work_struct *wk) me_recheck_wk.work); u32 val; - val = iwl_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG); + val = iwl_trans_pcie_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG); trans_pcie->me_present = !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP); } @@ -4211,14 +4164,14 @@ static void iwl_pcie_check_me_status(struct iwl_trans *trans) if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ) return; - val = iwl_read_prph(trans, CNVI_SCU_REG_FOR_ECO_1); + val = iwl_trans_pcie_read_prph(trans, CNVI_SCU_REG_FOR_ECO_1); if (val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_KNOWN) { trans_pcie->me_present = !!(val & CNVI_SCU_REG_FOR_ECO_1_WIAMT_PRESENT); return; } - val = iwl_read32(trans, CSR_HW_IF_CONFIG_REG); + val = iwl_trans_pcie_read32(trans, CSR_HW_IF_CONFIG_REG); if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN | CSR_HW_IF_CONFIG_REG_IAMT_UP)) { trans_pcie->me_present = 1; @@ -4229,10 +4182,9 @@ static void iwl_pcie_check_me_status(struct iwl_trans *trans) schedule_delayed_work(&trans_pcie->me_recheck_wk, HZ); } -int iwl_pci_gen1_2_probe(struct pci_dev *pdev, - const struct pci_device_id *ent, - const struct iwl_mac_cfg *mac_cfg, - u8 __iomem *hw_base, u32 hw_rev) +int _iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent, + const struct iwl_mac_cfg *mac_cfg, + u8 __iomem *hw_base, u32 hw_rev) { const struct iwl_dev_info *dev_info; struct iwl_trans_info info = { @@ -4241,6 +4193,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, }; struct iwl_trans *iwl_trans; struct iwl_trans_pcie *trans_pcie; + u32 hw_wfpm_id = 0; int ret; iwl_trans = iwl_trans_pcie_alloc(pdev, mac_cfg, &info, hw_base); @@ -4268,7 +4221,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, if (ret) goto out_free_trans; if (iwl_trans_grab_nic_access(iwl_trans)) { - get_crf_id(iwl_trans, &info); + get_crf_id(iwl_trans, &info, &hw_wfpm_id); /* all good */ iwl_trans_release_nic_access(iwl_trans); } else { @@ -4277,7 +4230,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, } } - info.hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID); + info.hw_rf_id = iwl_trans_pcie_read32(iwl_trans, CSR_HW_RF_ID); /* * The RF_ID is set to zero in blank OTP so read version to @@ -4285,7 +4238,8 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, * This is relevant only for family 9000 and up. */ if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_9000 && - !CSR_HW_RFID_TYPE(info.hw_rf_id) && map_crf_id(iwl_trans, &info)) { + !CSR_HW_RFID_TYPE(info.hw_rf_id) && + map_crf_id(iwl_trans, &info, hw_wfpm_id)) { ret = -EINVAL; goto out_free_trans; } @@ -4382,18 +4336,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, return ret; } -void iwl_pcie_gen1_2_remove(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - cancel_delayed_work_sync(&trans_pcie->me_recheck_wk); - - iwl_drv_stop(trans->drv); - - iwl_trans_pcie_free(trans); -} - -int iwl_pcie_gen1_2_activate_nic(struct iwl_trans *trans) +int iwl_pcie_activate_nic(struct iwl_trans *trans) { const struct iwl_mac_cfg *mac_cfg = trans->mac_cfg; u32 poll_ready; @@ -4409,13 +4352,13 @@ int iwl_pcie_gen1_2_activate_nic(struct iwl_trans *trans) * D0U* --> D0A* (powered-up active) state. */ if (mac_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) { - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ | - CSR_GP_CNTRL_REG_FLAG_MAC_INIT); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ | + CSR_GP_CNTRL_REG_FLAG_MAC_INIT); poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; } else { - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_INIT_DONE); poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY; } @@ -4424,10 +4367,10 @@ int iwl_pcie_gen1_2_activate_nic(struct iwl_trans *trans) /* * Wait for clock stabilization; once stabilized, access to - * device-internal resources is supported, e.g. iwl_write_prph() + * device-internal resources is supported, e.g. iwl_trans_write_prph() * and accesses to uCode SRAM. */ - err = iwl_poll_bits(trans, CSR_GP_CNTRL, poll_ready, 25000); + err = iwl_trans_poll_bits(trans, CSR_GP_CNTRL, poll_ready, 25000); if (err < 0) { IWL_DEBUG_INFO(trans, "Failed to wake NIC\n"); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c similarity index 99% rename from drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c rename to drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c index 27f4973791d0..b235a4539d7c 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx-gen2.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx-gen2.c @@ -1,14 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2020, 2023-2025 Intel Corporation + * Copyright (C) 2018-2020, 2023-2026 Intel Corporation */ #include #include #include "iwl-debug.h" #include "iwl-csr.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "internal.h" #include "fw/api/tx.h" #include "fw/api/commands.h" @@ -711,7 +711,7 @@ static void iwl_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq) * if not in power-save mode, uCode will never sleep when we're * trying to tx (during RFKILL, we're not trying to tx). */ - iwl_write32(trans, HBUS_TARG_WRPTR, txq->write_ptr | (txq->id << 16)); + iwl_trans_pcie_write32(trans, HBUS_TARG_WRPTR, txq->write_ptr | (txq->id << 16)); } int iwl_txq_gen2_tx(struct iwl_trans *trans, struct sk_buff *skb, @@ -1075,7 +1075,8 @@ int iwl_txq_dyn_alloc(struct iwl_trans *trans, u32 flags, u32 sta_mask, hcmd.id = SCD_QUEUE_CFG; hcmd.len[0] = sizeof(cmd.old); hcmd.data[0] = &cmd.old; - } else if (trans->conf.queue_alloc_cmd_ver == 3) { + } else if (trans->conf.queue_alloc_cmd_ver == 3 || + trans->conf.queue_alloc_cmd_ver == 4) { memset(&cmd.new, 0, sizeof(cmd.new)); cmd.new.operation = cpu_to_le32(IWL_SCD_QUEUE_ADD); cmd.new.u.add.tfdq_dram_addr = cpu_to_le64(txq->dma_addr); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c similarity index 94% rename from drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c rename to drivers/net/wireless/intel/iwlwifi/pcie/tx.c index dc2fe0c4f68c..0c29fb6b9ca7 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/tx.c @@ -20,7 +20,7 @@ #include "iwl-debug.h" #include "iwl-csr.h" #include "iwl-prph.h" -#include "iwl-io.h" +#include "iwl-trans.h" #include "iwl-scd.h" #include "iwl-op-mode.h" #include "internal.h" @@ -99,13 +99,13 @@ static void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, * uCode will wake up, and interrupt us again, so next * time we'll skip this part. */ - reg = iwl_read32(trans, CSR_UCODE_DRV_GP1); + reg = iwl_trans_pcie_read32(trans, CSR_UCODE_DRV_GP1); if (reg & CSR_UCODE_DRV_GP1_BIT_MAC_SLEEP) { IWL_DEBUG_INFO(trans, "Tx queue %d requesting wakeup, GP1 = 0x%x\n", txq_id, reg); - iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_trans_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); txq->need_update = true; return; } @@ -117,8 +117,8 @@ static void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, */ IWL_DEBUG_TX(trans, "Q:%d WR: 0x%x\n", txq_id, txq->write_ptr); if (!txq->block) - iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (txq_id << 8)); + iwl_trans_pcie_write32(trans, HBUS_TARG_WRPTR, + txq->write_ptr | (txq_id << 8)); } void iwl_pcie_txq_check_wrptrs(struct iwl_trans *trans) @@ -205,8 +205,8 @@ static void iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans) } trans_pcie->cmd_hold_nic_awake = false; - iwl_trans_clear_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + iwl_pcie_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); spin_unlock(&trans_pcie->reg_lock); } @@ -493,21 +493,21 @@ void iwl_pcie_tx_start(struct iwl_trans *trans) sizeof(trans_pcie->txqs.queue_used)); trans_pcie->scd_base_addr = - iwl_read_prph(trans, SCD_SRAM_BASE_ADDR); + iwl_trans_read_prph(trans, SCD_SRAM_BASE_ADDR); /* reset context data, TX status and translation data */ 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); + iwl_trans_write_prph(trans, SCD_DRAM_BASE_ADDR, + trans_pcie->txqs.scd_bc_tbls.dma >> 10); /* The chain extension of the SCD doesn't work well. This feature is * enabled by default by the HW, so we need to disable it manually. */ if (trans->mac_cfg->base->scd_chain_ext_wa) - iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); + iwl_trans_write_prph(trans, SCD_CHAINEXT_EN, 0); iwl_trans_ac_txq_enable(trans, trans->conf.cmd_queue, trans->conf.cmd_fifo, @@ -518,19 +518,19 @@ void iwl_pcie_tx_start(struct iwl_trans *trans) /* Enable DMA channel */ for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++) - iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + iwl_trans_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); /* Update FH chicken bits */ - reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG); - iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG, - reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); + reg_val = iwl_pcie_read_direct32(trans, FH_TX_CHICKEN_BITS_REG); + iwl_trans_write_direct32(trans, FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); /* Enable L1-Active */ if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_8000) - iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, - APMG_PCIDEV_STT_VAL_L1_ACT_DIS); + iwl_trans_clear_bits_prph(trans, APMG_PCIDEV_STT_REG, + APMG_PCIDEV_STT_VAL_L1_ACT_DIS); } void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) @@ -549,21 +549,21 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans) txq_id++) { struct iwl_txq *txq = trans_pcie->txqs.txq[txq_id]; if (trans->mac_cfg->gen2) - iwl_write_direct64(trans, - FH_MEM_CBBC_QUEUE(trans, txq_id), - txq->dma_addr); + iwl_pcie_write_direct64(trans, + FH_MEM_CBBC_QUEUE(trans, txq_id), + txq->dma_addr); else - iwl_write_direct32(trans, - FH_MEM_CBBC_QUEUE(trans, txq_id), - txq->dma_addr >> 8); + iwl_trans_write_direct32(trans, + FH_MEM_CBBC_QUEUE(trans, txq_id), + txq->dma_addr >> 8); iwl_pcie_txq_unmap(trans, txq_id); txq->read_ptr = 0; txq->write_ptr = 0; } /* Tell NIC where to find the "keep warm" buffer */ - iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, - trans_pcie->kw.dma >> 4); + iwl_trans_write_direct32(trans, FH_KW_MEM_ADDR_REG, + trans_pcie->kw.dma >> 4); /* * Send 0 as the scd_base_addr since the device may have be reset @@ -586,16 +586,16 @@ static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans) /* Stop each Tx DMA channel */ for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) { - iwl_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); + iwl_trans_pcie_write32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); mask |= FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch); } /* Wait for DMA channels to be idle */ - ret = iwl_poll_bits(trans, FH_TSSR_TX_STATUS_REG, mask, 5000); + ret = iwl_trans_poll_bits(trans, FH_TSSR_TX_STATUS_REG, mask, 5000); if (ret) IWL_ERR(trans, "Failing on timeout while stopping DMA channel %d [0x%08x]\n", - ch, iwl_read32(trans, FH_TSSR_TX_STATUS_REG)); + ch, iwl_trans_pcie_read32(trans, FH_TSSR_TX_STATUS_REG)); iwl_trans_release_nic_access(trans); @@ -684,7 +684,7 @@ void iwl_txq_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq) return; } - status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id)); + status = iwl_trans_read_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id)); fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7; active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE)); @@ -693,11 +693,11 @@ void iwl_txq_log_scd_error(struct iwl_trans *trans, struct iwl_txq *txq) txq_id, active ? "" : "in", fifo, jiffies_to_msecs(txq->wd_timeout), txq->read_ptr, txq->write_ptr, - iwl_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & + iwl_trans_read_prph(trans, SCD_QUEUE_RDPTR(txq_id)) & (trans->mac_cfg->base->max_tfd_queue_size - 1), - iwl_read_prph(trans, SCD_QUEUE_WRPTR(txq_id)) & + iwl_trans_read_prph(trans, SCD_QUEUE_WRPTR(txq_id)) & (trans->mac_cfg->base->max_tfd_queue_size - 1), - iwl_read_direct32(trans, FH_TX_TRB_REG(fifo))); + iwl_pcie_read_direct32(trans, FH_TX_TRB_REG(fifo))); } static void iwl_txq_stuck_timer(struct timer_list *t) @@ -715,7 +715,7 @@ static void iwl_txq_stuck_timer(struct timer_list *t) iwl_txq_log_scd_error(trans, txq); - iwl_force_nmi(trans); + iwl_trans_force_nmi(trans); } int iwl_pcie_txq_alloc(struct iwl_trans *trans, struct iwl_txq *txq, @@ -955,8 +955,8 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) iwl_scd_deactivate_fifos(trans); /* Tell NIC where to find the "keep warm" buffer */ - iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, - trans_pcie->kw.dma >> 4); + iwl_trans_write_direct32(trans, FH_KW_MEM_ADDR_REG, + trans_pcie->kw.dma >> 4); spin_unlock_bh(&trans_pcie->irq_lock); @@ -984,14 +984,14 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) * queue. * Circular buffer (TFD queue in DRAM) physical base address */ - iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(trans, txq_id), - trans_pcie->txqs.txq[txq_id]->dma_addr >> 8); + iwl_trans_write_direct32(trans, FH_MEM_CBBC_QUEUE(trans, txq_id), + trans_pcie->txqs.txq[txq_id]->dma_addr >> 8); } - iwl_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE); + iwl_trans_set_bits_prph(trans, SCD_GP_CTRL, SCD_GP_CTRL_AUTO_ACTIVE_MODE); if (trans->mac_cfg->base->num_of_queues > 20) - iwl_set_bits_prph(trans, SCD_GP_CTRL, - SCD_GP_CTRL_ENABLE_31_QUEUES); + iwl_trans_set_bits_prph(trans, SCD_GP_CTRL, + SCD_GP_CTRL_ENABLE_31_QUEUES); return 0; error: @@ -1105,7 +1105,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) if (nfreed++ > 0) { IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n", idx, txq->write_ptr, r); - iwl_force_nmi(trans); + iwl_trans_force_nmi(trans); } } @@ -1222,13 +1222,13 @@ bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, * Assumes that ssn_idx is valid (!= 0xFFF) */ txq->read_ptr = (ssn & 0xff); txq->write_ptr = (ssn & 0xff); - iwl_write_direct32(trans, HBUS_TARG_WRPTR, - (ssn & 0xff) | (txq_id << 8)); + iwl_trans_write_direct32(trans, HBUS_TARG_WRPTR, + (ssn & 0xff) | (txq_id << 8)); if (cfg) { u8 frame_limit = cfg->frame_limit; - iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); + iwl_trans_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn); /* Set up Tx window size and frame limit for this queue */ iwl_trans_write_mem32(trans, trans_pcie->scd_base_addr + @@ -1240,11 +1240,11 @@ bool iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn, SCD_QUEUE_CTX_REG2_VAL(FRAME_LIMIT, frame_limit)); /* Set up status area in SRAM, map to Tx DMA/FIFO, activate */ - iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), - (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) | - (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) | - (1 << SCD_QUEUE_STTS_REG_POS_WSL) | - SCD_QUEUE_STTS_REG_MSK); + iwl_trans_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id), + (1 << SCD_QUEUE_STTS_REG_POS_ACTIVE) | + (cfg->fifo << SCD_QUEUE_STTS_REG_POS_TXF) | + (1 << SCD_QUEUE_STTS_REG_POS_WSL) | + SCD_QUEUE_STTS_REG_MSK); /* enable the scheduler for this queue (only) */ if (txq_id == trans->conf.cmd_queue && @@ -1276,9 +1276,17 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id, bool configure_scd) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 stts_addr = trans_pcie->scd_base_addr + - SCD_TX_STTS_QUEUE_OFFSET(txq_id); static const u32 zero_val[4] = {}; + u32 stts_addr; + + if (WARN_ON(txq_id < 0 || + txq_id >= trans->mac_cfg->base->num_of_queues || + txq_id == trans->conf.cmd_queue || + !trans_pcie->txqs.txq[txq_id])) + return; + + stts_addr = trans_pcie->scd_base_addr + + SCD_TX_STTS_QUEUE_OFFSET(txq_id); trans_pcie->txqs.txq[txq_id]->frozen_expiry_remainder = 0; trans_pcie->txqs.txq[txq_id]->frozen = false; @@ -1327,8 +1335,8 @@ static void iwl_trans_pcie_block_txq_ptrs(struct iwl_trans *trans, bool block) if (!block && !(WARN_ON_ONCE(!txq->block))) { txq->block--; if (!txq->block) { - iwl_write32(trans, HBUS_TARG_WRPTR, - txq->write_ptr | (i << 8)); + iwl_trans_pcie_write32(trans, HBUS_TARG_WRPTR, + txq->write_ptr | (i << 8)); } } else if (block) { txq->block++; @@ -1894,18 +1902,27 @@ struct sg_table *iwl_pcie_prep_tso(struct iwl_trans *trans, struct sk_buff *skb, /* Only map the data, not the header (it is copied to the TSO page) */ orig_nents = skb_to_sgvec(skb, sgt->sgl, offset, skb->len - offset); if (WARN_ON_ONCE(orig_nents <= 0)) - return NULL; + goto err_cleanup; sgt->orig_nents = orig_nents; /* And map the entire SKB */ if (dma_map_sgtable(trans->dev, sgt, DMA_TO_DEVICE, 0) < 0) - return NULL; + goto err_cleanup; /* Store non-zero (i.e. valid) offset for unmapping */ cmd_meta->sg_offset = (unsigned long) sgt & ~PAGE_MASK; return sgt; + +err_cleanup: + /* + * Since cmd_meta->sg_offset is not set yet, iwl_pcie_free_tso_pages + * will only free the page without unmapping the SG table (which hasn't + * been successfully mapped yet anyway). + */ + iwl_pcie_free_tso_pages(trans, skb, cmd_meta); + return NULL; } static int iwl_fill_data_tbs_amsdu(struct iwl_trans *trans, struct sk_buff *skb, @@ -2130,6 +2147,9 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb, u16 wifi_seq; bool amsdu; + if (trans->mac_cfg->gen2) + return iwl_txq_gen2_tx(trans, skb, dev_cmd, txq_id); + txq = trans_pcie->txqs.txq[txq_id]; if (WARN_ONCE(!test_bit(txq_id, trans_pcie->txqs.queue_used), @@ -2552,6 +2572,7 @@ void iwl_pcie_freeze_txq_timer(struct iwl_trans *trans, } } +#define HOST_COMPLETE_QUICK_TIMEOUT msecs_to_jiffies(200) #define HOST_COMPLETE_TIMEOUT (2 * HZ) static int iwl_trans_pcie_send_hcmd_sync(struct iwl_trans *trans, @@ -2585,10 +2606,32 @@ static int iwl_trans_pcie_send_hcmd_sync(struct iwl_trans *trans, return ret; } - ret = wait_event_timeout(trans_pcie->wait_command_queue, - !test_bit(STATUS_SYNC_HCMD_ACTIVE, - &trans->status), - HOST_COMPLETE_TIMEOUT); + /* + * There is a race between the PCI link power save flows and the + * notification / MSI-X interrupt in the firmware. + * If we didn't get a response after 200ms, poke the config space + * to force a wake-up of the PCI link. + */ + for (int i = 0; i < 2; i++) { + ret = wait_event_timeout(trans_pcie->wait_command_queue, + !test_bit(STATUS_SYNC_HCMD_ACTIVE, + &trans->status), + i == 0 ? HOST_COMPLETE_QUICK_TIMEOUT : + HOST_COMPLETE_TIMEOUT); + if (ret) + break; + + if (i == 0) { + u32 val; + + pci_read_config_dword(trans_pcie->pci_dev, + PCI_VENDOR_ID, &val); + IWL_DEBUG_HC(trans, + "write_ptr: %d: no response after %ums poking config space\n", + txq->write_ptr, + jiffies_to_msecs(HOST_COMPLETE_QUICK_TIMEOUT)); + } + } if (!ret) { IWL_ERR(trans, "Error sending %s: time out after %dms.\n", cmd_str, jiffies_to_msecs(HOST_COMPLETE_TIMEOUT)); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/utils.c b/drivers/net/wireless/intel/iwlwifi/pcie/utils.c index 1bb274d8390c..8aa43e5ac0e1 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/utils.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/utils.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2025 Intel Corporation + * Copyright (C) 2025-2026 Intel Corporation */ #include #include -#include "iwl-io.h" +#include "iwl-trans.h" #include "pcie/utils.h" void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev) @@ -51,7 +51,7 @@ void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev) 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); + *ptr = iwl_trans_pcie_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); @@ -102,3 +102,88 @@ void iwl_trans_pcie_dump_regs(struct iwl_trans *trans, struct pci_dev *pdev) pcie_dbg_dumped_once = 1; kfree(buf); } + +u32 iwl_pcie_read_direct32(struct iwl_trans *trans, u32 reg) +{ + if (iwl_trans_grab_nic_access(trans)) { + u32 value = iwl_trans_pcie_read32(trans, reg); + + iwl_trans_release_nic_access(trans); + return value; + } + + /* return as if we have a HW timeout/failure */ + return 0x5a5a5a5a; +} + +#define IWL_PCIE_POLL_INTERVAL 10 /* microseconds */ + +int iwl_pcie_poll_direct_bit(struct iwl_trans *trans, + u32 addr, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_pcie_read_direct32(trans, addr) & mask) == mask) + return t; + udelay(IWL_PCIE_POLL_INTERVAL); + t += IWL_PCIE_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +int iwl_pcie_poll_prph_bit(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_trans_read_prph(trans, addr) & mask) == (bits & mask)) + return 0; + udelay(IWL_PCIE_POLL_INTERVAL); + t += IWL_PCIE_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +int iwl_pcie_poll_umac_prph_bit(struct iwl_trans *trans, + u32 addr, u32 bits, u32 mask, + int timeout) +{ + return iwl_pcie_poll_prph_bit(trans, addr + + trans->mac_cfg->umac_prph_offset, + bits, mask, timeout); +} + +int iwl_pcie_poll_umac_prph_bits_no_grab(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout) +{ + int t = 0; + + do { + if ((iwl_trans_read_umac_prph_no_grab(trans, addr) & mask) == + (bits & mask)) + return 0; + udelay(IWL_PCIE_POLL_INTERVAL); + t += IWL_PCIE_POLL_INTERVAL; + } while (t < timeout); + + return -ETIMEDOUT; +} + +void iwl_pcie_write_prph64_no_grab(struct iwl_trans *trans, u32 ofs, u64 val) +{ + trace_iwlwifi_dev_iowrite_prph64(trans->dev, ofs, val); + iwl_pcie_write_prph_no_grab(trans, ofs, val & 0xffffffff); + iwl_pcie_write_prph_no_grab(trans, ofs + 4, val >> 32); +} + +void iwl_pcie_write_direct64(struct iwl_trans *trans, u64 reg, u64 value) +{ + if (iwl_trans_grab_nic_access(trans)) { + iwl_pcie_write64(trans, reg, value); + iwl_trans_release_nic_access(trans); + } +} diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/utils.h b/drivers/net/wireless/intel/iwlwifi/pcie/utils.h index 27437d5e099b..ece1caaa4948 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/utils.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/utils.h @@ -1,17 +1,43 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2025 Intel Corporation + * Copyright (C) 2025-2026 Intel Corporation */ #ifndef __iwl_pcie_utils_h__ #define __iwl_pcie_utils_h__ -#include "iwl-io.h" +#include "iwl-trans.h" +#include "internal.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 iwl_pcie_read_direct32(struct iwl_trans *trans, u32 reg); +int iwl_pcie_poll_direct_bit(struct iwl_trans *trans, + u32 addr, u32 mask, int timeout); +int iwl_pcie_poll_prph_bit(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout); +int iwl_pcie_poll_umac_prph_bit(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout); +int iwl_pcie_poll_umac_prph_bits_no_grab(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout); +void iwl_pcie_write_prph64_no_grab(struct iwl_trans *trans, u32 ofs, u64 val); +void iwl_pcie_write_direct64(struct iwl_trans *trans, u64 reg, u64 value); + +static inline void iwl_pcie_write64(struct iwl_trans *trans, u64 ofs, u64 val) +{ + iwl_trans_pcie_write32(trans, ofs, lower_32_bits(val)); + iwl_trans_pcie_write32(trans, ofs + 4, upper_32_bits(val)); +} + +static inline void iwl_pcie_write_umac_prph_no_grab(struct iwl_trans *trans, + u32 ofs, u32 val) +{ + iwl_pcie_write_prph_no_grab(trans, ofs + trans->mac_cfg->umac_prph_offset, + val); +} + +static inline void iwl_pcie_set_bits_mask(struct iwl_trans *trans, + u32 reg, u32 mask, u32 value) { u32 v; @@ -19,22 +45,22 @@ static inline void _iwl_trans_set_bits_mask(struct iwl_trans *trans, WARN_ON_ONCE(value & ~mask); #endif - v = iwl_read32(trans, reg); + v = iwl_trans_pcie_read32(trans, reg); v &= ~mask; v |= value; - iwl_write32(trans, reg, v); + iwl_trans_pcie_write32(trans, reg, v); } -static inline void iwl_trans_clear_bit(struct iwl_trans *trans, +static inline void iwl_pcie_clear_bit(struct iwl_trans *trans, u32 reg, u32 mask) { - _iwl_trans_set_bits_mask(trans, reg, mask, 0); + iwl_pcie_set_bits_mask(trans, reg, mask, 0); } -static inline void iwl_trans_set_bit(struct iwl_trans *trans, +static inline void iwl_pcie_set_bit(struct iwl_trans *trans, u32 reg, u32 mask) { - _iwl_trans_set_bits_mask(trans, reg, mask, mask); + iwl_pcie_set_bits_mask(trans, reg, mask, mask); } #endif /* __iwl_pcie_utils_h__ */