From cf80c02a9fdb6c5bc8508beb6a0f6a1294fc32f6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 1 Jul 2025 13:08:42 -0500 Subject: [PATCH 01/16] wifi: iwlwifi: Fix error code in iwl_op_mode_dvm_start() Preserve the error code if iwl_setup_deferred_work() fails. The current code returns ERR_PTR(0) (which is NULL) on this path. I believe the missing error code potentially leads to a use after free involving debugfs. Fixes: 90a0d9f33996 ("iwlwifi: Add missing check for alloc_ordered_workqueue") Signed-off-by: Dan Carpenter Link: https://patch.msgid.link/a7a1cd2c-ce01-461a-9afd-dbe535f8df01@sabinyo.mountain Signed-off-by: Miri Korenblit --- drivers/net/wireless/intel/iwlwifi/dvm/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/main.c b/drivers/net/wireless/intel/iwlwifi/dvm/main.c index e015b83bb6e9..2b4dbebc71c2 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/main.c @@ -1467,7 +1467,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, /******************** * 6. Setup services ********************/ - if (iwl_setup_deferred_work(priv)) + err = iwl_setup_deferred_work(priv); + if (err) goto out_uninit_drv; iwl_setup_rx_handlers(priv); From 14db492738d922a982a1efdc9a4613d414c73a72 Mon Sep 17 00:00:00 2001 From: Rotem Kerem Date: Wed, 9 Jul 2025 08:16:20 +0300 Subject: [PATCH 02/16] wifi: iwlwifi: Add an helper function for polling bits Add iwl_poll_bits helper to simplify calls to iwl_poll_bit for the case when the bits and mask arguments are equal. Signed-off-by: Rotem Kerem Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.6bbc4bccc597.Ic7a10a7f8a9a32a9a9feecaf6e3a48fa37479f2d@changeid --- .../net/wireless/intel/iwlwifi/dvm/eeprom.c | 21 ++++++++----------- drivers/net/wireless/intel/iwlwifi/iwl-io.c | 8 +++---- drivers/net/wireless/intel/iwlwifi/iwl-io.h | 9 ++++++-- .../intel/iwlwifi/pcie/gen1_2/trans.c | 21 ++++++++----------- .../wireless/intel/iwlwifi/pcie/gen1_2/tx.c | 2 +- 5 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c b/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c index 2423125e5284..8087aee03d1c 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/eeprom.c @@ -676,10 +676,9 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans) CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM, - IWL_EEPROM_SEM_TIMEOUT); + ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_EEPROM_OWN_SEM, + IWL_EEPROM_SEM_TIMEOUT); if (ret >= 0) { IWL_DEBUG_EEPROM(trans->dev, "Acquired semaphore after %d tries.\n", @@ -797,10 +796,9 @@ static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, iwl_write32(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); + ret = iwl_poll_bits(trans, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { IWL_ERR(trans, "Time out reading OTP[%d]\n", addr); return ret; @@ -993,10 +991,9 @@ int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size) iwl_write32(trans, CSR_EEPROM_REG, CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); + ret = iwl_poll_bits(trans, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); if (ret < 0) { IWL_ERR(trans, "Time out reading EEPROM[%d]\n", addr); diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c index 80591809164e..47ad447b6226 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c @@ -47,8 +47,8 @@ IWL_EXPORT_SYMBOL(iwl_read32); #define IWL_POLL_INTERVAL 10 /* microseconds */ -int iwl_poll_bit(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout) +int iwl_poll_bits_mask(struct iwl_trans *trans, u32 addr, + u32 bits, u32 mask, int timeout) { int t = 0; @@ -61,7 +61,7 @@ int iwl_poll_bit(struct iwl_trans *trans, u32 addr, return -ETIMEDOUT; } -IWL_EXPORT_SYMBOL(iwl_poll_bit); +IWL_EXPORT_SYMBOL(iwl_poll_bits_mask); u32 iwl_read_direct32(struct iwl_trans *trans, u32 reg) { @@ -477,7 +477,7 @@ int iwl_finish_nic_init(struct iwl_trans *trans) * device-internal resources is supported, e.g. iwl_write_prph() * and accesses to uCode SRAM. */ - err = iwl_poll_bit(trans, CSR_GP_CNTRL, poll_ready, poll_ready, 25000); + err = iwl_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/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h index f4833c5fe86e..731cda1a4e66 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h @@ -23,8 +23,13 @@ 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_bit(struct iwl_trans *trans, u32 addr, - u32 bits, u32 mask, int timeout); +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); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 97e90cbeb6cd..4b063c2e7356 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -380,17 +380,15 @@ void iwl_pcie_apm_stop_master(struct iwl_trans *trans) iwl_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_REQ); - ret = iwl_poll_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, - CSR_GP_CNTRL_REG_FLAG_BUS_MASTER_DISABLE_STATUS, - 100); + ret = iwl_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); - ret = iwl_poll_bit(trans, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); + ret = iwl_poll_bits(trans, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); } if (ret < 0) @@ -492,10 +490,9 @@ static int iwl_pcie_set_hw_ready(struct iwl_trans *trans) CSR_HW_IF_CONFIG_REG_PCI_OWN_SET); /* See if we got it */ - ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_PCI_OWN_SET, - CSR_HW_IF_CONFIG_REG_PCI_OWN_SET, - HW_READY_TIMEOUT); + ret = iwl_poll_bits(trans, CSR_HW_IF_CONFIG_REG, + CSR_HW_IF_CONFIG_REG_PCI_OWN_SET, + HW_READY_TIMEOUT); if (ret >= 0) iwl_set_bit(trans, CSR_MBOX_SET_REG, CSR_MBOX_SET_REG_OS_ALIVE); @@ -2354,7 +2351,7 @@ 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_bit(trans, CSR_GP_CNTRL, poll, mask, 15000); + ret = iwl_poll_bits_mask(trans, CSR_GP_CNTRL, poll, mask, 15000); if (unlikely(ret < 0)) { u32 cntrl = iwl_read32(trans, CSR_GP_CNTRL); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c index 8676726d789b..3af6e3b3640d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/tx.c @@ -590,7 +590,7 @@ static void iwl_pcie_tx_stop_fh(struct iwl_trans *trans) } /* Wait for DMA channels to be idle */ - ret = iwl_poll_bit(trans, FH_TSSR_TX_STATUS_REG, mask, mask, 5000); + ret = iwl_poll_bits(trans, FH_TSSR_TX_STATUS_REG, mask, 5000); if (ret < 0) IWL_ERR(trans, "Failing on timeout while stopping DMA channel %d [0x%08x]\n", From 563abc938f21e2cb7d6ce895fb853f966b2c1f38 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Jul 2025 08:16:21 +0300 Subject: [PATCH 03/16] wifi: iwlwifi: use PNVM data embedded in .ucode files Given compatibility issues with external PNVM data that doesn't match the firmware it was designed with/for, future firmware releases will include the PNVM data in the firmware files directly, avoiding those mismatch issues. Make the driver load and use that embedded PNVM data in preference of external files, falling back to the external file if it isn't present. Co-developed-by: Emmanuel Grumbach Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.c843f77aa2d3.I7200f8dd40ef82aff1f5574fdd3966913cda592c@changeid --- drivers/net/wireless/intel/iwlwifi/fw/file.h | 3 ++ drivers/net/wireless/intel/iwlwifi/fw/img.h | 5 +++ drivers/net/wireless/intel/iwlwifi/fw/pnvm.c | 32 ++++++++++++-------- drivers/net/wireless/intel/iwlwifi/fw/pnvm.h | 4 +-- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 12 ++++++++ drivers/net/wireless/intel/iwlwifi/mld/fw.c | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 2 +- 7 files changed, 44 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/file.h b/drivers/net/wireless/intel/iwlwifi/fw/file.h index 5a1ec880ed72..dc1db563c5eb 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/file.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/file.h @@ -104,6 +104,9 @@ enum iwl_ucode_tlv_type { IWL_UCODE_TLV_CURRENT_PC = 68, IWL_UCODE_TLV_FSEQ_BIN_VERSION = 72, + /* contains sub-sections like PNVM file does (did) */ + IWL_UCODE_TLV_PNVM_DATA = 74, + IWL_UCODE_TLV_FW_NUM_STATIONS = IWL_UCODE_TLV_CONST_BASE + 0, IWL_UCODE_TLV_FW_NUM_LINKS = IWL_UCODE_TLV_CONST_BASE + 1, IWL_UCODE_TLV_FW_NUM_BEACONS = IWL_UCODE_TLV_CONST_BASE + 2, diff --git a/drivers/net/wireless/intel/iwlwifi/fw/img.h b/drivers/net/wireless/intel/iwlwifi/fw/img.h index e055f798a398..5256f20623e9 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/img.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/img.h @@ -195,6 +195,8 @@ struct iwl_dump_exclude { * @phy_integration_ver_len: length of @phy_integration_ver * @dump_excl: image dump exclusion areas for RT image * @dump_excl_wowlan: image dump exclusion areas for WoWLAN image + * @pnvm_data: PNVM data embedded in the .ucode file, if any + * @pnvm_size: size of the embedded PNVM data */ struct iwl_fw { u32 ucode_ver; @@ -227,6 +229,9 @@ struct iwl_fw { u32 phy_integration_ver_len; struct iwl_dump_exclude dump_excl[2], dump_excl_wowlan[2]; + + const void *pnvm_data; + u32 pnvm_size; }; static inline const char *get_fw_dbg_mode_string(int mode) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c index 3bcd375995cc..4d91ae065c8d 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.c @@ -11,6 +11,7 @@ #include "fw/api/nvm-reg.h" #include "fw/api/alive.h" #include "fw/uefi.h" +#include "fw/img.h" #define IWL_PNVM_REDUCED_CAP_BIT BIT(25) @@ -264,8 +265,8 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) return 0; } -static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, - __le32 sku_id[3]) +static const u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, + __le32 sku_id[3], const struct iwl_fw *fw) { struct pnvm_sku_package *package; u8 *image = NULL; @@ -290,6 +291,12 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, } } + if (fw->pnvm_data) { + *len = fw->pnvm_size; + + return fw->pnvm_data; + } + /* If it's not available, or for Intel SKU, try from the filesystem */ if (iwl_pnvm_get_from_fs(trans_p, &image, len)) return NULL; @@ -298,11 +305,11 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len, static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, - const struct iwl_ucode_capabilities *capa, + const struct iwl_fw *fw, __le32 sku_id[3]) { struct iwl_pnvm_image *pnvm_data = NULL; - u8 *data = NULL; + const u8 *data = NULL; size_t length; int ret; @@ -313,7 +320,7 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, if (trans->pnvm_loaded) goto set; - data = iwl_get_pnvm_image(trans, &length, sku_id); + data = iwl_get_pnvm_image(trans, &length, sku_id, fw); if (!data) { trans->fail_to_parse_pnvm_image = true; return; @@ -329,15 +336,17 @@ iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, goto free; } - ret = iwl_trans_load_pnvm(trans, pnvm_data, capa); + ret = iwl_trans_load_pnvm(trans, pnvm_data, &fw->ucode_capa); if (ret) goto free; IWL_DEBUG_INFO(trans, "loaded PNVM version %08x\n", pnvm_data->version); set: - iwl_trans_set_pnvm(trans, capa); + iwl_trans_set_pnvm(trans, &fw->ucode_capa); free: - kvfree(data); + /* free only if it was allocated, i.e. not just embedded PNVM data */ + if (data != fw->pnvm_data) + kvfree(data); kfree(pnvm_data); } @@ -392,8 +401,7 @@ iwl_pnvm_load_reduce_power_to_trans(struct iwl_trans *trans, int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait, - const struct iwl_ucode_capabilities *capa, - __le32 sku_id[3]) + const struct iwl_fw *fw, __le32 sku_id[3]) { struct iwl_notification_wait pnvm_wait; static const u16 ntf_cmds[] = { WIDE_ID(REGULATORY_AND_NVM_GROUP, @@ -403,8 +411,8 @@ int iwl_pnvm_load(struct iwl_trans *trans, if (!sku_id[0] && !sku_id[1] && !sku_id[2]) return 0; - iwl_pnvm_load_pnvm_to_trans(trans, capa, sku_id); - iwl_pnvm_load_reduce_power_to_trans(trans, capa, sku_id); + iwl_pnvm_load_pnvm_to_trans(trans, fw, sku_id); + iwl_pnvm_load_reduce_power_to_trans(trans, &fw->ucode_capa, sku_id); iwl_init_notification_wait(notif_wait, &pnvm_wait, ntf_cmds, ARRAY_SIZE(ntf_cmds), diff --git a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h index 9540926e8a0f..ad3b7e2423ac 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/pnvm.h @@ -7,6 +7,7 @@ #include "iwl-drv.h" #include "fw/notif-wait.h" +#include "fw/img.h" #define MVM_UCODE_PNVM_TIMEOUT (HZ / 4) @@ -14,8 +15,7 @@ int iwl_pnvm_load(struct iwl_trans *trans, struct iwl_notif_wait_data *notif_wait, - const struct iwl_ucode_capabilities *capa, - __le32 sku_id[3]); + const struct iwl_fw *fw, __le32 sku_id[3]); static inline void iwl_pnvm_get_fs_name(struct iwl_trans *trans, diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 6492bc7d1680..064ff2135411 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -136,6 +136,9 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) kfree(drv->fw.phy_integration_ver); kfree(drv->trans->dbg.pc_data); drv->trans->dbg.pc_data = NULL; + kvfree(drv->fw.pnvm_data); + drv->fw.pnvm_data = NULL; + drv->fw.pnvm_size = 0; for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) iwl_free_fw_img(drv, drv->fw.img + i); @@ -1400,6 +1403,15 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, drv->trans->dbg.num_pc = tlv_len / sizeof(struct iwl_pc_data); break; + case IWL_UCODE_TLV_PNVM_DATA: + if (drv->fw.pnvm_data) + break; + drv->fw.pnvm_data = + kvmemdup(tlv_data, tlv_len, GFP_KERNEL); + if (!drv->fw.pnvm_data) + return -ENOMEM; + drv->fw.pnvm_size = tlv_len; + break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); break; diff --git a/drivers/net/wireless/intel/iwlwifi/mld/fw.c b/drivers/net/wireless/intel/iwlwifi/mld/fw.c index 9d2c087360e7..b372173c4a79 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/fw.c @@ -294,7 +294,7 @@ static int iwl_mld_run_fw_init_sequence(struct iwl_mld *mld) return ret; ret = iwl_pnvm_load(mld->trans, &mld->notif_wait, - &mld->fw->ucode_capa, alive_data.sku_id); + mld->fw, alive_data.sku_id); if (ret) { IWL_ERR(mld, "Timeout waiting for PNVM load %d\n", ret); return ret; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c index 819e3228462a..ab3d78c1e20c 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c @@ -432,7 +432,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, iwl_trans_fw_alive(mvm->trans); ret = iwl_pnvm_load(mvm->trans, &mvm->notif_wait, - &mvm->fw->ucode_capa, alive_data.sku_id); + mvm->fw, alive_data.sku_id); if (ret) { IWL_ERR(mvm, "Timeout waiting for PNVM load!\n"); iwl_fw_set_current_image(&mvm->fwrt, old_type); From 377edee91b8977615ea5154817e07387ef67720c Mon Sep 17 00:00:00 2001 From: Yedidya Benshimol Date: Wed, 9 Jul 2025 08:16:22 +0300 Subject: [PATCH 04/16] wifi: iwlwifi: pcie move gen1_2 probe to gen1_2/trans.c In the process of splitting the transport's different generations, move gen1_2's probe flow and relevant helper functions to the gen1_2 subfolder Signed-off-by: Yedidya Benshimol Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.29b909144e1a.Idaa77eddd6650cf6f113833d2fbc8d3ef08cfd8f@changeid --- .../net/wireless/intel/iwlwifi/iwl-config.h | 5 +- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 325 +---------------- .../intel/iwlwifi/pcie/gen1_2/internal.h | 7 +- .../intel/iwlwifi/pcie/gen1_2/trans.c | 327 +++++++++++++++++- 4 files changed, 335 insertions(+), 329 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 91f22ce36d74..08c4f79f8335 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -499,11 +499,12 @@ struct iwl_dev_info { #if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) extern const struct iwl_dev_info iwl_dev_info_table[]; extern const unsigned int iwl_dev_info_table_size; +extern const struct pci_device_id iwl_hw_card_ids[]; +#endif + const struct iwl_dev_info * iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, u8 rf_id, u8 bw_limit, u8 rf_step); -extern const struct pci_device_id iwl_hw_card_ids[]; -#endif /* * This list declares the config structures for all devices. diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 52a48e82f3bf..2729e0890fc6 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1074,147 +1074,10 @@ const unsigned int iwl_dev_info_table_size = ARRAY_SIZE(iwl_dev_info_table); EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_dev_info_table_size); #endif -/* - * 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) -{ - u32 sd_reg_ver_addr; - u32 hw_wfpm_id; - u32 val = 0; - u8 step; - - if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - sd_reg_ver_addr = SD_REG_VER_GEN2; - else - sd_reg_ver_addr = SD_REG_VER; - - /* Enable access to peripheral registers */ - val = iwl_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); - - /* Read crf info */ - info->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr); - - /* Read cnv info */ - info->hw_cnv_id = iwl_read_prph_no_grab(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) - step = SILICON_B_STEP; - - /* In BZ, the MAC step must be read from the CNVI aux register */ - if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ) { - step = CNVI_AUX_MISC_CHIP_MAC_STEP(info->hw_cnv_id); - - /* For BZ-U, take B step also when A step is indicated */ - if ((CNVI_AUX_MISC_CHIP_PROD_TYPE(info->hw_cnv_id) == - CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U) && - step == SILICON_A_STEP) - step = SILICON_B_STEP; - } - - if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ || - CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) { - info->hw_rev_step = step; - info->hw_rev |= step; - } - - /* 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); - 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); -} - -/* - * In case that there is no OTP on the NIC, map the rf id and cdb info - * from the prph registers. - */ -static int map_crf_id(struct iwl_trans *iwl_trans, - struct iwl_trans_info *info) -{ - 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 jacket_id_cnv = REG_CRF_ID_SLAVE(info->hw_cnv_id); - u32 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, - WFPM_OTP_CFG1_ADDR); - u32 jacket_id_wfpm = WFPM_OTP_CFG1_IS_JACKET(hw_wfpm_id); - u32 cdb_id_wfpm = WFPM_OTP_CFG1_IS_CDB(hw_wfpm_id); - - /* Map between crf id to rf id */ - switch (REG_CRF_ID_TYPE(val)) { - case REG_CRF_ID_TYPE_JF_1: - info->hw_rf_id = (IWL_CFG_RF_TYPE_JF1 << 12); - break; - case REG_CRF_ID_TYPE_JF_2: - info->hw_rf_id = (IWL_CFG_RF_TYPE_JF2 << 12); - break; - case REG_CRF_ID_TYPE_HR_NONE_CDB_1X1: - info->hw_rf_id = (IWL_CFG_RF_TYPE_HR1 << 12); - break; - case REG_CRF_ID_TYPE_HR_NONE_CDB: - info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12); - break; - case REG_CRF_ID_TYPE_HR_CDB: - info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12); - break; - case REG_CRF_ID_TYPE_GF: - info->hw_rf_id = (IWL_CFG_RF_TYPE_GF << 12); - break; - case REG_CRF_ID_TYPE_FM: - info->hw_rf_id = (IWL_CFG_RF_TYPE_FM << 12); - break; - case REG_CRF_ID_TYPE_WHP: - info->hw_rf_id = (IWL_CFG_RF_TYPE_WH << 12); - break; - case REG_CRF_ID_TYPE_PE: - info->hw_rf_id = (IWL_CFG_RF_TYPE_PE << 12); - break; - default: - ret = -EIO; - IWL_ERR(iwl_trans, - "Can't find a correct rfid for crf id 0x%x\n", - REG_CRF_ID_TYPE(val)); - goto out; - - } - - /* Set Step-id */ - info->hw_rf_id |= (step_id << 8); - - /* Set CDB capabilities */ - if (cdb_id_wfpm || slave_id) { - info->hw_rf_id += BIT(28); - IWL_INFO(iwl_trans, "Adding cdb to rf id\n"); - } - - /* Set Jacket capabilities */ - if (jacket_id_wfpm || jacket_id_cnv) { - info->hw_rf_id += BIT(29); - IWL_INFO(iwl_trans, "Adding jacket to rf id\n"); - } - - IWL_INFO(iwl_trans, - "Detected rf-type 0x%x step-id 0x%x slave-id 0x%x from crf id 0x%x\n", - REG_CRF_ID_TYPE(val), step_id, slave_id, info->hw_rf_id); - IWL_INFO(iwl_trans, - "Detected cdb-id 0x%x jacket-id 0x%x from wfpm id 0x%x\n", - cdb_id_wfpm, jacket_id_wfpm, hw_wfpm_id); - IWL_INFO(iwl_trans, "Detected jacket-id 0x%x from cnvi id 0x%x\n", - jacket_id_cnv, info->hw_cnv_id); - -out: - return ret; -} - /* PCI registers */ #define PCI_CFG_RETRY_TIMEOUT 0x041 -VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info * +const struct iwl_dev_info * iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, u8 rf_id, u8 bw_limit, u8 rf_step) { @@ -1261,193 +1124,11 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, } EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_pci_find_dev_info); -static void iwl_pcie_recheck_me_status(struct work_struct *wk) -{ - struct iwl_trans_pcie *trans_pcie = container_of(wk, - typeof(*trans_pcie), - me_recheck_wk.work); - u32 val; - - val = iwl_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG); - trans_pcie->me_present = !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP); -} - -static void iwl_pcie_check_me_status(struct iwl_trans *trans) -{ - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 val; - - trans_pcie->me_present = -1; - - INIT_DELAYED_WORK(&trans_pcie->me_recheck_wk, - iwl_pcie_recheck_me_status); - - /* we don't have a good way of determining this until BZ */ - if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ) - return; - - val = iwl_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); - if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN | - CSR_HW_IF_CONFIG_REG_IAMT_UP)) { - trans_pcie->me_present = 1; - return; - } - - /* recheck again later, ME might still be initializing */ - schedule_delayed_work(&trans_pcie->me_recheck_wk, HZ); -} - static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - const struct iwl_mac_cfg *trans; - const struct iwl_dev_info *dev_info; - struct iwl_trans_info info = { - .hw_id = (pdev->device << 16) + pdev->subsystem_device, - }; - struct iwl_trans *iwl_trans; - struct iwl_trans_pcie *trans_pcie; - int ret; + const struct iwl_mac_cfg *mac_cfg = (void *)ent->driver_data; - trans = (void *)ent->driver_data; - - iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info); - if (IS_ERR(iwl_trans)) - return PTR_ERR(iwl_trans); - - trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); - - iwl_trans_pcie_check_product_reset_status(pdev); - iwl_trans_pcie_check_product_reset_mode(pdev); - - /* set the things we know so far for the grab NIC access */ - iwl_trans_set_info(iwl_trans, &info); - - /* - * Let's try to grab NIC access early here. Sometimes, NICs may - * fail to initialize, and if that happens it's better if we see - * issues early on (and can reprobe, per the logic inside), than - * first trying to load the firmware etc. and potentially only - * detecting any problems when the first interface is brought up. - */ - ret = iwl_pcie_prepare_card_hw(iwl_trans); - if (!ret) { - ret = iwl_finish_nic_init(iwl_trans); - if (ret) - goto out_free_trans; - if (iwl_trans_grab_nic_access(iwl_trans)) { - get_crf_id(iwl_trans, &info); - /* all good */ - iwl_trans_release_nic_access(iwl_trans); - } else { - ret = -EIO; - goto out_free_trans; - } - } - - info.hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID); - - /* - * The RF_ID is set to zero in blank OTP so read version to - * extract the RF_ID. - * 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)) { - ret = -EINVAL; - goto out_free_trans; - } - - IWL_INFO(iwl_trans, "PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", - pdev->device, pdev->subsystem_device, - info.hw_rev, info.hw_rf_id); - - dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device, - CSR_HW_RFID_TYPE(info.hw_rf_id), - CSR_HW_RFID_IS_CDB(info.hw_rf_id), - IWL_SUBDEVICE_RF_ID(pdev->subsystem_device), - IWL_SUBDEVICE_BW_LIM(pdev->subsystem_device), - CSR_HW_RFID_STEP(info.hw_rf_id)); - if (dev_info) { - iwl_trans->cfg = dev_info->cfg; - info.name = dev_info->name; - } - -#if IS_ENABLED(CONFIG_IWLMVM) - /* - * special-case 7265D, it has the same PCI IDs. - * - * Note that because we already pass the cfg to the transport above, - * all the parameters that the transport uses must, until that is - * changed, be identical to the ones in the 7265D configuration. - */ - if (iwl_trans->cfg == &iwl7265_cfg && - (info.hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) - iwl_trans->cfg = &iwl7265d_cfg; -#endif - if (!iwl_trans->cfg) { - pr_err("No config found for PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", - pdev->device, pdev->subsystem_device, - info.hw_rev, info.hw_rf_id); - ret = -EINVAL; - goto out_free_trans; - } - - IWL_INFO(iwl_trans, "Detected %s\n", info.name); - - if (iwl_trans->mac_cfg->mq_rx_supported) { - if (WARN_ON(!iwl_trans->cfg->num_rbds)) { - ret = -EINVAL; - goto out_free_trans; - } - trans_pcie->num_rx_bufs = iwl_trans_get_num_rbds(iwl_trans); - } else { - trans_pcie->num_rx_bufs = RX_QUEUE_SIZE; - } - - if (!iwl_trans->mac_cfg->integrated) { - u16 link_status; - - pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &link_status); - - info.pcie_link_speed = - u16_get_bits(link_status, PCI_EXP_LNKSTA_CLS); - } - - iwl_trans_set_info(iwl_trans, &info); - - ret = iwl_trans_init(iwl_trans); - if (ret) - goto out_free_trans; - - pci_set_drvdata(pdev, iwl_trans); - - iwl_pcie_check_me_status(iwl_trans); - - /* try to get ownership so that we'll know if we don't own it */ - iwl_pcie_prepare_card_hw(iwl_trans); - - iwl_trans->drv = iwl_drv_start(iwl_trans); - - if (IS_ERR(iwl_trans->drv)) { - ret = PTR_ERR(iwl_trans->drv); - goto out_free_trans; - } - - /* register transport layer debugfs here */ - iwl_trans_pcie_dbgfs_register(iwl_trans); - - return 0; - -out_free_trans: - iwl_trans_pcie_free(iwl_trans); - return ret; + return iwl_pci_gen1_2_probe(pdev, ent, mac_cfg); } static void iwl_pci_remove(struct pci_dev *pdev) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h index 23c0771a4231..5530f35042ad 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h @@ -538,10 +538,6 @@ iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie) * Convention: trans API functions: iwl_trans_pcie_XXX * Other functions: iwl_pcie_XXX */ -struct iwl_trans -*iwl_trans_pcie_alloc(struct pci_dev *pdev, - const struct iwl_mac_cfg *mac_cfg, - struct iwl_trans_info *info); void iwl_trans_pcie_free(struct iwl_trans *trans); void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_regions, struct device *dev); @@ -1081,6 +1077,9 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); void __releases(nic_access_nobh) 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 *trans); /* transport gen 1 exported functions */ void iwl_trans_pcie_fw_alive(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 4b063c2e7356..0ebb1e7e4bf5 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -3683,7 +3683,7 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans) iwl_trans_sync_nmi_with_addr(trans, inta_addr, sw_err_bit); } -struct iwl_trans * +static struct iwl_trans * iwl_trans_pcie_alloc(struct pci_dev *pdev, const struct iwl_mac_cfg *mac_cfg, struct iwl_trans_info *info) @@ -3949,3 +3949,328 @@ int iwl_trans_pcie_copy_imr(struct iwl_trans *trans, trans_pcie->imr_status = IMR_D2S_IDLE; return 0; } + +/* + * 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) +{ + u32 sd_reg_ver_addr; + u32 hw_wfpm_id; + u32 val = 0; + u8 step; + + if (iwl_trans->mac_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + sd_reg_ver_addr = SD_REG_VER_GEN2; + else + sd_reg_ver_addr = SD_REG_VER; + + /* Enable access to peripheral registers */ + val = iwl_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); + + /* Read crf info */ + info->hw_crf_id = iwl_read_prph_no_grab(iwl_trans, sd_reg_ver_addr); + + /* Read cnv info */ + info->hw_cnv_id = iwl_read_prph_no_grab(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) + step = SILICON_B_STEP; + + /* In BZ, the MAC step must be read from the CNVI aux register */ + if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ) { + step = CNVI_AUX_MISC_CHIP_MAC_STEP(info->hw_cnv_id); + + /* For BZ-U, take B step also when A step is indicated */ + if ((CNVI_AUX_MISC_CHIP_PROD_TYPE(info->hw_cnv_id) == + CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U) && + step == SILICON_A_STEP) + step = SILICON_B_STEP; + } + + if (CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ || + CSR_HW_REV_TYPE(info->hw_rev) == IWL_CFG_MAC_TYPE_BZ_W) { + info->hw_rev_step = step; + info->hw_rev |= step; + } + + /* 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); + 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); +} + +/* + * In case that there is no OTP on the NIC, map the rf id and cdb info + * from the prph registers. + */ +static int map_crf_id(struct iwl_trans *iwl_trans, + struct iwl_trans_info *info) +{ + 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 jacket_id_cnv = REG_CRF_ID_SLAVE(info->hw_cnv_id); + u32 hw_wfpm_id = iwl_read_umac_prph_no_grab(iwl_trans, + WFPM_OTP_CFG1_ADDR); + u32 jacket_id_wfpm = WFPM_OTP_CFG1_IS_JACKET(hw_wfpm_id); + u32 cdb_id_wfpm = WFPM_OTP_CFG1_IS_CDB(hw_wfpm_id); + + /* Map between crf id to rf id */ + switch (REG_CRF_ID_TYPE(val)) { + case REG_CRF_ID_TYPE_JF_1: + info->hw_rf_id = (IWL_CFG_RF_TYPE_JF1 << 12); + break; + case REG_CRF_ID_TYPE_JF_2: + info->hw_rf_id = (IWL_CFG_RF_TYPE_JF2 << 12); + break; + case REG_CRF_ID_TYPE_HR_NONE_CDB_1X1: + info->hw_rf_id = (IWL_CFG_RF_TYPE_HR1 << 12); + break; + case REG_CRF_ID_TYPE_HR_NONE_CDB: + info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12); + break; + case REG_CRF_ID_TYPE_HR_CDB: + info->hw_rf_id = (IWL_CFG_RF_TYPE_HR2 << 12); + break; + case REG_CRF_ID_TYPE_GF: + info->hw_rf_id = (IWL_CFG_RF_TYPE_GF << 12); + break; + case REG_CRF_ID_TYPE_FM: + info->hw_rf_id = (IWL_CFG_RF_TYPE_FM << 12); + break; + case REG_CRF_ID_TYPE_WHP: + info->hw_rf_id = (IWL_CFG_RF_TYPE_WH << 12); + break; + case REG_CRF_ID_TYPE_PE: + info->hw_rf_id = (IWL_CFG_RF_TYPE_PE << 12); + break; + default: + ret = -EIO; + IWL_ERR(iwl_trans, + "Can't find a correct rfid for crf id 0x%x\n", + REG_CRF_ID_TYPE(val)); + goto out; + } + + /* Set Step-id */ + info->hw_rf_id |= (step_id << 8); + + /* Set CDB capabilities */ + if (cdb_id_wfpm || slave_id) { + info->hw_rf_id += BIT(28); + IWL_INFO(iwl_trans, "Adding cdb to rf id\n"); + } + + /* Set Jacket capabilities */ + if (jacket_id_wfpm || jacket_id_cnv) { + info->hw_rf_id += BIT(29); + IWL_INFO(iwl_trans, "Adding jacket to rf id\n"); + } + + IWL_INFO(iwl_trans, + "Detected rf-type 0x%x step-id 0x%x slave-id 0x%x from crf id 0x%x\n", + REG_CRF_ID_TYPE(val), step_id, slave_id, info->hw_rf_id); + IWL_INFO(iwl_trans, + "Detected cdb-id 0x%x jacket-id 0x%x from wfpm id 0x%x\n", + cdb_id_wfpm, jacket_id_wfpm, hw_wfpm_id); + IWL_INFO(iwl_trans, "Detected jacket-id 0x%x from cnvi id 0x%x\n", + jacket_id_cnv, info->hw_cnv_id); + +out: + return ret; +} + +static void iwl_pcie_recheck_me_status(struct work_struct *wk) +{ + struct iwl_trans_pcie *trans_pcie = container_of(wk, + typeof(*trans_pcie), + me_recheck_wk.work); + u32 val; + + val = iwl_read32(trans_pcie->trans, CSR_HW_IF_CONFIG_REG); + trans_pcie->me_present = !!(val & CSR_HW_IF_CONFIG_REG_IAMT_UP); +} + +static void iwl_pcie_check_me_status(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 val; + + trans_pcie->me_present = -1; + + INIT_DELAYED_WORK(&trans_pcie->me_recheck_wk, + iwl_pcie_recheck_me_status); + + /* we don't have a good way of determining this until BZ */ + if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_BZ) + return; + + val = iwl_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); + if (val & (CSR_HW_IF_CONFIG_REG_ME_OWN | + CSR_HW_IF_CONFIG_REG_IAMT_UP)) { + trans_pcie->me_present = 1; + return; + } + + /* recheck again later, ME might still be initializing */ + 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 *trans) +{ + const struct iwl_dev_info *dev_info; + struct iwl_trans_info info = { + .hw_id = (pdev->device << 16) + pdev->subsystem_device, + }; + struct iwl_trans *iwl_trans; + struct iwl_trans_pcie *trans_pcie; + int ret; + + iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info); + if (IS_ERR(iwl_trans)) + return PTR_ERR(iwl_trans); + + trans_pcie = IWL_TRANS_GET_PCIE_TRANS(iwl_trans); + + iwl_trans_pcie_check_product_reset_status(pdev); + iwl_trans_pcie_check_product_reset_mode(pdev); + + /* set the things we know so far for the grab NIC access */ + iwl_trans_set_info(iwl_trans, &info); + + /* + * Let's try to grab NIC access early here. Sometimes, NICs may + * fail to initialize, and if that happens it's better if we see + * issues early on (and can reprobe, per the logic inside), than + * first trying to load the firmware etc. and potentially only + * detecting any problems when the first interface is brought up. + */ + ret = iwl_pcie_prepare_card_hw(iwl_trans); + if (!ret) { + ret = iwl_finish_nic_init(iwl_trans); + if (ret) + goto out_free_trans; + if (iwl_trans_grab_nic_access(iwl_trans)) { + get_crf_id(iwl_trans, &info); + /* all good */ + iwl_trans_release_nic_access(iwl_trans); + } else { + ret = -EIO; + goto out_free_trans; + } + } + + info.hw_rf_id = iwl_read32(iwl_trans, CSR_HW_RF_ID); + + /* + * The RF_ID is set to zero in blank OTP so read version to + * extract the RF_ID. + * 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)) { + ret = -EINVAL; + goto out_free_trans; + } + + IWL_INFO(iwl_trans, "PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", + pdev->device, pdev->subsystem_device, + info.hw_rev, info.hw_rf_id); + + dev_info = iwl_pci_find_dev_info(pdev->device, pdev->subsystem_device, + CSR_HW_RFID_TYPE(info.hw_rf_id), + CSR_HW_RFID_IS_CDB(info.hw_rf_id), + IWL_SUBDEVICE_RF_ID(pdev->subsystem_device), + IWL_SUBDEVICE_BW_LIM(pdev->subsystem_device), + CSR_HW_RFID_STEP(info.hw_rf_id)); + if (dev_info) { + iwl_trans->cfg = dev_info->cfg; + info.name = dev_info->name; + } + +#if IS_ENABLED(CONFIG_IWLMVM) + + /* + * special-case 7265D, it has the same PCI IDs. + * + * Note that because we already pass the cfg to the transport above, + * all the parameters that the transport uses must, until that is + * changed, be identical to the ones in the 7265D configuration. + */ + if (iwl_trans->cfg == &iwl7265_cfg && + (info.hw_rev & CSR_HW_REV_TYPE_MSK) == CSR_HW_REV_TYPE_7265D) + iwl_trans->cfg = &iwl7265d_cfg; +#endif + if (!iwl_trans->cfg) { + pr_err("No config found for PCI dev %04x/%04x, rev=0x%x, rfid=0x%x\n", + pdev->device, pdev->subsystem_device, + info.hw_rev, info.hw_rf_id); + ret = -EINVAL; + goto out_free_trans; + } + + IWL_INFO(iwl_trans, "Detected %s\n", info.name); + + if (iwl_trans->mac_cfg->mq_rx_supported) { + if (WARN_ON(!iwl_trans->cfg->num_rbds)) { + ret = -EINVAL; + goto out_free_trans; + } + trans_pcie->num_rx_bufs = iwl_trans_get_num_rbds(iwl_trans); + } else { + trans_pcie->num_rx_bufs = RX_QUEUE_SIZE; + } + + if (!iwl_trans->mac_cfg->integrated) { + u16 link_status; + + pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &link_status); + + info.pcie_link_speed = + u16_get_bits(link_status, PCI_EXP_LNKSTA_CLS); + } + + iwl_trans_set_info(iwl_trans, &info); + + ret = iwl_trans_init(iwl_trans); + if (ret) + goto out_free_trans; + + pci_set_drvdata(pdev, iwl_trans); + + iwl_pcie_check_me_status(iwl_trans); + + /* try to get ownership so that we'll know if we don't own it */ + iwl_pcie_prepare_card_hw(iwl_trans); + + iwl_trans->drv = iwl_drv_start(iwl_trans); + + if (IS_ERR(iwl_trans->drv)) { + ret = PTR_ERR(iwl_trans->drv); + goto out_free_trans; + } + + /* register transport layer debugfs here */ + iwl_trans_pcie_dbgfs_register(iwl_trans); + + return 0; + +out_free_trans: + iwl_trans_pcie_free(iwl_trans); + return ret; +} From 0b261b014a99fa9f9879fb6b819d67c13f0731a1 Mon Sep 17 00:00:00 2001 From: Yedidya Benshimol Date: Wed, 9 Jul 2025 08:16:23 +0300 Subject: [PATCH 05/16] wifi: iwlwifi: pcie: Move txcmd size/align calculation to callers Refactor iwl_trans_init to accept txcmd_size and txcmd_align as parameters instead of calculating them internally. Signed-off-by: Yedidya Benshimol Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.237285d81461.I3552860dd062a523606c8a5c85c9a6f0d4f04262@changeid --- drivers/net/wireless/intel/iwlwifi/iwl-trans.c | 16 ++-------------- drivers/net/wireless/intel/iwlwifi/iwl-trans.h | 3 ++- .../wireless/intel/iwlwifi/pcie/gen1_2/trans.c | 16 +++++++++++++++- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 78808c956444..6288779ff8ec 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -293,25 +293,13 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, return trans; } -int iwl_trans_init(struct iwl_trans *trans) +int iwl_trans_init(struct iwl_trans *trans, unsigned int txcmd_size, + unsigned int txcmd_align) { - int txcmd_size, txcmd_align; - /* check if name/num_rx_queues were set as a proxy for info being set */ if (WARN_ON(!trans->info.name || !trans->info.num_rxqs)) return -EINVAL; - if (!trans->mac_cfg->gen2) { - txcmd_size = sizeof(struct iwl_tx_cmd_v6); - txcmd_align = sizeof(void *); - } else if (trans->mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { - txcmd_size = sizeof(struct iwl_tx_cmd_v9); - txcmd_align = 64; - } else { - txcmd_size = sizeof(struct iwl_tx_cmd); - txcmd_align = 128; - } - txcmd_size += sizeof(struct iwl_cmd_header); txcmd_size += 36; /* biggest possible 802.11 header */ diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 012b1e44bce3..49a695e30109 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1206,7 +1206,8 @@ 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_mac_cfg *cfg_trans); -int iwl_trans_init(struct iwl_trans *trans); +int iwl_trans_init(struct iwl_trans *trans, unsigned int txcmd_size, + unsigned int txcmd_align); void iwl_trans_free(struct iwl_trans *trans); static inline bool iwl_trans_is_hw_error_value(u32 val) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 0ebb1e7e4bf5..9355d5a9d933 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -25,6 +25,7 @@ #include "fw/dbg.h" #include "fw/api/tx.h" #include "fw/acpi.h" +#include "fw/api/tx.h" #include "mei/iwl-mei.h" #include "internal.h" #include "iwl-fh.h" @@ -4139,6 +4140,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, }; struct iwl_trans *iwl_trans; struct iwl_trans_pcie *trans_pcie; + unsigned int txcmd_size, txcmd_align; int ret; iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info); @@ -4247,7 +4249,19 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, iwl_trans_set_info(iwl_trans, &info); - ret = iwl_trans_init(iwl_trans); + if (!iwl_trans->mac_cfg->gen2) { + txcmd_size = sizeof(struct iwl_tx_cmd_v6); + txcmd_align = sizeof(void *); + } else if (iwl_trans->mac_cfg->device_family < + IWL_DEVICE_FAMILY_AX210) { + txcmd_size = sizeof(struct iwl_tx_cmd_v9); + txcmd_align = 64; + } else { + txcmd_size = sizeof(struct iwl_tx_cmd); + txcmd_align = 128; + } + ret = iwl_trans_init(iwl_trans, txcmd_size, txcmd_align); + if (ret) goto out_free_trans; From 318f54a6486c769e796cf5bee1a822111b7fc98d Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 9 Jul 2025 08:16:24 +0300 Subject: [PATCH 06/16] wifi: iwlwifi: bump FW API to 102 for BZ/SC/DR Start supporting FW API version 102 on those devices. Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.da98a7b6be42.I77150bbf55eb160dbe0ef75c3e28afc053f27ec3@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/dr.c | 2 +- drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index b5ad6d635fcb..c6cd892bff69 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -10,7 +10,7 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 99 +#define IWL_BZ_UCODE_API_MAX 102 /* Lowest firmware API version supported */ #define IWL_BZ_UCODE_API_MIN 94 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c index 95aa27c35357..807f4e29d55a 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 API version supported */ -#define IWL_DR_UCODE_API_MAX 99 +#define IWL_DR_UCODE_API_MAX 102 /* Lowest firmware API version supported */ #define IWL_DR_UCODE_API_MIN 98 diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c index 12c2adb4b5c4..97e503a25eae 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 API version supported */ -#define IWL_SC_UCODE_API_MAX 99 +#define IWL_SC_UCODE_API_MAX 102 /* Lowest firmware API version supported */ #define IWL_SC_UCODE_API_MIN 98 From e1dbd37f145af4e3ed39c0f2fea879f68c94e721 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 9 Jul 2025 08:16:25 +0300 Subject: [PATCH 07/16] wifi: iwlwifi: pcie move common probe logic Move the parts of the probe that are not gen specific to the common probe function. Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.91aee0874e79.Ib762365933d4dd4fc0bf07833226cd7118dee0a1@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 38 +++++++++++++++- .../intel/iwlwifi/pcie/gen1_2/internal.h | 5 ++- .../intel/iwlwifi/pcie/gen1_2/trans.c | 45 +++---------------- 3 files changed, 47 insertions(+), 41 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 2729e0890fc6..02a031433b23 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -1127,8 +1127,44 @@ EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_pci_find_dev_info); static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { const struct iwl_mac_cfg *mac_cfg = (void *)ent->driver_data; + u8 __iomem *hw_base; + u32 bar0, hw_rev; + int ret; - return iwl_pci_gen1_2_probe(pdev, ent, mac_cfg); + /* reassign our BAR 0 if invalid due to possible runtime PM races */ + pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0); + if (bar0 == PCI_BASE_ADDRESS_MEM_TYPE_64) { + ret = pci_assign_resource(pdev, 0); + if (ret) + return ret; + } + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + ret = pcim_request_all_regions(pdev, DRV_NAME); + if (ret) { + dev_err(&pdev->dev, "Requesting all PCI BARs failed.\n"); + return ret; + } + + hw_base = pcim_iomap(pdev, 0, 0); + if (!hw_base) { + dev_err(&pdev->dev, "Failed to map BAR 0.\n"); + return -ENOMEM; + } + + /* We can't use iwl_read32 because trans wasn't allocated */ + hw_rev = readl(hw_base + CSR_HW_REV); + if (hw_rev == 0xffffffff) { + dev_err(&pdev->dev, "HW_REV=0xFFFFFFFF, PCI issues?\n"); + return -EIO; + } + + return iwl_pci_gen1_2_probe(pdev, ent, mac_cfg, hw_base, hw_rev); } static void iwl_pci_remove(struct pci_dev *pdev) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h index 5530f35042ad..ec17e2e84151 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h @@ -1078,8 +1078,9 @@ void __releases(nic_access_nobh) 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 *trans); + const struct pci_device_id *ent, + const struct iwl_mac_cfg *trans, u8 __iomem *hw_base, + u32 hw_rev); /* transport gen 1 exported functions */ void iwl_trans_pcie_fw_alive(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 9355d5a9d933..3f1861efc716 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -3687,25 +3687,12 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans) static struct iwl_trans * iwl_trans_pcie_alloc(struct pci_dev *pdev, const struct iwl_mac_cfg *mac_cfg, - struct iwl_trans_info *info) + struct iwl_trans_info *info, u8 __iomem *hw_base) { struct iwl_trans_pcie *trans_pcie, **priv; struct iwl_trans *trans; unsigned int bc_tbl_n_entries; int ret, addr_size; - u32 bar0; - - /* reassign our BAR 0 if invalid due to possible runtime PM races */ - pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &bar0); - if (bar0 == PCI_BASE_ADDRESS_MEM_TYPE_64) { - ret = pci_assign_resource(pdev, 0); - if (ret) - return ERR_PTR(ret); - } - - ret = pcim_enable_device(pdev); - if (ret) - return ERR_PTR(ret); trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev, mac_cfg); @@ -3714,6 +3701,8 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + trans_pcie->hw_base = hw_base; + /* Initialize the wait queue for commands */ init_waitqueue_head(&trans_pcie->wait_command_queue); @@ -3811,8 +3800,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, PCIE_LINK_STATE_CLKPM); } - pci_set_master(pdev); - addr_size = trans_pcie->txqs.tfd.addr_size; ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(addr_size)); if (ret) { @@ -3824,19 +3811,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, } } - ret = pcim_request_all_regions(pdev, DRV_NAME); - if (ret) { - dev_err(&pdev->dev, "Requesting all PCI BARs failed.\n"); - goto out_no_pci; - } - - trans_pcie->hw_base = pcim_iomap(pdev, 0, 0); - if (!trans_pcie->hw_base) { - dev_err(&pdev->dev, "Could not ioremap PCI BAR 0.\n"); - ret = -ENODEV; - goto out_no_pci; - } - /* We disable the RETRY_TIMEOUT register (0x41) to keep * PCI Tx retries from interfering with C3 CPU state */ pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00); @@ -3844,13 +3818,6 @@ iwl_trans_pcie_alloc(struct pci_dev *pdev, trans_pcie->pci_dev = pdev; iwl_disable_interrupts(trans); - info->hw_rev = iwl_read32(trans, CSR_HW_REV); - if (info->hw_rev == 0xffffffff) { - dev_err(&pdev->dev, "HW_REV=0xFFFFFFFF, PCI issues?\n"); - ret = -EIO; - goto out_no_pci; - } - /* * In the 8000 HW family the format of the 4 bytes of CSR_HW_REV have * changed, and now the revision step also includes bit 0-1 (no more @@ -4132,18 +4099,20 @@ static void iwl_pcie_check_me_status(struct iwl_trans *trans) int iwl_pci_gen1_2_probe(struct pci_dev *pdev, const struct pci_device_id *ent, - const struct iwl_mac_cfg *trans) + const struct iwl_mac_cfg *trans, u8 __iomem *hw_base, + u32 hw_rev) { const struct iwl_dev_info *dev_info; struct iwl_trans_info info = { .hw_id = (pdev->device << 16) + pdev->subsystem_device, + .hw_rev = hw_rev, }; struct iwl_trans *iwl_trans; struct iwl_trans_pcie *trans_pcie; unsigned int txcmd_size, txcmd_align; int ret; - iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info); + iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info, hw_base); if (IS_ERR(iwl_trans)) return PTR_ERR(iwl_trans); From 46f29dbfa9c8208eb1f7a6ec7e14a9de6823ad36 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 9 Jul 2025 08:16:26 +0300 Subject: [PATCH 08/16] wifi: iwlwifi: trans: remove iwl_trans_init We needed it for setting up trans parameters that could change later in the probe flow. This is no longer true, now we know all the parameters before we allocate the trans, so we can just send the right parameters to iwl_trans_alloc and have all initializations done there. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit .../net/wireless/intel/iwlwifi/iwl-trans.c | 25 ++-------- .../net/wireless/intel/iwlwifi/iwl-trans.h | 8 +-- .../intel/iwlwifi/pcie/gen1_2/trans.c | 50 ++++++++++++------- 3 files changed, 41 insertions(+), 42 deletions(-) Link: https://patch.msgid.link/20250709081300.9602fde079de.Iaede14c91095560852f9b441f1e16546b0a06bdd@changeid --- .../net/wireless/intel/iwlwifi/iwl-trans.c | 25 ++-------- .../net/wireless/intel/iwlwifi/iwl-trans.h | 8 +-- .../intel/iwlwifi/pcie/gen1_2/trans.c | 50 ++++++++++++------- 3 files changed, 41 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c index 6288779ff8ec..9604781dd0b7 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -268,7 +268,9 @@ static void iwl_trans_restart_wk(struct work_struct *wk) struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, - const struct iwl_mac_cfg *mac_cfg) + const struct iwl_mac_cfg *mac_cfg, + unsigned int txcmd_size, + unsigned int txcmd_align) { struct iwl_trans *trans; #ifdef CONFIG_LOCKDEP @@ -290,23 +292,6 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, INIT_DELAYED_WORK(&trans->restart.wk, iwl_trans_restart_wk); - return trans; -} - -int iwl_trans_init(struct iwl_trans *trans, unsigned int txcmd_size, - unsigned int txcmd_align) -{ - /* check if name/num_rx_queues were set as a proxy for info being set */ - if (WARN_ON(!trans->info.name || !trans->info.num_rxqs)) - return -EINVAL; - - txcmd_size += sizeof(struct iwl_cmd_header); - txcmd_size += 36; /* biggest possible 802.11 header */ - - /* Ensure device TX cmd cannot reach/cross a page boundary in gen2 */ - if (WARN_ON(trans->mac_cfg->gen2 && txcmd_size >= txcmd_align)) - return -EINVAL; - snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), "iwl_cmd_pool:%s", dev_name(trans->dev)); trans->dev_cmd_pool = @@ -314,9 +299,9 @@ int iwl_trans_init(struct iwl_trans *trans, unsigned int txcmd_size, txcmd_size, txcmd_align, SLAB_HWCACHE_ALIGN, NULL); if (!trans->dev_cmd_pool) - return -ENOMEM; + return NULL; - return 0; + return trans; } void iwl_trans_free(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h index 49a695e30109..103a36d8ee30 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1204,10 +1204,10 @@ static inline void iwl_trans_finish_sw_reset(struct iwl_trans *trans) * transport helper functions *****************************************************/ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, - struct device *dev, - const struct iwl_mac_cfg *cfg_trans); -int iwl_trans_init(struct iwl_trans *trans, unsigned int txcmd_size, - unsigned int txcmd_align); + struct device *dev, + const struct iwl_mac_cfg *mac_cfg, + unsigned int txcmd_size, + unsigned int txcmd_align); void iwl_trans_free(struct iwl_trans *trans); static inline bool iwl_trans_is_hw_error_value(u32 val) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 3f1861efc716..2262c1e96e8d 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -3684,18 +3684,49 @@ void iwl_trans_pcie_sync_nmi(struct iwl_trans *trans) iwl_trans_sync_nmi_with_addr(trans, inta_addr, sw_err_bit); } +static int iwl_trans_pcie_set_txcmd_info(const struct iwl_mac_cfg *mac_cfg, + unsigned int *txcmd_size, + unsigned int *txcmd_align) +{ + if (!mac_cfg->gen2) { + *txcmd_size = sizeof(struct iwl_tx_cmd_v6); + *txcmd_align = sizeof(void *); + } else if (mac_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { + *txcmd_size = sizeof(struct iwl_tx_cmd_v9); + *txcmd_align = 64; + } else { + *txcmd_size = sizeof(struct iwl_tx_cmd); + *txcmd_align = 128; + } + + *txcmd_size += sizeof(struct iwl_cmd_header); + *txcmd_size += 36; /* biggest possible 802.11 header */ + + /* Ensure device TX cmd cannot reach/cross a page boundary in gen2 */ + if (WARN_ON((mac_cfg->gen2 && *txcmd_size >= *txcmd_align))) + return -EINVAL; + + return 0; +} + static struct iwl_trans * iwl_trans_pcie_alloc(struct pci_dev *pdev, const struct iwl_mac_cfg *mac_cfg, struct iwl_trans_info *info, u8 __iomem *hw_base) { struct iwl_trans_pcie *trans_pcie, **priv; + unsigned int txcmd_size, txcmd_align; struct iwl_trans *trans; unsigned int bc_tbl_n_entries; int ret, addr_size; + ret = iwl_trans_pcie_set_txcmd_info(mac_cfg, &txcmd_size, + &txcmd_align); + if (ret) + return ERR_PTR(ret); + trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie), &pdev->dev, - mac_cfg); + mac_cfg, txcmd_size, txcmd_align); if (!trans) return ERR_PTR(-ENOMEM); @@ -4109,7 +4140,6 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, }; struct iwl_trans *iwl_trans; struct iwl_trans_pcie *trans_pcie; - unsigned int txcmd_size, txcmd_align; int ret; iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info, hw_base); @@ -4218,22 +4248,6 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, iwl_trans_set_info(iwl_trans, &info); - if (!iwl_trans->mac_cfg->gen2) { - txcmd_size = sizeof(struct iwl_tx_cmd_v6); - txcmd_align = sizeof(void *); - } else if (iwl_trans->mac_cfg->device_family < - IWL_DEVICE_FAMILY_AX210) { - txcmd_size = sizeof(struct iwl_tx_cmd_v9); - txcmd_align = 64; - } else { - txcmd_size = sizeof(struct iwl_tx_cmd); - txcmd_align = 128; - } - ret = iwl_trans_init(iwl_trans, txcmd_size, txcmd_align); - - if (ret) - goto out_free_trans; - pci_set_drvdata(pdev, iwl_trans); iwl_pcie_check_me_status(iwl_trans); From c0a44a7bd26c7ed39f96ca3cd31c2f94bedbf5e8 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Jul 2025 08:16:27 +0300 Subject: [PATCH 09/16] wifi: iwlwifi: mvm/mld: make PHC messages debug messages These have no real value for normal users, print them as debug messages instead. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.bd2df0705d89.Ic6f042588ef17719653c077ff89a8b9149c22f92@changeid --- drivers/net/wireless/intel/iwlwifi/mld/ptp.c | 12 ++++++------ drivers/net/wireless/intel/iwlwifi/mvm/ptp.c | 14 +++++++------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c index 5ee38fc168c1..ffeb37a7f830 100644 --- a/drivers/net/wireless/intel/iwlwifi/mld/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mld/ptp.c @@ -299,18 +299,18 @@ void iwl_mld_ptp_init(struct iwl_mld *mld) PTR_ERR(mld->ptp_data.ptp_clock)); mld->ptp_data.ptp_clock = NULL; } else { - IWL_INFO(mld, "Registered PHC clock: %s, with index: %d\n", - mld->ptp_data.ptp_clock_info.name, - ptp_clock_index(mld->ptp_data.ptp_clock)); + IWL_DEBUG_INFO(mld, "Registered PHC clock: %s, with index: %d\n", + mld->ptp_data.ptp_clock_info.name, + ptp_clock_index(mld->ptp_data.ptp_clock)); } } void iwl_mld_ptp_remove(struct iwl_mld *mld) { if (mld->ptp_data.ptp_clock) { - IWL_INFO(mld, "Unregistering PHC clock: %s, with index: %d\n", - mld->ptp_data.ptp_clock_info.name, - ptp_clock_index(mld->ptp_data.ptp_clock)); + IWL_DEBUG_INFO(mld, "Unregistering PHC clock: %s, with index: %d\n", + mld->ptp_data.ptp_clock_info.name, + ptp_clock_index(mld->ptp_data.ptp_clock)); ptp_clock_unregister(mld->ptp_data.ptp_clock); mld->ptp_data.ptp_clock = NULL; diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c index e89259de6f4c..06a4c9f74797 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/ptp.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2021 - 2023 Intel Corporation + * Copyright (C) 2021 - 2023, 2025 Intel Corporation */ #include "mvm.h" @@ -298,9 +298,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm) PTR_ERR(mvm->ptp_data.ptp_clock)); mvm->ptp_data.ptp_clock = NULL; } else if (mvm->ptp_data.ptp_clock) { - IWL_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", - mvm->ptp_data.ptp_clock_info.name, - ptp_clock_index(mvm->ptp_data.ptp_clock)); + IWL_DEBUG_INFO(mvm, "Registered PHC clock: %s, with index: %d\n", + mvm->ptp_data.ptp_clock_info.name, + ptp_clock_index(mvm->ptp_data.ptp_clock)); } } @@ -312,9 +312,9 @@ void iwl_mvm_ptp_init(struct iwl_mvm *mvm) void iwl_mvm_ptp_remove(struct iwl_mvm *mvm) { if (mvm->ptp_data.ptp_clock) { - IWL_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n", - mvm->ptp_data.ptp_clock_info.name, - ptp_clock_index(mvm->ptp_data.ptp_clock)); + IWL_DEBUG_INFO(mvm, "Unregistering PHC clock: %s, with index: %d\n", + mvm->ptp_data.ptp_clock_info.name, + ptp_clock_index(mvm->ptp_data.ptp_clock)); ptp_clock_unregister(mvm->ptp_data.ptp_clock); mvm->ptp_data.ptp_clock = NULL; From 43375cf823479693a095f51db4fe2f3f1e168eaa Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Jul 2025 08:16:28 +0300 Subject: [PATCH 10/16] wifi: iwlwifi: remove Intel driver load message There's really not much value in printing something just because the driver loaded, remove that message. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.fe33c279a45d.I16a9cbcfce92a1d1b8b26a20ea9911e8a5a0b1cc@changeid --- drivers/net/wireless/intel/iwlwifi/iwl-drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c index 064ff2135411..f62f7c7ee7f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-drv.c @@ -2049,8 +2049,6 @@ static int __init iwl_drv_init(void) for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++) INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv); - pr_info(DRV_DESCRIPTION "\n"); - #ifdef CONFIG_IWLWIFI_DEBUGFS /* Create the root of iwlwifi debugfs subsystem. */ iwl_dbgfs_root = debugfs_create_dir(DRV_NAME, NULL); From c5fbdf0ba7c1a6ed52dc3650bee73ce00c86cf7f Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Jul 2025 08:16:29 +0300 Subject: [PATCH 11/16] wifi: iwlwifi: match discrete/integrated to fix some names Some device names were wrong because our internal data suggested that discrete Ga devices have B-step RF, when they actually have C-step. However, matching the step for them is bad anyway. Change the code to be able to find the devinfo depending on the device being integrated or discrete. This is only for the names, since the RF config cannot be different for the same RF because it's discrete or integrated, so add a kunit test that ensures both (a) the RF config is the same and (b) the name is different (the latter really only because that's the whole point of having a match on the discrete/integrated bit.) Remove the RF step matching since it's no longer needed now. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.e048a94659f1.Ie5919c70e9d8e3a28152aaf3cdffd19ed3d4f5c7@changeid --- .../net/wireless/intel/iwlwifi/iwl-config.h | 6 +-- drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 13 +++--- .../intel/iwlwifi/pcie/gen1_2/trans.c | 2 +- .../wireless/intel/iwlwifi/tests/devinfo.c | 45 ++++++++++++++----- 4 files changed, 46 insertions(+), 20 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-config.h b/drivers/net/wireless/intel/iwlwifi/iwl-config.h index 08c4f79f8335..30e5f5a5cd89 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-config.h @@ -488,8 +488,8 @@ struct iwl_dev_info { rf_type:9, match_bw_limit:1, bw_limit:1, - match_rf_step:1, - rf_step:4, + match_discrete:1, + discrete:1, match_rf_id:1, rf_id:4, match_cdb:1, @@ -504,7 +504,7 @@ extern const struct pci_device_id iwl_hw_card_ids[]; const struct iwl_dev_info * iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, - u8 rf_id, u8 bw_limit, u8 rf_step); + u8 rf_id, u8 bw_limit, bool discrete); /* * This list declares the config structures for all devices. diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c index 02a031433b23..0bd9b44d295b 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c @@ -577,8 +577,10 @@ EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_hw_card_ids); .subdevice_m_h = _HIGHEST_BIT(m) #define RF_TYPE(n) .match_rf_type = 1, \ .rf_type = IWL_CFG_RF_TYPE_##n -#define RF_STEP(n) .match_rf_step = 1, \ - .rf_step = SILICON_##n##_STEP +#define DISCRETE .match_discrete = 1, \ + .discrete = 1 +#define INTEGRATED .match_discrete = 1, \ + .discrete = 0 #define RF_ID(n) .match_rf_id = 1, \ .rf_id = IWL_CFG_RF_ID_##n #define NO_CDB .match_cdb = 1, .cdb = 0 @@ -1032,9 +1034,8 @@ VISIBLE_IF_IWLWIFI_KUNIT const struct iwl_dev_info iwl_dev_info_table[] = { /* FM RF */ IWL_DEV_INFO(iwl_rf_fm, iwl_be201_name, RF_TYPE(FM)), IWL_DEV_INFO(iwl_rf_fm, iwl_be401_name, RF_TYPE(FM), CDB), - /* the discrete NICs got the RF B0, it's only for the name anyway */ IWL_DEV_INFO(iwl_rf_fm, iwl_be200_name, RF_TYPE(FM), - DEVICE(0x272B), RF_STEP(B)), + DEVICE(0x272B), DISCRETE), IWL_DEV_INFO(iwl_rf_fm_160mhz, iwl_be202_name, RF_TYPE(FM), BW_LIMITED), @@ -1079,7 +1080,7 @@ EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_dev_info_table_size); const struct iwl_dev_info * iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, - u8 rf_id, u8 bw_limit, u8 rf_step) + u8 rf_id, u8 bw_limit, bool discrete) { int num_devices = ARRAY_SIZE(iwl_dev_info_table); int i; @@ -1114,7 +1115,7 @@ iwl_pci_find_dev_info(u16 device, u16 subsystem_device, u16 rf_type, u8 cdb, if (dev_info->match_bw_limit && dev_info->bw_limit != bw_limit) continue; - if (dev_info->match_rf_step && dev_info->rf_step != rf_step) + if (dev_info->match_discrete && dev_info->discrete != discrete) continue; return dev_info; diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 2262c1e96e8d..8440f0c8a78e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -4198,7 +4198,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, CSR_HW_RFID_IS_CDB(info.hw_rf_id), IWL_SUBDEVICE_RF_ID(pdev->subsystem_device), IWL_SUBDEVICE_BW_LIM(pdev->subsystem_device), - CSR_HW_RFID_STEP(info.hw_rf_id)); + !iwl_trans->mac_cfg->integrated); if (dev_info) { iwl_trans->cfg = dev_info->cfg; info.name = dev_info->name; diff --git a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c index 784433bb246a..4d660cef3de9 100644 --- a/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c +++ b/drivers/net/wireless/intel/iwlwifi/tests/devinfo.c @@ -31,15 +31,6 @@ static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *d pos += scnprintf(buf + pos, sizeof(buf) - pos, " bw_limit=*"); - if (di->match_rf_step) - pos += scnprintf(buf + pos, sizeof(buf) - pos, - " rf_step=%c", - di->rf_step == SILICON_Z_STEP ? 'Z' : - 'A' + di->rf_step); - else - pos += scnprintf(buf + pos, sizeof(buf) - pos, - " rf_step=*"); - if (di->match_rf_id) pos += scnprintf(buf + pos, sizeof(buf) - pos, " rf_id=0x%x", di->rf_id); @@ -54,6 +45,13 @@ static void iwl_pci_print_dev_info(const char *pfx, const struct iwl_dev_info *d pos += scnprintf(buf + pos, sizeof(buf) - pos, " cdb=*"); + if (di->match_discrete) + pos += scnprintf(buf + pos, sizeof(buf) - pos, + " discrete=%d", + di->discrete); + else + pos += scnprintf(buf + pos, sizeof(buf) - pos, + " discrete=*"); printk(KERN_DEBUG "%sdev=%04x subdev=%04x/%04x%s\n", pfx, di->device, di->subdevice, subdevice_mask, buf); @@ -70,7 +68,7 @@ static void devinfo_table_order(struct kunit *test) ret = iwl_pci_find_dev_info(di->device, di->subdevice, di->rf_type, di->cdb, di->rf_id, di->bw_limit, - di->rf_step); + di->discrete); if (!ret) { iwl_pci_print_dev_info("No entry found for: ", di); KUNIT_FAIL(test, @@ -85,6 +83,32 @@ static void devinfo_table_order(struct kunit *test) } } +static void devinfo_discrete_match(struct kunit *test) +{ + /* + * Validate that any entries with discrete/integrated match have + * the same config with the value inverted (if they match at all.) + */ + + for (int idx = 0; idx < iwl_dev_info_table_size; idx++) { + const struct iwl_dev_info *di = &iwl_dev_info_table[idx]; + const struct iwl_dev_info *ret; + + if (!di->match_discrete) + continue; + + ret = iwl_pci_find_dev_info(di->device, di->subdevice, + di->rf_type, di->cdb, + di->rf_id, di->bw_limit, + !di->discrete); + if (!ret) + continue; + KUNIT_EXPECT_PTR_EQ(test, di->cfg, ret->cfg); + /* and check the name is different, that'd be the point of it */ + KUNIT_EXPECT_NE(test, strcmp(di->name, ret->name), 0); + } +} + static void devinfo_names(struct kunit *test) { int idx; @@ -216,6 +240,7 @@ static void devinfo_no_mac_cfg_dups(struct kunit *test) static struct kunit_case devinfo_test_cases[] = { KUNIT_CASE(devinfo_table_order), + KUNIT_CASE(devinfo_discrete_match), KUNIT_CASE(devinfo_names), KUNIT_CASE(devinfo_no_cfg_dups), KUNIT_CASE(devinfo_no_name_dups), From 8a4583d6264c1c5a4124b93f5f110adec1163e6d Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 9 Jul 2025 08:16:30 +0300 Subject: [PATCH 12/16] wifi: iwlwifi: pcie: rename iwl_pci_gen1_2_probe() argument Using 'trans' for the mac config is confusing, rename the argument to 'mac_cfg'. Signed-off-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.72d87406f8d7.I8b39f01e06ad7791efe718c267cbf367233920a3@changeid --- drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h | 6 +++--- drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h index ec17e2e84151..7dd11891ccfe 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/internal.h @@ -1078,9 +1078,9 @@ void __releases(nic_access_nobh) 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 *trans, u8 __iomem *hw_base, - u32 hw_rev); + 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); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c index 8440f0c8a78e..585d845b53fa 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c @@ -4130,8 +4130,8 @@ static void iwl_pcie_check_me_status(struct iwl_trans *trans) int iwl_pci_gen1_2_probe(struct pci_dev *pdev, const struct pci_device_id *ent, - const struct iwl_mac_cfg *trans, u8 __iomem *hw_base, - u32 hw_rev) + 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 = { @@ -4142,7 +4142,7 @@ int iwl_pci_gen1_2_probe(struct pci_dev *pdev, struct iwl_trans_pcie *trans_pcie; int ret; - iwl_trans = iwl_trans_pcie_alloc(pdev, trans, &info, hw_base); + iwl_trans = iwl_trans_pcie_alloc(pdev, mac_cfg, &info, hw_base); if (IS_ERR(iwl_trans)) return PTR_ERR(iwl_trans); From cb09c80f5904cd99d2e2419733a502f7bdc209b9 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 9 Jul 2025 08:16:31 +0300 Subject: [PATCH 13/16] wifi: iwlwifi: mvm: remove MLO GTK rekey code iwlmvm driver does not support MLO. Remove this code Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.4957e50dee91.I2a432256dbc3069e0300e1f833e10a93d203f538@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 210 +------------------- 1 file changed, 10 insertions(+), 200 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index e1070b891300..1af9e54a882d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1474,9 +1474,6 @@ struct iwl_wowlan_status_data { struct iwl_multicast_key_data igtk; struct iwl_multicast_key_data bigtk[WOWLAN_BIGTK_KEYS_NUM]; - int num_mlo_keys; - struct iwl_wowlan_mlo_gtk mlo_keys[WOWLAN_MAX_MLO_KEYS]; - u8 *wake_packet; }; @@ -1986,167 +1983,6 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, } } -struct iwl_mvm_d3_mlo_old_keys { - u32 cipher[IEEE80211_MLD_MAX_NUM_LINKS][WOWLAN_MLO_GTK_KEY_NUM_TYPES]; - struct ieee80211_key_conf *key[IEEE80211_MLD_MAX_NUM_LINKS][8]; -}; - -static void iwl_mvm_mlo_key_ciphers(struct ieee80211_hw *hw, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct ieee80211_key_conf *key, - void *data) -{ - struct iwl_mvm_d3_mlo_old_keys *old_keys = data; - enum iwl_wowlan_mlo_gtk_type key_type; - - if (key->link_id < 0) - return; - - if (WARN_ON(key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS || - key->keyidx >= 8)) - return; - - if (WARN_ON(old_keys->key[key->link_id][key->keyidx])) - return; - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - case WLAN_CIPHER_SUITE_GCMP_256: - key_type = WOWLAN_MLO_GTK_KEY_TYPE_GTK; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - case WLAN_CIPHER_SUITE_AES_CMAC: - if (key->keyidx == 4 || key->keyidx == 5) { - key_type = WOWLAN_MLO_GTK_KEY_TYPE_IGTK; - break; - } else if (key->keyidx == 6 || key->keyidx == 7) { - key_type = WOWLAN_MLO_GTK_KEY_TYPE_BIGTK; - break; - } - return; - default: - /* ignore WEP/TKIP or unknown ciphers */ - return; - } - - old_keys->cipher[key->link_id][key_type] = key->cipher; - old_keys->key[key->link_id][key->keyidx] = key; -} - -static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status, - struct ieee80211_vif *vif, - struct iwl_mvm *mvm) -{ - int i; - struct iwl_mvm_d3_mlo_old_keys *old_keys; - bool ret = true; - - IWL_DEBUG_WOWLAN(mvm, "Num of MLO Keys: %d\n", status->num_mlo_keys); - if (!status->num_mlo_keys) - return true; - - old_keys = kzalloc(sizeof(*old_keys), GFP_KERNEL); - if (!old_keys) - return false; - - /* find the cipher for each mlo key */ - ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mlo_key_ciphers, old_keys); - - for (i = 0; i < status->num_mlo_keys; i++) { - struct iwl_wowlan_mlo_gtk *mlo_key = &status->mlo_keys[i]; - struct ieee80211_key_conf *key, *old_key; - struct ieee80211_key_seq seq; - DEFINE_RAW_FLEX(struct ieee80211_key_conf, conf, key, - WOWLAN_KEY_MAX_SIZE); - u16 flags = le16_to_cpu(mlo_key->flags); - int j, link_id, key_id, key_type; - - link_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK); - key_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK); - key_type = u16_get_bits(flags, - WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK); - - if (!(vif->valid_links & BIT(link_id))) - continue; - - if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS || - key_id >= 8 || - key_type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES)) - continue; - - conf->cipher = old_keys->cipher[link_id][key_type]; - /* WARN_ON? */ - if (!conf->cipher) - continue; - - conf->keylen = 0; - switch (conf->cipher) { - case WLAN_CIPHER_SUITE_CCMP: - case WLAN_CIPHER_SUITE_GCMP: - conf->keylen = WLAN_KEY_LEN_CCMP; - break; - case WLAN_CIPHER_SUITE_GCMP_256: - conf->keylen = WLAN_KEY_LEN_GCMP_256; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_128: - conf->keylen = WLAN_KEY_LEN_BIP_GMAC_128; - break; - case WLAN_CIPHER_SUITE_BIP_GMAC_256: - conf->keylen = WLAN_KEY_LEN_BIP_GMAC_256; - break; - case WLAN_CIPHER_SUITE_AES_CMAC: - conf->keylen = WLAN_KEY_LEN_AES_CMAC; - break; - case WLAN_CIPHER_SUITE_BIP_CMAC_256: - conf->keylen = WLAN_KEY_LEN_BIP_CMAC_256; - break; - } - - if (WARN_ON(!conf->keylen || - conf->keylen > WOWLAN_KEY_MAX_SIZE)) - continue; - - memcpy(conf->key, mlo_key->key, conf->keylen); - conf->keyidx = key_id; - - old_key = old_keys->key[link_id][key_id]; - if (old_key) { - IWL_DEBUG_WOWLAN(mvm, - "Remove MLO key id %d, link id %d\n", - key_id, link_id); - ieee80211_remove_key(old_key); - } - - IWL_DEBUG_WOWLAN(mvm, "Add MLO key id %d, link id %d\n", - key_id, link_id); - key = ieee80211_gtk_rekey_add(vif, conf, link_id); - if (WARN_ON(IS_ERR(key))) { - ret = false; - goto out; - } - - /* - * mac80211 expects the pn in big-endian - * also note that seq is a union of all cipher types - * (ccmp, gcmp, cmac, gmac), and they all have the same - * pn field (of length 6) so just copy it to ccmp.pn. - */ - for (j = 5; j >= 0; j--) - seq.ccmp.pn[5 - j] = mlo_key->pn[j]; - - /* group keys are non-QoS and use TID 0 */ - ieee80211_set_key_rx_seq(key, 0, &seq); - } - -out: - kfree(old_keys); - return ret; -} - static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, struct ieee80211_vif *vif, struct iwl_mvm *mvm, u32 gtk_cipher) @@ -2346,9 +2182,6 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, return false; } - if (!iwl_mvm_mlo_gtk_rekey(status, vif, mvm)) - return false; - ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, (void *)&replay_ctr, GFP_KERNEL); } @@ -2479,10 +2312,11 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, struct iwl_wowlan_status_data *status, u32 len) { - u32 expected_len = sizeof(*data) + - data->num_mlo_link_keys * sizeof(status->mlo_keys[0]); + if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys, + "MLO is not supported, shouldn't receive MLO keys\n")) + return; - if (len < expected_len) { + if (len < sizeof(*data)) { IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); status = NULL; return; @@ -2511,33 +2345,21 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, le32_to_cpu(data->num_of_gtk_rekeys); status->received_beacons = le32_to_cpu(data->received_beacons); status->tid_tear_down = data->tid_tear_down; - - if (data->num_mlo_link_keys) { - status->num_mlo_keys = data->num_mlo_link_keys; - if (IWL_FW_CHECK(mvm, - status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, - "Too many mlo keys: %d, max %d\n", - status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) - status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; - memcpy(status->mlo_keys, data->mlo_gtks, - status->num_mlo_keys * sizeof(status->mlo_keys[0])); - } } static void iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm, struct iwl_wowlan_info_notif_v4 *data, struct iwl_wowlan_status_data *status, - u32 len, bool has_mlo_keys) + u32 len) { u32 i; - u32 expected_len = sizeof(*data); - if (has_mlo_keys) - expected_len += (data->num_mlo_link_keys * - sizeof(status->mlo_keys[0])); + if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys, + "MLO is not supported, shouldn't receive MLO keys\n")) + return; - if (len < expected_len) { + if (len < sizeof(*data)) { IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); status = NULL; return; @@ -2560,17 +2382,6 @@ iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm, le32_to_cpu(data->num_of_gtk_rekeys); status->received_beacons = le32_to_cpu(data->received_beacons); status->tid_tear_down = data->tid_tear_down; - - if (has_mlo_keys && data->num_mlo_link_keys) { - status->num_mlo_keys = data->num_mlo_link_keys; - if (IWL_FW_CHECK(mvm, - status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, - "Too many mlo keys: %d, max %d\n", - status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) - status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; - memcpy(status->mlo_keys, data->mlo_gtks, - status->num_mlo_keys * sizeof(status->mlo_keys[0])); - } } static void @@ -3321,8 +3132,7 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, (void *)pkt->data; iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif, - d3_data->status, len, - wowlan_info_ver > 3); + d3_data->status, len); } else { struct iwl_wowlan_info_notif *notif = (void *)pkt->data; From 915d3522563b6ca672d76b0bf459062ffd575fe6 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 9 Jul 2025 08:16:32 +0300 Subject: [PATCH 14/16] wifi: iwlwifi: mvm: remove unneeded argument iwl_mvm_set_key_rx_seq is called only once when the installed argument is false. Remove this argument. Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.2586112afd70.Iddf9a2b24546cb3a1506d68ca41ed215f88cff5c@changeid --- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 1af9e54a882d..7f0b2089ab8e 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -1787,8 +1787,7 @@ static void iwl_mvm_set_key_rx_seq_idx(struct ieee80211_key_conf *key, } static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, - struct iwl_wowlan_status_data *status, - bool installed) + struct iwl_wowlan_status_data *status) { int i; @@ -1812,7 +1811,7 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, /* handle the case where we didn't, last key only */ if (status->gtk_seq[i].key_id == -1 && - (!status->num_of_gtk_rekeys || installed)) + (!status->num_of_gtk_rekeys)) iwl_mvm_set_key_rx_seq_idx(key, status, i); } } @@ -1963,7 +1962,7 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, (status->gtk[1].len && keyidx == status->gtk[1].id))) { ieee80211_remove_key(key); } else { - iwl_mvm_set_key_rx_seq(key, data->status, false); + iwl_mvm_set_key_rx_seq(key, data->status); } break; case WLAN_CIPHER_SUITE_BIP_GMAC_128: From e9b7a0264baf9b4aa55ff3ddae275d26b56f476b Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 9 Jul 2025 08:16:33 +0300 Subject: [PATCH 15/16] wifi: iwlwifi: bump minimum API version in BZ Stop supporting older FWs Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.71404c289481.Iea4f3d36e18029a817ec5d6641d08ac5ee025678@changeid --- drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c index c6cd892bff69..50d454514fe5 100644 --- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c +++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c @@ -13,7 +13,7 @@ #define IWL_BZ_UCODE_API_MAX 102 /* Lowest firmware API version supported */ -#define IWL_BZ_UCODE_API_MIN 94 +#define IWL_BZ_UCODE_API_MIN 98 /* Memory offsets and lengths */ #define IWL_BZ_SMEM_OFFSET 0x400000 From 34f2573661e3e644efaf383178af634a2fd67828 Mon Sep 17 00:00:00 2001 From: Miri Korenblit Date: Wed, 9 Jul 2025 08:16:34 +0300 Subject: [PATCH 16/16] wifi: iwlwifi: mvm: remove support for iwl_wowlan_info_notif_v4 FWs with this version are no longer supported on any device. Reviewed-by: Johannes Berg Signed-off-by: Miri Korenblit Link: https://patch.msgid.link/20250709081300.1668a7430521.I488d69251aed62f0b11a2553f972a1730bc8b6cf@changeid --- .../net/wireless/intel/iwlwifi/fw/api/d3.h | 13 ++++-------- drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 21 ++++++++++--------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h index 9ce819503aed..99554496300a 100644 --- a/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h +++ b/drivers/net/wireless/intel/iwlwifi/fw/api/d3.h @@ -912,7 +912,7 @@ struct iwl_wowlan_mlo_gtk { } __packed; /* WOWLAN_MLO_GTK_KEY_API_S_VER_1 */ /** - * struct iwl_wowlan_info_notif_v4 - WoWLAN information notification + * struct iwl_wowlan_info_notif_v3 - WoWLAN information notification * @gtk: GTK data * @igtk: IGTK data * @bigtk: BIGTK data @@ -927,12 +927,9 @@ struct iwl_wowlan_mlo_gtk { * @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, or reserved in version < 4 * @reserved2: reserved - * @mlo_gtks: array of GTKs of size num_mlo_link_keys for version >= 4 */ -struct iwl_wowlan_info_notif_v4 { +struct iwl_wowlan_info_notif_v3 { struct iwl_wowlan_gtk_status_v3 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]; @@ -946,10 +943,8 @@ struct iwl_wowlan_info_notif_v4 { __le32 received_beacons; u8 tid_tear_down; u8 station_id; - u8 num_mlo_link_keys; - u8 reserved2; - struct iwl_wowlan_mlo_gtk mlo_gtks[]; -} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */ + u8 reserved2[2]; +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3 */ /** * struct iwl_wowlan_info_notif - WoWLAN information notification diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index 7f0b2089ab8e..66749dc38fc5 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c @@ -2347,17 +2347,13 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, } static void -iwl_mvm_parse_wowlan_info_notif_v4(struct iwl_mvm *mvm, - struct iwl_wowlan_info_notif_v4 *data, +iwl_mvm_parse_wowlan_info_notif_v3(struct iwl_mvm *mvm, + struct iwl_wowlan_info_notif_v3 *data, struct iwl_wowlan_status_data *status, u32 len) { u32 i; - if (IWL_FW_CHECK(mvm, data->num_mlo_link_keys, - "MLO is not supported, shouldn't receive MLO keys\n")) - return; - if (len < sizeof(*data)) { IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); status = NULL; @@ -3126,18 +3122,23 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, d3_data->status, len); - } else if (wowlan_info_ver < 5) { - struct iwl_wowlan_info_notif_v4 *notif = + } else if (wowlan_info_ver == 3) { + struct iwl_wowlan_info_notif_v3 *notif = (void *)pkt->data; - iwl_mvm_parse_wowlan_info_notif_v4(mvm, notif, + iwl_mvm_parse_wowlan_info_notif_v3(mvm, notif, d3_data->status, len); - } else { + } else if (wowlan_info_ver == 5) { struct iwl_wowlan_info_notif *notif = (void *)pkt->data; iwl_mvm_parse_wowlan_info_notif(mvm, notif, d3_data->status, len); + } else { + IWL_FW_CHECK(mvm, 1, + "Firmware advertises unknown WoWLAN info notification %d!\n", + wowlan_info_ver); + return false; } d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO;