wifi: iwlwifi: updates - 2026-10-14

This contains our usual development commits, notably:
 - UHR sniffer support
 - Transport refactor: avoid indirection, bring virtualization back
 - A UEFI lock for UEFI tables security
 - New BIOS tables support
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQQM3A3Pv7vbm9vtjWbacY7uyt+OfQUCas9IlgAKCRDacY7uyt+O
 fUibAP0V/fsGHLVVrYd8qbBi25Vmul2ozWvwr31Lj2gb8asXdwEAlBSc4mw2xwSu
 /IOdQQkLVl0fR1P5HyB5QMBvj/CwCww=
 =lSVE
 -----END PGP SIGNATURE-----

Merge tag 'iwlwifi-next-2026-10-14' of https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next

Miri Korenblit says:
====================
wifi: iwlwifi: updates - 2026-10-14

This contains our usual development commits, notably:
- UHR sniffer support
- Transport refactor: avoid indirection, bring virtualization back
- A UEFI lock for UEFI tables security
- New BIOS tables support
====================

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
This commit is contained in:
Johannes Berg 2026-10-14 12:16:26 +02:00
commit 313f802d6f
112 changed files with 4953 additions and 2990 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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 <linux/slab.h>
@ -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: ");

View File

@ -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 <linux/units.h>
@ -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);

View File

@ -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 <linux/types.h>
#include <linux/slab.h>
@ -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);
}
}

View File

@ -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 <net/mac80211.h>
#include <linux/etherdevice.h>
#include <linux/unaligned.h>
#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);
}

View File

@ -2,6 +2,7 @@
/******************************************************************************
*
* Copyright(c) 2008 - 2014, 2022 Intel Corporation. All rights reserved.
* Copyright (C) 2026 Intel Corporation
*****************************************************************************/
#include <linux/etherdevice.h>
#include <linux/kernel.h>
@ -9,7 +10,6 @@
#include <linux/sched.h>
#include <net/mac80211.h>
#include "iwl-io.h"
#include "iwl-agn-hw.h"
#include "iwl-trans.h"
#include "iwl-modparams.h"

View File

@ -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 <asm/div64.h>
#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)) {

View File

@ -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 <asm/div64.h>
#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);

View File

@ -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 <linux/module.h>
#include <linux/slab.h>
#include <net/mac80211.h>
#include "iwl-io.h"
#include "iwl-debug.h"
#include "iwl-trans.h"
#include "iwl-modparams.h"

View File

@ -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 <linux/unaligned.h>
#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);

View File

@ -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 <linux/module.h>
#include <linux/slab.h>
#include <net/mac80211.h>
#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);

View File

@ -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 <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/ieee80211.h>
#include "iwl-io.h"
#include "iwl-trans.h"
#include "iwl-agn-hw.h"
#include "dev.h"

View File

@ -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 <linux/kernel.h>
#include "iwl-io.h"
#include "iwl-agn-hw.h"
#include "iwl-trans.h"
#include "iwl-fh.h"

View File

@ -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)
{

View File

@ -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;

View File

@ -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,

View File

@ -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 <linux/types.h>
#include <linux/bits.h>
#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__ */

View File

@ -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 <linux/types.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 */
#endif /* __iwl_fw_api_context_info_h__ */

View File

@ -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

View File

@ -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

View File

@ -7,6 +7,8 @@
#ifndef __iwl_fw_api_mac_cfg_h__
#define __iwl_fw_api_mac_cfg_h__
#include <linux/ieee80211-p2p.h>
#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

View File

@ -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,

View File

@ -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

View File

@ -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;
};

View File

@ -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

View File

@ -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

View File

@ -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
*/
/*

View File

@ -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,

View File

@ -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;

View File

@ -10,7 +10,7 @@
#include <net/cfg80211.h>
#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"

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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;

View File

@ -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);
}

View File

@ -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__ */

View File

@ -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)

View File

@ -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);
}

View File

@ -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),

View File

@ -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

View File

@ -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 <linux/device.h>
#include <linux/export.h>
#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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -6,14 +6,14 @@
*/
#include <linux/kernel.h>
#include <linux/bsearch.h>
#include <linux/delay.h>
#include <linux/list.h>
#include "iwl-trans.h"
#include "iwl-drv.h"
#include "iwl-prph.h"
#include <linux/dmapool.h>
#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);
}

View File

@ -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,

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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"

View File

@ -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:

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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);
}
/*

View File

@ -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 *)&notif->membership_status,
(u8 *)&notif->user_position);
(const u8 *)&notif->membership_status,
(const u8 *)&notif->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,

View File

@ -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);

View File

@ -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",

View File

@ -6,7 +6,6 @@
#include <linux/dmi.h>
#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;

View File

@ -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__ */

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
};

View File

@ -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);

View File

@ -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 = &notif->per_sta[fw_sta_id];
} else if (notif_ver == 4) {
const struct iwl_system_statistics_notif_oper_v4 *notif =
(void *)&pkt->data;
per_sta = &notif->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;

View File

@ -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

View File

@ -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 <kunit/test.h>
#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);

View File

@ -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,

View File

@ -2,6 +2,7 @@
/*
* Copyright (C) 2024 - 2026 Intel Corporation
*/
#include <linux/timekeeping.h>
#include <net/ip.h>
#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 ?

View File

@ -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 <linux/atomic.h>
#include <net/mac80211.h>
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__ */

View File

@ -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;

View File

@ -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);

View File

@ -7,7 +7,7 @@
#include <linux/math64.h>
#include <net/cfg80211.h>
#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 = {

View File

@ -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);

View File

@ -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 <linux/leds.h>
#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,

View File

@ -7,7 +7,7 @@
#include <linux/etherdevice.h>
#include <linux/crc32.h>
#include <net/mac80211.h>
#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));

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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,

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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 <linux/etherdevice.h>
#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)

View File

@ -12,7 +12,6 @@
#include "fw-api.h"
#include "time-event.h"
#include "mvm.h"
#include "iwl-io.h"
#include "iwl-prph.h"
/*

View File

@ -7,7 +7,7 @@
#include <net/mac80211.h>
#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;

View File

@ -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 <linux/dmi.h>
#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)

Some files were not shown because too many files have changed in this diff Show More