diff options
author | Bjoern A. Zeeb <bz@FreeBSD.org> | 2024-09-27 21:53:40 +0000 |
---|---|---|
committer | Bjoern A. Zeeb <bz@FreeBSD.org> | 2024-10-28 14:42:25 +0000 |
commit | a4128aad8503277614f2d214011ef60a19447b83 (patch) | |
tree | 5442f1a66fbd0cb3746ef1f586c4c17b54acb1b0 | |
parent | 7b43f4d064195bcf66816cb9fe350a1392fe24ce (diff) | |
parent | 5d6ad179ba1337044d054d06596e2169952660b6 (diff) | |
download | src-a4128aad8503.tar.gz src-a4128aad8503.zip |
iwlwifi: update Intel's iwlwifi/mvm driver.
This version is based on
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
98f7e32f20d28ec452afb208f9cffc08448a2652 ( tag: v6.11 ).
Sponsored by: The FreeBSD Foundation
MFC after: 14 days
127 files changed, 14846 insertions, 9010 deletions
diff --git a/share/man/man4/iwlwifi.4 b/share/man/man4/iwlwifi.4 index ddeeb549d0f4..c5622f2586f1 100644 --- a/share/man/man4/iwlwifi.4 +++ b/share/man/man4/iwlwifi.4 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 30, 2024 +.Dd October 12, 2024 .Dt IWLWIFI 4 .Os .Sh NAME @@ -86,12 +86,36 @@ The .Nm driver supports PCIe devices from the .Em mvm -sub-driver with the following chipsets: +sub-driver with the following chipset generations: +.Pp +.\" awk -F\\t '{ print $5 }' ~/tmp/iwlwifi_pci_ids_name.txt | \ +.\" grep -v undefined | sort -V | uniq | grep -v ^$ | \ +.\" awk '{ printf ".It\n%s\n", $0 }' +.Bl -bullet -compact +.It +7000 +.It +8000 +.It +9000 +.It +22000 +.It +AX210 +.It +BZ +.It +SC +.El +.Pp +These chipset generations match the following common device names: .Pp .Bl -bullet -compact .\" --------------------------------------------------------------------- .\" This list is manually generated from a sysctl and post-processing. .\" Edits will be overwritten on next update. +.\" awk -F\\t '{ if ($2 == "") { next; } if (seen[$2]) { next; } \ +.\" seen[$2]=1; printf ".It\n%s\n", $2; }' iwlwifi_pci_ids_name.txt .\" --------------------------------------------------------------------- .It Intel(R) Dual Band Wireless AC 7260 @@ -200,15 +224,19 @@ Intel(R) Wi-Fi 6 AX101 .It Intel(R) Wi-Fi 6 AX203 .It -Intel(R) Wi-Fi 6E AX221 160MHz -.It Intel(R) Wi-Fi 6E AX231 160MHz .It -Intel(R) TBD Bz device +Intel(R) Wi-Fi 7 BE201 320MHz .It -Intel(R) Wi-Fi 6 AX204 160MHz +Intel(R) Wi-Fi 7 BE200 320MHz +.It +Intel(R) Wi-Fi 7 BE202 160MHz .It Intel(R) TBD Sc device +.It +Intel(R) TBD Sc2 device +.It +Intel(R) TBD Sc2f device .\" --------------------------------------------------------------------- .El .Sh BUGS diff --git a/share/man/man4/iwlwififw.4 b/share/man/man4/iwlwififw.4 index debd0cda36b5..491a634e70b5 100644 --- a/share/man/man4/iwlwififw.4 +++ b/share/man/man4/iwlwififw.4 @@ -1,5 +1,5 @@ .\"- -.\" Copyright (c) 2021-2023 The FreeBSD Foundation +.\" Copyright (c) 2021-2024 The FreeBSD Foundation .\" .\" This documentation was written by Bj\xc3\xb6rn Zeeb under sponsorship from .\" the FreeBSD Foundation. @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd September 21, 2023 +.Dd October 12, 2024 .Dt iwlwififw 4 .Os .Sh NAME @@ -43,13 +43,18 @@ models supported by the .Xr iwlwifi 4 driver. .Pp +One can use +.Xr fwget 8 +to install the correct firmware package. +.Pp .Bl -column -compact "Vendor" "Device" "Subv. " "Subd. " "Firmware-Prefix" .It Ar Name .It Ar Vendor Ta Ar Device Ta Ar Subv. Ta Ar Subd. Ta Ar Firmware-Prefix -.\" --------------------------------------------------------------------- -.\" This list is manually generated from a sysctl and post-processing. -.\" Edits will be overwritten on next update. -.\" --------------------------------------------------------------------- +.% --------------------------------------------------------------------- +.% This list is manually generated from a sysctl and post-processing +.% by sys/contrib/dev/iwlwifi/zzz_fw_ports_fwget.sh generating the list. +.% Edits will be overwritten on next update. +.% --------------------------------------------------------------------- .It "" .It Intel(R) Dual Band Wireless AC 7260 .It 0x8086 Ta 0x08b1 Ta any Ta 0x4070 Ta iwlwifi-7260 @@ -735,6 +740,198 @@ driver. .It Intel(R) Dual Band Wireless AC 8265 .It 0x8086 Ta 0x24fd Ta any Ta 0x9074 Ta iwlwifi-8265 .It "" +.It (unknown) +.It 0x8086 Ta 0x2526 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x271b Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x271c Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x30dc Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x31dc Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x9df0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa370 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x02f0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x06f0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x34f0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x3df0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x4df0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x43f0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa0f0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x2723 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x2725 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x7a70 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x7af0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x51f0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x51f1 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x54f0 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x7f70 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x2729 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x7e40 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x2727 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x272d Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x272b Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 000000 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0090 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0094 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0098 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x009c Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x00c0 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x00c4 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x00e0 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x00e4 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x00e8 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x00ec Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0100 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0110 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0114 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0118 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x011c Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0310 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0314 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0510 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x0a10 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x1671 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x1672 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x1771 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x1772 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x1791 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x1792 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x4090 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x40c4 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x40e0 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x4110 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xa840 Ta any Ta 0x4314 Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x7740 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x4d40 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xe440 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xe340 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0xd340 Ta any Ta any Ta (unknown) +.It "" +.It (unknown) +.It 0x8086 Ta 0x6e70 Ta any Ta any Ta (unknown) +.It "" .It Killer (R) Wireless-AC 1550 Wireless Network Adapter (9260NGW) 160MHz .It 0x8086 Ta 0x2526 Ta any Ta 0x1550 Ta iwlwifi-9260-th-b0-jf-b0 .It "" @@ -1290,9 +1487,6 @@ driver. .It Intel(R) Wi-Fi 6E AX211 160MHz .It 0x8086 Ta any Ta any Ta any Ta (null) .It "" -.It Intel(R) Wi-Fi 6E AX221 160MHz -.It 0x8086 Ta any Ta any Ta any Ta (null) -.It "" .It Intel(R) Wi-Fi 6E AX231 160MHz .It 0x8086 Ta any Ta any Ta any Ta (null) .It "" @@ -1311,9 +1505,6 @@ driver. .It Intel(R) Wi-Fi 6E AX411 160MHz .It 0x8086 Ta any Ta any Ta any Ta iwlwifi-so-a0-gf4-a0 .It "" -.It Intel(R) TBD Bz device -.It 0x8086 Ta any Ta any Ta any Ta (null) -.It "" .It Intel(R) Wireless-AC 9560 160MHz .It 0x8086 Ta any Ta any Ta any Ta iwlwifi-so-a0-jf-b0 .It "" @@ -1332,14 +1523,23 @@ driver. .It Intel(R) Wireless-AC 9462 .It 0x8086 Ta any Ta any Ta any Ta iwlwifi-so-a0-jf-b0 .It "" -.It Intel(R) Wi-Fi 6 AX204 160MHz -.It 0x8086 Ta any Ta any Ta any Ta iwlwifi-so-a0-mr-a0 +.It Intel(R) Wi-Fi 7 BE201 320MHz +.It 0x8086 Ta any Ta any Ta any Ta (null) +.It "" +.It Intel(R) Wi-Fi 7 BE200 320MHz +.It 0x8086 Ta any Ta any Ta any Ta (null) .It "" -.It Intel(R) Wi-Fi 6 AX204 160MHz +.It Intel(R) Wi-Fi 7 BE202 160MHz .It 0x8086 Ta any Ta any Ta any Ta (null) .It "" .It Intel(R) TBD Sc device .It 0x8086 Ta any Ta any Ta any Ta (null) +.It "" +.It Intel(R) TBD Sc2 device +.It 0x8086 Ta any Ta any Ta any Ta (null) +.It "" +.It Intel(R) TBD Sc2f device +.It 0x8086 Ta any Ta any Ta any Ta (null) .\" --------------------------------------------------------------------- .El .Pp @@ -1350,10 +1550,14 @@ in the above listing). .Sh FILES A copy of the .Xr iwlwifi 4 -firmware license is installed at -.Em /usr/share/doc/legal/intel_iwlwifi_firmware.LICENCE . +firmware license is installed along with the +.Pa wifi-firmware-iwlwifi-kmod +package or the +.Pa ports/net/wifi-firmware-iwlwifi-kmod +port (or each of its flavors). .Sh SEE ALSO .Xr iwlwifi 4 , +.Xr fwget 8 , .Xr firmware 9 .Sh HISTORY The diff --git a/sys/contrib/dev/iwlwifi/cfg/22000.c b/sys/contrib/dev/iwlwifi/cfg/22000.c index d594694206b3..2e2fcb3807ef 100644 --- a/sys/contrib/dev/iwlwifi/cfg/22000.c +++ b/sys/contrib/dev/iwlwifi/cfg/22000.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/module.h> #include <linux/stringify.h> @@ -13,7 +13,7 @@ #define IWL_22000_UCODE_API_MAX 77 /* Lowest firmware API version supported */ -#define IWL_22000_UCODE_API_MIN 50 +#define IWL_22000_UCODE_API_MIN 77 /* NVM versions */ #define IWL_22000_NVM_VERSION 0x0a1d diff --git a/sys/contrib/dev/iwlwifi/cfg/ax210.c b/sys/contrib/dev/iwlwifi/cfg/ax210.c index 8d5f9dce71d5..975e8aed1526 100644 --- a/sys/contrib/dev/iwlwifi/cfg/ax210.c +++ b/sys/contrib/dev/iwlwifi/cfg/ax210.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/module.h> #include <linux/stringify.h> @@ -10,10 +10,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_AX210_UCODE_API_MAX 83 +#define IWL_AX210_UCODE_API_MAX 89 /* Lowest firmware API version supported */ -#define IWL_AX210_UCODE_API_MIN 59 +#define IWL_AX210_UCODE_API_MIN 77 /* NVM versions */ #define IWL_AX210_NVM_VERSION 0x0a1d @@ -299,3 +299,9 @@ MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_GF4_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_MA_B_MR_A_FW_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX)); + +MODULE_FIRMWARE("iwlwifi-so-a0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-so-a0-gf4-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ty-a0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ma-b0-gf-a0.pnvm"); +MODULE_FIRMWARE("iwlwifi-ma-b0-gf4-a0.pnvm"); diff --git a/sys/contrib/dev/iwlwifi/cfg/bz.c b/sys/contrib/dev/iwlwifi/cfg/bz.c index b9893b22e41d..3b6b8b410be5 100644 --- a/sys/contrib/dev/iwlwifi/cfg/bz.c +++ b/sys/contrib/dev/iwlwifi/cfg/bz.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/module.h> #include <linux/stringify.h> @@ -10,10 +10,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_BZ_UCODE_API_MAX 83 +#define IWL_BZ_UCODE_API_MAX 92 /* Lowest firmware API version supported */ -#define IWL_BZ_UCODE_API_MIN 80 +#define IWL_BZ_UCODE_API_MIN 90 /* NVM versions */ #define IWL_BZ_NVM_VERSION 0x0a1d @@ -129,17 +129,11 @@ static const struct iwl_base_params iwl_bz_base_params = { IWL_DEVICE_BZ_COMMON, \ .ht_params = &iwl_22000_ht_params -#define IWL_DEVICE_GL_A \ - IWL_DEVICE_BZ_COMMON, \ - .ht_params = &iwl_gl_a_ht_params - /* - * If the device doesn't support HE, no need to have that many buffers. - * These sizes were picked according to 8 MSDUs inside 256 A-MSDUs in an + * This size was picked according to 8 MSDUs inside 512 A-MSDUs in an * A-MPDU, with additional overhead to account for processing time. */ -#define IWL_NUM_RBDS_NON_HE 512 -#define IWL_NUM_RBDS_BZ_HE 4096 +#define IWL_NUM_RBDS_BZ_EHT (512 * 16) const struct iwl_cfg_trans_params iwl_bz_trans_cfg = { .device_family = IWL_DEVICE_FAMILY_BZ, @@ -155,21 +149,24 @@ const struct iwl_cfg_trans_params iwl_bz_trans_cfg = { }; const char iwl_bz_name[] = "Intel(R) TBD Bz device"; +const char iwl_fm_name[] = "Intel(R) Wi-Fi 7 BE201 320MHz"; +const char iwl_gl_name[] = "Intel(R) Wi-Fi 7 BE200 320MHz"; +const char iwl_mtp_name[] = "Intel(R) Wi-Fi 7 BE202 160MHz"; const struct iwl_cfg iwl_cfg_bz = { .fw_name_mac = "bz", .uhb_supported = true, IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_EHT, }; const struct iwl_cfg iwl_cfg_gl = { .fw_name_mac = "gl", .uhb_supported = true, IWL_DEVICE_BZ, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_BZ_HE, + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, + .num_rbds = IWL_NUM_RBDS_BZ_EHT, }; @@ -181,3 +178,5 @@ MODULE_FIRMWARE(IWL_BZ_A_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM4_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_B_FM_B_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_C_FM_C_MODULE_FIRMWARE(IWL_BZ_UCODE_API_MAX)); + +MODULE_FIRMWARE("iwlwifi-gl-c0-fm-c0.pnvm"); diff --git a/sys/contrib/dev/iwlwifi/cfg/sc.c b/sys/contrib/dev/iwlwifi/cfg/sc.c index ad283fd22e2a..4ccb0b7bdc20 100644 --- a/sys/contrib/dev/iwlwifi/cfg/sc.c +++ b/sys/contrib/dev/iwlwifi/cfg/sc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/module.h> #include <linux/stringify.h> @@ -10,10 +10,10 @@ #include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_SC_UCODE_API_MAX 83 +#define IWL_SC_UCODE_API_MAX 92 /* Lowest firmware API version supported */ -#define IWL_SC_UCODE_API_MIN 82 +#define IWL_SC_UCODE_API_MIN 90 /* NVM versions */ #define IWL_SC_NVM_VERSION 0x0a1d @@ -33,6 +33,10 @@ #define IWL_SC_A_GF_A_FW_PRE "iwlwifi-sc-a0-gf-a0" #define IWL_SC_A_GF4_A_FW_PRE "iwlwifi-sc-a0-gf4-a0" #define IWL_SC_A_WH_A_FW_PRE "iwlwifi-sc-a0-wh-a0" +#define IWL_SC2_A_FM_C_FW_PRE "iwlwifi-sc2-a0-fm-c0" +#define IWL_SC2_A_WH_A_FW_PRE "iwlwifi-sc2-a0-wh-a0" +#define IWL_SC2F_A_FM_C_FW_PRE "iwlwifi-sc2f-a0-fm-c0" +#define IWL_SC2F_A_WH_A_FW_PRE "iwlwifi-sc2f-a0-wh-a0" #define IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(api) \ IWL_SC_A_FM_B_FW_PRE "-" __stringify(api) ".ucode" @@ -48,6 +52,14 @@ IWL_SC_A_GF4_A_FW_PRE "-" __stringify(api) ".ucode" #define IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(api) \ IWL_SC_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2_A_FM_C_FW_MODULE_FIRMWARE(api) \ + IWL_SC2_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2_A_WH_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC2_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2F_A_FM_C_FW_MODULE_FIRMWARE(api) \ + IWL_SC2F_A_FM_C_FW_PRE "-" __stringify(api) ".ucode" +#define IWL_SC2F_A_WH_A_FW_MODULE_FIRMWARE(api) \ + IWL_SC2F_A_WH_A_FW_PRE "-" __stringify(api) ".ucode" static const struct iwl_base_params iwl_sc_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -124,15 +136,16 @@ static const struct iwl_base_params iwl_sc_base_params = { #define IWL_DEVICE_SC \ IWL_DEVICE_BZ_COMMON, \ + .uhb_supported = true, \ + .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .num_rbds = IWL_NUM_RBDS_SC_EHT, \ .ht_params = &iwl_22000_ht_params /* - * If the device doesn't support HE, no need to have that many buffers. - * These sizes were picked according to 8 MSDUs inside 256 A-MSDUs in an + * This size was picked according to 8 MSDUs inside 512 A-MSDUs in an * A-MPDU, with additional overhead to account for processing time. */ -#define IWL_NUM_RBDS_NON_HE 512 -#define IWL_NUM_RBDS_SC_HE 4096 +#define IWL_NUM_RBDS_SC_EHT (512 * 16) const struct iwl_cfg_trans_params iwl_sc_trans_cfg = { .device_family = IWL_DEVICE_FAMILY_SC, @@ -151,10 +164,21 @@ const char iwl_sc_name[] = "Intel(R) TBD Sc device"; const struct iwl_cfg iwl_cfg_sc = { .fw_name_mac = "sc", - .uhb_supported = true, IWL_DEVICE_SC, - .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, - .num_rbds = IWL_NUM_RBDS_SC_HE, +}; + +const char iwl_sc2_name[] = "Intel(R) TBD Sc2 device"; + +const struct iwl_cfg iwl_cfg_sc2 = { + .fw_name_mac = "sc2", + IWL_DEVICE_SC, +}; + +const char iwl_sc2f_name[] = "Intel(R) TBD Sc2f device"; + +const struct iwl_cfg iwl_cfg_sc2f = { + .fw_name_mac = "sc2f", + IWL_DEVICE_SC, }; MODULE_FIRMWARE(IWL_SC_A_FM_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); @@ -164,3 +188,7 @@ MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_GF_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_GF4_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_SC_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2_A_FM_C_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2F_A_FM_C_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_SC2F_A_WH_A_FW_MODULE_FIRMWARE(IWL_SC_UCODE_API_MAX)); diff --git a/sys/contrib/dev/iwlwifi/fw/acpi.c b/sys/contrib/dev/iwlwifi/fw/acpi.c index dfe8357036eb..8c8880b44827 100644 --- a/sys/contrib/dev/iwlwifi/fw/acpi.c +++ b/sys/contrib/dev/iwlwifi/fw/acpi.c @@ -1,10 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2019-2023 Intel Corporation + * Copyright (C) 2019-2024 Intel Corporation */ #include <linux/uuid.h> -#include <linux/dmi.h> #include "iwl-drv.h" #include "iwl-debug.h" #include "acpi.h" @@ -13,63 +12,22 @@ const guid_t iwl_guid = GUID_INIT(0xF21202BF, 0x8F78, 0x4DC6, 0xA5, 0xB3, 0x1F, 0x73, 0x8E, 0x28, 0x5A, 0xDE); -IWL_EXPORT_SYMBOL(iwl_guid); -const guid_t iwl_rfi_guid = GUID_INIT(0x7266172C, 0x220B, 0x4B29, - 0x81, 0x4F, 0x75, 0xE4, - 0xDD, 0x26, 0xB5, 0xFD); -IWL_EXPORT_SYMBOL(iwl_rfi_guid); - -static const struct dmi_system_id dmi_ppag_approved_list[] = { - { .ident = "HP", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - }, - }, - { .ident = "SAMSUNG", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), - }, - }, - { .ident = "MSFT", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - }, - }, - { .ident = "ASUS", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - }, - }, - { .ident = "GOOGLE-HP", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_BOARD_VENDOR, "HP"), - }, - }, - { .ident = "GOOGLE-ASUS", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."), - }, - }, - { .ident = "GOOGLE-SAMSUNG", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Google"), - DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), - }, - }, - { .ident = "DELL", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - }, - }, - { .ident = "DELL", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), - }, - }, - {} +static const size_t acpi_dsm_size[DSM_FUNC_NUM_FUNCS] = { + [DSM_FUNC_QUERY] = sizeof(u32), + [DSM_FUNC_DISABLE_SRD] = sizeof(u8), + [DSM_FUNC_ENABLE_INDONESIA_5G2] = sizeof(u8), + [DSM_FUNC_ENABLE_6E] = sizeof(u32), + [DSM_FUNC_REGULATORY_CONFIG] = sizeof(u32), + /* Not supported in driver */ + [5] = (size_t)0, + [DSM_FUNC_11AX_ENABLEMENT] = sizeof(u32), + [DSM_FUNC_ENABLE_UNII4_CHAN] = sizeof(u32), + [DSM_FUNC_ACTIVATE_CHANNEL] = sizeof(u32), + [DSM_FUNC_FORCE_DISABLE_CHANNELS] = sizeof(u32), + [DSM_FUNC_ENERGY_DETECTION_THRESHOLD] = sizeof(u32), + [DSM_FUNC_RFI_CONFIG] = sizeof(u32), + [DSM_FUNC_ENABLE_11BE] = sizeof(u32), }; static int iwl_acpi_get_handle(struct device *dev, acpi_string method, @@ -195,46 +153,41 @@ out: } /* - * Evaluate a DSM with no arguments and a u8 return value, + * This function receives a DSM function number, calculates its expected size + * according to Intel BIOS spec, and fills in the value in a 32-bit field. + * In case the expected size is smaller than 32-bit, padding will be added. */ -int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, - const guid_t *guid, u8 *value) +int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs func, u32 *value) { + size_t expected_size; + u64 tmp; int ret; - u64 val; - ret = iwl_acpi_get_dsm_integer(dev, rev, func, - guid, &val, sizeof(u8)); + BUILD_BUG_ON(ARRAY_SIZE(acpi_dsm_size) != DSM_FUNC_NUM_FUNCS); - if (ret < 0) - return ret; - - /* cast val (u64) to be u8 */ - *value = (u8)val; - return 0; -} -IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8); + if (WARN_ON(func >= ARRAY_SIZE(acpi_dsm_size))) + return -EINVAL; -/* - * Evaluate a DSM with no arguments and a u32 return value, - */ -int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, - const guid_t *guid, u32 *value) -{ - int ret; - u64 val; + expected_size = acpi_dsm_size[func]; - ret = iwl_acpi_get_dsm_integer(dev, rev, func, - guid, &val, sizeof(u32)); + /* Currently all ACPI DSMs are either 8-bit or 32-bit */ + if (expected_size != sizeof(u8) && expected_size != sizeof(u32)) + return -EOPNOTSUPP; - if (ret < 0) + ret = iwl_acpi_get_dsm_integer(fwrt->dev, ACPI_DSM_REV, func, + &iwl_guid, &tmp, expected_size); + if (ret) return ret; - /* cast val (u64) to be u32 */ - *value = (u32)val; + if ((expected_size == sizeof(u8) && tmp != (u8)tmp) || + (expected_size == sizeof(u32) && tmp != (u32)tmp)) + IWL_DEBUG_RADIO(fwrt, + "DSM value overflows the expected size, truncating\n"); + *value = (u32)tmp; + return 0; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32); static union acpi_object * iwl_acpi_get_wifi_pkg_range(struct device *dev, @@ -302,9 +255,8 @@ iwl_acpi_get_wifi_pkg(struct device *dev, tbl_rev); } - -int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - union iwl_tas_config_cmd *cmd, int fw_ver) +int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *tas_data) { union acpi_object *wifi_pkg, *data; int ret, tbl_rev, i, block_list_size, enabled; @@ -326,22 +278,9 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, ACPI_TYPE_INTEGER) { u32 tas_selection = (u32)wifi_pkg->package.elements[1].integer.value; - u16 override_iec = - (tas_selection & ACPI_WTAS_OVERRIDE_IEC_MSK) >> ACPI_WTAS_OVERRIDE_IEC_POS; - u16 enabled_iec = (tas_selection & ACPI_WTAS_ENABLE_IEC_MSK) >> - ACPI_WTAS_ENABLE_IEC_POS; - u8 usa_tas_uhb = (tas_selection & ACPI_WTAS_USA_UHB_MSK) >> ACPI_WTAS_USA_UHB_POS; - - enabled = tas_selection & ACPI_WTAS_ENABLED_MSK; - if (fw_ver <= 3) { - cmd->v3.override_tas_iec = cpu_to_le16(override_iec); - cmd->v3.enable_tas_iec = cpu_to_le16(enabled_iec); - } else { - cmd->v4.usa_tas_uhb_allowed = usa_tas_uhb; - cmd->v4.override_tas_iec = (u8)override_iec; - cmd->v4.enable_tas_iec = (u8)enabled_iec; - } + enabled = iwl_parse_tas_selection(fwrt, tas_data, + tas_selection); } else if (tbl_rev == 0 && wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) { @@ -360,22 +299,16 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", tbl_rev); if (wifi_pkg->package.elements[2].type != ACPI_TYPE_INTEGER || wifi_pkg->package.elements[2].integer.value > - APCI_WTAS_BLACK_LIST_MAX) { + IWL_WTAS_BLACK_LIST_MAX) { IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %llu\n", wifi_pkg->package.elements[2].integer.value); ret = -EINVAL; goto out_free; } block_list_size = wifi_pkg->package.elements[2].integer.value; - cmd->v4.block_list_size = cpu_to_le32(block_list_size); + tas_data->block_list_size = cpu_to_le32(block_list_size); IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", block_list_size); - if (block_list_size > APCI_WTAS_BLACK_LIST_MAX) { - IWL_DEBUG_RADIO(fwrt, "TAS invalid array size value %u\n", - block_list_size); - ret = -EINVAL; - goto out_free; - } for (i = 0; i < block_list_size; i++) { u32 country; @@ -389,7 +322,7 @@ int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, } country = wifi_pkg->package.elements[3 + i].integer.value; - cmd->v4.block_list_array[i] = cpu_to_le32(country); + tas_data->block_list_array[i] = cpu_to_le32(country); IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); } @@ -398,19 +331,19 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_tas); -int iwl_acpi_get_mcc(struct device *dev, char *mcc) +int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) { union acpi_object *wifi_pkg, *data; u32 mcc_val; int ret, tbl_rev; - data = iwl_acpi_get_object(dev, ACPI_WRDD_METHOD); + data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDD_METHOD); if (IS_ERR(data)) return PTR_ERR(data); - wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_WRDD_WIFI_DATA_SIZE, + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDD_WIFI_DATA_SIZE, &tbl_rev); if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); @@ -434,46 +367,42 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc); -u64 iwl_acpi_get_pwr_limit(struct device *dev) +int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit) { union acpi_object *data, *wifi_pkg; - u64 dflt_pwr_limit; - int tbl_rev; + int tbl_rev, ret = -EINVAL; - data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD); - if (IS_ERR(data)) { - dflt_pwr_limit = 0; + *dflt_pwr_limit = 0; + data = iwl_acpi_get_object(fwrt->dev, ACPI_SPLC_METHOD); + if (IS_ERR(data)) goto out; - } - wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, ACPI_SPLC_WIFI_DATA_SIZE, &tbl_rev); if (IS_ERR(wifi_pkg) || tbl_rev != 0 || - wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) { - dflt_pwr_limit = 0; + wifi_pkg->package.elements[1].integer.value != ACPI_TYPE_INTEGER) goto out_free; - } - dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; + *dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; + ret = 0; out_free: kfree(data); out: - return dflt_pwr_limit; + return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); -int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) +int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) { union acpi_object *wifi_pkg, *data; int ret, tbl_rev; - data = iwl_acpi_get_object(dev, ACPI_ECKV_METHOD); + data = iwl_acpi_get_object(fwrt->dev, ACPI_ECKV_METHOD); if (IS_ERR(data)) return PTR_ERR(data); - wifi_pkg = iwl_acpi_get_wifi_pkg(dev, data, ACPI_ECKV_WIFI_DATA_SIZE, + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_ECKV_WIFI_DATA_SIZE, &tbl_rev); if (IS_ERR(wifi_pkg)) { ret = PTR_ERR(wifi_pkg); @@ -494,11 +423,11 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_eckv); -static int iwl_sar_set_profile(union acpi_object *table, - struct iwl_sar_profile *profile, - bool enabled, u8 num_chains, u8 num_sub_bands) +static int iwl_acpi_sar_set_profile(union acpi_object *table, + struct iwl_sar_profile *profile, + bool enabled, u8 num_chains, + u8 num_sub_bands) { int i, j, idx = 0; @@ -506,8 +435,8 @@ static int iwl_sar_set_profile(union acpi_object *table, * The table from ACPI is flat, but we store it in a * structured array. */ - for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV2; i++) { - for (j = 0; j < ACPI_SAR_NUM_SUB_BANDS_REV2; j++) { + for (i = 0; i < BIOS_SAR_MAX_CHAINS_PER_PROFILE; i++) { + for (j = 0; j < BIOS_SAR_MAX_SUB_BANDS_NUM; j++) { /* if we don't have the values, use the default */ if (i >= num_chains || j >= num_sub_bands) { profile->chains[i].subbands[j] = 0; @@ -530,73 +459,7 @@ static int iwl_sar_set_profile(union acpi_object *table, return 0; } -static int iwl_sar_fill_table(struct iwl_fw_runtime *fwrt, - __le16 *per_chain, u32 n_subbands, - int prof_a, int prof_b) -{ - int profs[ACPI_SAR_NUM_CHAINS_REV0] = { prof_a, prof_b }; - int i, j; - - for (i = 0; i < ACPI_SAR_NUM_CHAINS_REV0; i++) { - struct iwl_sar_profile *prof; - - /* don't allow SAR to be disabled (profile 0 means disable) */ - if (profs[i] == 0) - return -EPERM; - - /* we are off by one, so allow up to ACPI_SAR_PROFILE_NUM */ - if (profs[i] > ACPI_SAR_PROFILE_NUM) - return -EINVAL; - - /* profiles go from 1 to 4, so decrement to access the array */ - prof = &fwrt->sar_profiles[profs[i] - 1]; - - /* if the profile is disabled, do nothing */ - if (!prof->enabled) { - IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", - profs[i]); - /* - * if one of the profiles is disabled, we - * ignore all of them and return 1 to - * differentiate disabled from other failures. - */ - return 1; - } - - IWL_DEBUG_INFO(fwrt, - "SAR EWRD: chain %d profile index %d\n", - i, profs[i]); - IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); - for (j = 0; j < n_subbands; j++) { - per_chain[i * n_subbands + j] = - cpu_to_le16(prof->chains[i].subbands[j]); - IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", - j, prof->chains[i].subbands[j]); - } - } - - return 0; -} - -int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, - __le16 *per_chain, u32 n_tables, u32 n_subbands, - int prof_a, int prof_b) -{ - int i, ret = 0; - - for (i = 0; i < n_tables; i++) { - ret = iwl_sar_fill_table(fwrt, - &per_chain[i * n_subbands * ACPI_SAR_NUM_CHAINS_REV0], - n_subbands, prof_a, prof_b); - if (ret) - break; - } - - return ret; -} -IWL_EXPORT_SYMBOL(iwl_sar_select_profile); - -int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) +int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *table, *data; int ret, tbl_rev; @@ -613,7 +476,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 2) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -629,7 +492,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 1) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -645,7 +508,7 @@ int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 0) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -675,16 +538,15 @@ read_table: /* The profile from WRDS is officially profile 1, but goes * into sar_profiles[0] (because we don't have a profile 0). */ - ret = iwl_sar_set_profile(table, &fwrt->sar_profiles[0], - flags & IWL_SAR_ENABLE_MSK, - num_chains, num_sub_bands); + ret = iwl_acpi_sar_set_profile(table, &fwrt->sar_profiles[0], + flags & IWL_SAR_ENABLE_MSK, + num_chains, num_sub_bands); out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_sar_get_wrds_table); -int iwl_sar_get_ewrd_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; @@ -702,7 +564,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 2) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -718,7 +580,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 1) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -734,7 +596,7 @@ int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) &tbl_rev); if (!IS_ERR(wifi_pkg)) { if (tbl_rev != 0) { - ret = PTR_ERR(wifi_pkg); + ret = -EINVAL; goto out_free; } @@ -762,7 +624,7 @@ read_table: * from index 1, so the maximum value allowed here is * ACPI_SAR_PROFILES_NUM - 1. */ - if (n_profiles <= 0 || n_profiles >= ACPI_SAR_PROFILE_NUM) { + if (n_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { ret = -EINVAL; goto out_free; } @@ -771,13 +633,15 @@ read_table: pos = 3; 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_sar_set_profile(&wifi_pkg->package.elements[pos], - &fwrt->sar_profiles[i + 1], enabled, - num_chains, num_sub_bands); + ret = iwl_acpi_sar_set_profile(table, + &fwrt->sar_profiles[i + 1], + enabled, num_chains, + num_sub_bands); if (ret < 0) break; @@ -789,9 +653,8 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_sar_get_ewrd_table); -int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) +int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data; int i, j, k, ret, tbl_rev; @@ -806,7 +669,7 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) .revisions = BIT(3), .bands = ACPI_GEO_NUM_BANDS_REV2, .profiles = ACPI_NUM_GEO_PROFILES_REV3, - .min_profiles = 3, + .min_profiles = BIOS_GEO_MIN_PROFILE_NUM, }, { .revisions = BIT(2), @@ -862,22 +725,25 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) entry = &wifi_pkg->package.elements[entry_idx]; entry_idx++; if (entry->type != ACPI_TYPE_INTEGER || - entry->integer.value > num_profiles) { + entry->integer.value > num_profiles || + entry->integer.value < + rev_data[idx].min_profiles) { ret = -EINVAL; goto out_free; } - num_profiles = entry->integer.value; /* - * this also validates >= min_profiles since we - * otherwise wouldn't have gotten the data when - * looking up in ACPI + * Check to see if we received package count + * same as max # of profiles */ if (wifi_pkg->package.count != hdr_size + profile_size * num_profiles) { ret = -EINVAL; goto out_free; } + + /* Number of valid profiles */ + num_profiles = entry->integer.value; } goto read_table; } @@ -892,7 +758,7 @@ int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) read_table: fwrt->geo_rev = tbl_rev; for (i = 0; i < num_profiles; i++) { - for (j = 0; j < ACPI_GEO_NUM_BANDS_REV2; j++) { + for (j = 0; j < BIOS_GEO_MAX_NUM_BANDS; j++) { union acpi_object *entry; /* @@ -916,7 +782,7 @@ read_table: entry->integer.value; } - for (k = 0; k < ACPI_GEO_NUM_CHAINS; k++) { + for (k = 0; k < BIOS_GEO_NUM_CHAINS; k++) { /* same here as above */ if (j >= num_bands) { fwrt->geo_profiles[i].bands[j].chains[k] = @@ -944,123 +810,26 @@ out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_sar_get_wgds_table); - -bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) -{ - /* - * 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. - */ - return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || - (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 && - fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) || - (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && - ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == - CSR_HW_REV_TYPE_7265D)); -} -IWL_EXPORT_SYMBOL(iwl_sar_geo_support); - -int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, - struct iwl_per_chain_offset *table, - u32 n_bands, u32 n_profiles) -{ - int i, j; - - if (!fwrt->geo_enabled) - return -ENODATA; - - if (!iwl_sar_geo_support(fwrt)) - return -EOPNOTSUPP; - - for (i = 0; i < n_profiles; i++) { - for (j = 0; j < n_bands; j++) { - struct iwl_per_chain_offset *chain = - &table[i * n_bands + j]; - - chain->max_tx_power = - cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); - chain->chain_a = fwrt->geo_profiles[i].bands[j].chains[0]; - chain->chain_b = fwrt->geo_profiles[i].bands[j].chains[1]; - IWL_DEBUG_RADIO(fwrt, - "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", - i, j, - fwrt->geo_profiles[i].bands[j].chains[0], - fwrt->geo_profiles[i].bands[j].chains[1], - fwrt->geo_profiles[i].bands[j].max); - } - } - - return 0; -} -IWL_EXPORT_SYMBOL(iwl_sar_geo_init); - -__le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) -{ - int ret; - u8 value; - __le32 config_bitmap = 0; - - /* - ** Evaluate func 'DSM_FUNC_ENABLE_INDONESIA_5G2' - */ - ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, - DSM_FUNC_ENABLE_INDONESIA_5G2, - &iwl_guid, &value); - - if (!ret && value == DSM_VALUE_INDONESIA_ENABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); - - /* - ** Evaluate func 'DSM_FUNC_DISABLE_SRD' - */ - ret = iwl_acpi_get_dsm_u8(fwrt->dev, 0, - DSM_FUNC_DISABLE_SRD, - &iwl_guid, &value); - if (!ret) { - if (value == DSM_VALUE_SRD_PASSIVE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); - else if (value == DSM_VALUE_SRD_DISABLE) - config_bitmap |= - cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); - } - - return config_bitmap; -} -IWL_EXPORT_SYMBOL(iwl_acpi_get_lari_config_bitmap); int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) { union acpi_object *wifi_pkg, *data, *flags; int i, j, ret, tbl_rev, num_sub_bands = 0; int idx = 2; - u8 cmd_ver; - - fwrt->ppag_flags = 0; - fwrt->ppag_table_valid = false; data = iwl_acpi_get_object(fwrt->dev, ACPI_PPAG_METHOD); if (IS_ERR(data)) return PTR_ERR(data); - /* try to read ppag table rev 2 or 1 (both have the same data size) */ + /* try to read ppag table rev 3, 2 or 1 (all have the same data size) */ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev); if (!IS_ERR(wifi_pkg)) { - if (tbl_rev == 1 || tbl_rev == 2) { + if (tbl_rev >= 1 && tbl_rev <= 3) { num_sub_bands = IWL_NUM_SUB_BANDS_V2; IWL_DEBUG_RADIO(fwrt, - "Reading PPAG table v2 (tbl_rev=%d)\n", + "Reading PPAG table (tbl_rev=%d)\n", tbl_rev); goto read_table; } else { @@ -1083,6 +852,9 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) goto read_table; } + ret = PTR_ERR(wifi_pkg); + goto out_free; + read_table: fwrt->ppag_ver = tbl_rev; flags = &wifi_pkg->package.elements[1]; @@ -1092,19 +864,8 @@ read_table: goto out_free; } - fwrt->ppag_flags = flags->integer.value & ACPI_PPAG_MASK; - cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, - WIDE_ID(PHY_OPS_GROUP, - PER_PLATFORM_ANT_GAIN_CMD), - IWL_FW_CMD_VER_UNKNOWN); - if (cmd_ver == IWL_FW_CMD_VER_UNKNOWN) { - ret = -EINVAL; - goto out_free; - } - if (!fwrt->ppag_flags && cmd_ver <= 3) { - ret = 0; - goto out_free; - } + fwrt->ppag_flags = iwl_bios_get_ppag_flags(flags->integer.value, + fwrt->ppag_ver); /* * read, verify gain values and save them into the PPAG table. @@ -1122,132 +883,15 @@ read_table: } fwrt->ppag_chains[i].subbands[j] = ent->integer.value; - /* from ver 4 the fw deals with out of range values */ - if (cmd_ver >= 4) - continue; - if ((j == 0 && - (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_LB || - fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_LB)) || - (j != 0 && - (fwrt->ppag_chains[i].subbands[j] > ACPI_PPAG_MAX_HB || - fwrt->ppag_chains[i].subbands[j] < ACPI_PPAG_MIN_HB))) { - ret = -EINVAL; - goto out_free; - } } } - fwrt->ppag_table_valid = true; ret = 0; out_free: kfree(data); return ret; } -IWL_EXPORT_SYMBOL(iwl_acpi_get_ppag_table); - -int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd, - int *cmd_size) -{ - u8 cmd_ver; - int i, j, num_sub_bands; - s8 *gain; - - /* many firmware images for JF lie about this */ - if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == - CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) - return -EOPNOTSUPP; - - if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { - IWL_DEBUG_RADIO(fwrt, - "PPAG capability not supported by FW, command not sent.\n"); - return -EINVAL; - } - - cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, - WIDE_ID(PHY_OPS_GROUP, - PER_PLATFORM_ANT_GAIN_CMD), - IWL_FW_CMD_VER_UNKNOWN); - if (!fwrt->ppag_table_valid || (cmd_ver <= 3 && !fwrt->ppag_flags)) { - IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n"); - return -EINVAL; - } - - /* The 'flags' field is the same in v1 and in v2 so we can just - * use v1 to access it. - */ - cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); - - IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver); - if (cmd_ver == 1) { - num_sub_bands = IWL_NUM_SUB_BANDS_V1; - gain = cmd->v1.gain[0]; - *cmd_size = sizeof(cmd->v1); - if (fwrt->ppag_ver == 1 || fwrt->ppag_ver == 2) { - /* in this case FW supports revision 0 */ - IWL_DEBUG_RADIO(fwrt, - "PPAG table rev is %d, send truncated table\n", - fwrt->ppag_ver); - } - } else if (cmd_ver >= 2 && cmd_ver <= 4) { - num_sub_bands = IWL_NUM_SUB_BANDS_V2; - gain = cmd->v2.gain[0]; - *cmd_size = sizeof(cmd->v2); - if (fwrt->ppag_ver == 0) { - /* in this case FW supports revisions 1 or 2 */ - IWL_DEBUG_RADIO(fwrt, - "PPAG table rev is 0, send padded table\n"); - } - } else { - IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); - return -EINVAL; - } - - /* ppag mode */ - IWL_DEBUG_RADIO(fwrt, - "PPAG MODE bits were read from bios: %d\n", - cmd->v1.flags & cpu_to_le32(ACPI_PPAG_MASK)); - if ((cmd_ver == 1 && !fw_has_capa(&fwrt->fw->ucode_capa, - IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || - (cmd_ver == 2 && fwrt->ppag_ver == 2)) { - cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); - IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); - } else { - IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); - } - - IWL_DEBUG_RADIO(fwrt, - "PPAG MODE bits going to be sent: %d\n", - cmd->v1.flags & cpu_to_le32(ACPI_PPAG_MASK)); - - for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { - for (j = 0; j < num_sub_bands; j++) { - gain[i * num_sub_bands + j] = - fwrt->ppag_chains[i].subbands[j]; - IWL_DEBUG_RADIO(fwrt, - "PPAG table: chain[%d] band[%d]: gain = %d\n", - i, j, gain[i * num_sub_bands + j]); - } - } - - return 0; -} -IWL_EXPORT_SYMBOL(iwl_read_ppag_table); - -bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) -{ - - if (!dmi_check_system(dmi_ppag_approved_list)) { - IWL_DEBUG_RADIO(fwrt, - "System vendor '%s' is not in the approved list, disabling PPAG.\n", - dmi_get_system_info(DMI_SYS_VENDOR)); - fwrt->ppag_flags = 0; - return false; - } - - return true; -} -IWL_EXPORT_SYMBOL(iwl_acpi_is_ppag_approved); void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, struct iwl_phy_specific_cfg *filters) @@ -1260,7 +904,6 @@ void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, if (IS_ERR(data)) return; - /* try to read wtas table revision 1 or revision 0*/ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, ACPI_WPFC_WIFI_DATA_SIZE, &tbl_rev); @@ -1270,13 +913,14 @@ void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, if (tbl_rev != 0) goto out_free; - BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != ACPI_WPFC_WIFI_DATA_SIZE); + BUILD_BUG_ON(ARRAY_SIZE(filters->filter_cfg_chains) != + ACPI_WPFC_WIFI_DATA_SIZE - 1); for (i = 0; i < ARRAY_SIZE(filters->filter_cfg_chains); i++) { - if (wifi_pkg->package.elements[i].type != ACPI_TYPE_INTEGER) - return; + if (wifi_pkg->package.elements[i + 1].type != ACPI_TYPE_INTEGER) + goto out_free; tmp.filter_cfg_chains[i] = - cpu_to_le32(wifi_pkg->package.elements[i].integer.value); + cpu_to_le32(wifi_pkg->package.elements[i + 1].integer.value); } IWL_DEBUG_RADIO(fwrt, "Loaded WPFC filter config from ACPI\n"); @@ -1285,3 +929,72 @@ out_free: kfree(data); } IWL_EXPORT_SYMBOL(iwl_acpi_get_phy_filters); + +void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) +{ + union acpi_object *wifi_pkg, *data; + int tbl_rev; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_GLAI_METHOD); + if (IS_ERR(data)) + return; + + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_GLAI_WIFI_DATA_SIZE, + &tbl_rev); + if (IS_ERR(wifi_pkg)) + goto out_free; + + if (tbl_rev != 0) { + IWL_DEBUG_RADIO(fwrt, "Invalid GLAI revision: %d\n", tbl_rev); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + wifi_pkg->package.elements[1].integer.value > ACPI_GLAI_MAX_STATUS) + goto out_free; + + fwrt->uefi_tables_lock_status = + wifi_pkg->package.elements[1].integer.value; + + IWL_DEBUG_RADIO(fwrt, + "Loaded UEFI WIFI GUID lock status: %d from ACPI\n", + fwrt->uefi_tables_lock_status); +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) +{ + union acpi_object *wifi_pkg, *data; + int ret = -ENOENT; + int tbl_rev; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_WBEM_METHOD); + if (IS_ERR(data)) + return ret; + + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WBEM_WIFI_DATA_SIZE, + &tbl_rev); + if (IS_ERR(wifi_pkg)) + goto out_free; + + if (tbl_rev != IWL_ACPI_WBEM_REVISION) { + IWL_DEBUG_RADIO(fwrt, "Unsupported ACPI WBEM revision:%d\n", + tbl_rev); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) + goto out_free; + + *value = wifi_pkg->package.elements[1].integer.value & + IWL_ACPI_WBEM_REV0_MASK; + IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from ACPI\n"); + ret = 0; +out_free: + kfree(data); + return ret; +} diff --git a/sys/contrib/dev/iwlwifi/fw/acpi.h b/sys/contrib/dev/iwlwifi/fw/acpi.h index c36c62d6414d..bb88398a6987 100644 --- a/sys/contrib/dev/iwlwifi/fw/acpi.h +++ b/sys/contrib/dev/iwlwifi/fw/acpi.h @@ -7,6 +7,7 @@ #define __iwl_fw_acpi__ #include <linux/acpi.h> +#include "fw/regulatory.h" #include "fw/api/commands.h" #include "fw/api/power.h" #include "fw/api/phy.h" @@ -25,6 +26,8 @@ #define ACPI_PPAG_METHOD "PPAG" #define ACPI_WTAS_METHOD "WTAS" #define ACPI_WPFC_METHOD "WPFC" +#define ACPI_GLAI_METHOD "GLAI" +#define ACPI_WBEM_METHOD "WBEM" #define ACPI_WIFI_DOMAIN (0x07) @@ -56,181 +59,100 @@ #define ACPI_EWRD_WIFI_DATA_SIZE_REV2 ((ACPI_SAR_PROFILE_NUM - 1) * \ ACPI_SAR_NUM_CHAINS_REV2 * \ ACPI_SAR_NUM_SUB_BANDS_REV2 + 3) -#define ACPI_WPFC_WIFI_DATA_SIZE 4 /* 4 filter config words */ +#define ACPI_WPFC_WIFI_DATA_SIZE 5 /* domain and 4 filter config words */ /* revision 0 and 1 are identical, except for the semantics in the FW */ #define ACPI_GEO_NUM_BANDS_REV0 2 #define ACPI_GEO_NUM_BANDS_REV2 3 -#define ACPI_GEO_NUM_CHAINS 2 #define ACPI_WRDD_WIFI_DATA_SIZE 2 #define ACPI_SPLC_WIFI_DATA_SIZE 2 #define ACPI_ECKV_WIFI_DATA_SIZE 2 /* + * One element for domain type, + * and one for enablement of Wi-Fi 320MHz per MCC + */ +#define ACPI_WBEM_WIFI_DATA_SIZE 2 +/* + * One element for domain type, + * 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, * 1 element for block list size, * 16 elements for block list array */ -#define APCI_WTAS_BLACK_LIST_MAX 16 -#define ACPI_WTAS_WIFI_DATA_SIZE (3 + APCI_WTAS_BLACK_LIST_MAX) -#define ACPI_WTAS_ENABLED_MSK 0x1 -#define ACPI_WTAS_OVERRIDE_IEC_MSK 0x2 -#define ACPI_WTAS_ENABLE_IEC_MSK 0x4 -#define ACPI_WTAS_OVERRIDE_IEC_POS 0x1 -#define ACPI_WTAS_ENABLE_IEC_POS 0x2 -#define ACPI_WTAS_USA_UHB_MSK BIT(16) -#define ACPI_WTAS_USA_UHB_POS 16 - +#define ACPI_WTAS_WIFI_DATA_SIZE (3 + IWL_WTAS_BLACK_LIST_MAX) #define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((IWL_NUM_CHAIN_LIMITS * \ IWL_NUM_SUB_BANDS_V1) + 2) #define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \ IWL_NUM_SUB_BANDS_V2) + 2) -/* PPAG gain value bounds in 1/8 dBm */ -#define ACPI_PPAG_MIN_LB -16 -#define ACPI_PPAG_MAX_LB 24 -#define ACPI_PPAG_MIN_HB -16 -#define ACPI_PPAG_MAX_HB 40 -#define ACPI_PPAG_MASK 3 -#define IWL_PPAG_ETSI_MASK BIT(0) - #define IWL_SAR_ENABLE_MSK BIT(0) #define IWL_REDUCE_POWER_FLAGS_POS 1 -/* - * The profile for revision 2 is a superset of revision 1, which is in - * turn a superset of revision 0. So we can store all revisions - * inside revision 2, which is what we represent here. - */ -struct iwl_sar_profile_chain { - u8 subbands[ACPI_SAR_NUM_SUB_BANDS_REV2]; -}; - -struct iwl_sar_profile { - bool enabled; - struct iwl_sar_profile_chain chains[ACPI_SAR_NUM_CHAINS_REV2]; -}; - -/* Same thing as with SAR, all revisions fit in revision 2 */ -struct iwl_geo_profile_band { - u8 max; - u8 chains[ACPI_GEO_NUM_CHAINS]; -}; - -struct iwl_geo_profile { - struct iwl_geo_profile_band bands[ACPI_GEO_NUM_BANDS_REV2]; -}; - -/* Same thing as with SAR, all revisions fit in revision 2 */ -struct iwl_ppag_chain { - s8 subbands[ACPI_SAR_NUM_SUB_BANDS_REV2]; -}; - -enum iwl_dsm_funcs_rev_0 { - DSM_FUNC_QUERY = 0, - DSM_FUNC_DISABLE_SRD = 1, - DSM_FUNC_ENABLE_INDONESIA_5G2 = 2, - DSM_FUNC_ENABLE_6E = 3, - DSM_FUNC_11AX_ENABLEMENT = 6, - DSM_FUNC_ENABLE_UNII4_CHAN = 7, - DSM_FUNC_ACTIVATE_CHANNEL = 8, - DSM_FUNC_FORCE_DISABLE_CHANNELS = 9 -}; - -enum iwl_dsm_values_srd { - DSM_VALUE_SRD_ACTIVE, - DSM_VALUE_SRD_PASSIVE, - DSM_VALUE_SRD_DISABLE, - DSM_VALUE_SRD_MAX -}; - -enum iwl_dsm_values_indonesia { - DSM_VALUE_INDONESIA_DISABLE, - DSM_VALUE_INDONESIA_ENABLE, - DSM_VALUE_INDONESIA_RESERVED, - DSM_VALUE_INDONESIA_MAX -}; - -/* DSM RFI uses a different GUID, so need separate definitions */ - -#define DSM_RFI_FUNC_ENABLE 3 - -enum iwl_dsm_values_rfi { - DSM_VALUE_RFI_ENABLE, - DSM_VALUE_RFI_DISABLE, - DSM_VALUE_RFI_MAX -}; +/* 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 IWL_ACPI_WBEM_REV0_MASK (BIT(0) | BIT(1)) +#define IWL_ACPI_WBEM_REVISION 0 #ifdef CONFIG_ACPI struct iwl_fw_runtime; extern const guid_t iwl_guid; -extern const guid_t iwl_rfi_guid; - -int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, - const guid_t *guid, u8 *value); - -int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, - const guid_t *guid, u32 *value); /** * iwl_acpi_get_mcc - read MCC from ACPI, if available * - * @dev: the struct device + * @fwrt: the fw runtime struct * @mcc: output buffer (3 bytes) that will get the MCC * * This function tries to read the current MCC from ACPI if available. */ -int iwl_acpi_get_mcc(struct device *dev, char *mcc); +int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); -u64 iwl_acpi_get_pwr_limit(struct device *dev); +int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *dflt_pwr_limit); /* * iwl_acpi_get_eckv - read external clock validation from ACPI, if available * - * @dev: the struct device + * @fwrt: the fw runtime struct * @extl_clk: output var (2 bytes) that will get the clk indication. * * This function tries to read the external clock indication * from ACPI if available. */ -int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk); - -int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, - __le16 *per_chain, u32 n_tables, u32 n_subbands, - int prof_a, int prof_b); - -int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk); -int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt); -int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt); -bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt); -int iwl_sar_geo_init(struct iwl_fw_runtime *fwrt, - struct iwl_per_chain_offset *table, - u32 n_bands, u32 n_profiles); - -int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - union iwl_tas_config_cmd *cmd, int fw_ver); - -__le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt); +int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data); int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt); -int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, union iwl_ppag_table_cmd *cmd, - int *cmd_size); - -bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt); - void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, struct iwl_phy_specific_cfg *filters); +void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt); + +int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs func, u32 *value); + +int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value); #else /* CONFIG_ACPI */ static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev, @@ -239,92 +161,66 @@ static inline void *iwl_acpi_get_dsm_object(struct device *dev, int rev, return ERR_PTR(-ENOENT); } -static inline int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, - const guid_t *guid, u8 *value) -{ - return -ENOENT; -} - -static inline int iwl_acpi_get_dsm_u32(struct device *dev, int rev, int func, - const guid_t *guid, u32 *value) -{ - return -ENOENT; -} - -static inline int iwl_acpi_get_mcc(struct device *dev, char *mcc) +static inline int iwl_acpi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) { return -ENOENT; } -static inline u64 iwl_acpi_get_pwr_limit(struct device *dev) +static inline int iwl_acpi_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit) { + *dflt_pwr_limit = 0; return 0; } -static inline int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) +static inline int iwl_acpi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) { return -ENOENT; } -static inline int iwl_sar_select_profile(struct iwl_fw_runtime *fwrt, - __le16 *per_chain, u32 n_tables, u32 n_subbands, - int prof_a, int prof_b) +static inline int iwl_acpi_get_wrds_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; } -static inline int iwl_sar_get_wrds_table(struct iwl_fw_runtime *fwrt) +static inline int iwl_acpi_get_ewrd_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; } -static inline int iwl_sar_get_ewrd_table(struct iwl_fw_runtime *fwrt) -{ - return -ENOENT; -} - -static inline int iwl_sar_get_wgds_table(struct iwl_fw_runtime *fwrt) +static inline int iwl_acpi_get_wgds_table(struct iwl_fw_runtime *fwrt) { return 1; } -static inline bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) -{ - return false; -} - -static inline int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, - union iwl_tas_config_cmd *cmd, int fw_ver) +static inline int iwl_acpi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data) { return -ENOENT; } -static inline __le32 iwl_acpi_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) -{ - return 0; -} - static inline int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt) { return -ENOENT; } -static inline int iwl_read_ppag_table(struct iwl_fw_runtime *fwrt, - union iwl_ppag_table_cmd *cmd, int *cmd_size) +/* macro since the second argument doesn't always exist */ +#define iwl_acpi_get_phy_filters(fwrt, filters) do { } while (0) + +static inline void iwl_acpi_get_guid_lock_status(struct iwl_fw_runtime *fwrt) { - return -ENOENT; } -static inline bool iwl_acpi_is_ppag_approved(struct iwl_fw_runtime *fwrt) +static inline int iwl_acpi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs func, u32 *value) { - return false; + return -ENOENT; } -static inline void iwl_acpi_get_phy_filters(struct iwl_fw_runtime *fwrt, - struct iwl_phy_specific_cfg *filters) +static inline int iwl_acpi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value) { + return -ENOENT; } - #endif /* CONFIG_ACPI */ #endif /* __iwl_fw_acpi__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/alive.h b/sys/contrib/dev/iwlwifi/fw/api/alive.h index e00ab21e7358..ebe85fdf08d3 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/alive.h +++ b/sys/contrib/dev/iwlwifi/fw/api/alive.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018, 2020-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2020-2021, 2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -113,7 +113,7 @@ struct iwl_alive_ntf_v6 { } __packed; /* UCODE_ALIVE_NTFY_API_S_VER_6 */ /** - * enum iwl_extended_cfg_flag - commands driver may send before + * enum iwl_extended_cfg_flags - commands driver may send before * finishing init flow * @IWL_INIT_DEBUG_CFG: driver is going to send debug config command * @IWL_INIT_NVM: driver is going to send NVM_ACCESS commands @@ -126,7 +126,7 @@ enum iwl_extended_cfg_flags { }; /** - * struct iwl_extended_cfg_cmd - mark what commands ucode should wait for + * struct iwl_init_extended_cfg_cmd - mark what commands ucode should wait for * before finishing init flows * @init_flags: values from iwl_extended_cfg_flags */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/binding.h b/sys/contrib/dev/iwlwifi/fw/api/binding.h index d9044ada6a43..2397fdc37fc5 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/binding.h +++ b/sys/contrib/dev/iwlwifi/fw/api/binding.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2020, 2022 Intel Corporation + * Copyright (C) 2012-2014, 2020, 2022, 2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -77,7 +77,7 @@ struct iwl_time_quota_data_v1 { } __packed; /* TIME_QUOTA_DATA_API_S_VER_1 */ /** - * struct iwl_time_quota_cmd - configuration of time quota between bindings + * struct iwl_time_quota_cmd_v1 - configuration of time quota between bindings * ( TIME_QUOTA_CMD = 0x2c ) * @quotas: allocations per binding * Note: on non-CDB the fourth one is the auxilary mac and is diff --git a/sys/contrib/dev/iwlwifi/fw/api/coex.h b/sys/contrib/dev/iwlwifi/fw/api/coex.h index 3e81e9369224..b97a43353779 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/coex.h +++ b/sys/contrib/dev/iwlwifi/fw/api/coex.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* + * Copyright (C) 2023-2024 Intel Corporation * Copyright (C) 2013-2014, 2018-2019 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2017 Intel Deutschland GmbH @@ -76,73 +77,6 @@ struct iwl_bt_coex_ci_cmd { __le32 secondary_ch_phy_id; } __packed; /* BT_CI_MSG_API_S_VER_2 */ -#define BT_MBOX(n_dw, _msg, _pos, _nbits) \ - BT_MBOX##n_dw##_##_msg##_POS = (_pos), \ - BT_MBOX##n_dw##_##_msg = BITS(_nbits) << BT_MBOX##n_dw##_##_msg##_POS - -enum iwl_bt_mxbox_dw0 { - BT_MBOX(0, LE_SLAVE_LAT, 0, 3), - BT_MBOX(0, LE_PROF1, 3, 1), - BT_MBOX(0, LE_PROF2, 4, 1), - BT_MBOX(0, LE_PROF_OTHER, 5, 1), - BT_MBOX(0, CHL_SEQ_N, 8, 4), - BT_MBOX(0, INBAND_S, 13, 1), - BT_MBOX(0, LE_MIN_RSSI, 16, 4), - BT_MBOX(0, LE_SCAN, 20, 1), - BT_MBOX(0, LE_ADV, 21, 1), - BT_MBOX(0, LE_MAX_TX_POWER, 24, 4), - BT_MBOX(0, OPEN_CON_1, 28, 2), -}; - -enum iwl_bt_mxbox_dw1 { - BT_MBOX(1, BR_MAX_TX_POWER, 0, 4), - BT_MBOX(1, IP_SR, 4, 1), - BT_MBOX(1, LE_MSTR, 5, 1), - BT_MBOX(1, AGGR_TRFC_LD, 8, 6), - BT_MBOX(1, MSG_TYPE, 16, 3), - BT_MBOX(1, SSN, 19, 2), -}; - -enum iwl_bt_mxbox_dw2 { - BT_MBOX(2, SNIFF_ACT, 0, 3), - BT_MBOX(2, PAG, 3, 1), - BT_MBOX(2, INQUIRY, 4, 1), - BT_MBOX(2, CONN, 5, 1), - BT_MBOX(2, SNIFF_INTERVAL, 8, 5), - BT_MBOX(2, DISC, 13, 1), - BT_MBOX(2, SCO_TX_ACT, 16, 2), - BT_MBOX(2, SCO_RX_ACT, 18, 2), - BT_MBOX(2, ESCO_RE_TX, 20, 2), - BT_MBOX(2, SCO_DURATION, 24, 6), -}; - -enum iwl_bt_mxbox_dw3 { - BT_MBOX(3, SCO_STATE, 0, 1), - BT_MBOX(3, SNIFF_STATE, 1, 1), - BT_MBOX(3, A2DP_STATE, 2, 1), - BT_MBOX(3, ACL_STATE, 3, 1), - BT_MBOX(3, MSTR_STATE, 4, 1), - BT_MBOX(3, OBX_STATE, 5, 1), - BT_MBOX(3, A2DP_SRC, 6, 1), - BT_MBOX(3, OPEN_CON_2, 8, 2), - BT_MBOX(3, TRAFFIC_LOAD, 10, 2), - BT_MBOX(3, CHL_SEQN_LSB, 12, 1), - BT_MBOX(3, INBAND_P, 13, 1), - BT_MBOX(3, MSG_TYPE_2, 16, 3), - BT_MBOX(3, SSN_2, 19, 2), - BT_MBOX(3, UPDATE_REQUEST, 21, 1), -}; - -#define BT_MBOX_MSG(_notif, _num, _field) \ - ((le32_to_cpu((_notif)->mbox_msg[(_num)]) & BT_MBOX##_num##_##_field)\ - >> BT_MBOX##_num##_##_field##_POS) - -#define BT_MBOX_PRINT(_num, _field, _end) \ - pos += scnprintf(buf + pos, bufsz - pos, \ - "\t%s: %d%s", \ - #_field, \ - BT_MBOX_MSG(notif, _num, _field), \ - true ? "\n" : ", ") enum iwl_bt_activity_grading { BT_OFF = 0, BT_ON_NO_CONNECTION = 1, @@ -170,7 +104,11 @@ enum iwl_bt_ci_compliance { * @bt_activity_grading: the activity of BT &enum iwl_bt_activity_grading * @ttc_status: is TTC enabled - one bit per PHY * @rrc_status: is RRC enabled - one bit per PHY - * @reserved: reserved + * The following fields are only for version 5, and are reserved in version 4: + * @wifi_loss_low_rssi: The predicted lost WiFi rate (% of air time that BT is + * utilizing) when the RSSI is low (<= -65 dBm) + * @wifi_loss_mid_high_rssi: The predicted lost WiFi rate (% of air time that + * BT is utilizing) when the RSSI is mid/high (>= -65 dBm) */ struct iwl_bt_coex_profile_notif { __le32 mbox_msg[4]; @@ -182,7 +120,10 @@ struct iwl_bt_coex_profile_notif { __le32 bt_activity_grading; u8 ttc_status; u8 rrc_status; - __le16 reserved; -} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_4 */ + u8 wifi_loss_low_rssi; + u8 wifi_loss_mid_high_rssi; +} __packed; /* BT_COEX_PROFILE_NTFY_API_S_VER_4 + * BT_COEX_PROFILE_NTFY_API_S_VER_5 + */ #endif /* __iwl_fw_api_coex_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/commands.h b/sys/contrib/dev/iwlwifi/fw/api/commands.h index 13cb0d53a1a3..7544c4cb1a30 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/commands.h +++ b/sys/contrib/dev/iwlwifi/fw/api/commands.h @@ -30,6 +30,8 @@ * @REGULATORY_AND_NVM_GROUP: regulatory/NVM group, uses command IDs from * &enum iwl_regulatory_and_nvm_subcmd_ids * @DEBUG_GROUP: Debug group, uses command IDs from &enum iwl_debug_cmds + * @STATISTICS_GROUP: Statistics group, uses command IDs from + * &enum iwl_statistics_subcmd_ids */ enum iwl_mvm_command_groups { LEGACY_GROUP = 0x0, @@ -44,6 +46,7 @@ enum iwl_mvm_command_groups { PROT_OFFLOAD_GROUP = 0xb, REGULATORY_AND_NVM_GROUP = 0xc, DEBUG_GROUP = 0xf, + STATISTICS_GROUP = 0x10, }; /** @@ -617,9 +620,36 @@ enum iwl_system_subcmd_ids { SYSTEM_FEATURES_CONTROL_CMD = 0xd, /** + * @SYSTEM_STATISTICS_CMD: &struct iwl_system_statistics_cmd + */ + SYSTEM_STATISTICS_CMD = 0xf, + + /** + * @SYSTEM_STATISTICS_END_NOTIF: &struct iwl_system_statistics_end_notif + */ + SYSTEM_STATISTICS_END_NOTIF = 0xfd, + + /** * @RFI_DEACTIVATE_NOTIF: &struct iwl_rfi_deactivate_notif */ RFI_DEACTIVATE_NOTIF = 0xff, }; +/** + * enum iwl_statistics_subcmd_ids - Statistics group command IDs + */ +enum iwl_statistics_subcmd_ids { + /** + * @STATISTICS_OPER_NOTIF: Notification about operational + * statistics &struct iwl_system_statistics_notif_oper + */ + STATISTICS_OPER_NOTIF = 0x0, + + /** + * @STATISTICS_OPER_PART1_NOTIF: Notification about operational part1 + * statistics &struct iwl_system_statistics_part1_notif_oper + */ + STATISTICS_OPER_PART1_NOTIF = 0x1, +}; + #endif /* __iwl_fw_api_commands_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/config.h b/sys/contrib/dev/iwlwifi/fw/api/config.h index 4419631604b4..1fc65469990e 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/config.h +++ b/sys/contrib/dev/iwlwifi/fw/api/config.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2019, 2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2023-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -76,7 +76,7 @@ struct iwl_phy_specific_cfg { } __packed; /* PHY_SPECIFIC_CONFIGURATION_API_VER_1*/ /** - * struct iwl_phy_cfg_cmd - Phy configuration command + * struct iwl_phy_cfg_cmd_v1 - Phy configuration command * * @phy_cfg: PHY configuration value, uses &enum iwl_fw_phy_cfg * @calib_control: calibration control data diff --git a/sys/contrib/dev/iwlwifi/fw/api/d3.h b/sys/contrib/dev/iwlwifi/fw/api/d3.h index 72d461c47323..ffee7927cf26 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/d3.h +++ b/sys/contrib/dev/iwlwifi/fw/api/d3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -42,7 +42,7 @@ struct iwl_d3_manager_config { /* TODO: OFFLOADS_QUERY_API_S_VER_1 */ /** - * enum iwl_d3_proto_offloads - enabled protocol offloads + * enum iwl_proto_offloads - enabled protocol offloads * @IWL_D3_PROTO_OFFLOAD_ARP: ARP data is enabled * @IWL_D3_PROTO_OFFLOAD_NS: NS (Neighbor Solicitation) is enabled * @IWL_D3_PROTO_IPV4_VALID: IPv4 data is valid @@ -195,7 +195,7 @@ struct iwl_wowlan_pattern_v1 { #define IWL_WOWLAN_MAX_PATTERNS 20 /** - * struct iwl_wowlan_patterns_cmd - WoWLAN wakeup patterns + * struct iwl_wowlan_patterns_cmd_v1 - WoWLAN wakeup patterns */ struct iwl_wowlan_patterns_cmd_v1 { /** @@ -324,7 +324,7 @@ struct iwl_wowlan_patterns_cmd { u8 n_patterns; /** - * @n_patterns: sta_id + * @sta_id: sta_id */ u8 sta_id; @@ -397,6 +397,8 @@ struct iwl_wowlan_config_cmd { #define WOWLAN_GTK_KEYS_NUM 2 #define WOWLAN_IGTK_KEYS_NUM 2 #define WOWLAN_IGTK_MIN_INDEX 4 +#define WOWLAN_BIGTK_KEYS_NUM 2 +#define WOWLAN_BIGTK_MIN_INDEX 6 /* * WOWLAN_TSC_RSC_PARAMS @@ -621,9 +623,10 @@ struct iwl_wowlan_gtk_status_v3 { * @ipn: the IGTK packet number (replay counter) * @key_len: IGTK length, if set to 0, the key is not available * @key_flags: information about the key: - * bits[0]: key index assigned by the AP (0: index 4, 1: index 5) - * bits[1:5]: IGTK index of the key in the internal DB - * bit[6]: Set iff this is the currently used IGTK + * bits[0]: key index assigned by the AP (0: index 4, 1: index 5) + * (0: index 6, 1: index 7 with bigtk) + * bits[1:5]: IGTK index of the key in the internal DB + * bit[6]: Set iff this is the currently used IGTK */ struct iwl_wowlan_igtk_status { u8 key[WOWLAN_KEY_MAX_SIZE]; @@ -808,7 +811,7 @@ struct iwl_wowlan_info_notif_v1 { } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_1 */ /** - * struct iwl_wowlan_info_notif - WoWLAN information notification + * struct iwl_wowlan_info_notif_v2 - WoWLAN information notification * @gtk: GTK data * @igtk: IGTK data * @replay_ctr: GTK rekey replay counter @@ -824,7 +827,7 @@ struct iwl_wowlan_info_notif_v1 { * @station_id: station id * @reserved2: reserved */ -struct iwl_wowlan_info_notif { +struct iwl_wowlan_info_notif_v2 { struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; __le64 replay_ctr; @@ -840,6 +843,92 @@ struct iwl_wowlan_info_notif { u8 reserved2[2]; } __packed; /* WOWLAN_INFO_NTFY_API_S_VER_2 */ +/* MAX MLO keys of non-active links that can arrive in the notification */ +#define WOWLAN_MAX_MLO_KEYS 18 + +/** + * 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_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_NUM_TYPES +}; /* WOWLAN_MLO_GTK_KEY_TYPE_API_E_VER_1 */ + +/** + * enum iwl_wowlan_mlo_gtk_flag - MLO GTK flags + * @WOWLAN_MLO_GTK_FLAG_KEY_LEN_MSK: 0 for len 16, 1 for len 32 + * @WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK: key id (ranges from 0 to 7) + * @WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK: spec link id of the key + * @WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK: &enum iwl_wowlan_mlo_gtk_type + * @WOWLAN_MLO_GTK_FLAG_LAST_KEY_MSK: is this the last given key per + * key-type / link-id - the currently used key + */ +enum iwl_wowlan_mlo_gtk_flag { + WOWLAN_MLO_GTK_FLAG_KEY_LEN_MSK = 0x0001, + WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK = 0x000E, + WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK = 0x00F0, + WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK = 0x0300, + WOWLAN_MLO_GTK_FLAG_LAST_KEY_MSK = 0x0400 +}; /* WOWLAN_MLO_GTK_FLAG_API_E_VER_1 */ + +/** + * struct iwl_wowlan_mlo_gtk - MLO GTK info + * @key: key material + * @flags: &enum iwl_wowlan_mlo_gtk_flag + * @pn: packet number + */ +struct iwl_wowlan_mlo_gtk { + u8 key[WOWLAN_KEY_MAX_SIZE]; + __le16 flags; + u8 pn[6]; +} __packed; /* WOWLAN_MLO_GTK_KEY_API_S_VER_1 */ + +/** + * struct iwl_wowlan_info_notif - 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 + * @reserved1: reserved + * @qos_seq_ctr: QoS sequence counters to use next + * @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, or reserved in version < 4 + * @reserved2: reserved + * @mlo_gtks: array of GTKs of size num_mlo_link_keys for version >= 4 + */ +struct iwl_wowlan_info_notif { + struct iwl_wowlan_gtk_status_v3 gtk[WOWLAN_GTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status igtk[WOWLAN_IGTK_KEYS_NUM]; + struct iwl_wowlan_igtk_status bigtk[WOWLAN_BIGTK_KEYS_NUM]; + __le64 replay_ctr; + __le16 pattern_number; + __le16 reserved1; + __le16 qos_seq_ctr[8]; + __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 reserved2; + struct iwl_wowlan_mlo_gtk mlo_gtks[]; +} __packed; /* WOWLAN_INFO_NTFY_API_S_VER_3, _VER_4 */ + /** * struct iwl_wowlan_wake_pkt_notif - WoWLAN wake packet notification * @wake_packet_length: wakeup packet length diff --git a/sys/contrib/dev/iwlwifi/fw/api/datapath.h b/sys/contrib/dev/iwlwifi/fw/api/datapath.h index 751b596ea1a5..2ab38eaeb290 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/datapath.h +++ b/sys/contrib/dev/iwlwifi/fw/api/datapath.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* + * Copyright (C) 2024 Intel Corporation * Copyright (C) 2012-2014, 2018-2022 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH @@ -90,6 +91,12 @@ enum iwl_data_path_subcmd_ids { SEC_KEY_CMD = 0x18, /** + * @ESR_MODE_NOTIF: notification to recommend/force a wanted esr mode, + * uses &struct iwl_mvm_esr_mode_notif + */ + ESR_MODE_NOTIF = 0xF3, + + /** * @MONITOR_NOTIF: Datapath monitoring notification, using * &struct iwl_datapath_monitor_notif */ @@ -101,7 +108,7 @@ enum iwl_data_path_subcmd_ids { RX_NO_DATA_NOTIF = 0xF5, /** - * @THERMAL_DUAL_CHAIN_DISABLE_REQ: firmware request for SMPS mode, + * @THERMAL_DUAL_CHAIN_REQUEST: firmware request for SMPS mode, * &struct iwl_thermal_dual_chain_request */ THERMAL_DUAL_CHAIN_REQUEST = 0xF6, @@ -224,28 +231,33 @@ struct iwl_synced_time_rsp { #define PTP_CTX_MAX_DATA_SIZE 128 /** - * struct iwl_time_msmt_ptp_ctx - Vendor specific information element + * struct iwl_time_msmt_ptp_ctx - Vendor specific element * to allow a space for flexibility for the userspace App * - * @element_id: element id of vendor specific ie - * @length: length of vendor specific ie - * @reserved: for alignment - * @data: vendor specific data blob + * @ftm: FTM specific vendor element + * @ftm.element_id: element id of vendor specific ie + * @ftm.length: length of vendor specific ie + * @ftm.reserved: for alignment + * @ftm.data: vendor specific data blob + * @tm: TM specific vendor element + * @tm.element_id: element id of vendor specific ie + * @tm.length: length of vendor specific ie + * @tm.data: vendor specific data blob */ struct iwl_time_msmt_ptp_ctx { - /* Differentiate between FTM and TM specific Vendor IEs */ + /* Differentiate between FTM and TM specific Vendor elements */ union { struct { u8 element_id; u8 length; __le16 reserved; u8 data[PTP_CTX_MAX_DATA_SIZE]; - } ftm; /* FTM specific vendor IE */ + } ftm; struct { u8 element_id; u8 length; u8 data[PTP_CTX_MAX_DATA_SIZE]; - } tm; /* TM specific vendor IE */ + } tm; }; } __packed /* PTP_CTX_VER_1 */; @@ -524,6 +536,10 @@ 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 + * @remove_v1: remove data (version 1) + * @remove: remove data */ struct iwl_rx_baid_cfg_cmd { __le32 action; @@ -558,6 +574,7 @@ enum iwl_scd_queue_cfg_operation { /** * struct iwl_scd_queue_cfg_cmd - scheduler queue allocation command * @operation: the operation, see &enum iwl_scd_queue_cfg_operation + * @u: union depending on command usage * @u.add.sta_mask: station mask * @u.add.tid: TID * @u.add.reserved: reserved @@ -627,6 +644,7 @@ enum iwl_sec_key_flags { /** * struct iwl_sec_key_cmd - security key command * @action: action from &enum iwl_ctxt_action + * @u: union depending on command type * @u.add.sta_mask: station mask for the new key * @u.add.key_id: key ID (0-7) for the new key * @u.add.key_flags: key flags per &enum iwl_sec_key_flags diff --git a/sys/contrib/dev/iwlwifi/fw/api/dbg-tlv.h b/sys/contrib/dev/iwlwifi/fw/api/dbg-tlv.h index ba538d70985f..855cd13a181e 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/dbg-tlv.h +++ b/sys/contrib/dev/iwlwifi/fw/api/dbg-tlv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef __iwl_fw_dbg_tlv_h__ #define __iwl_fw_dbg_tlv_h__ @@ -13,6 +13,7 @@ #define IWL_FW_INI_DOMAIN_ALWAYS_ON 0 #define IWL_FW_INI_REGION_ID_MASK GENMASK(15, 0) #define IWL_FW_INI_REGION_DUMP_POLICY_MASK GENMASK(31, 16) +#define IWL_FW_INI_PRESET_DISABLE 0xff /** * struct iwl_fw_ini_hcmd @@ -42,6 +43,30 @@ struct iwl_fw_ini_header { } __packed; /* FW_TLV_DEBUG_HEADER_S_VER_1 */ /** + * struct iwl_fw_ini_addr_size - Base address and size that defines + * a chunk of memory + * + * @addr: the base address (fixed size - 4 bytes) + * @size: the size to read + */ +struct iwl_fw_ini_addr_size { + __le32 addr; + __le32 size; +} __packed; /* FW_TLV_DEBUG_ADDR_SIZE_VER_1 */ + +/** + * struct iwl_fw_ini_region_dev_addr_range - Configuration to read + * device address range + * + * @offset: offset to add to the base address of each chunk + * The addrs[] array will be treated as an array of &iwl_fw_ini_addr_size - + * an array of (addr, size) pairs. + */ +struct iwl_fw_ini_region_dev_addr_range { + __le32 offset; +} __packed; /* FW_TLV_DEBUG_DEVICE_ADDR_RANGE_API_S_VER_1 */ + +/** * struct iwl_fw_ini_region_dev_addr - Configuration to read device addresses * * @size: size of each memory chunk @@ -122,28 +147,34 @@ struct iwl_fw_ini_region_internal_buffer { * Configures parameters for region data collection * * @hdr: debug header - * @id: region id. Max id is &IWL_FW_INI_MAX_REGION_ID + * @id: region id. Max id is %IWL_FW_INI_MAX_REGION_ID * @type: region type. One of &enum iwl_fw_ini_region_type * @sub_type: region sub type * @sub_type_ver: region sub type version * @reserved: not in use * @name: region name * @dev_addr: device address configuration. Used by - * &IWL_FW_INI_REGION_DEVICE_MEMORY, &IWL_FW_INI_REGION_PERIPHERY_MAC, - * &IWL_FW_INI_REGION_PERIPHERY_PHY, &IWL_FW_INI_REGION_PERIPHERY_AUX, - * &IWL_FW_INI_REGION_PAGING, &IWL_FW_INI_REGION_CSR, - * &IWL_FW_INI_REGION_DRAM_IMR and &IWL_FW_INI_REGION_PCI_IOSF_CONFIG - * &IWL_FW_INI_REGION_DBGI_SRAM, &FW_TLV_DEBUG_REGION_TYPE_DBGI_SRAM, - * @fifos: fifos configuration. Used by &IWL_FW_INI_REGION_TXF and - * &IWL_FW_INI_REGION_RXF + * %IWL_FW_INI_REGION_DEVICE_MEMORY, %IWL_FW_INI_REGION_PERIPHERY_MAC, + * %IWL_FW_INI_REGION_PERIPHERY_PHY, %IWL_FW_INI_REGION_PERIPHERY_AUX, + * %IWL_FW_INI_REGION_PAGING, %IWL_FW_INI_REGION_CSR, + * %IWL_FW_INI_REGION_DRAM_IMR and %IWL_FW_INI_REGION_PCI_IOSF_CONFIG + * %IWL_FW_INI_REGION_DBGI_SRAM, %FW_TLV_DEBUG_REGION_TYPE_DBGI_SRAM, + * %IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP, + * @dev_addr_range: device address range configuration. Used by + * %IWL_FW_INI_REGION_PERIPHERY_MAC_RANGE and + * %IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE + * @fifos: fifos configuration. Used by %IWL_FW_INI_REGION_TXF and + * %IWL_FW_INI_REGION_RXF * @err_table: error table configuration. Used by - * IWL_FW_INI_REGION_LMAC_ERROR_TABLE and - * IWL_FW_INI_REGION_UMAC_ERROR_TABLE + * %IWL_FW_INI_REGION_LMAC_ERROR_TABLE and + * %IWL_FW_INI_REGION_UMAC_ERROR_TABLE * @internal_buffer: internal monitor buffer configuration. Used by - * &IWL_FW_INI_REGION_INTERNAL_BUFFER + * %IWL_FW_INI_REGION_INTERNAL_BUFFER + * @special_mem: special device memory region, used by + * %IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY * @dram_alloc_id: dram allocation id. One of &enum iwl_fw_ini_allocation_id. - * Used by &IWL_FW_INI_REGION_DRAM_BUFFER - * @tlv_mask: tlv collection mask. Used by &IWL_FW_INI_REGION_TLV + * Used by %IWL_FW_INI_REGION_DRAM_BUFFER + * @tlv_mask: tlv collection mask. Used by %IWL_FW_INI_REGION_TLV * @addrs: array of addresses attached to the end of the region tlv */ struct iwl_fw_ini_region_tlv { @@ -156,6 +187,7 @@ struct iwl_fw_ini_region_tlv { u8 name[IWL_FW_INI_MAX_NAME]; union { struct iwl_fw_ini_region_dev_addr dev_addr; + struct iwl_fw_ini_region_dev_addr_range dev_addr_range; struct iwl_fw_ini_region_fifos fifos; struct iwl_fw_ini_region_err_table err_table; struct iwl_fw_ini_region_internal_buffer internal_buffer; @@ -261,7 +293,7 @@ struct iwl_fw_ini_addr_val { } __packed; /* FW_TLV_DEBUG_ADDR_VALUE_VER_1 */ /** - * struct iwl_fw_ini_conf_tlv - configuration TLV to set register/memory. + * struct iwl_fw_ini_conf_set_tlv - configuration TLV to set register/memory. * * @hdr: debug header * @time_point: time point to apply config. One of &enum iwl_fw_ini_time_point @@ -289,7 +321,7 @@ struct iwl_fw_ini_conf_set_tlv { * @IWL_FW_INI_CONFIG_SET_TYPE_CSR: for CSR configuration * @IWL_FW_INI_CONFIG_SET_TYPE_DBGC_DRAM_ADDR: for DBGC_DRAM_ADDR configuration * @IWL_FW_INI_CONFIG_SET_TYPE_PERIPH_SCRATCH_HWM: for PERIPH SCRATCH HWM configuration - * @IWL_FW_INI_ALLOCATION_NUM: max number of configuration supported + * @IWL_FW_INI_CONFIG_SET_TYPE_MAX_NUM: max number of configuration supported */ enum iwl_fw_ini_config_set_type { @@ -330,6 +362,7 @@ enum iwl_fw_ini_allocation_id { * @IWL_FW_INI_LOCATION_SRAM_PATH: SRAM location * @IWL_FW_INI_LOCATION_DRAM_PATH: DRAM location * @IWL_FW_INI_LOCATION_NPK_PATH: NPK location + * @IWL_FW_INI_LOCATION_NUM: number of valid locations */ enum iwl_fw_ini_buffer_location { IWL_FW_INI_LOCATION_INVALID, @@ -361,6 +394,9 @@ enum iwl_fw_ini_buffer_location { * @IWL_FW_INI_REGION_PCI_IOSF_CONFIG: PCI/IOSF config * @IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY: special device memory * @IWL_FW_INI_REGION_DBGI_SRAM: periphery registers of DBGI SRAM + * @IWL_FW_INI_REGION_PERIPHERY_MAC_RANGE: a range of periphery registers of MAC + * @IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE: a range of periphery registers of PHY + * @IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP: periphery registers of SNPS DPHYIP * @IWL_FW_INI_REGION_NUM: number of region types */ enum iwl_fw_ini_region_type { @@ -383,6 +419,9 @@ enum iwl_fw_ini_region_type { IWL_FW_INI_REGION_PCI_IOSF_CONFIG, IWL_FW_INI_REGION_SPECIAL_DEVICE_MEMORY, IWL_FW_INI_REGION_DBGI_SRAM, + IWL_FW_INI_REGION_PERIPHERY_MAC_RANGE, + IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE, + IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP, IWL_FW_INI_REGION_NUM }; /* FW_TLV_DEBUG_REGION_TYPE_API_E */ @@ -403,6 +442,7 @@ enum iwl_fw_ini_region_device_memory_subtype { * Hard coded time points in which the driver can send hcmd or perform dump * collection * + * @IWL_FW_INI_TIME_POINT_INVALID: invalid timepoint * @IWL_FW_INI_TIME_POINT_EARLY: pre loading the FW * @IWL_FW_INI_TIME_POINT_AFTER_ALIVE: first cmd from host after alive notif * @IWL_FW_INI_TIME_POINT_POST_INIT: last cmd in series of init sequence @@ -432,6 +472,10 @@ enum iwl_fw_ini_region_device_memory_subtype { * @IWL_FW_INI_TIME_POINT_EAPOL_FAILED: EAPOL failed * @IWL_FW_INI_TIME_POINT_FAKE_TX: fake Tx * @IWL_FW_INI_TIME_POINT_DEASSOC: de association + * @IWL_FW_INI_TIME_POINT_PRESET_OVERRIDE_EXT_REQ: request to override preset + * @IWL_FW_INI_TIME_POINT_PRESET_OVERRIDE_START: start handling override preset + * request + * @IWL_FW_INI_TIME_SCAN_FAILURE: failed scan channel list * @IWL_FW_INI_TIME_POINT_NUM: number of time points */ enum iwl_fw_ini_time_point { @@ -462,6 +506,9 @@ enum iwl_fw_ini_time_point { IWL_FW_INI_TIME_POINT_EAPOL_FAILED, IWL_FW_INI_TIME_POINT_FAKE_TX, IWL_FW_INI_TIME_POINT_DEASSOC, + IWL_FW_INI_TIME_POINT_PRESET_OVERRIDE_EXT_REQ, + IWL_FW_INI_TIME_POINT_PRESET_OVERRIDE_START, + IWL_FW_INI_TIME_SCAN_FAILURE, IWL_FW_INI_TIME_POINT_NUM, }; /* FW_TLV_DEBUG_TIME_POINT_API_E */ @@ -517,7 +564,7 @@ enum iwl_fw_ini_dump_policy { * enum iwl_fw_ini_dump_type - Determines dump type based on size defined by FW. * * @IWL_FW_INI_DUMP_BRIEF : only dump the most important regions - * @IWL_FW_INI_DEBUG_MEDIUM: dump more regions than "brief", but not all regions + * @IWL_FW_INI_DUMP_MEDIUM: dump more regions than "brief", but not all regions * @IWL_FW_INI_DUMP_VERBOSE : dump all regions */ enum iwl_fw_ini_dump_type { diff --git a/sys/contrib/dev/iwlwifi/fw/api/debug.h b/sys/contrib/dev/iwlwifi/fw/api/debug.h index 8fef38139bf6..bea0f4668cc8 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/debug.h +++ b/sys/contrib/dev/iwlwifi/fw/api/debug.h @@ -1,11 +1,12 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2022 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_debug_h__ #define __iwl_fw_api_debug_h__ +#include "dbg-tlv.h" /** * enum iwl_debug_cmds - debug commands @@ -30,6 +31,11 @@ enum iwl_debug_cmds { */ HOST_EVENT_CFG = 0x3, /** + * @INVALID_WR_PTR_CMD: invalid write pointer, set in the TFD + * when it's not in use + */ + INVALID_WR_PTR_CMD = 0x6, + /** * @DBGC_SUSPEND_RESUME: * DBGC suspend/resume commad. Uses a single dword as data: * 0 - resume DBGC recording @@ -55,6 +61,12 @@ enum iwl_debug_cmds { */ FW_DUMP_COMPLETE_CMD = 0xB, /** + * @FW_CLEAR_BUFFER: + * clears the firmware's internal buffer + * no payload + */ + FW_CLEAR_BUFFER = 0xD, + /** * @MFU_ASSERT_DUMP_NTF: * &struct iwl_mfu_assert_dump_notif */ @@ -377,13 +389,13 @@ struct iwl_buf_alloc_cmd { #define DRAM_INFO_SECOND_MAGIC_WORD 0x89ABCDEF /** - * struct iwL_dram_info - DRAM fragments allocation struct + * struct iwl_dram_info - DRAM fragments allocation struct * * Driver will fill in the first 1K(+) of the pointed DRAM fragment * * @first_word: magic word value * @second_word: magic word value - * @framfrags: DRAM fragmentaion detail + * @dram_frags: DRAM fragmentaion detail */ struct iwl_dram_info { __le32 first_word; @@ -517,4 +529,26 @@ enum iwl_mvm_tas_statically_disabled_reason { TAS_DISABLED_REASON_MAX, }; /*_TAS_STATICALLY_DISABLED_REASON_E*/ +/** + * enum iwl_fw_dbg_config_cmd_type - types of FW debug config command + * @DEBUG_TOKEN_CONFIG_TYPE: token config type + */ +enum iwl_fw_dbg_config_cmd_type { + DEBUG_TOKEN_CONFIG_TYPE = 0x2B, +}; /* LDBG_CFG_CMD_TYPE_API_E_VER_1 */ + +/* this token disables debug asserts in the firmware */ +#define IWL_FW_DBG_CONFIG_TOKEN 0x00010001 + +/** + * struct iwl_fw_dbg_config_cmd - configure FW debug + * + * @type: according to &enum iwl_fw_dbg_config_cmd_type + * @conf: FW configuration + */ +struct iwl_fw_dbg_config_cmd { + __le32 type; + __le32 conf; +} __packed; /* LDBG_CFG_CMD_API_S_VER_7 */ + #endif /* __iwl_fw_api_debug_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/location.h b/sys/contrib/dev/iwlwifi/fw/api/location.h index b044990c7b87..30a54c7fa001 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/location.h +++ b/sys/contrib/dev/iwlwifi/fw/api/location.h @@ -2,6 +2,7 @@ /* * Copyright (C) 2015-2017 Intel Deutschland GmbH * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2024 Intel Corporation */ #ifndef __iwl_fw_api_location_h__ #define __iwl_fw_api_location_h__ @@ -390,10 +391,62 @@ struct iwl_tof_responder_config_cmd_v9 { __le16 max_time_between_msr; } __packed; /* TOF_RESPONDER_CONFIG_CMD_API_S_VER_8 */ +/** + * struct iwl_tof_responder_config_cmd - ToF AP mode + * @cmd_valid_fields: &iwl_tof_responder_cmd_valid_field + * @responder_cfg_flags: &iwl_tof_responder_cfg_flags + * @format_bw: bits 0 - 3: &enum iwl_location_frame_format. + * bits 4 - 7: &enum iwl_location_bw. + * @bss_color: current AP bss_color + * @channel_num: current AP Channel + * @ctrl_ch_position: coding of the control channel position relative to + * the center frequency, see iwl_mvm_get_ctrl_pos() + * @sta_id: index of the AP STA when in AP mode + * @band: current AP band + * @toa_offset: Artificial addition [pSec] for the ToA - to be used for debug + * purposes, simulating station movement by adding various values + * to this field + * @common_calib: XVT: common calibration value + * @specific_calib: XVT: specific calibration value + * @bssid: Current AP BSSID + * @r2i_ndp_params: parameters for R2I NDP. + * bits 0 - 2: max number of LTF repetitions + * bits 3 - 5: max number of spatial streams (supported values are < 2) + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf + * @i2r_ndp_params: parameters for I2R NDP. + * bits 0 - 2: max number of LTF repetitions + * bits 3 - 5: max number of spatial streams + * bits 6 - 7: max number of total LTFs see + * &enum ieee80211_range_params_max_total_ltf + * @min_time_between_msr: for non trigger based NDP ranging, minimum time + * between measurements in milliseconds. + * @max_time_between_msr: for non trigger based NDP ranging, maximum time + * between measurements in milliseconds. + */ +struct iwl_tof_responder_config_cmd { + __le32 cmd_valid_fields; + __le32 responder_cfg_flags; + u8 format_bw; + u8 bss_color; + u8 channel_num; + u8 ctrl_ch_position; + u8 sta_id; + u8 band; + __le16 toa_offset; + __le16 common_calib; + __le16 specific_calib; + u8 bssid[ETH_ALEN]; + u8 r2i_ndp_params; + u8 i2r_ndp_params; + __le16 min_time_between_msr; + __le16 max_time_between_msr; +} __packed; /* TOF_RESPONDER_CONFIG_CMD_API_S_VER_10 */ + #define IWL_LCI_CIVIC_IE_MAX_SIZE 400 /** - * struct iwl_tof_responder_dyn_config_cmd - Dynamic responder settings + * struct iwl_tof_responder_dyn_config_cmd_v2 - Dynamic responder settings * @lci_len: The length of the 1st (LCI) part in the @lci_civic buffer * @civic_len: The length of the 2nd (CIVIC) part in the @lci_civic buffer * @lci_civic: The LCI/CIVIC buffer. LCI data (if exists) comes first, then, if @@ -561,6 +614,8 @@ struct iwl_tof_range_req_ap_entry_v2 { * the responder asked for LMR feedback although the initiator did not set * the LMR feedback bit in the FTM request. If not set, the initiator will * continue with the session and will provide the LMR feedback. + * @IWL_INITIATOR_AP_FLAGS_TEST_INCORRECT_SAC: send an incorrect SAC in the + * first NDP exchange. This is used for testing. */ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_ASAP = BIT(1), @@ -577,6 +632,7 @@ enum iwl_initiator_ap_flags { IWL_INITIATOR_AP_FLAGS_USE_CALIB = BIT(13), IWL_INITIATOR_AP_FLAGS_PMF = BIT(14), IWL_INITIATOR_AP_FLAGS_TERMINATE_ON_LMR_FEEDBACK = BIT(15), + IWL_INITIATOR_AP_FLAGS_TEST_INCORRECT_SAC = BIT(16), }; /** @@ -630,6 +686,7 @@ enum iwl_location_frame_format { * @IWL_LOCATION_BW_20MHZ: 20MHz * @IWL_LOCATION_BW_40MHZ: 40MHz * @IWL_LOCATION_BW_80MHZ: 80MHz + * @IWL_LOCATION_BW_160MHZ: 160MHz */ enum iwl_location_bw { IWL_LOCATION_BW_20MHZ, @@ -796,6 +853,7 @@ struct iwl_tof_range_req_ap_entry_v7 { } __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_7 */ #define IWL_LOCATION_MAX_STS_POS 3 +#define IWL_LOCATION_TOTAL_LTF_POS 6 /** * struct iwl_tof_range_req_ap_entry_v8 - AP configuration parameters @@ -953,6 +1011,78 @@ struct iwl_tof_range_req_ap_entry_v9 { } __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_9 */ /** + * struct iwl_tof_range_req_ap_entry_v10 - AP configuration parameters + * @initiator_ap_flags: see &enum iwl_initiator_ap_flags. + * @band: 0 for 5.2 GHz, 1 for 2.4 GHz, 2 for 6GHz + * @channel_num: AP Channel number + * @format_bw: bits 0 - 3: &enum iwl_location_frame_format. + * bits 4 - 7: &enum iwl_location_bw. + * @ctrl_ch_position: Coding of the control channel position relative to the + * center frequency, see iwl_mvm_get_ctrl_pos(). + * @bssid: AP's BSSID + * @burst_period: For EDCA based ranging: Recommended value to be sent to the + * AP. Measurement periodicity In units of 100ms. ignored if + * num_of_bursts_exp = 0. + * For non trigger based NDP ranging, the maximum time between + * measurements in units of milliseconds. + * @samples_per_burst: the number of FTMs pairs in single Burst (1-31); + * @num_of_bursts: Recommended value to be sent to the AP. 2s Exponent of + * the number of measurement iterations (min 2^0 = 1, max 2^14) + * @sta_id: the station id of the AP. Only relevant when associated to the AP, + * otherwise should be set to &IWL_MVM_INVALID_STA. + * @cipher: pairwise cipher suite for secured measurement. + * &enum iwl_location_cipher. + * @hltk: HLTK to be used for secured 11az measurement + * @tk: TK to be used for secured 11az measurement + * @calib: An array of calibration values per FTM rx bandwidth. + * If &IWL_INITIATOR_AP_FLAGS_USE_CALIB is set, the fw will use the + * calibration value that corresponds to the rx bandwidth of the FTM + * frame. + * @beacon_interval: beacon interval of the AP in TUs. Only required if + * &IWL_INITIATOR_AP_FLAGS_TB is set. + * @rx_pn: the next expected PN for protected management frames Rx. LE byte + * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id + * is set to &IWL_MVM_INVALID_STA. + * @tx_pn: the next PN to use for protected management frames Tx. LE byte + * order. Only valid if &IWL_INITIATOR_AP_FLAGS_SECURED is set and sta_id + * is set to &IWL_MVM_INVALID_STA. + * @r2i_ndp_params: parameters for R2I NDP ranging negotiation. + * bits 0 - 2: max LTF repetitions + * bits 3 - 5: max number of spatial streams + * bits 6 - 7: max total LTFs. One of + * &enum ieee80211_range_params_max_total_ltf. + * @i2r_ndp_params: parameters for I2R NDP ranging negotiation. + * bits 0 - 2: max LTF repetitions + * bits 3 - 5: max number of spatial streams (supported values are < 2) + * bits 6 - 7: max total LTFs. One of + * &enum ieee80211_range_params_max_total_ltf. + * @min_time_between_msr: For non trigger based NDP ranging, the minimum time + * between measurements in units of milliseconds + */ +struct iwl_tof_range_req_ap_entry_v10 { + __le32 initiator_ap_flags; + u8 band; + u8 channel_num; + u8 format_bw; + u8 ctrl_ch_position; + u8 bssid[ETH_ALEN]; + __le16 burst_period; + u8 samples_per_burst; + u8 num_of_bursts; + u8 sta_id; + u8 cipher; + u8 hltk[HLTK_11AZ_LEN]; + u8 tk[TK_11AZ_LEN]; + __le16 calib[IWL_TOF_BW_NUM]; + __le16 beacon_interval; + u8 rx_pn[IEEE80211_CCMP_PN_LEN]; + u8 tx_pn[IEEE80211_CCMP_PN_LEN]; + u8 r2i_ndp_params; + u8 i2r_ndp_params; + __le16 min_time_between_msr; +} __packed; /* LOCATION_RANGE_REQ_AP_ENTRY_CMD_API_S_VER_9 */ + +/** * enum iwl_tof_response_mode * @IWL_MVM_TOF_RESPONSE_ASAP: report each AP measurement separately as soon as * possible (not supported for this release) @@ -1229,6 +1359,34 @@ struct iwl_tof_range_req_cmd_v13 { struct iwl_tof_range_req_ap_entry_v9 ap[IWL_MVM_TOF_MAX_APS]; } __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_13 */ +/** + * struct iwl_tof_range_req_cmd_v14 - start measurement cmd + * @initiator_flags: see flags @ iwl_tof_initiator_flags + * @request_id: A Token incremented per request. The same Token will be + * sent back in the range response + * @num_of_ap: Number of APs to measure (error if > IWL_MVM_TOF_MAX_APS) + * @range_req_bssid: ranging request BSSID + * @macaddr_mask: Bits set to 0 shall be copied from the MAC address template. + * Bits set to 1 shall be randomized by the UMAC + * @macaddr_template: MAC address template to use for non-randomized bits + * @req_timeout_ms: Requested timeout of the response in units of milliseconds. + * This is the session time for completing the measurement. + * @tsf_mac_id: report the measurement start time for each ap in terms of the + * TSF of this mac id. 0xff to disable TSF reporting. + * @ap: per-AP request data, see &struct iwl_tof_range_req_ap_entry_v10. + */ +struct iwl_tof_range_req_cmd_v14 { + __le32 initiator_flags; + u8 request_id; + u8 num_of_ap; + u8 range_req_bssid[ETH_ALEN]; + u8 macaddr_mask[ETH_ALEN]; + u8 macaddr_template[ETH_ALEN]; + __le32 req_timeout_ms; + __le32 tsf_mac_id; + struct iwl_tof_range_req_ap_entry_v10 ap[IWL_MVM_TOF_MAX_APS]; +} __packed; /* LOCATION_RANGE_REQ_CMD_API_S_VER_13 */ + /* * enum iwl_tof_range_request_status - status of the sent request * @IWL_TOF_RANGE_REQUEST_STATUS_SUCCESSFUL - FW successfully received the diff --git a/sys/contrib/dev/iwlwifi/fw/api/mac-cfg.h b/sys/contrib/dev/iwlwifi/fw/api/mac-cfg.h index 184db5a6f06f..ca6fa66d1917 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/mac-cfg.h +++ b/sys/contrib/dev/iwlwifi/fw/api/mac-cfg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2019, 2021-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2019, 2021-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -58,6 +58,14 @@ enum iwl_mac_conf_subcmd_ids { */ STA_DISABLE_TX_CMD = 0xD, /** + * @ROC_CMD: &struct iwl_roc_req + */ + ROC_CMD = 0xE, + /** + * @ROC_NOTIF: &struct iwl_roc_notif + */ + ROC_NOTIF = 0xF8, + /** * @SESSION_PROTECTION_NOTIF: &struct iwl_mvm_session_prot_notif */ SESSION_PROTECTION_NOTIF = 0xFB, @@ -136,7 +144,7 @@ struct iwl_missed_vap_notif { } __packed; /* MISSED_VAP_NTFY_API_S_VER_1 */ /** - * struct iwl_channel_switch_start_notif - Channel switch start notification + * struct iwl_channel_switch_start_notif_v1 - Channel switch start notification * * @id_and_color: ID and color of the MAC */ @@ -234,9 +242,9 @@ struct iwl_mac_low_latency_cmd { * @esr_transition_timeout: the timeout required by the AP for the * eSR transition. * Available only from version 2 of the command. - * This values comes from the EMLSR transition delay in the EML + * This value comes from the EMLSR transition delay in the EML * Capabilities subfield. - * @medium_sync_delay: the value as it appeasr in P802.11be_D2.2 Figure 9-1002j. + * @medium_sync_delay: the value as it appears in P802.11be_D2.2 Figure 9-1002j. * @assoc_id: unique ID assigned by the AP during association * @reserved1: alignment * @data_policy: see &enum iwl_mac_data_policy @@ -309,7 +317,6 @@ enum iwl_mac_config_filter_flags { * If the NIC is not ACK_ENABLED it may use the EOF-bit in first non-0 * len delim to determine if AGG or single. * @client: client mac data - * @go_ibss: mac data for go or ibss * @p2p_dev: mac data for p2p device */ struct iwl_mac_config_cmd { @@ -366,7 +373,7 @@ struct iwl_mac_config_cmd { * iwl_link_ctx_cfg_cmd::bss_color_disable * @LINK_CONTEXT_MODIFY_EHT_PARAMS: covers iwl_link_ctx_cfg_cmd::puncture_mask. * This flag can be set only if the MAC that this link relates to has - * eht_support set to true. + * eht_support set to true. No longer used since _VER_3 of this command. * @LINK_CONTEXT_MODIFY_ALL: set all above flags */ enum iwl_link_ctx_modify_flags { @@ -439,6 +446,7 @@ enum iwl_link_ctx_flags { * @listen_lmac: indicates whether the link should be allocated on the Listen * Lmac or on the Main Lmac. Cannot be changed on an active Link. * Relevant only for eSR. + * @reserved1: in version 2, listen_lmac became reserved * @cck_rates: basic rates available for CCK * @ofdm_rates: basic rates available for OFDM * @cck_short_preamble: 1 for enabling short preamble, 0 otherwise @@ -454,7 +462,7 @@ enum iwl_link_ctx_flags { * @bi: beacon interval in TU, applicable only when associated * @dtim_interval: DTIM interval in TU. * Relevant only for GO, otherwise this is offloaded. - * @puncture_mask: puncture mask for EHT + * @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 @@ -464,10 +472,10 @@ enum iwl_link_ctx_flags { * @bssid_index: index of the associated VAP * @bss_color: 11ax AP ID that is used in the HE SIG-A to mark inter BSS frame * @spec_link_id: link_id as the AP knows it - * @reserved: alignment + * @reserved2: alignment * @ibss_bssid_addr: bssid for ibss * @reserved_for_ibss_bssid_addr: reserved - * @reserved1: reserved for future use + * @reserved3: reserved for future use */ struct iwl_link_config_cmd { __le32 action; @@ -478,7 +486,10 @@ struct iwl_link_config_cmd { __le16 reserved_for_local_link_addr; __le32 modify_mask; __le32 active; - __le32 listen_lmac; + union { + __le32 listen_lmac; + __le32 reserved1; + }; __le32 cck_rates; __le32 ofdm_rates; __le32 cck_short_preamble; @@ -494,7 +505,7 @@ struct iwl_link_config_cmd { struct iwl_he_backoff_conf trig_based_txf[AC_NUM]; __le32 bi; __le32 dtim_interval; - __le16 puncture_mask; + __le16 puncture_mask; /* removed in _VER_3 */ __le16 frame_time_rts_th; __le32 flags; __le32 flags_mask; @@ -504,11 +515,11 @@ struct iwl_link_config_cmd { u8 bssid_index; u8 bss_color; u8 spec_link_id; - u8 reserved; + u8 reserved2; u8 ibss_bssid_addr[6]; __le16 reserved_for_ibss_bssid_addr; - __le32 reserved1[8]; -} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1 */ + __le32 reserved3[8]; +} __packed; /* LINK_CONTEXT_CONFIG_CMD_API_S_VER_1, _VER_2, _VER_3 */ /* Currently FW supports link ids in the range 0-3 and can have * at most two active links for each vif. @@ -631,4 +642,25 @@ struct iwl_mvm_sta_disable_tx_cmd { __le32 disable; } __packed; /* STA_DISABLE_TX_API_S_VER_1 */ +/** + * enum iwl_mvm_fw_esr_recommendation - FW recommendation code + * @ESR_RECOMMEND_LEAVE: recommendation to leave esr + * @ESR_FORCE_LEAVE: force exiting esr + * @ESR_RECOMMEND_ENTER: recommendation to enter esr + */ +enum iwl_mvm_fw_esr_recommendation { + ESR_RECOMMEND_LEAVE, + ESR_FORCE_LEAVE, + ESR_RECOMMEND_ENTER, +}; /* ESR_MODE_RECOMMENDATION_CODE_API_E_VER_1 */ + +/** + * struct iwl_mvm_esr_mode_notif - FWs recommendation/force for esr mode + * + * @action: the action to apply on esr state. See &iwl_mvm_fw_esr_recommendation + */ +struct iwl_mvm_esr_mode_notif { + __le32 action; +} __packed; /* ESR_MODE_RECOMMENDATION_NTFY_API_S_VER_1 */ + #endif /* __iwl_fw_api_mac_cfg_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/mac.h b/sys/contrib/dev/iwlwifi/fw/api/mac.h index 55882190251c..bcbbf8c4a297 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/mac.h +++ b/sys/contrib/dev/iwlwifi/fw/api/mac.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022, 2024 Intel Corporation * Copyright (C) 2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_mac_h__ @@ -310,6 +310,13 @@ struct iwl_ac_qos { * @filter_flags: combination of &enum iwl_mac_filter_flags * @qos_flags: from &enum iwl_mac_qos_flags * @ac: one iwl_mac_qos configuration for each AC + * @ap: AP specific config data, see &struct iwl_mac_data_ap + * @go: GO specific config data, see &struct iwl_mac_data_go + * @sta: BSS client specific config data, see &struct iwl_mac_data_sta + * @p2p_sta: P2P client specific config data, see &struct iwl_mac_data_p2p_sta + * @p2p_dev: P2P-device specific config data, see &struct iwl_mac_data_p2p_dev + * @pibss: Pseudo-IBSS specific data, unused; see struct iwl_mac_data_pibss + * @ibss: IBSS specific config data, see &struct iwl_mac_data_ibss */ struct iwl_mac_ctx_cmd { /* COMMON_INDEX_HDR_API_S_VER_1 */ @@ -431,8 +438,8 @@ enum iwl_he_pkt_ext_constellations { }; #define MAX_HE_SUPP_NSS 2 -#define MAX_CHANNEL_BW_INDX_API_D_VER_2 4 -#define MAX_CHANNEL_BW_INDX_API_D_VER_3 5 +#define MAX_CHANNEL_BW_INDX_API_D_VER_1 4 +#define MAX_CHANNEL_BW_INDX_API_D_VER_2 5 /** * struct iwl_he_pkt_ext_v1 - QAM thresholds @@ -455,7 +462,7 @@ enum iwl_he_pkt_ext_constellations { * (0-low_th, 1-high_th) */ struct iwl_he_pkt_ext_v1 { - u8 pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_2][2]; + u8 pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_1][2]; } __packed; /* PKT_EXT_DOT11AX_API_S_VER_1 */ /** @@ -480,7 +487,7 @@ struct iwl_he_pkt_ext_v1 { * (0-low_th, 1-high_th) */ struct iwl_he_pkt_ext_v2 { - u8 pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_3][2]; + u8 pkt_ext_qam_th[MAX_HE_SUPP_NSS][MAX_CHANNEL_BW_INDX_API_D_VER_2][2]; } __packed; /* PKT_EXT_DOT11AX_API_S_VER_2 */ /** diff --git a/sys/contrib/dev/iwlwifi/fw/api/nvm-reg.h b/sys/contrib/dev/iwlwifi/fw/api/nvm-reg.h index 28bfabb399b2..d424d0126367 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/nvm-reg.h +++ b/sys/contrib/dev/iwlwifi/fw/api/nvm-reg.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -21,8 +21,11 @@ enum iwl_regulatory_and_nvm_subcmd_ids { * &struct iwl_lari_config_change_cmd_v2, * &struct iwl_lari_config_change_cmd_v3, * &struct iwl_lari_config_change_cmd_v4, - * &struct iwl_lari_config_change_cmd_v5 or - * &struct iwl_lari_config_change_cmd_v6 + * &struct iwl_lari_config_change_cmd_v5, + * &struct iwl_lari_config_change_cmd_v6, + * &struct iwl_lari_config_change_cmd_v7, + * &struct iwl_lari_config_change_cmd_v10 or + * &struct iwl_lari_config_change_cmd */ LARI_CONFIG_CHANGE = 0x1, @@ -44,6 +47,11 @@ enum iwl_regulatory_and_nvm_subcmd_ids { SAR_OFFSET_MAPPING_TABLE_CMD = 0x4, /** + * @MCC_ALLOWED_AP_TYPE_CMD: &struct iwl_mcc_allowed_ap_type_cmd + */ + MCC_ALLOWED_AP_TYPE_CMD = 0x5, + + /** * @PNVM_INIT_COMPLETE_NTFY: &struct iwl_pnvm_init_complete_ntfy */ PNVM_INIT_COMPLETE_NTFY = 0xFE, @@ -112,7 +120,7 @@ struct iwl_nvm_access_cmd { } __packed; /* NVM_ACCESS_CMD_API_S_VER_2 */ /** - * struct iwl_nvm_access_resp_ver2 - response to NVM_ACCESS_CMD + * struct iwl_nvm_access_resp - response to NVM_ACCESS_CMD * @offset: offset in bytes into the section * @length: in bytes, either how much was written or read * @type: NVM_SECTION_TYPE_* @@ -204,7 +212,7 @@ struct iwl_nvm_get_info_phy { #define IWL_NUM_CHANNELS 110 /** - * struct iwl_nvm_get_info_regulatory - regulatory information + * struct iwl_nvm_get_info_regulatory_v1 - regulatory information * @lar_enabled: is LAR enabled * @channel_profile: regulatory data of this channel * @reserved: reserved @@ -263,6 +271,9 @@ struct iwl_nvm_access_complete_cmd { __le32 reserved; } __packed; /* NVM_ACCESS_COMPLETE_CMD_API_S_VER_1 */ +#define IWL_MCC_US 0x5553 +#define IWL_MCC_CANADA 0x4341 + /** * struct iwl_mcc_update_cmd - Request the device to update geographic * regulatory profile according to the given MCC (Mobile Country Code). @@ -429,36 +440,31 @@ enum iwl_mcc_source { MCC_SOURCE_GETTING_MCC_TEST_MODE = 0x11, }; -#define IWL_TAS_BLOCK_LIST_MAX 16 +#define IWL_WTAS_BLACK_LIST_MAX 16 /** - * struct iwl_tas_config_cmd_v2 - configures the TAS + * struct iwl_tas_config_cmd_common - configures the TAS. + * This is also the v2 structure. * @block_list_size: size of relevant field in block_list_array * @block_list_array: list of countries where TAS must be disabled */ -struct iwl_tas_config_cmd_v2 { +struct iwl_tas_config_cmd_common { __le32 block_list_size; - __le32 block_list_array[IWL_TAS_BLOCK_LIST_MAX]; + __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; } __packed; /* TAS_CONFIG_CMD_API_S_VER_2 */ /** * struct iwl_tas_config_cmd_v3 - configures the TAS - * @block_list_size: size of relevant field in block_list_array - * @block_list_array: list of countries where TAS must be disabled * @override_tas_iec: indicates whether to override default value of IEC regulatory * @enable_tas_iec: in case override_tas_iec is set - * indicates whether IEC regulatory is enabled or disabled */ struct iwl_tas_config_cmd_v3 { - __le32 block_list_size; - __le32 block_list_array[IWL_TAS_BLOCK_LIST_MAX]; __le16 override_tas_iec; __le16 enable_tas_iec; } __packed; /* TAS_CONFIG_CMD_API_S_VER_3 */ /** - * struct iwl_tas_config_cmd_v3 - configures the TAS - * @block_list_size: size of relevant field in block_list_array - * @block_list_array: list of countries where TAS must be disabled + * struct iwl_tas_config_cmd_v4 - configures the TAS * @override_tas_iec: indicates whether to override default value of IEC regulatory * @enable_tas_iec: in case override_tas_iec is set - * indicates whether IEC regulatory is enabled or disabled @@ -466,32 +472,35 @@ struct iwl_tas_config_cmd_v3 { * @reserved: reserved */ struct iwl_tas_config_cmd_v4 { - __le32 block_list_size; - __le32 block_list_array[IWL_TAS_BLOCK_LIST_MAX]; u8 override_tas_iec; u8 enable_tas_iec; u8 usa_tas_uhb_allowed; u8 reserved; } __packed; /* TAS_CONFIG_CMD_API_S_VER_4 */ -union iwl_tas_config_cmd { - struct iwl_tas_config_cmd_v2 v2; - struct iwl_tas_config_cmd_v3 v3; - struct iwl_tas_config_cmd_v4 v4; +struct iwl_tas_config_cmd { + struct iwl_tas_config_cmd_common common; + union { + struct iwl_tas_config_cmd_v3 v3; + struct iwl_tas_config_cmd_v4 v4; + }; }; + /** - * enum iwl_lari_configs - bit masks for the various LARI config operations + * enum iwl_lari_config_masks - bit masks for the various LARI config operations * @LARI_CONFIG_DISABLE_11AC_UKRAINE_MSK: disable 11ac in ukraine * @LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK: ETSI 5.8GHz SRD passive scan * @LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK: ETSI 5.8GHz SRD disabled * @LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK: enable 5.15/5.35GHz bands in * Indonesia + * @LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK: enable 2022 china regulatory */ enum iwl_lari_config_masks { LARI_CONFIG_DISABLE_11AC_UKRAINE_MSK = BIT(0), LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK = BIT(1), LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK = BIT(2), LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK = BIT(3), + LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK = BIT(7), }; #define IWL_11AX_UKRAINE_MASK 3 @@ -601,6 +610,136 @@ struct iwl_lari_config_change_cmd_v6 { } __packed; /* LARI_CHANGE_CONF_CMD_S_VER_6 */ /** + * struct iwl_lari_config_change_cmd_v7 - change LARI configuration + * This structure is used also for lari cmd version 8 and 9. + * @config_bitmap: Bitmap of the config commands. Each bit will trigger a + * different predefined FW config operation. + * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. + * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits + * per country, one to indicate whether to override and the other to + * indicate the value to use. + * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits + * per country, one to indicate whether to override and the other to + * indicate allow/disallow unii4 channels. + * For LARI cmd version 4 to 8 - bits 0:3 are supported. + * For LARI cmd version 9 - bits 0:5 are supported. + * @chan_state_active_bitmap: Bitmap to enable different bands per country + * or region. + * Each bit represents a country or region, and a band to activate + * according to the BIOS definitions. + * For LARI cmd version 7 - bits 0:3 are supported. + * For LARI cmd version 8 - bits 0:4 are supported. + * @force_disable_channels_bitmap: Bitmap of disabled bands/channels. + * Each bit represents a set of channels in a specific band that should be + * disabled + * @edt_bitmap: Bitmap of energy detection threshold table. + * Disable/enable the EDT optimization method for different band. + */ +struct iwl_lari_config_change_cmd_v7 { + __le32 config_bitmap; + __le32 oem_uhb_allow_bitmap; + __le32 oem_11ax_allow_bitmap; + __le32 oem_unii4_allow_bitmap; + __le32 chan_state_active_bitmap; + __le32 force_disable_channels_bitmap; + __le32 edt_bitmap; +} __packed; +/* LARI_CHANGE_CONF_CMD_S_VER_7 */ +/* LARI_CHANGE_CONF_CMD_S_VER_8 */ +/* LARI_CHANGE_CONF_CMD_S_VER_9 */ + +/** + * struct iwl_lari_config_change_cmd_v10 - change LARI configuration + * @config_bitmap: Bitmap of the config commands. Each bit will trigger a + * different predefined FW config operation. + * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. + * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits + * per country, one to indicate whether to override and the other to + * indicate the value to use. + * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits + * per country, one to indicate whether to override and the other to + * indicate allow/disallow unii4 channels. + * For LARI cmd version 10 - bits 0:5 are supported. + * @chan_state_active_bitmap: Bitmap to enable different bands per country + * or region. + * Each bit represents a country or region, and a band to activate + * according to the BIOS definitions. + * For LARI cmd version 10 - bits 0:4 are supported. + * @force_disable_channels_bitmap: Bitmap of disabled bands/channels. + * Each bit represents a set of channels in a specific band that should be + * disabled + * @edt_bitmap: Bitmap of energy detection threshold table. + * Disable/enable the EDT optimization method for different band. + * @oem_320mhz_allow_bitmap: 320Mhz bandwidth enablement bitmap per MCC. + * bit0: enable 320Mhz in Japan. + * bit1: enable 320Mhz in South Korea. + * bit 2 - 31: reserved. + */ +struct iwl_lari_config_change_cmd_v10 { + __le32 config_bitmap; + __le32 oem_uhb_allow_bitmap; + __le32 oem_11ax_allow_bitmap; + __le32 oem_unii4_allow_bitmap; + __le32 chan_state_active_bitmap; + __le32 force_disable_channels_bitmap; + __le32 edt_bitmap; + __le32 oem_320mhz_allow_bitmap; +} __packed; +/* LARI_CHANGE_CONF_CMD_S_VER_10 */ + +/** + * struct iwl_lari_config_change_cmd - change LARI configuration + * @config_bitmap: Bitmap of the config commands. Each bit will trigger a + * different predefined FW config operation. + * @oem_uhb_allow_bitmap: Bitmap of UHB enabled MCC sets. + * @oem_11ax_allow_bitmap: Bitmap of 11ax allowed MCCs. There are two bits + * per country, one to indicate whether to override and the other to + * indicate the value to use. + * @oem_unii4_allow_bitmap: Bitmap of unii4 allowed MCCs.There are two bits + * per country, one to indicate whether to override and the other to + * indicate allow/disallow unii4 channels. + * For LARI cmd version 11 - bits 0:5 are supported. + * @chan_state_active_bitmap: Bitmap to enable different bands per country + * or region. + * Each bit represents a country or region, and a band to activate + * according to the BIOS definitions. + * For LARI cmd version 11 - bits 0:4 are supported. + * For LARI cmd version 12 - bits 0:6 are supported and bits 7:31 are + * reserved. No need to mask out the reserved bits. + * @force_disable_channels_bitmap: Bitmap of disabled bands/channels. + * Each bit represents a set of channels in a specific band that should be + * disabled + * @edt_bitmap: Bitmap of energy detection threshold table. + * Disable/enable the EDT optimization method for different band. + * @oem_320mhz_allow_bitmap: 320Mhz bandwidth enablement bitmap per MCC. + * bit0: enable 320Mhz in Japan. + * bit1: enable 320Mhz in South Korea. + * bit 2 - 31: reserved. + * @oem_11be_allow_bitmap: Bitmap of 11be allowed MCCs. No need to mask out the + * unsupported bits + * bit0: enable 11be in China(CB/CN). + * bit1: enable 11be in South Korea. + * bit 2 - 31: reserved. + */ +struct iwl_lari_config_change_cmd { + __le32 config_bitmap; + __le32 oem_uhb_allow_bitmap; + __le32 oem_11ax_allow_bitmap; + __le32 oem_unii4_allow_bitmap; + __le32 chan_state_active_bitmap; + __le32 force_disable_channels_bitmap; + __le32 edt_bitmap; + __le32 oem_320mhz_allow_bitmap; + __le32 oem_11be_allow_bitmap; +} __packed; +/* LARI_CHANGE_CONF_CMD_S_VER_11 */ +/* LARI_CHANGE_CONF_CMD_S_VER_12 */ + +/* Activate UNII-1 (5.2GHz) for World Wide */ +#define ACTIVATE_5G2_IN_WW_MASK BIT(4) +#define CHAN_STATE_ACTIVE_BITMAP_CMD_V11 0x1F + +/** * struct iwl_pnvm_init_complete_ntfy - PNVM initialization complete * @status: PNVM image loading status */ @@ -608,4 +747,17 @@ struct iwl_pnvm_init_complete_ntfy { __le32 status; } __packed; /* PNVM_INIT_COMPLETE_NTFY_S_VER_1 */ +#define UATS_TABLE_ROW_SIZE 26 +#define UATS_TABLE_COL_SIZE 13 + +/** + * struct iwl_mcc_allowed_ap_type_cmd - struct for MCC_ALLOWED_AP_TYPE_CMD + * @offset_map: mapping a mcc to UHB AP type support (UATS) allowed + * @reserved: reserved + */ +struct iwl_mcc_allowed_ap_type_cmd { + u8 offset_map[UATS_TABLE_ROW_SIZE][UATS_TABLE_COL_SIZE]; + __le16 reserved; +} __packed; /* MCC_ALLOWED_AP_TYPE_CMD_API_S_VER_1 */ + #endif /* __iwl_fw_api_nvm_reg_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/offload.h b/sys/contrib/dev/iwlwifi/fw/api/offload.h index 898bf351f6e4..6a7bbfd6b2b7 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/offload.h +++ b/sys/contrib/dev/iwlwifi/fw/api/offload.h @@ -3,7 +3,7 @@ * Copyright (C) 2012-2014 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2021-2022 Intel Corporation + * Copyright (C) 2021-2024 Intel Corporation */ #ifndef __iwl_fw_api_offload_h__ #define __iwl_fw_api_offload_h__ @@ -18,7 +18,9 @@ enum iwl_prot_offload_subcmd_ids { WOWLAN_WAKE_PKT_NOTIFICATION = 0xFC, /** - * @WOWLAN_INFO_NOTIFICATION: Notification in &struct iwl_wowlan_info_notif + * @WOWLAN_INFO_NOTIFICATION: Notification in + * &struct iwl_wowlan_info_notif_v1, &struct iwl_wowlan_info_notif_v2, + * or &struct iwl_wowlan_info_notif */ WOWLAN_INFO_NOTIFICATION = 0xFD, @@ -58,7 +60,7 @@ struct iwl_stored_beacon_notif_common { } __packed; /** - * struct iwl_stored_beacon_notif - Stored beacon notification + * struct iwl_stored_beacon_notif_v2 - Stored beacon notification * * @common: fields common for all versions * @data: beacon data, length in @byte_count diff --git a/sys/contrib/dev/iwlwifi/fw/api/phy-ctxt.h b/sys/contrib/dev/iwlwifi/fw/api/phy-ctxt.h index 8fe42cff1102..4d8a12799c4d 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/phy-ctxt.h +++ b/sys/contrib/dev/iwlwifi/fw/api/phy-ctxt.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018, 2020-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2020-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -25,8 +25,8 @@ * For legacy set bit means upper channel, otherwise lower. * For VHT - bit-2 marks if the control is lower/upper relative to center-freq * bits-1:0 mark the distance from the center freq. for 20Mhz, offset is 0. - * center_freq * For EHT - bit-3 is used for extended distance + * center_freq * | * 40Mhz |____|____| * 80Mhz |____|____|____|____| @@ -113,7 +113,7 @@ struct iwl_phy_context_cmd_tail { } __packed; /** - * struct iwl_phy_context_cmd - config of the PHY context + * struct iwl_phy_context_cmd_v1 - config of the PHY context * ( PHY_CONTEXT_CMD = 0x8 ) * @id_and_color: ID and color of the relevant Binding * @action: action to perform, see &enum iwl_ctxt_action @@ -142,6 +142,9 @@ struct iwl_phy_context_cmd_v1 { * @lmac_id: the lmac id the phy context belongs to * @ci: channel info * @rxchain_info: ??? + * @sbb_bandwidth: 0 disabled, 1 - 40Mhz ... 4 - 320MHz + * @sbb_ctrl_channel_loc: location of the control channel + * @puncture_mask: bitmap of punctured subchannels * @dsp_cfg_flags: set to 0 * @reserved: reserved to align to 64 bit */ @@ -152,9 +155,20 @@ struct iwl_phy_context_cmd { /* PHY_CONTEXT_DATA_API_S_VER_3, PHY_CONTEXT_DATA_API_S_VER_4 */ struct iwl_fw_channel_info ci; __le32 lmac_id; - __le32 rxchain_info; /* reserved in _VER_4 */ + union { + __le32 rxchain_info; /* reserved in _VER_4 */ + struct { /* used for _VER_5/_VER_6 */ + u8 sbb_bandwidth; + u8 sbb_ctrl_channel_loc; + __le16 puncture_mask; /* added in VER_6 */ + }; + }; __le32 dsp_cfg_flags; __le32 reserved; -} __packed; /* PHY_CONTEXT_CMD_API_VER_3, PHY_CONTEXT_CMD_API_VER_4 */ +} __packed; /* PHY_CONTEXT_CMD_API_VER_3, + * PHY_CONTEXT_CMD_API_VER_4, + * PHY_CONTEXT_CMD_API_VER_5, + * PHY_CONTEXT_CMD_API_VER_6 + */ #endif /* __iwl_fw_api_phy_ctxt_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/phy.h b/sys/contrib/dev/iwlwifi/fw/api/phy.h index 5a3f30e5e06d..c73d4d597857 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/phy.h +++ b/sys/contrib/dev/iwlwifi/fw/api/phy.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2019-2022 Intel Corporation + * Copyright (C) 2012-2014, 2019-2022, 2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -43,6 +43,11 @@ enum iwl_phy_ops_subcmd_ids { PER_PLATFORM_ANT_GAIN_CMD = 0x07, /** + * @AP_TX_POWER_CONSTRAINTS_CMD: &struct iwl_txpower_constraints_cmd + */ + AP_TX_POWER_CONSTRAINTS_CMD = 0x0C, + + /** * @CT_KILL_NOTIFICATION: &struct ct_kill_notif */ CT_KILL_NOTIFICATION = 0xFE, @@ -190,7 +195,7 @@ struct ct_kill_notif { } __packed; /* CT_KILL_NOTIFICATION_API_S_VER_1, CT_KILL_NOTIFICATION_API_S_VER_2 */ /** -* enum ctdp_cmd_operation - CTDP command operations +* enum iwl_mvm_ctdp_cmd_operation - CTDP command operations * @CTDP_CMD_OPERATION_START: update the current budget * @CTDP_CMD_OPERATION_STOP: stop ctdp * @CTDP_CMD_OPERATION_REPORT: get the average budget diff --git a/sys/contrib/dev/iwlwifi/fw/api/power.h b/sys/contrib/dev/iwlwifi/fw/api/power.h index 85d89f559f6c..6e6a92d173cc 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/power.h +++ b/sys/contrib/dev/iwlwifi/fw/api/power.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -144,6 +144,8 @@ struct iwl_powertable_cmd { * receiver and transmitter. '0' - does not allow. * @DEVICE_POWER_FLAGS_ALLOW_MEM_RETENTION_MSK: * Device Retention indication, '1' indicate retention is enabled. + * @DEVICE_POWER_FLAGS_NO_SLEEP_TILL_D3_MSK: + * Prevent power save until entering d3 is completed. * @DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK: * 32Khz external slow clock valid indication, '1' indicate cloack is * valid. @@ -151,6 +153,7 @@ struct iwl_powertable_cmd { enum iwl_device_power_flags { DEVICE_POWER_FLAGS_POWER_SAVE_ENA_MSK = BIT(0), DEVICE_POWER_FLAGS_ALLOW_MEM_RETENTION_MSK = BIT(1), + DEVICE_POWER_FLAGS_NO_SLEEP_TILL_D3_MSK = BIT(7), DEVICE_POWER_FLAGS_32K_CLK_VALID_MSK = BIT(12), }; @@ -162,7 +165,7 @@ enum iwl_device_power_flags { * @reserved: reserved (padding) */ struct iwl_device_power_cmd { - /* PM_POWER_TABLE_CMD_API_S_VER_6 */ + /* PM_POWER_TABLE_CMD_API_S_VER_7 */ __le16 flags; __le16 reserved; } __packed; @@ -382,6 +385,33 @@ struct iwl_dev_tx_power_cmd_v7 { __le32 timer_period; __le32 flags; } __packed; /* TX_REDUCED_POWER_API_S_VER_7 */ + +/** + * struct iwl_dev_tx_power_cmd_v8 - TX power reduction command version 8 + * @per_chain: per chain restrictions + * @enable_ack_reduction: enable or disable close range ack TX power + * reduction. + * @per_chain_restriction_changed: is per_chain_restriction has changed + * from last command. used if set_mode is + * IWL_TX_POWER_MODE_SET_SAR_TIMER. + * note: if not changed, the command is used for keep alive only. + * @reserved: reserved (padding) + * @timer_period: timer in milliseconds. if expires FW will change to default + * BIOS values. relevant if setMode is IWL_TX_POWER_MODE_SET_SAR_TIMER + * @flags: reduce power flags. + * @tpc_vlp_backoff_level: user backoff of UNII5,7 VLP channels in USA. + * Not in use. + */ +struct iwl_dev_tx_power_cmd_v8 { + __le16 per_chain[IWL_NUM_CHAIN_TABLES_V2][IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2]; + u8 enable_ack_reduction; + u8 per_chain_restriction_changed; + u8 reserved[2]; + __le32 timer_period; + __le32 flags; + __le32 tpc_vlp_backoff_level; +} __packed; /* TX_REDUCED_POWER_API_S_VER_8 */ + /** * struct iwl_dev_tx_power_cmd - TX power reduction command (multiversion) * @common: common part of the command @@ -389,6 +419,8 @@ struct iwl_dev_tx_power_cmd_v7 { * @v4: version 4 part of the command * @v5: version 5 part of the command * @v6: version 6 part of the command + * @v7: version 7 part of the command + * @v8: version 8 part of the command */ struct iwl_dev_tx_power_cmd { struct iwl_dev_tx_power_common common; @@ -398,6 +430,7 @@ struct iwl_dev_tx_power_cmd { struct iwl_dev_tx_power_cmd_v5 v5; struct iwl_dev_tx_power_cmd_v6 v6; struct iwl_dev_tx_power_cmd_v7 v7; + struct iwl_dev_tx_power_cmd_v8 v8; }; }; @@ -429,7 +462,7 @@ struct iwl_per_chain_offset { } __packed; /* PER_CHAIN_LIMIT_OFFSET_PER_CHAIN_S_VER_1 */ /** - * struct iwl_geo_tx_power_profile_cmd_v1 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. + * struct iwl_geo_tx_power_profiles_cmd_v1 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation * @table: offset profile per band. */ @@ -439,7 +472,7 @@ struct iwl_geo_tx_power_profiles_cmd_v1 { } __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_1 */ /** - * struct iwl_geo_tx_power_profile_cmd_v2 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. + * struct iwl_geo_tx_power_profiles_cmd_v2 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation * @table: offset profile per band. * @table_revision: 0 for not-South Korea, 1 for South Korea (the name is misleading) @@ -451,7 +484,7 @@ struct iwl_geo_tx_power_profiles_cmd_v2 { } __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_2 */ /** - * struct iwl_geo_tx_power_profile_cmd_v3 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. + * struct iwl_geo_tx_power_profiles_cmd_v3 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation * @table: offset profile per band. * @table_revision: 0 for not-South Korea, 1 for South Korea (the name is misleading) @@ -463,7 +496,7 @@ struct iwl_geo_tx_power_profiles_cmd_v3 { } __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_3 */ /** - * struct iwl_geo_tx_power_profile_cmd_v4 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. + * struct iwl_geo_tx_power_profiles_cmd_v4 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation * @table: offset profile per band. * @table_revision: 0 for not-South Korea, 1 for South Korea (the name is misleading) @@ -475,7 +508,7 @@ struct iwl_geo_tx_power_profiles_cmd_v4 { } __packed; /* PER_CHAIN_LIMIT_OFFSET_CMD_VER_4 */ /** - * struct iwl_geo_tx_power_profile_cmd_v5 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. + * struct iwl_geo_tx_power_profiles_cmd_v5 - struct for PER_CHAIN_LIMIT_OFFSET_CMD cmd. * @ops: operations, value from &enum iwl_geo_per_chain_offset_operation * @table: offset profile per band. * @table_revision: 0 for not-South Korea, 1 for South Korea (the name is misleading) @@ -503,15 +536,45 @@ struct iwl_geo_tx_power_profiles_resp { } __packed; /* PER_CHAIN_LIMIT_OFFSET_RSP */ /** + * enum iwl_ppag_flags - PPAG enable masks + * @IWL_PPAG_ETSI_MASK: enable PPAG in ETSI + * @IWL_PPAG_CHINA_MASK: enable PPAG in China + * @IWL_PPAG_ETSI_LPI_UHB_MASK: enable LPI in ETSI for UHB + * @IWL_PPAG_ETSI_VLP_UHB_MASK: enable VLP in ETSI for UHB + * @IWL_PPAG_ETSI_SP_UHB_MASK: enable SP in ETSI for UHB + * @IWL_PPAG_USA_LPI_UHB_MASK: enable LPI in USA for UHB + * @IWL_PPAG_USA_VLP_UHB_MASK: enable VLP in USA for UHB + * @IWL_PPAG_USA_SP_UHB_MASK: enable SP in USA for UHB + * @IWL_PPAG_CANADA_LPI_UHB_MASK: enable LPI in CANADA for UHB + * @IWL_PPAG_CANADA_VLP_UHB_MASK: enable VLP in CANADA for UHB + * @IWL_PPAG_CANADA_SP_UHB_MASK: enable SP in CANADA for UHB + */ +enum iwl_ppag_flags { + IWL_PPAG_ETSI_MASK = BIT(0), + IWL_PPAG_CHINA_MASK = BIT(1), + IWL_PPAG_ETSI_LPI_UHB_MASK = BIT(2), + IWL_PPAG_ETSI_VLP_UHB_MASK = BIT(3), + IWL_PPAG_ETSI_SP_UHB_MASK = BIT(4), + IWL_PPAG_USA_LPI_UHB_MASK = BIT(5), + IWL_PPAG_USA_VLP_UHB_MASK = BIT(6), + IWL_PPAG_USA_SP_UHB_MASK = BIT(7), + IWL_PPAG_CANADA_LPI_UHB_MASK = BIT(8), + IWL_PPAG_CANADA_VLP_UHB_MASK = BIT(9), + IWL_PPAG_CANADA_SP_UHB_MASK = BIT(10), +}; + +/** * union iwl_ppag_table_cmd - union for all versions of PPAG command * @v1: version 1 * @v2: version 2 - * - * @flags: bit 0 - indicates enablement of PPAG for ETSI - * bit 1 - indicates enablement of PPAG for CHINA BIOS - * bit 1 can be used only in v3 (identical to v2) - * @gain: table of antenna gain values per chain and sub-band - * @reserved: reserved + * version 3, 4, 5 and 6 are the same structure as v2, + * but has a different format of the flags bitmap + * @v1.flags: values from &enum iwl_ppag_flags + * @v1.gain: table of antenna gain values per chain and sub-band + * @v1.reserved: reserved + * @v2.flags: values from &enum iwl_ppag_flags + * @v2.gain: table of antenna gain values per chain and sub-band + * @v2.reserved: reserved */ union iwl_ppag_table_cmd { struct { @@ -526,6 +589,11 @@ union iwl_ppag_table_cmd { } v2; } __packed; +#define IWL_PPAG_CMD_V4_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK) +#define IWL_PPAG_CMD_V5_MASK (IWL_PPAG_CMD_V4_MASK | \ + IWL_PPAG_ETSI_LPI_UHB_MASK | \ + IWL_PPAG_USA_LPI_UHB_MASK) + #define MCC_TO_SAR_OFFSET_TABLE_ROW_SIZE 26 #define MCC_TO_SAR_OFFSET_TABLE_COL_SIZE 13 @@ -667,4 +735,44 @@ struct iwl_beacon_filter_cmd { #define IWL_BF_CMD_CONFIG_DEFAULTS IWL_BF_CMD_CONFIG(_DEFAULT) #define IWL_BF_CMD_CONFIG_D0I3 IWL_BF_CMD_CONFIG(_D0I3) + +#define DEFAULT_TPE_TX_POWER 0x7F + +/* + * Bandwidth: 20/40/80/(160/80+80)/320 + */ +#define IWL_MAX_TX_EIRP_PWR_MAX_SIZE 5 +#define IWL_MAX_TX_EIRP_PSD_PWR_MAX_SIZE 16 + +enum iwl_6ghz_ap_type { + IWL_6GHZ_AP_TYPE_LPI, + IWL_6GHZ_AP_TYPE_SP, + IWL_6GHZ_AP_TYPE_VLP, +}; /* PHY_AP_TYPE_API_E_VER_1 */ + +/** + * struct iwl_txpower_constraints_cmd + * AP_TX_POWER_CONSTRAINTS_CMD + * Used for VLP/LPI/AFC Access Point power constraints for 6GHz channels + * @link_id: linkId + * @ap_type: see &enum iwl_ap_type + * @eirp_pwr: 8-bit 2s complement signed integer in the range + * -64 dBm to 63 dBm with a 0.5 dB step + * default &DEFAULT_TPE_TX_POWER (no maximum limit) + * @psd_pwr: 8-bit 2s complement signed integer in the range + * -63.5 to +63 dBm/MHz with a 0.5 step + * value - 128 indicates that the corresponding 20 + * MHz channel cannot be used for transmission. + * value +127 indicates that no maximum PSD limit + * is specified for the corresponding 20 MHz channel + * default &DEFAULT_TPE_TX_POWER (no maximum limit) + * @reserved: reserved (padding) + */ +struct iwl_txpower_constraints_cmd { + __le16 link_id; + __le16 ap_type; + __s8 eirp_pwr[IWL_MAX_TX_EIRP_PWR_MAX_SIZE]; + __s8 psd_pwr[IWL_MAX_TX_EIRP_PSD_PWR_MAX_SIZE]; + u8 reserved[3]; +} __packed; /* PHY_AP_TX_POWER_CONSTRAINTS_CMD_API_S_VER_1 */ #endif /* __iwl_fw_api_power_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/rfi.h b/sys/contrib/dev/iwlwifi/fw/api/rfi.h index 1a84a4081e7c..34d664023473 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/rfi.h +++ b/sys/contrib/dev/iwlwifi/fw/api/rfi.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2020-2021 Intel Corporation + * Copyright (C) 2020-2021, 2023 Intel Corporation */ #ifndef __iwl_fw_api_rfi_h__ #define __iwl_fw_api_rfi_h__ @@ -25,8 +25,9 @@ struct iwl_rfi_lut_entry { /** * struct iwl_rfi_config_cmd - RFI configuration table * - * @entry: a table can have 24 frequency/channel mappings + * @table: a table can have 24 frequency/channel mappings * @oem: specifies if this is the default table or set by OEM + * @reserved: (reserved/padding) */ struct iwl_rfi_config_cmd { struct iwl_rfi_lut_entry table[IWL_RFI_LUT_SIZE]; @@ -35,7 +36,7 @@ struct iwl_rfi_config_cmd { } __packed; /* RFI_CONFIG_CMD_API_S_VER_1 */ /** - * iwl_rfi_freq_table_status - status of the frequency table query + * enum iwl_rfi_freq_table_status - status of the frequency table query * @RFI_FREQ_TABLE_OK: can be used * @RFI_FREQ_TABLE_DVFS_NOT_READY: DVFS is not ready yet, should try later * @RFI_FREQ_TABLE_DISABLED: the feature is disabled in FW diff --git a/sys/contrib/dev/iwlwifi/fw/api/rs.h b/sys/contrib/dev/iwlwifi/fw/api/rs.h index a1a272433b09..1a60f0cdf972 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/rs.h +++ b/sys/contrib/dev/iwlwifi/fw/api/rs.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2022, 2024 Intel Corporation * Copyright (C) 2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_rs_h__ @@ -9,7 +9,7 @@ #include "mac.h" /** - * enum iwl_tlc_mng_cfg_flags_enum - options for TLC config flags + * enum iwl_tlc_mng_cfg_flags - options for TLC config flags * @IWL_TLC_MNG_CFG_FLAGS_STBC_MSK: enable STBC. For HE this enables STBC for * bandwidths <= 80MHz * @IWL_TLC_MNG_CFG_FLAGS_LDPC_MSK: enable LDPC diff --git a/sys/contrib/dev/iwlwifi/fw/api/rx.h b/sys/contrib/dev/iwlwifi/fw/api/rx.h index c8ae4d8005c7..ec89e9576d2e 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/rx.h +++ b/sys/contrib/dev/iwlwifi/fw/api/rx.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -374,7 +374,7 @@ enum iwl_rx_phy_eht_data1 { IWL_RX_PHY_DATA1_EHT_RU_ALLOC_B1_B7 = 0x0000fe00, }; -/* goes into Metadata DW 7 */ +/* goes into Metadata DW 7 (Qu) or 8 (So or higher) */ enum iwl_rx_phy_he_data2 { /* info type: HE MU-EXT */ /* the a1/a2/... is what the PHY/firmware calls the values */ @@ -390,7 +390,7 @@ enum iwl_rx_phy_he_data2 { IWL_RX_PHY_DATA2_HE_TB_EXT_SPTL_REUSE4 = 0x0000f000, }; -/* goes into Metadata DW 8 */ +/* goes into Metadata DW 8 (Qu) or 7 (So or higher) */ enum iwl_rx_phy_he_data3 { /* info type: HE MU-EXT */ IWL_RX_PHY_DATA3_HE_MU_EXT_CH1_RU1 = 0x000000ff, /* c1 */ @@ -411,10 +411,9 @@ enum iwl_rx_phy_he_he_data4 { IWL_RX_PHY_DATA4_HE_MU_EXT_PREAMBLE_PUNC_TYPE_MASK = 0x0600, }; -/* goes into Metadata DW 7 */ +/* goes into Metadata DW 8 (Qu has no EHT) */ enum iwl_rx_phy_eht_data2 { /* info type: EHT-MU-EXT */ - /* OFDM_RX_VECTOR_COMMON_RU_ALLOC_0_OUT */ IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_A1 = 0x000001ff, IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_A2 = 0x0003fe00, IWL_RX_PHY_DATA2_EHT_MU_EXT_RU_ALLOC_B1 = 0x07fc0000, @@ -423,11 +422,10 @@ enum iwl_rx_phy_eht_data2 { IWL_RX_PHY_DATA2_EHT_TB_EXT_TRIG_SIGA1 = 0xffffffff, }; -/* goes into Metadata DW 8 */ +/* goes into Metadata DW 7 (Qu has no EHT) */ enum iwl_rx_phy_eht_data3 { + /* note: low 8 bits cannot be used */ /* info type: EHT-MU-EXT */ - /* OFDM_RX_VECTOR_COMMON_RU_ALLOC_1_OUT */ - IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_B2 = 0x000001ff, IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_C1 = 0x0003fe00, IWL_RX_PHY_DATA3_EHT_MU_EXT_RU_ALLOC_C2 = 0x07fc0000, }; @@ -435,10 +433,10 @@ enum iwl_rx_phy_eht_data3 { /* goes into Metadata DW 4 */ enum iwl_rx_phy_eht_data4 { /* info type: EHT-MU-EXT */ - /* OFDM_RX_VECTOR_COMMON_RU_ALLOC_2_OUT */ IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_D1 = 0x000001ff, IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_D2 = 0x0003fe00, IWL_RX_PHY_DATA4_EHT_MU_EXT_SIGB_MCS = 0x000c0000, + IWL_RX_PHY_DATA4_EHT_MU_EXT_RU_ALLOC_B2 = 0x1ff00000, }; /* goes into Metadata DW 16 */ @@ -715,7 +713,15 @@ struct iwl_rx_mpdu_desc { __le32 reorder_data; union { + /** + * @v1: version 1 of the remaining RX descriptor, + * see &struct iwl_rx_mpdu_desc_v1 + */ struct iwl_rx_mpdu_desc_v1 v1; + /** + * @v3: version 3 of the remaining RX descriptor, + * see &struct iwl_rx_mpdu_desc_v3 + */ struct iwl_rx_mpdu_desc_v3 v3; }; } __packed; /* RX_MPDU_RES_START_API_S_VER_3, @@ -989,7 +995,7 @@ struct iwl_ba_window_status_notif { } __packed; /* BA_WINDOW_STATUS_NTFY_API_S_VER_1 */ /** - * struct iwl_rfh_queue_config - RX queue configuration + * struct iwl_rfh_queue_data - RX queue configuration * @q_num: Q num * @enable: enable queue * @reserved: alignment diff --git a/sys/contrib/dev/iwlwifi/fw/api/scan.h b/sys/contrib/dev/iwlwifi/fw/api/scan.h index 93078f8cc08c..8598031567bb 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/scan.h +++ b/sys/contrib/dev/iwlwifi/fw/api/scan.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -14,6 +14,10 @@ */ enum iwl_scan_subcmd_ids { /** + * @CHANNEL_SURVEY_NOTIF: &struct iwl_umac_scan_channel_survey_notif + */ + CHANNEL_SURVEY_NOTIF = 0xFB, + /** * @OFFLOAD_MATCH_INFO_NOTIF: &struct iwl_scan_offload_match_info */ OFFLOAD_MATCH_INFO_NOTIF = 0xFC, @@ -62,6 +66,8 @@ struct iwl_ssid_ie { #define IWL_FAST_SCHED_SCAN_ITERATIONS 3 #define IWL_MAX_SCHED_SCAN_PLANS 2 +#define IWL_MAX_NUM_NOISE_RESULTS 22 + enum scan_framework_client { SCAN_CLIENT_SCHED_SCAN = BIT(0), SCAN_CLIENT_NETDETECT = BIT(1), @@ -143,7 +149,7 @@ struct iwl_scan_offload_profile_cfg_data { } __packed; /** - * struct iwl_scan_offload_profile_cfg + * struct iwl_scan_offload_profile_cfg_v1 - scan offload profile config * @profiles: profiles to search for match * @data: the rest of the data for profile_cfg */ @@ -417,7 +423,7 @@ struct iwl_lmac_scan_complete_notif { } __packed; /** - * struct iwl_scan_offload_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 + * struct iwl_periodic_scan_complete - PERIODIC_SCAN_COMPLETE_NTF_API_S_VER_2 * @last_schedule_line: last schedule line executed (fast or regular) * @last_schedule_iteration: last scan iteration executed before scan abort * @status: &enum iwl_scan_offload_complete_status @@ -437,10 +443,10 @@ struct iwl_periodic_scan_complete { /* UMAC Scan API */ /* The maximum of either of these cannot exceed 8, because we use an - * 8-bit mask (see IWL_MVM_SCAN_MASK in mvm.h). + * 8-bit mask (see enum iwl_scan_status). */ -#define IWL_MVM_MAX_UMAC_SCANS 4 -#define IWL_MVM_MAX_LMAC_SCANS 1 +#define IWL_MAX_UMAC_SCANS 4 +#define IWL_MAX_LMAC_SCANS 1 enum scan_config_flags { SCAN_CONFIG_FLAG_ACTIVATE = BIT(0), @@ -642,10 +648,13 @@ enum iwl_umac_scan_general_flags { * notification per channel or not. * @IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER: Whether to allow channel * reorder optimization or not. + * @IWL_UMAC_SCAN_GEN_FLAGS2_COLLECT_CHANNEL_STATS: Enable channel statistics + * collection when #IWL_UMAC_SCAN_GEN_FLAGS_V2_FORCE_PASSIVE is set. */ enum iwl_umac_scan_general_flags2 { IWL_UMAC_SCAN_GEN_FLAGS2_NOTIF_PER_CHNL = BIT(0), IWL_UMAC_SCAN_GEN_FLAGS2_ALLOW_CHNL_REORDER = BIT(1), + IWL_UMAC_SCAN_GEN_FLAGS2_COLLECT_CHANNEL_STATS = BIT(3), }; /** @@ -780,7 +789,7 @@ struct iwl_scan_req_umac_tail_v1 { } __packed; /** - * struct iwl_scan_req_umac_tail - the rest of the UMAC scan request command + * struct iwl_scan_req_umac_tail_v2 - the rest of the UMAC scan request command * parameters following channels configuration array. * @schedule: two scheduling plans. * @delay: delay in TUs before starting the first scan iteration @@ -1076,7 +1085,7 @@ struct iwl_scan_req_params_v12 { } __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_12 */ /** - * struct iwl_scan_req_params_v16 + * struct iwl_scan_req_params_v17 - scan request parameters (v17) * @general_params: &struct iwl_scan_general_params_v11 * @channel_params: &struct iwl_scan_channel_params_v7 * @periodic_params: &struct iwl_scan_periodic_parms_v1 @@ -1102,7 +1111,7 @@ struct iwl_scan_req_umac_v12 { } __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_12 */ /** - * struct iwl_scan_req_umac_v16 + * struct iwl_scan_req_umac_v17 - scan request command (v17) * @uid: scan id, &enum iwl_umac_scan_uid_offsets * @ooc_priority: out of channel priority - &enum iwl_scan_priority * @scan_params: scan parameters @@ -1258,4 +1267,26 @@ 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_channel_survey_notif - data for survey + * @channel: the channel scanned + * @band: band of channel + * @noise: noise floor measurements in negative dBm, invalid 0xff + * @reserved: for future use and alignment + * @active_time: time in ms the radio was turned on (on the channel) + * @busy_time: time in ms the channel was sensed busy, 0 for a clean channel + * @tx_time: time the radio spent transmitting data + * @rx_time: time the radio spent receiving data + */ +struct iwl_umac_scan_channel_survey_notif { + __le32 channel; + __le32 band; + u8 noise[IWL_MAX_NUM_NOISE_RESULTS]; + u8 reserved[2]; + __le32 active_time; + __le32 busy_time; + __le32 tx_time; + __le32 rx_time; +} __packed; /* SCAN_CHANNEL_SURVEY_NTF_API_S_VER_1 */ + #endif /* __iwl_fw_api_scan_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/sta.h b/sys/contrib/dev/iwlwifi/fw/api/sta.h index 18f9470db301..893049edb4ae 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/sta.h +++ b/sys/contrib/dev/iwlwifi/fw/api/sta.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2021 Intel Corporation + * Copyright (C) 2012-2014, 2018-2021, 2023 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -109,6 +109,7 @@ enum iwl_sta_flags { * @STA_KEY_FLG_EN_MSK: mask for encryption algorithmi value * @STA_KEY_FLG_WEP_KEY_MAP: wep is either a group key (0 - legacy WEP) or from * station info array (1 - n 1X mode) + * @STA_KEY_FLG_AMSDU_SPP: SPP (signaling and payload protected) A-MSDU * @STA_KEY_FLG_KEYID_MSK: the index of the key * @STA_KEY_FLG_KEYID_POS: key index bit position * @STA_KEY_NOT_VALID: key is invalid @@ -129,6 +130,7 @@ enum iwl_sta_key_flag { STA_KEY_FLG_EN_MSK = (7 << 0), STA_KEY_FLG_WEP_KEY_MAP = BIT(3), + STA_KEY_FLG_AMSDU_SPP = BIT(7), STA_KEY_FLG_KEYID_POS = 8, STA_KEY_FLG_KEYID_MSK = (3 << STA_KEY_FLG_KEYID_POS), STA_KEY_NOT_VALID = BIT(11), diff --git a/sys/contrib/dev/iwlwifi/fw/api/stats.h b/sys/contrib/dev/iwlwifi/fw/api/stats.h index 898e62326e6c..2271b19213fa 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/stats.h +++ b/sys/contrib/dev/iwlwifi/fw/api/stats.h @@ -1,12 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018, 2020 - 2021 Intel Corporation + * Copyright (C) 2012-2014, 2018, 2020 - 2021, 2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_stats_h__ #define __iwl_fw_api_stats_h__ #include "mac.h" +#include "mac-cfg.h" struct mvm_statistics_dbg { __le32 burst_check; @@ -412,6 +413,49 @@ struct iwl_statistics_cmd { #define MAX_BCAST_FILTER_NUM 8 /** + * enum iwl_statistics_notify_type_id - type_id used in system statistics + * command + * @IWL_STATS_NTFY_TYPE_ID_OPER: request legacy statistics + * @IWL_STATS_NTFY_TYPE_ID_OPER_PART1: request operational part1 statistics + * @IWL_STATS_NTFY_TYPE_ID_OPER_PART2: request operational part2 statistics + * @IWL_STATS_NTFY_TYPE_ID_OPER_PART3: request operational part3 statistics + * @IWL_STATS_NTFY_TYPE_ID_OPER_PART4: request operational part4 statistics + */ +enum iwl_statistics_notify_type_id { + IWL_STATS_NTFY_TYPE_ID_OPER = BIT(0), + IWL_STATS_NTFY_TYPE_ID_OPER_PART1 = BIT(1), + IWL_STATS_NTFY_TYPE_ID_OPER_PART2 = BIT(2), + IWL_STATS_NTFY_TYPE_ID_OPER_PART3 = BIT(3), + IWL_STATS_NTFY_TYPE_ID_OPER_PART4 = BIT(4), +}; + +/** + * enum iwl_statistics_cfg_flags - cfg_mask used in system statistics command + * @IWL_STATS_CFG_FLG_DISABLE_NTFY_MSK: 0 for enable, 1 for disable + * @IWL_STATS_CFG_FLG_ON_DEMAND_NTFY_MSK: 0 for periodic, 1 for on-demand + * @IWL_STATS_CFG_FLG_RESET_MSK: 0 for reset statistics after + * sending the notification, 1 for do not reset statistics after sending + * the notification + */ +enum iwl_statistics_cfg_flags { + IWL_STATS_CFG_FLG_DISABLE_NTFY_MSK = BIT(0), + IWL_STATS_CFG_FLG_ON_DEMAND_NTFY_MSK = BIT(1), + IWL_STATS_CFG_FLG_RESET_MSK = BIT(2), +}; + +/** + * struct iwl_system_statistics_cmd - system statistics command + * @cfg_mask: configuration mask, &enum iwl_statistics_cfg_flags + * @config_time_sec: time in sec for periodic notification + * @type_id_mask: type_id masks, &enum iwl_statistics_notify_type_id + */ +struct iwl_system_statistics_cmd { + __le32 cfg_mask; + __le32 config_time_sec; + __le32 type_id_mask; +} __packed; /* STATISTICS_FW_CMD_API_S_VER_1 */ + +/** * enum iwl_fw_statistics_type * * @FW_STATISTICS_OPERATIONAL: operational statistics @@ -447,7 +491,49 @@ struct iwl_statistics_ntfy_hdr { }; /* STATISTICS_NTFY_HDR_API_S_VER_1 */ /** - * struct iwl_statistics_ntfy_per_mac + * struct iwl_stats_ntfy_per_link + * + * @beacon_filter_average_energy: Average energy [-dBm] of the 2 + * antennas. + * @air_time: air time + * @beacon_counter: all beacons (both filtered and not filtered) + * @beacon_average_energy: Average energy [-dBm] of all beacons + * (both filtered and not filtered) + * @beacon_rssi_a: beacon RSSI on antenna A + * @beacon_rssi_b: beacon RSSI on antenna B + * @rx_bytes: RX byte count + */ +struct iwl_stats_ntfy_per_link { + __le32 beacon_filter_average_energy; + __le32 air_time; + __le32 beacon_counter; + __le32 beacon_average_energy; + __le32 beacon_rssi_a; + __le32 beacon_rssi_b; + __le32 rx_bytes; +} __packed; /* STATISTICS_NTFY_PER_LINK_API_S_VER_1 */ + +/** + * struct iwl_stats_ntfy_part1_per_link + * + * @rx_time: rx time + * @tx_time: tx time + * @rx_action: action frames handled by FW + * @tx_action: action frames generated and transmitted by FW + * @cca_defers: cca defer count + * @beacon_filtered: filtered out beacons + */ +struct iwl_stats_ntfy_part1_per_link { + __le64 rx_time; + __le64 tx_time; + __le32 rx_action; + __le32 tx_action; + __le32 cca_defers; + __le32 beacon_filtered; +} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_PER_LINK_API_S_VER_1 */ + +/** + * struct iwl_stats_ntfy_per_mac * * @beacon_filter_average_energy: Average energy [-dBm] of the 2 * antennas. @@ -459,7 +545,7 @@ struct iwl_statistics_ntfy_hdr { * @beacon_rssi_b: beacon RSSI on antenna B * @rx_bytes: RX byte count */ -struct iwl_statistics_ntfy_per_mac { +struct iwl_stats_ntfy_per_mac { __le32 beacon_filter_average_energy; __le32 air_time; __le32 beacon_counter; @@ -470,7 +556,7 @@ struct iwl_statistics_ntfy_per_mac { } __packed; /* STATISTICS_NTFY_PER_MAC_API_S_VER_1 */ #define IWL_STATS_MAX_BW_INDEX 5 -/** struct iwl_statistics_ntfy_per_phy +/** struct iwl_stats_ntfy_per_phy * @channel_load: channel load * @channel_load_by_us: device contribution to MCLM * @channel_load_not_by_us: other devices' contribution to MCLM @@ -485,7 +571,7 @@ struct iwl_statistics_ntfy_per_mac { * per channel BW. note BACK counted as 1 * @last_tx_ch_width_indx: last txed frame channel width index */ -struct iwl_statistics_ntfy_per_phy { +struct iwl_stats_ntfy_per_phy { __le32 channel_load; __le32 channel_load_by_us; __le32 channel_load_not_by_us; @@ -499,23 +585,62 @@ struct iwl_statistics_ntfy_per_phy { } __packed; /* STATISTICS_NTFY_PER_PHY_API_S_VER_1 */ /** - * struct iwl_statistics_ntfy_per_sta + * struct iwl_stats_ntfy_per_sta * * @average_energy: in fact it is minus the energy.. */ -struct iwl_statistics_ntfy_per_sta { +struct iwl_stats_ntfy_per_sta { __le32 average_energy; } __packed; /* STATISTICS_NTFY_PER_STA_API_S_VER_1 */ -#define IWL_STATS_MAX_PHY_OPERTINAL 3 +#define IWL_STATS_MAX_PHY_OPERATIONAL 3 +#define IWL_STATS_MAX_FW_LINKS (IWL_MVM_FW_MAX_LINK_ID + 1) + +/** + * struct iwl_system_statistics_notif_oper + * + * @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 + * @per_sta: per sta statistics, &struct iwl_stats_ntfy_per_sta + */ +struct iwl_system_statistics_notif_oper { + __le32 time_stamp; + struct iwl_stats_ntfy_per_link per_link[IWL_STATS_MAX_FW_LINKS]; + struct iwl_stats_ntfy_per_phy per_phy[IWL_STATS_MAX_PHY_OPERATIONAL]; + struct iwl_stats_ntfy_per_sta per_sta[IWL_MVM_STATION_COUNT_MAX]; +} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_API_S_VER_3 */ + +/** + * struct iwl_system_statistics_part1_notif_oper + * + * @time_stamp: time when the notification is sent from firmware + * @per_link: per link statistics &struct iwl_stats_ntfy_part1_per_link + * @per_phy_crc_error_stats: per phy crc error statistics + */ +struct iwl_system_statistics_part1_notif_oper { + __le32 time_stamp; + struct iwl_stats_ntfy_part1_per_link per_link[IWL_STATS_MAX_FW_LINKS]; + __le32 per_phy_crc_error_stats[IWL_STATS_MAX_PHY_OPERATIONAL]; +} __packed; /* STATISTICS_FW_NTFY_OPERATIONAL_PART1_API_S_VER_4 */ + +/** + * struct iwl_system_statistics_end_notif + * + * @time_stamp: time when the notification is sent from firmware + */ +struct iwl_system_statistics_end_notif { + __le32 time_stamp; +} __packed; /* STATISTICS_FW_NTFY_END_API_S_VER_1 */ + /** * struct iwl_statistics_operational_ntfy * * @hdr: general statistics header * @flags: bitmap of possible notification structures - * @per_mac_stats: per mac statistics, &struct iwl_statistics_ntfy_per_mac - * @per_phy_stats: per phy statistics, &struct iwl_statistics_ntfy_per_phy - * @per_sta_stats: per sta statistics, &struct iwl_statistics_ntfy_per_sta + * @per_mac: per mac statistics, &struct iwl_stats_ntfy_per_mac + * @per_phy: per phy statistics, &struct iwl_stats_ntfy_per_phy + * @per_sta: per sta statistics, &struct iwl_stats_ntfy_per_sta * @rx_time: rx time * @tx_time: usec the radio is transmitting. * @on_time_rf: The total time in usec the RF is awake. @@ -524,9 +649,9 @@ struct iwl_statistics_ntfy_per_sta { struct iwl_statistics_operational_ntfy { struct iwl_statistics_ntfy_hdr hdr; __le32 flags; - struct iwl_statistics_ntfy_per_mac per_mac_stats[MAC_INDEX_AUX]; - struct iwl_statistics_ntfy_per_phy per_phy_stats[IWL_STATS_MAX_PHY_OPERTINAL]; - struct iwl_statistics_ntfy_per_sta per_sta_stats[IWL_MVM_STATION_COUNT_MAX]; + struct iwl_stats_ntfy_per_mac per_mac[MAC_INDEX_AUX]; + struct iwl_stats_ntfy_per_phy per_phy[IWL_STATS_MAX_PHY_OPERATIONAL]; + struct iwl_stats_ntfy_per_sta per_sta[IWL_MVM_STATION_COUNT_MAX]; __le64 rx_time; __le64 tx_time; __le64 on_time_rf; diff --git a/sys/contrib/dev/iwlwifi/fw/api/time-event.h b/sys/contrib/dev/iwlwifi/fw/api/time-event.h index 7cc706731d70..f4b827b58bd3 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/time-event.h +++ b/sys/contrib/dev/iwlwifi/fw/api/time-event.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2020, 2022 Intel Corporation + * Copyright (C) 2012-2014, 2018-2020, 2022-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -335,6 +335,65 @@ struct iwl_hs20_roc_res { __le32 status; } __packed; /* HOT_SPOT_RSP_API_S_VER_1 */ +/* + * Activity types for the ROC command + * @ROC_ACTIVITY_HOTSPOT: ROC for hs20 activity + * @ROC_ACTIVITY_P2P_DISC: ROC for p2p discoverability activity + * @ROC_ACTIVITY_P2P_TXRX: ROC for p2p action frames activity + * @ROC_ACTIVITY_P2P_NEG: ROC for p2p negotiation (used also for TX) + */ +enum iwl_roc_activity { + ROC_ACTIVITY_HOTSPOT, + ROC_ACTIVITY_P2P_DISC, + ROC_ACTIVITY_P2P_TXRX, + ROC_ACTIVITY_P2P_NEG, + ROC_NUM_ACTIVITIES +}; /* ROC_ACTIVITY_API_E_VER_1 */ + +/* + * ROC command + * + * Command requests the firmware to remain on a channel for a certain duration. + * + * ( MAC_CONF_GROUP 0x3, ROC_CMD 0xE ) + * + * @action: action to perform, see &enum iwl_ctxt_action + * @activity: type of activity, see &enum iwl_roc_activity + * @sta_id: station id, resumed during "Remain On Channel" activity. + * @channel_info: &struct iwl_fw_channel_info + * @node_addr: node MAC address for Rx filtering + * @reserved: align to a dword + * @max_delay: max delay the ROC can start in TU + * @duration: remain on channel duration in TU + */ +struct iwl_roc_req { + __le32 action; + __le32 activity; + __le32 sta_id; + struct iwl_fw_channel_info channel_info; + u8 node_addr[ETH_ALEN]; + __le16 reserved; + __le32 max_delay; + __le32 duration; +} __packed; /* ROC_CMD_API_S_VER_3 */ + +/* + * ROC notification + * + * Notification when ROC startes and when ROC ended. + * + * ( MAC_CONF_GROUP 0x3, ROC_NOTIF 0xf8 ) + * + * @status: true if ROC succeeded to start + * @start_end: true if ROC started, false if ROC ended + * @activity: notification to which activity - &enum iwl_roc_activity + */ +struct iwl_roc_notif { + __le32 success; + __le32 started; + __le32 activity; +} __packed; /* ROC_NOTIF_API_S_VER_1 */ + /** * enum iwl_mvm_session_prot_conf_id - session protection's configurations * @SESSION_PROTECT_CONF_ASSOC: Start a session protection for association. @@ -375,8 +434,8 @@ enum iwl_mvm_session_prot_conf_id { /** * struct iwl_mvm_session_prot_cmd - configure a session protection - * @id_and_color: the id and color of the mac for which this session protection - * is sent + * @id_and_color: the id and color of the link (or mac, for command version 1) + * for which this session protection is sent * @action: can be either FW_CTXT_ACTION_ADD or FW_CTXT_ACTION_REMOVE, * see &enum iwl_ctxt_action * @conf_id: see &enum iwl_mvm_session_prot_conf_id @@ -397,11 +456,15 @@ struct iwl_mvm_session_prot_cmd { __le32 duration_tu; __le32 repetition_count; __le32 interval; -} __packed; /* SESSION_PROTECTION_CMD_API_S_VER_1 */ +} __packed; +/* SESSION_PROTECTION_CMD_API_S_VER_1 and + * SESSION_PROTECTION_CMD_API_S_VER_2 + */ /** * struct iwl_mvm_session_prot_notif - session protection started / ended - * @mac_id: the mac id for which the session protection started / ended + * @mac_link_id: the mac id (or link id, for notif ver > 2) for which the + * session protection started / ended * @status: 1 means success, 0 means failure * @start: 1 means the session protection started, 0 means it ended * @conf_id: see &enum iwl_mvm_session_prot_conf_id @@ -410,10 +473,13 @@ struct iwl_mvm_session_prot_cmd { * and end even the firmware could not schedule it. */ struct iwl_mvm_session_prot_notif { - __le32 mac_id; + __le32 mac_link_id; __le32 status; __le32 start; __le32 conf_id; -} __packed; /* SESSION_PROTECTION_NOTIFICATION_API_S_VER_2 */ +} __packed; +/* SESSION_PROTECTION_NOTIFICATION_API_S_VER_2 and + * SESSION_PROTECTION_NOTIFICATION_API_S_VER_3 + */ #endif /* __iwl_fw_api_time_event_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/tx.h b/sys/contrib/dev/iwlwifi/fw/api/tx.h index 842360b1e995..c5277e2f8cd4 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/tx.h +++ b/sys/contrib/dev/iwlwifi/fw/api/tx.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_fw_api_tx_h__ @@ -76,6 +76,8 @@ enum iwl_tx_flags { * to a secured STA * @IWL_TX_FLAGS_HIGH_PRI: high priority frame (like EAPOL) - can affect rate * selection, retry limits and BT kill + * @IWL_TX_FLAGS_RTS: firmware used an RTS + * @IWL_TX_FLAGS_CTS: firmware used CTS-to-self */ enum iwl_tx_cmd_flags { IWL_TX_FLAGS_CMD_RATE = BIT(0), @@ -696,6 +698,7 @@ enum iwl_mvm_ba_resp_flags { * @query_frame_cnt: SCD query frame count * @txed: number of frames sent in the aggregation (all-TIDs) * @done: number of frames that were Acked by the BA (all-TIDs) + * @rts_retry_cnt: RTS retry count * @reserved: reserved (for alignment) * @wireless_time: Wireless-media time * @tx_rate: the rate the aggregation was sent at @@ -716,7 +719,8 @@ struct iwl_mvm_compressed_ba_notif { __le16 query_frame_cnt; __le16 txed; __le16 done; - __le16 reserved; + u8 rts_retry_cnt; + u8 reserved; __le32 wireless_time; __le32 tx_rate; __le16 tfd_cnt; @@ -791,7 +795,8 @@ enum iwl_mac_beacon_flags { * @reserved: reserved * @link_id: the firmware id of the link that will use this beacon * @tim_idx: the offset of the tim IE in the beacon - * @tim_size: the length of the tim IE + * @tim_size: the length of the tim IE (version < 14) + * @btwt_offset: offset to the broadcast TWT IE if present (version >= 14) * @ecsa_offset: offset to the ECSA IE if present * @csa_offset: offset to the CSA IE if present * @frame: the template of the beacon frame @@ -803,14 +808,18 @@ struct iwl_mac_beacon_cmd { __le32 reserved; __le32 link_id; __le32 tim_idx; - __le32 tim_size; + union { + __le32 tim_size; + __le32 btwt_offset; + }; __le32 ecsa_offset; __le32 csa_offset; struct ieee80211_hdr frame[]; } __packed; /* BEACON_TEMPLATE_CMD_API_S_VER_10, * BEACON_TEMPLATE_CMD_API_S_VER_11, * BEACON_TEMPLATE_CMD_API_S_VER_12, - * BEACON_TEMPLATE_CMD_API_S_VER_13 + * BEACON_TEMPLATE_CMD_API_S_VER_13, + * BEACON_TEMPLATE_CMD_API_S_VER_14 */ struct iwl_beacon_notif { @@ -857,7 +866,7 @@ enum iwl_dump_control { }; /** - * struct iwl_tx_path_flush_cmd -- queue/FIFO flush command + * struct iwl_tx_path_flush_cmd_v1 -- queue/FIFO flush command * @queues_ctl: bitmap of queues to flush * @flush_ctl: control flags * @reserved: reserved @@ -884,6 +893,7 @@ struct iwl_tx_path_flush_cmd { /** * struct iwl_flush_queue_info - virtual flush queue info + * @tid: the tid to flush * @queue_num: virtual queue id * @read_before_flush: read pointer before flush * @read_after_flush: read pointer after flush @@ -897,6 +907,7 @@ struct iwl_flush_queue_info { /** * struct iwl_tx_path_flush_cmd_rsp -- queue/FIFO flush command response + * @sta_id: the station for which the queue was flushed * @num_flushed_queues: number of queues in queues array * @queues: all flushed queues */ diff --git a/sys/contrib/dev/iwlwifi/fw/api/txq.h b/sys/contrib/dev/iwlwifi/fw/api/txq.h index e018946310d1..e6c0f928a6bb 100644 --- a/sys/contrib/dev/iwlwifi/fw/api/txq.h +++ b/sys/contrib/dev/iwlwifi/fw/api/txq.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2019-2021 Intel Corporation + * Copyright (C) 2005-2014, 2019-2021, 2023-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -66,6 +66,16 @@ enum iwl_gen2_tx_fifo { IWL_GEN2_TRIG_TX_FIFO_VO, }; +enum iwl_bz_tx_fifo { + IWL_BZ_EDCA_TX_FIFO_BK, + IWL_BZ_EDCA_TX_FIFO_BE, + IWL_BZ_EDCA_TX_FIFO_VI, + IWL_BZ_EDCA_TX_FIFO_VO, + IWL_BZ_TRIG_TX_FIFO_BK, + IWL_BZ_TRIG_TX_FIFO_BE, + IWL_BZ_TRIG_TX_FIFO_VI, + IWL_BZ_TRIG_TX_FIFO_VO, +}; /** * enum iwl_tx_queue_cfg_actions - TXQ config options * @TX_QUEUE_CFG_ENABLE_QUEUE: enable a queue @@ -76,7 +86,7 @@ enum iwl_tx_queue_cfg_actions { TX_QUEUE_CFG_TFD_SHORT_FORMAT = BIT(1), }; -#define IWL_DEFAULT_QUEUE_SIZE_EHT (1024 * 4) +#define IWL_DEFAULT_QUEUE_SIZE_EHT (512 * 4) #define IWL_DEFAULT_QUEUE_SIZE_HE 1024 #define IWL_DEFAULT_QUEUE_SIZE 256 #define IWL_MGMT_QUEUE_SIZE 16 diff --git a/sys/contrib/dev/iwlwifi/fw/dbg.c b/sys/contrib/dev/iwlwifi/fw/dbg.c index ba73701781f5..57e1cdec6b27 100644 --- a/sys/contrib/dev/iwlwifi/fw/dbg.c +++ b/sys/contrib/dev/iwlwifi/fw/dbg.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2015-2017 Intel Deutschland GmbH */ @@ -22,7 +22,6 @@ * @fwrt_ptr: pointer to the buffer coming from fwrt * @trans_ptr: pointer to struct %iwl_trans_dump_data which contains the * transport's data. - * @trans_len: length of the valid data in trans_ptr * @fwrt_len: length of the valid data in fwrt_ptr */ struct iwl_fw_dump_ptrs { @@ -883,14 +882,14 @@ iwl_fw_error_dump_file(struct iwl_fw_runtime *fwrt, cpu_to_le32(fwrt->trans->hw_rev_step); memcpy(dump_info->fw_human_readable, fwrt->fw->human_readable, sizeof(dump_info->fw_human_readable)); - strncpy(dump_info->dev_human_readable, fwrt->trans->name, - sizeof(dump_info->dev_human_readable) - 1); + strscpy_pad(dump_info->dev_human_readable, fwrt->trans->name, + sizeof(dump_info->dev_human_readable)); #if defined(__linux__) - strncpy(dump_info->bus_human_readable, fwrt->dev->bus->name, - sizeof(dump_info->bus_human_readable) - 1); + strscpy_pad(dump_info->bus_human_readable, fwrt->dev->bus->name, + sizeof(dump_info->bus_human_readable)); #elif defined(__FreeBSD__) /* XXX TODO */ - strncpy(dump_info->bus_human_readable, "<bus>", - sizeof(dump_info->bus_human_readable) - 1); + strscpy_pad(dump_info->bus_human_readable, "<bus>", + sizeof(dump_info->bus_human_readable)); #endif dump_info->num_of_lmacs = fwrt->smem_cfg.num_lmacs; dump_info->lmac_err_id[0] = @@ -1029,64 +1028,78 @@ struct iwl_dump_ini_region_data { struct iwl_fwrt_dump_data *dump_data; }; -static int -iwl_dump_ini_prph_mac_iter(struct iwl_fw_runtime *fwrt, - struct iwl_dump_ini_region_data *reg_data, - void *range_ptr, u32 range_len, int idx) +static int iwl_dump_ini_prph_mac_iter_common(struct iwl_fw_runtime *fwrt, + void *range_ptr, u32 addr, + __le32 size) { - struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; struct iwl_fw_ini_error_dump_range *range = range_ptr; __le32 *val = range->data; - u32 prph_val; - u32 addr = le32_to_cpu(reg->addrs[idx]) + - le32_to_cpu(reg->dev_addr.offset); int i; range->internal_base_addr = cpu_to_le32(addr); - range->range_data_size = reg->dev_addr.size; - for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) { - prph_val = iwl_read_prph(fwrt->trans, addr + i); - if (iwl_trans_is_hw_error_value(prph_val)) - return -EBUSY; - *val++ = cpu_to_le32(prph_val); - } + range->range_data_size = size; + for (i = 0; i < le32_to_cpu(size); i += 4) + *val++ = cpu_to_le32(iwl_read_prph(fwrt->trans, addr + i)); return sizeof(*range) + le32_to_cpu(range->range_data_size); } static int -iwl_dump_ini_prph_phy_iter(struct iwl_fw_runtime *fwrt, +iwl_dump_ini_prph_mac_iter(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data, void *range_ptr, u32 range_len, int idx) { struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 addr = le32_to_cpu(reg->addrs[idx]) + + le32_to_cpu(reg->dev_addr.offset); + + return iwl_dump_ini_prph_mac_iter_common(fwrt, range_ptr, addr, + reg->dev_addr.size); +} + +static int +iwl_dump_ini_prph_mac_block_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, u32 range_len, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_addr_size *pairs = (void *)reg->addrs; + u32 addr = le32_to_cpu(reg->dev_addr_range.offset) + + le32_to_cpu(pairs[idx].addr); + + return iwl_dump_ini_prph_mac_iter_common(fwrt, range_ptr, addr, + pairs[idx].size); +} + +static int iwl_dump_ini_prph_phy_iter_common(struct iwl_fw_runtime *fwrt, + void *range_ptr, u32 addr, + __le32 size, __le32 offset) +{ struct iwl_fw_ini_error_dump_range *range = range_ptr; __le32 *val = range->data; u32 indirect_wr_addr = WMAL_INDRCT_RD_CMD1; u32 indirect_rd_addr = WMAL_MRSPF_1; u32 prph_val; - u32 addr = le32_to_cpu(reg->addrs[idx]); u32 dphy_state; u32 dphy_addr; int i; range->internal_base_addr = cpu_to_le32(addr); - range->range_data_size = reg->dev_addr.size; + range->range_data_size = size; if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) indirect_wr_addr = WMAL_INDRCT_CMD1; - indirect_wr_addr += le32_to_cpu(reg->dev_addr.offset); - indirect_rd_addr += le32_to_cpu(reg->dev_addr.offset); + indirect_wr_addr += le32_to_cpu(offset); + indirect_rd_addr += le32_to_cpu(offset); if (!iwl_trans_grab_nic_access(fwrt->trans)) return -EBUSY; - dphy_addr = (reg->dev_addr.offset) ? WFPM_LMAC2_PS_CTL_RW : - WFPM_LMAC1_PS_CTL_RW; + 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); - for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) { + for (i = 0; i < le32_to_cpu(size); i += 4) { if (dphy_state == HBUS_TIMEOUT || (dphy_state & WFPM_PS_CTL_RW_PHYRF_PD_FSM_CURSTATE_MSK) != WFPM_PHYRF_STATE_ON) { @@ -1105,6 +1118,33 @@ iwl_dump_ini_prph_phy_iter(struct iwl_fw_runtime *fwrt, return sizeof(*range) + le32_to_cpu(range->range_data_size); } +static int +iwl_dump_ini_prph_phy_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, u32 range_len, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + u32 addr = le32_to_cpu(reg->addrs[idx]); + + return iwl_dump_ini_prph_phy_iter_common(fwrt, range_ptr, addr, + reg->dev_addr.size, + reg->dev_addr.offset); +} + +static int +iwl_dump_ini_prph_phy_block_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, u32 range_len, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_addr_size *pairs = (void *)reg->addrs; + u32 addr = le32_to_cpu(pairs[idx].addr); + + return iwl_dump_ini_prph_phy_iter_common(fwrt, range_ptr, addr, + pairs[idx].size, + reg->dev_addr_range.offset); +} + static int iwl_dump_ini_csr_iter(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data, void *range_ptr, u32 range_len, int idx) @@ -1136,17 +1176,13 @@ static int iwl_dump_ini_config_iter(struct iwl_fw_runtime *fwrt, le32_to_cpu(reg->dev_addr.offset); int i; - /* we shouldn't get here if the trans doesn't have read_config32 */ - if (WARN_ON_ONCE(!trans->ops->read_config32)) - return -EOPNOTSUPP; - range->internal_base_addr = cpu_to_le32(addr); range->range_data_size = reg->dev_addr.size; for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) { int ret; u32 tmp; - ret = trans->ops->read_config32(trans, addr + i, &tmp); + ret = iwl_trans_read_config32(trans, addr + i, &tmp); if (ret < 0) return ret; @@ -1378,6 +1414,53 @@ out: return sizeof(*range) + le32_to_cpu(range->range_data_size); } +static int +iwl_dump_ini_prph_snps_dphyip_iter(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data, + void *range_ptr, u32 range_len, int idx) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + struct iwl_fw_ini_error_dump_range *range = range_ptr; + __le32 *val = range->data; + __le32 offset = reg->dev_addr.offset; + u32 indirect_rd_wr_addr = DPHYIP_INDIRECT; + u32 addr = le32_to_cpu(reg->addrs[idx]); + u32 dphy_state, dphy_addr, prph_val; + int i; + + range->internal_base_addr = cpu_to_le32(addr); + range->range_data_size = reg->dev_addr.size; + + if (!iwl_trans_grab_nic_access(fwrt->trans)) + return -EBUSY; + + 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); + + for (i = 0; i < le32_to_cpu(reg->dev_addr.size); i += 4) { + if (dphy_state == HBUS_TIMEOUT || + (dphy_state & WFPM_PS_CTL_RW_PHYRF_PD_FSM_CURSTATE_MSK) != + WFPM_PHYRF_STATE_ON) { + *val++ = cpu_to_le32(WFPM_DPHY_OFF); + continue; + } + + iwl_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_read_prph_no_grab(fwrt->trans, + indirect_rd_wr_addr); + *val++ = cpu_to_le32((prph_val & DPHYIP_INDIRECT_RD_MSK) >> + DPHYIP_INDIRECT_RD_SHIFT); + } + + iwl_trans_release_nic_access(fwrt->trans); + return sizeof(*range) + le32_to_cpu(range->range_data_size); +} + struct iwl_ini_rxf_data { u32 fifo_num; u32 size; @@ -1646,10 +1729,12 @@ iwl_dump_ini_mem_fill_header(struct iwl_fw_runtime *fwrt, /** * mask_apply_and_normalize - applies mask on val and normalize the result * - * The normalization is based on the first set bit in the mask - * * @val: value * @mask: mask to apply and to normalize with + * + * The normalization is based on the first set bit in the mask + * + * Returns: the extracted value */ static u32 mask_apply_and_normalize(u32 val, u32 mask) { @@ -1792,6 +1877,16 @@ static u32 iwl_dump_ini_mem_ranges(struct iwl_fw_runtime *fwrt, return iwl_tlv_array_len(reg_data->reg_tlv, reg, addrs); } +static u32 +iwl_dump_ini_mem_block_ranges(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + size_t size = sizeof(struct iwl_fw_ini_addr_size); + + return iwl_tlv_array_len_with_size(reg_data->reg_tlv, reg, size); +} + static u32 iwl_dump_ini_paging_ranges(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data) { @@ -1878,6 +1973,25 @@ static u32 iwl_dump_ini_mem_get_size(struct iwl_fw_runtime *fwrt, } static u32 +iwl_dump_ini_mem_block_get_size(struct iwl_fw_runtime *fwrt, + struct iwl_dump_ini_region_data *reg_data) +{ + struct iwl_fw_ini_region_tlv *reg = (void *)reg_data->reg_tlv->data; + 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); + int range; + + if (!ranges) + return 0; + + for (range = 0; range < ranges; range++) + size += le32_to_cpu(pairs[range].size); + + return size + ranges * sizeof(struct iwl_fw_ini_error_dump_range); +} + +static u32 iwl_dump_ini_paging_get_size(struct iwl_fw_runtime *fwrt, struct iwl_dump_ini_region_data *reg_data) { @@ -2092,15 +2206,16 @@ struct iwl_dump_ini_mem_ops { }; /** - * iwl_dump_ini_mem - * - * Creates a dump tlv and copy a memory region into it. - * Returns the size of the current dump tlv or 0 if failed + * iwl_dump_ini_mem - dump memory region * * @fwrt: fw runtime struct * @list: list to add the dump tlv to * @reg_data: memory region * @ops: memory dump operations + * + * Creates a dump tlv and copy a memory region into it. + * + * Returns: the size of the current dump tlv or 0 if failed */ static u32 iwl_dump_ini_mem(struct iwl_fw_runtime *fwrt, struct list_head *list, struct iwl_dump_ini_region_data *reg_data, @@ -2324,9 +2439,12 @@ static u32 iwl_dump_ini_info(struct iwl_fw_runtime *fwrt, struct iwl_fw_ini_debug_info_tlv *debug_info = (void *)node->tlv.data; + BUILD_BUG_ON(sizeof(cfg_name->cfg_name) != + sizeof(debug_info->debug_cfg_name)); + cfg_name->image_type = debug_info->image_type; cfg_name->cfg_name_len = - cpu_to_le32(IWL_FW_INI_MAX_CFG_NAME); + cpu_to_le32(sizeof(cfg_name->cfg_name)); memcpy(cfg_name->cfg_name, debug_info->debug_cfg_name, sizeof(cfg_name->cfg_name)); cfg_name++; @@ -2432,6 +2550,18 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .fill_mem_hdr = iwl_dump_ini_mem_fill_header, .fill_range = iwl_dump_ini_prph_phy_iter, }, + [IWL_FW_INI_REGION_PERIPHERY_MAC_RANGE] = { + .get_num_of_ranges = iwl_dump_ini_mem_block_ranges, + .get_size = iwl_dump_ini_mem_block_get_size, + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .fill_range = iwl_dump_ini_prph_mac_block_iter, + }, + [IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE] = { + .get_num_of_ranges = iwl_dump_ini_mem_block_ranges, + .get_size = iwl_dump_ini_mem_block_get_size, + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .fill_range = iwl_dump_ini_prph_phy_block_iter, + }, [IWL_FW_INI_REGION_PERIPHERY_AUX] = {}, [IWL_FW_INI_REGION_PAGING] = { .fill_mem_hdr = iwl_dump_ini_mem_fill_header, @@ -2469,6 +2599,12 @@ static const struct iwl_dump_ini_mem_ops iwl_dump_ini_region_ops[] = { .fill_mem_hdr = iwl_dump_ini_mon_dbgi_fill_header, .fill_range = iwl_dump_ini_dbgi_sram_iter, }, + [IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP] = { + .get_num_of_ranges = iwl_dump_ini_mem_ranges, + .get_size = iwl_dump_ini_mem_get_size, + .fill_mem_hdr = iwl_dump_ini_mem_fill_header, + .fill_range = iwl_dump_ini_prph_snps_dphyip_iter, + }, }; static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, @@ -2511,7 +2647,9 @@ static u32 iwl_dump_ini_trigger(struct iwl_fw_runtime *fwrt, if (reg_type >= ARRAY_SIZE(iwl_dump_ini_region_ops)) continue; - if (reg_type == IWL_FW_INI_REGION_PERIPHERY_PHY && + if ((reg_type == IWL_FW_INI_REGION_PERIPHERY_PHY || + reg_type == IWL_FW_INI_REGION_PERIPHERY_PHY_RANGE || + reg_type == IWL_FW_INI_REGION_PERIPHERY_SNPS_DPHYIP) && tp_id != IWL_FW_INI_TIME_POINT_FW_ASSERT) { IWL_WARN(fwrt, "WRT: trying to collect phy prph at time point: %d, skipping\n", @@ -2754,7 +2892,8 @@ int iwl_fw_dbg_collect_desc(struct iwl_fw_runtime *fwrt, IWL_WARN(fwrt, "Collecting data: trigger %d fired.\n", le32_to_cpu(desc->trig_desc.type)); - schedule_delayed_work(&wk_data->wk, usecs_to_jiffies(delay)); + queue_delayed_work(system_unbound_wq, &wk_data->wk, + usecs_to_jiffies(delay)); return 0; } @@ -2956,11 +3095,10 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx) struct iwl_fw_dbg_params params = {0}; struct iwl_fwrt_dump_data *dump_data = &fwrt->dump.wks[wk_idx].dump_data; - u32 policy; - u32 time_point; if (!test_bit(wk_idx, &fwrt->dump.active_wks)) return; + /* also checks 'desc' for pre-ini mode, since that shadows in union */ if (!dump_data->trig) { IWL_ERR(fwrt, "dump trigger data is not set\n"); goto out; @@ -2988,13 +3126,16 @@ static void iwl_fw_dbg_collect_sync(struct iwl_fw_runtime *fwrt, u8 wk_idx) iwl_fw_dbg_stop_restart_recording(fwrt, ¶ms, false); - policy = le32_to_cpu(dump_data->trig->apply_policy); - time_point = le32_to_cpu(dump_data->trig->time_point); + if (iwl_trans_dbg_ini_valid(fwrt->trans)) { + u32 policy = le32_to_cpu(dump_data->trig->apply_policy); + u32 time_point = le32_to_cpu(dump_data->trig->time_point); - if (policy & IWL_FW_INI_APPLY_POLICY_DUMP_COMPLETE_CMD) { - IWL_DEBUG_FW_INFO(fwrt, "WRT: sending dump complete\n"); - iwl_send_dbg_dump_complete_cmd(fwrt, time_point, 0); + if (policy & IWL_FW_INI_APPLY_POLICY_DUMP_COMPLETE_CMD) { + IWL_DEBUG_FW_INFO(fwrt, "WRT: sending dump complete\n"); + iwl_send_dbg_dump_complete_cmd(fwrt, time_point, 0); + } } + if (fwrt->trans->dbg.last_tp_resetfw == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) iwl_force_nmi(fwrt->trans); @@ -3056,7 +3197,9 @@ int iwl_fw_dbg_ini_collect(struct iwl_fw_runtime *fwrt, if (sync) iwl_fw_dbg_collect_sync(fwrt, idx); else - schedule_delayed_work(&fwrt->dump.wks[idx].wk, usecs_to_jiffies(delay)); + queue_delayed_work(system_unbound_wq, + &fwrt->dump.wks[idx].wk, + usecs_to_jiffies(delay)); return 0; } @@ -3228,7 +3371,7 @@ void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt, { int ret __maybe_unused = 0; - if (test_bit(STATUS_FW_ERROR, &fwrt->trans->status)) + if (!iwl_trans_fw_running(fwrt->trans)) return; if (fw_has_capa(&fwrt->fw->ucode_capa, @@ -3251,3 +3394,47 @@ void iwl_fw_dbg_stop_restart_recording(struct iwl_fw_runtime *fwrt, #endif } IWL_EXPORT_SYMBOL(iwl_fw_dbg_stop_restart_recording); + +void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt) +{ + struct iwl_fw_dbg_config_cmd cmd = { + .type = cpu_to_le32(DEBUG_TOKEN_CONFIG_TYPE), + .conf = cpu_to_le32(IWL_FW_DBG_CONFIG_TOKEN), + }; + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(LONG_GROUP, LDBG_CONFIG_CMD), + .data[0] = &cmd, + .len[0] = sizeof(cmd), + }; + u32 preset = u32_get_bits(fwrt->trans->dbg.domains_bitmap, + GENMASK(31, IWL_FW_DBG_DOMAIN_POS + 1)); + + /* supported starting from 9000 devices */ + if (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000) + return; + + if (fwrt->trans->dbg.yoyo_bin_loaded || (preset && preset != 1)) + return; + + iwl_trans_send_cmd(fwrt->trans, &hcmd); +} +IWL_EXPORT_SYMBOL(iwl_fw_disable_dbg_asserts); + +void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt) +{ + struct iwl_fw_dbg_params params = {0}; + + iwl_fw_dbg_stop_sync(fwrt); + + if (fw_has_api(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR)) { + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(DEBUG_GROUP, FW_CLEAR_BUFFER), + }; + iwl_trans_send_cmd(fwrt->trans, &hcmd); + } + + iwl_dbg_tlv_init_cfg(fwrt); + iwl_fw_dbg_stop_restart_recording(fwrt, ¶ms, false); +} +IWL_EXPORT_SYMBOL(iwl_fw_dbg_clear_monitor_buf); diff --git a/sys/contrib/dev/iwlwifi/fw/dbg.h b/sys/contrib/dev/iwlwifi/fw/dbg.h index 8340bb991135..7ef061e090c7 100644 --- a/sys/contrib/dev/iwlwifi/fw/dbg.h +++ b/sys/contrib/dev/iwlwifi/fw/dbg.h @@ -310,8 +310,6 @@ static inline void iwl_fw_error_collect(struct iwl_fw_runtime *fwrt, bool sync) _iwl_dbg_tlv_time_point(fwrt, tp_id, NULL, sync); } -void iwl_fw_error_print_fseq_regs(struct iwl_fw_runtime *fwrt); - static inline void iwl_fwrt_update_fw_versions(struct iwl_fw_runtime *fwrt, struct iwl_lmac_alive *lmac, struct iwl_umac_alive *umac) @@ -333,6 +331,8 @@ void iwl_fwrt_dump_error_logs(struct iwl_fw_runtime *fwrt); void iwl_send_dbg_dump_complete_cmd(struct iwl_fw_runtime *fwrt, u32 timepoint, u32 timepoint_data); +void iwl_fw_disable_dbg_asserts(struct iwl_fw_runtime *fwrt); +void iwl_fw_dbg_clear_monitor_buf(struct iwl_fw_runtime *fwrt); #define IWL_FW_CHECK_FAILED(_obj, _fmt, ...) \ IWL_ERR_LIMIT(_obj, _fmt, __VA_ARGS__) diff --git a/sys/contrib/dev/iwlwifi/fw/debugfs.c b/sys/contrib/dev/iwlwifi/fw/debugfs.c index 3cdbc6ac7ae5..893b21fcaf87 100644 --- a/sys/contrib/dev/iwlwifi/fw/debugfs.c +++ b/sys/contrib/dev/iwlwifi/fw/debugfs.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2020 Intel Corporation + * Copyright (C) 2012-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -141,7 +141,11 @@ static int iwl_dbgfs_enabled_severities_write(struct iwl_fw_runtime *fwrt, event_cfg.enabled_severities = cpu_to_le32(enabled_severities); - ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); + if (fwrt->ops && fwrt->ops->send_hcmd) + ret = fwrt->ops->send_hcmd(fwrt->ops_ctx, &hcmd); + else + ret = -EPERM; + IWL_INFO(fwrt, "sent host event cfg with enabled_severities: %u, ret: %d\n", enabled_severities, ret); @@ -226,8 +230,7 @@ static ssize_t iwl_dbgfs_send_hcmd_write(struct iwl_fw_runtime *fwrt, char *buf, .data = { NULL, }, }; - if (fwrt->ops && fwrt->ops->fw_running && - !fwrt->ops->fw_running(fwrt->ops_ctx)) + if (!iwl_trans_fw_running(fwrt->trans)) return -EIO; if (count < header_size + 1 || count > 1024 * 4) @@ -342,6 +345,12 @@ static int iwl_dbgfs_fw_info_seq_show(struct seq_file *seq, void *v) " %d: %d\n", IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT, has_capa); + has_capa = fw_has_capa(&fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT) ? 1 : 0; + seq_printf(seq, + " %d: %d\n", + IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT, + has_capa); seq_puts(seq, "fw_api_ver:\n"); } diff --git a/sys/contrib/dev/iwlwifi/fw/dump.c b/sys/contrib/dev/iwlwifi/fw/dump.c index 5876f917e536..8f107ceec407 100644 --- a/sys/contrib/dev/iwlwifi/fw/dump.c +++ b/sys/contrib/dev/iwlwifi/fw/dump.c @@ -182,8 +182,7 @@ static void iwl_fwrt_dump_lmac_error_log(struct iwl_fw_runtime *fwrt, u8 lmac_nu base = fwrt->fw->inst_errlog_ptr; } - if ((fwrt->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ && !base) || - (fwrt->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_BZ && base < 0x400000)) { + if (!base) { IWL_ERR(fwrt, "Not valid error log pointer 0x%08X for %s uCode\n", base, diff --git a/sys/contrib/dev/iwlwifi/fw/error-dump.h b/sys/contrib/dev/iwlwifi/fw/error-dump.h index f5e08988dc7b..e63b08b7d336 100644 --- a/sys/contrib/dev/iwlwifi/fw/error-dump.h +++ b/sys/contrib/dev/iwlwifi/fw/error-dump.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2014, 2018-2022 Intel Corporation + * Copyright (C) 2014, 2018-2024 Intel Corporation * Copyright (C) 2014-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -16,7 +16,7 @@ /** * enum iwl_fw_error_dump_type - types of data in the dump file * @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0 - * @IWL_FW_ERROR_DUMP_RXF: + * @IWL_FW_ERROR_DUMP_RXF: RX FIFO contents * @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as * &struct iwl_fw_error_dump_txcmd packets * @IWL_FW_ERROR_DUMP_DEV_FW_INFO: struct %iwl_fw_error_dump_info @@ -24,21 +24,24 @@ * @IWL_FW_ERROR_DUMP_FW_MONITOR: firmware monitor * @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several * sections like this in a single file. + * @IWL_FW_ERROR_DUMP_TXF: TX FIFO contents * @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers * @IWL_FW_ERROR_DUMP_MEM: chunk of memory * @IWL_FW_ERROR_DUMP_ERROR_INFO: description of what triggered this dump. * Structured as &struct iwl_fw_error_dump_trigger_desc. * @IWL_FW_ERROR_DUMP_RB: the content of an RB structured as * &struct iwl_fw_error_dump_rb - * @IWL_FW_ERROR_PAGING: UMAC's image memory segments which were + * @IWL_FW_ERROR_DUMP_PAGING: UMAC's image memory segments which were * paged to the DRAM. * @IWL_FW_ERROR_DUMP_RADIO_REG: Dump the radio registers. + * @IWL_FW_ERROR_DUMP_INTERNAL_TXF: internal TX FIFO data * @IWL_FW_ERROR_DUMP_EXTERNAL: used only by external code utilities, and * for that reason is not in use in any other place in the Linux Wi-Fi * stack. * @IWL_FW_ERROR_DUMP_MEM_CFG: the addresses and sizes of fifos in the smem, * which we get from the fw after ALIVE. The content is structured as * &struct iwl_fw_error_dump_smem_cfg. + * @IWL_FW_ERROR_DUMP_D3_DEBUG_DATA: D3 debug data */ enum iwl_fw_error_dump_type { /* 0 is deprecated */ @@ -59,8 +62,6 @@ enum iwl_fw_error_dump_type { IWL_FW_ERROR_DUMP_EXTERNAL = 15, /* Do not move */ IWL_FW_ERROR_DUMP_MEM_CFG = 16, IWL_FW_ERROR_DUMP_D3_DEBUG_DATA = 17, - - IWL_FW_ERROR_DUMP_MAX, }; /** @@ -247,7 +248,7 @@ struct iwl_fw_error_dump_mem { #define IWL_INI_DUMP_NAME_TYPE (BIT(31) | BIT(24)) /** - * struct iwl_fw_error_dump_data - data for one type + * struct iwl_fw_ini_error_dump_data - data for one type * @type: &enum iwl_fw_ini_region_type * @sub_type: sub type id * @sub_type_ver: sub type version @@ -277,7 +278,7 @@ struct iwl_fw_ini_dump_entry { } __packed; /** - * struct iwl_fw_error_dump_file - header of dump file + * struct iwl_fw_ini_dump_file_hdr - header of dump file * @barker: must be %IWL_FW_INI_ERROR_DUMP_BARKER * @file_len: the length of all the file including the header */ @@ -310,9 +311,9 @@ struct iwl_fw_ini_fifo_hdr { struct iwl_fw_ini_error_dump_range { __le32 range_data_size; union { - __le32 internal_base_addr; - __le64 dram_base_addr; - __le32 page_num; + __le32 internal_base_addr __packed; + __le64 dram_base_addr __packed; + __le32 page_num __packed; struct iwl_fw_ini_fifo_hdr fifo_hdr; struct iwl_cmd_header fw_pkt_hdr; }; @@ -442,7 +443,7 @@ struct iwl_fw_ini_err_table_dump { * struct iwl_fw_error_dump_rb - content of an Receive Buffer * @index: the index of the Receive Buffer in the Rx queue * @rxq: the RB's Rx queue - * @reserved: + * @reserved: reserved * @data: the content of the Receive Buffer */ struct iwl_fw_error_dump_rb { @@ -488,7 +489,7 @@ struct iwl_fw_ini_special_device_memory { * struct iwl_fw_error_dump_paging - content of the UMAC's image page * block on DRAM * @index: the index of the page block - * @reserved: + * @reserved: reserved * @data: the content of the page block */ struct iwl_fw_error_dump_paging { @@ -511,6 +512,7 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) /** * enum iwl_fw_dbg_trigger - triggers available * + * @FW_DBG_TRIGGER_INVALID: invalid trigger value * @FW_DBG_TRIGGER_USER: trigger log collection by user * This should not be defined as a trigger to the driver, but a value the * driver should set to indicate that the trigger was initiated by the @@ -530,14 +532,15 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data) * @FW_DBG_TRIGGER_TIME_EVENT: trigger log collection upon time events related * events. * @FW_DBG_TRIGGER_BA: trigger log collection upon BlockAck related events. - * @FW_DBG_TX_LATENCY: trigger log collection when the tx latency goes above a - * threshold. - * @FW_DBG_TDLS: trigger log collection upon TDLS related events. + * @FW_DBG_TRIGGER_TX_LATENCY: trigger log collection when the tx latency + * goes above a threshold. + * @FW_DBG_TRIGGER_TDLS: trigger log collection upon TDLS related events. * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when * the firmware sends a tx reply. * @FW_DBG_TRIGGER_ALIVE_TIMEOUT: trigger log collection if alive flow timeouts * @FW_DBG_TRIGGER_DRIVER: trigger log collection upon a flow failure * in the driver. + * @FW_DBG_TRIGGER_MAX: beyond triggers, number for sizing arrays etc. */ enum iwl_fw_dbg_trigger { FW_DBG_TRIGGER_INVALID = 0, diff --git a/sys/contrib/dev/iwlwifi/fw/file.h b/sys/contrib/dev/iwlwifi/fw/file.h index b36e9613a52c..ae05227b6153 100644 --- a/sys/contrib/dev/iwlwifi/fw/file.h +++ b/sys/contrib/dev/iwlwifi/fw/file.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2008-2014, 2018-2021 Intel Corporation + * Copyright (C) 2008-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -20,7 +20,7 @@ struct iwl_ucode_header { __le32 init_size; /* bytes of init code */ __le32 init_data_size; /* bytes of init data */ __le32 boot_size; /* bytes of bootstrap code */ - u8 data[0]; /* in same order as sizes */ + u8 data[]; /* in same order as sizes */ } v1; struct { __le32 build; /* build number */ @@ -29,7 +29,7 @@ struct iwl_ucode_header { __le32 init_size; /* bytes of init code */ __le32 init_data_size; /* bytes of init data */ __le32 boot_size; /* bytes of bootstrap code */ - u8 data[0]; /* in same order as sizes */ + u8 data[]; /* in same order as sizes */ } v2; } u; }; @@ -216,6 +216,7 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * ADD_MODIFY_STA_KEY_API_S_VER_2. * @IWL_UCODE_TLV_API_STA_TYPE: This ucode supports station type assignement. * @IWL_UCODE_TLV_API_NAN2_VER2: This ucode supports NAN API version 2 + * @IWL_UCODE_TLV_API_ADAPTIVE_DWELL: support for adaptive dwell in scanning * @IWL_UCODE_TLV_API_NEW_RX_STATS: should new RX STATISTICS API be used * @IWL_UCODE_TLV_API_QUOTA_LOW_LATENCY: Quota command includes a field * indicating low latency direction. @@ -239,10 +240,21 @@ typedef unsigned int __bitwise iwl_ucode_tlv_api_t; * SCAN_OFFLOAD_PROFILES_QUERY_RSP_S. * @IWL_UCODE_TLV_API_MBSSID_HE: This ucode supports v2 of * STA_CONTEXT_DOT11AX_API_S + * @IWL_UCODE_TLV_API_FTM_RTT_ACCURACY: version 7 of the range response API + * is supported by FW, this indicates the RTT confidence value * @IWL_UCODE_TLV_API_SAR_TABLE_VER: This ucode supports different sar * version tables. * @IWL_UCODE_TLV_API_REDUCED_SCAN_CONFIG: This ucode supports v3 of - * SCAN_CONFIG_DB_CMD_API_S. + * SCAN_CONFIG_DB_CMD_API_S. + * @IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP: support for setting adaptive dwell + * number of APs in the 5 GHz band + * @IWL_UCODE_TLV_API_BAND_IN_RX_DATA: FW reports band number in RX notification + * @IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX: Firmware offloaded the station disable tx + * logic. + * @IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR: Firmware supports clearing the debug + * internal buffer + * @IWL_UCODE_TLV_API_SMART_FIFO_OFFLOAD: Firmware doesn't need the host to + * configure the smart fifo * * @NUM_IWL_UCODE_TLV_API: number of bits used */ @@ -280,13 +292,21 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_ADWELL_HB_DEF_N_AP = (__force iwl_ucode_tlv_api_t)57, IWL_UCODE_TLV_API_SCAN_EXT_CHAN_VER = (__force iwl_ucode_tlv_api_t)58, IWL_UCODE_TLV_API_BAND_IN_RX_DATA = (__force iwl_ucode_tlv_api_t)59, + /* API Set 2 */ + IWL_UCODE_TLV_API_NO_HOST_DISABLE_TX = (__force iwl_ucode_tlv_api_t)66, + IWL_UCODE_TLV_API_INT_DBG_BUF_CLEAR = (__force iwl_ucode_tlv_api_t)67, + IWL_UCODE_TLV_API_SMART_FIFO_OFFLOAD = (__force iwl_ucode_tlv_api_t)68, - -#ifdef __CHECKER__ - /* sparse says it cannot increment the previous enum member */ -#define NUM_IWL_UCODE_TLV_API 128 -#else NUM_IWL_UCODE_TLV_API +/* + * This construction make both sparse (which cannot increment the previous + * member due to its bitwise type) and kernel-doc (which doesn't understand + * the ifdef/else properly) work. + */ +#ifdef __CHECKER__ +#define __CHECKER_NUM_IWL_UCODE_TLV_API 128 + = (__force iwl_ucode_tlv_api_t)__CHECKER_NUM_IWL_UCODE_TLV_API, +#define NUM_IWL_UCODE_TLV_API __CHECKER_NUM_IWL_UCODE_TLV_API #endif }; @@ -372,6 +392,11 @@ typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; * channels even when these are not enabled. * @IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT: Support for indicating dump collection * complete to FW. + * @IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT: Support SPP (signaling and payload + * protected) A-MSDU. + * @IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT: Support secure LTF measurement. + * @IWL_UCODE_TLV_CAPA_MONITOR_PASSIVE_CHANS: Support monitor mode on otherwise + * passive channels * * @NUM_IWL_UCODE_TLV_CAPA: number of bits used */ @@ -457,6 +482,7 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_PSC_CHAN_SUPPORT = (__force iwl_ucode_tlv_capa_t)98, IWL_UCODE_TLV_CAPA_BIGTK_SUPPORT = (__force iwl_ucode_tlv_capa_t)100, + IWL_UCODE_TLV_CAPA_SPP_AMSDU_SUPPORT = (__force iwl_ucode_tlv_capa_t)103, IWL_UCODE_TLV_CAPA_DRAM_FRAG_SUPPORT = (__force iwl_ucode_tlv_capa_t)104, IWL_UCODE_TLV_CAPA_DUMP_COMPLETE_SUPPORT = (__force iwl_ucode_tlv_capa_t)105, IWL_UCODE_TLV_CAPA_SYNCED_TIME = (__force iwl_ucode_tlv_capa_t)106, @@ -468,12 +494,19 @@ enum iwl_ucode_tlv_capa { IWL_UCODE_TLV_CAPA_OFFLOAD_BTM_SUPPORT = (__force iwl_ucode_tlv_capa_t)113, IWL_UCODE_TLV_CAPA_STA_EXP_MFP_SUPPORT = (__force iwl_ucode_tlv_capa_t)114, IWL_UCODE_TLV_CAPA_SNIFF_VALIDATE_SUPPORT = (__force iwl_ucode_tlv_capa_t)116, - -#ifdef __CHECKER__ - /* sparse says it cannot increment the previous enum member */ -#define NUM_IWL_UCODE_TLV_CAPA 128 -#else + IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT = (__force iwl_ucode_tlv_capa_t)117, + IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT = (__force iwl_ucode_tlv_capa_t)121, + IWL_UCODE_TLV_CAPA_MONITOR_PASSIVE_CHANS = (__force iwl_ucode_tlv_capa_t)122, NUM_IWL_UCODE_TLV_CAPA +/* + * This construction make both sparse (which cannot increment the previous + * member due to its bitwise type) and kernel-doc (which doesn't understand + * the ifdef/else properly) work. + */ +#ifdef __CHECKER__ +#define __CHECKER_NUM_IWL_UCODE_TLV_CAPA 128 + = (__force iwl_ucode_tlv_capa_t)__CHECKER_NUM_IWL_UCODE_TLV_CAPA, +#define NUM_IWL_UCODE_TLV_CAPA __CHECKER_NUM_IWL_UCODE_TLV_CAPA #endif }; @@ -549,6 +582,7 @@ enum iwl_fw_dbg_reg_operator { * struct iwl_fw_dbg_reg_op - an operation on a register * * @op: &enum iwl_fw_dbg_reg_operator + * @reserved: reserved * @addr: offset of the register * @val: value */ @@ -595,6 +629,7 @@ struct iwl_fw_dbg_mem_seg_tlv { * @version: version of the TLV - currently 0 * @monitor_mode: &enum iwl_fw_dbg_monitor_mode * @size_power: buffer size will be 2^(size_power + 11) + * @reserved: reserved * @base_reg: addr of the base addr register (PRPH) * @end_reg: addr of the end addr register (PRPH) * @write_ptr_reg: the addr of the reg of the write pointer @@ -705,6 +740,8 @@ enum iwl_fw_dbg_trigger_vif_type { * @trig_dis_ms: the time, in milliseconds, after an occurrence of this * trigger in which another occurrence should be ignored. * @flags: &enum iwl_fw_dbg_trigger_flags + * @reserved: reserved (for alignment) + * @data: trigger data */ struct iwl_fw_dbg_trigger_tlv { __le32 id; @@ -745,7 +782,7 @@ struct iwl_fw_dbg_trigger_missed_bcon { /** * struct iwl_fw_dbg_trigger_cmd - configures trigger for messages from FW. - * cmds: the list of commands to trigger the collection on + * @cmds: the list of commands to trigger the collection on */ struct iwl_fw_dbg_trigger_cmd { struct cmd { @@ -755,7 +792,7 @@ struct iwl_fw_dbg_trigger_cmd { } __packed; /** - * iwl_fw_dbg_trigger_stats - configures trigger for statistics + * struct iwl_fw_dbg_trigger_stats - configures trigger for statistics * @stop_offset: the offset of the value to be monitored * @stop_threshold: the threshold above which to collect * @start_offset: the offset of the value to be monitored @@ -965,4 +1002,6 @@ static inline size_t _iwl_tlv_array_len(const struct iwl_ucode_tlv *tlv, _iwl_tlv_array_len((_tlv_ptr), sizeof(*(_struct_ptr)), \ sizeof(_struct_ptr->_memb[0])) +#define iwl_tlv_array_len_with_size(_tlv_ptr, _struct_ptr, _size) \ + _iwl_tlv_array_len((_tlv_ptr), sizeof(*(_struct_ptr)), _size) #endif /* __iwl_fw_file_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/img.h b/sys/contrib/dev/iwlwifi/fw/img.h index 8d0d58d61892..96bda80632f3 100644 --- a/sys/contrib/dev/iwlwifi/fw/img.h +++ b/sys/contrib/dev/iwlwifi/fw/img.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2021 Intel Corporation + * Copyright (C) 2005-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -198,7 +198,7 @@ struct iwl_dump_exclude { struct iwl_fw { u32 ucode_ver; - char fw_version[64]; + char fw_version[128]; /* ucode images */ struct fw_img img[IWL_UCODE_TYPE_MAX]; diff --git a/sys/contrib/dev/iwlwifi/fw/init.c b/sys/contrib/dev/iwlwifi/fw/init.c index 135bd48bfe9f..d8b083be5b6b 100644 --- a/sys/contrib/dev/iwlwifi/fw/init.c +++ b/sys/contrib/dev/iwlwifi/fw/init.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2019-2021 Intel Corporation + * Copyright (C) 2019-2021, 2024 Intel Corporation */ #include "iwl-drv.h" #include "runtime.h" @@ -135,7 +135,9 @@ int iwl_configure_rxq(struct iwl_fw_runtime *fwrt) struct iwl_trans_rxq_dma_data data; cmd->data[i].q_num = i + 1; - iwl_trans_get_rxq_dma_data(fwrt->trans, i + 1, &data); + ret = iwl_trans_get_rxq_dma_data(fwrt->trans, i + 1, &data); + if (ret) + goto out; cmd->data[i].fr_bd_cb = cpu_to_le64(data.fr_bd_cb); cmd->data[i].urbd_stts_wrptr = @@ -149,6 +151,7 @@ int iwl_configure_rxq(struct iwl_fw_runtime *fwrt) ret = iwl_trans_send_cmd(fwrt->trans, &hcmd); +out: kfree(cmd); if (ret) diff --git a/sys/contrib/dev/iwlwifi/fw/notif-wait.h b/sys/contrib/dev/iwlwifi/fw/notif-wait.h index 49e8ba11b6a8..0e49794911c1 100644 --- a/sys/contrib/dev/iwlwifi/fw/notif-wait.h +++ b/sys/contrib/dev/iwlwifi/fw/notif-wait.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014 Intel Corporation + * Copyright (C) 2005-2014, 2023 Intel Corporation * Copyright (C) 2015-2017 Intel Deutschland GmbH */ #ifndef __iwl_notif_wait_h__ @@ -25,6 +25,7 @@ struct iwl_notif_wait_data { * returns true, the wait is over, if it returns false then * the waiter stays blocked. If no function is given, any * of the listed commands will unblock the waiter. + * @fn_data: pointer to pass to the @fn's data argument * @cmds: command IDs * @n_cmds: number of command IDs * @triggered: waiter should be woken up diff --git a/sys/contrib/dev/iwlwifi/fw/pnvm.c b/sys/contrib/dev/iwlwifi/fw/pnvm.c index 650e4bde9c17..1195e708caa9 100644 --- a/sys/contrib/dev/iwlwifi/fw/pnvm.c +++ b/sys/contrib/dev/iwlwifi/fw/pnvm.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright(c) 2020-2023 Intel Corporation + * Copyright(c) 2020-2024 Intel Corporation */ #include "iwl-drv.h" @@ -12,6 +12,8 @@ #include "fw/api/alive.h" #include "fw/uefi.h" +#define IWL_PNVM_REDUCED_CAP_BIT BIT(25) + struct iwl_pnvm_section { __le32 offset; const u8 data[]; @@ -173,6 +175,7 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, while (len >= sizeof(*tlv)) { u32 tlv_len, tlv_type; + u32 rf_type; len -= sizeof(*tlv); tlv = (const void *)data; @@ -201,6 +204,16 @@ static int iwl_pnvm_parse(struct iwl_trans *trans, const u8 *data, data += sizeof(*tlv) + ALIGN(tlv_len, 4); len -= ALIGN(tlv_len, 4); + trans->reduced_cap_sku = false; + rf_type = CSR_HW_RFID_TYPE(trans->hw_rf_id); + if ((trans->sku_id[0] & IWL_PNVM_REDUCED_CAP_BIT) && + rf_type == IWL_CFG_RF_TYPE_FM) + trans->reduced_cap_sku = true; + + IWL_DEBUG_FW(trans, + "Reduced SKU device %d\n", + trans->reduced_cap_sku); + if (trans->sku_id[0] == le32_to_cpu(sku_id->data[0]) && trans->sku_id[1] == le32_to_cpu(sku_id->data[1]) && trans->sku_id[2] == le32_to_cpu(sku_id->data[2])) { @@ -239,7 +252,7 @@ static int iwl_pnvm_get_from_fs(struct iwl_trans *trans, u8 **data, size_t *len) } new_len = pnvm->size; - *data = kmemdup(pnvm->data, pnvm->size, GFP_KERNEL); + *data = kvmemdup(pnvm->data, pnvm->size, GFP_KERNEL); release_firmware(pnvm); if (!*data) @@ -255,21 +268,27 @@ static u8 *iwl_get_pnvm_image(struct iwl_trans *trans_p, size_t *len) struct pnvm_sku_package *package; u8 *image = NULL; - /* First attempt to get the PNVM from BIOS */ - package = iwl_uefi_get_pnvm(trans_p, len); - if (!IS_ERR_OR_NULL(package)) { - if (*len >= sizeof(*package)) { - /* we need only the data */ - *len -= sizeof(*package); - image = kmemdup(package->data, *len, GFP_KERNEL); + /* Get PNVM from BIOS for non-Intel SKU */ + if (trans_p->sku_id[2]) { + package = iwl_uefi_get_pnvm(trans_p, len); + if (!IS_ERR_OR_NULL(package)) { + if (*len >= sizeof(*package)) { + /* we need only the data */ + *len -= sizeof(*package); + image = kvmemdup(package->data, + *len, GFP_KERNEL); + } + /* + * free package regardless of whether kmemdup + * succeeded + */ + kfree(package); + if (image) + return image; } - /* free package regardless of whether kmemdup succeeded */ - kfree(package); - if (image) - return image; } - /* If it's not available, try from the filesystem */ + /* If it's not available, or for Intel SKU, try from the filesystem */ if (iwl_pnvm_get_from_fs(trans_p, &image, len)) return NULL; return image; @@ -314,7 +333,7 @@ static void iwl_pnvm_load_pnvm_to_trans(struct iwl_trans *trans, set: iwl_trans_set_pnvm(trans, capa); free: - kfree(data); + kvfree(data); kfree(pnvm_data); } diff --git a/sys/contrib/dev/iwlwifi/fw/regulatory.c b/sys/contrib/dev/iwlwifi/fw/regulatory.c new file mode 100644 index 000000000000..777564068166 --- /dev/null +++ b/sys/contrib/dev/iwlwifi/fw/regulatory.c @@ -0,0 +1,639 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2023 Intel Corporation + */ +#if defined(__FreeBSD__) +#include <linux/bitfield.h> +#endif +#include <linux/dmi.h> +#include "iwl-drv.h" +#include "iwl-debug.h" +#include "regulatory.h" +#include "fw/runtime.h" +#include "fw/uefi.h" + +#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__); \ + if (ret < 0) \ + ret = iwl_acpi_get_ ## __name(__VA_ARGS__); \ + return ret; \ +} while (0) + +#define IWL_BIOS_TABLE_LOADER(__name) \ +int iwl_bios_get_ ## __name(struct iwl_fw_runtime *fwrt) \ +{GET_BIOS_TABLE(__name, fwrt); } \ +IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name) + +#define IWL_BIOS_TABLE_LOADER_DATA(__name, data_type) \ +int iwl_bios_get_ ## __name(struct iwl_fw_runtime *fwrt, \ + data_type * data) \ +{GET_BIOS_TABLE(__name, fwrt, data); } \ +IWL_EXPORT_SYMBOL(iwl_bios_get_ ## __name) + +IWL_BIOS_TABLE_LOADER(wrds_table); +IWL_BIOS_TABLE_LOADER(ewrd_table); +IWL_BIOS_TABLE_LOADER(wgds_table); +IWL_BIOS_TABLE_LOADER(ppag_table); +IWL_BIOS_TABLE_LOADER_DATA(tas_table, struct iwl_tas_data); +IWL_BIOS_TABLE_LOADER_DATA(pwr_limit, u64); +IWL_BIOS_TABLE_LOADER_DATA(mcc, char); +IWL_BIOS_TABLE_LOADER_DATA(eckv, u32); +IWL_BIOS_TABLE_LOADER_DATA(wbem, u32); + + +static const struct dmi_system_id dmi_ppag_approved_list[] = { + { .ident = "HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + }, + }, + { .ident = "SAMSUNG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), + }, + }, + { .ident = "MSFT", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + }, + }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + }, + }, + { .ident = "GOOGLE-HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), + }, + }, + { .ident = "GOOGLE-ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek COMPUTER INC."), + }, + }, + { .ident = "GOOGLE-SAMSUNG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), + }, + }, + { .ident = "RAZER", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Razer"), + }, + }, + { .ident = "Honor", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + }, + }, + {} +}; + +static const struct dmi_system_id dmi_tas_approved_list[] = { + { .ident = "HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + }, + }, + { .ident = "SAMSUNG", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), + }, + }, + { .ident = "LENOVO", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + }, + }, + { .ident = "DELL", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + }, + }, + { .ident = "MSFT", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + }, + }, + { .ident = "Acer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + }, + }, + { .ident = "ASUS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + }, + }, + { .ident = "GOOGLE-HP", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Google"), + DMI_MATCH(DMI_BOARD_VENDOR, "HP"), + }, + }, + { .ident = "MSI", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), + }, + }, + { .ident = "Honor", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), + }, + }, + /* keep last */ + {} +}; + +bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt) +{ + /* + * 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. + */ + return IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) >= 38 || + (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 17 && + fwrt->trans->hw_rev != CSR_HW_REV_TYPE_3160) || + (IWL_UCODE_SERIAL(fwrt->fw->ucode_ver) == 29 && + ((fwrt->trans->hw_rev & CSR_HW_REV_TYPE_MSK) == + CSR_HW_REV_TYPE_7265D)); +} +IWL_EXPORT_SYMBOL(iwl_sar_geo_support); + +int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt, + struct iwl_per_chain_offset *table, + u32 n_bands, u32 n_profiles) +{ + int i, j; + + if (!fwrt->geo_enabled) + return -ENODATA; + + if (!iwl_sar_geo_support(fwrt)) + return -EOPNOTSUPP; + + for (i = 0; i < n_profiles; i++) { + for (j = 0; j < n_bands; j++) { + struct iwl_per_chain_offset *chain = + &table[i * n_bands + j]; + + chain->max_tx_power = + cpu_to_le16(fwrt->geo_profiles[i].bands[j].max); + chain->chain_a = + fwrt->geo_profiles[i].bands[j].chains[0]; + chain->chain_b = + fwrt->geo_profiles[i].bands[j].chains[1]; + IWL_DEBUG_RADIO(fwrt, + "SAR geographic profile[%d] Band[%d]: chain A = %d chain B = %d max_tx_power = %d\n", + i, j, + fwrt->geo_profiles[i].bands[j].chains[0], + fwrt->geo_profiles[i].bands[j].chains[1], + fwrt->geo_profiles[i].bands[j].max); + } + } + + return 0; +} +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 profs[BIOS_SAR_NUM_CHAINS] = { prof_a, prof_b }; + int i, j; + + for (i = 0; i < BIOS_SAR_NUM_CHAINS; i++) { + struct iwl_sar_profile *prof; + + /* don't allow SAR to be disabled (profile 0 means disable) */ + if (profs[i] == 0) + return -EPERM; + + /* we are off by one, so allow up to BIOS_SAR_MAX_PROFILE_NUM */ + if (profs[i] > BIOS_SAR_MAX_PROFILE_NUM) + return -EINVAL; + + /* profiles go from 1 to 4, so decrement to access the array */ + prof = &fwrt->sar_profiles[profs[i] - 1]; + + /* if the profile is disabled, do nothing */ + if (!prof->enabled) { + IWL_DEBUG_RADIO(fwrt, "SAR profile %d is disabled.\n", + profs[i]); + /* + * if one of the profiles is disabled, we + * ignore all of them and return 1 to + * differentiate disabled from other failures. + */ + return 1; + } + + IWL_DEBUG_INFO(fwrt, + "SAR EWRD: chain %d profile index %d\n", + i, profs[i]); + IWL_DEBUG_RADIO(fwrt, " Chain[%d]:\n", i); + for (j = 0; j < n_subbands; j++) { + per_chain[i * n_subbands + j] = + cpu_to_le16(prof->chains[i].subbands[j]); + IWL_DEBUG_RADIO(fwrt, " Band[%d] = %d * .125dBm\n", + j, prof->chains[i].subbands[j]); + } + } + + return 0; +} + +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 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); + if (ret) + break; + } + + return ret; +} +IWL_EXPORT_SYMBOL(iwl_sar_fill_profile); + +static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain, + int subband) +{ + s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband]; + + if ((subband == 0 && + (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) || + (subband != 0 && + (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) { + IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val); + return false; + } + return true; +} + +int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, + union iwl_ppag_table_cmd *cmd, int *cmd_size) +{ + u8 cmd_ver; + int i, j, num_sub_bands; + s8 *gain; + bool send_ppag_always; + + /* many firmware images for JF lie about this */ + if (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id) == + CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF)) + return -EOPNOTSUPP; + + if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) { + IWL_DEBUG_RADIO(fwrt, + "PPAG capability not supported by FW, command not sent.\n"); + return -EINVAL; + } + + cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, + WIDE_ID(PHY_OPS_GROUP, + PER_PLATFORM_ANT_GAIN_CMD), 1); + /* + * Starting from ver 4, driver needs to send the PPAG CMD regardless + * if PPAG is enabled/disabled or valid/invalid. + */ + send_ppag_always = cmd_ver > 3; + + /* Don't send PPAG if it is disabled */ + if (!send_ppag_always && !fwrt->ppag_flags) { + IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n"); + return -EINVAL; + } + + /* The 'flags' field is the same in v1 and in v2 so we can just + * use v1 to access it. + */ + cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags); + + IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver); + if (cmd_ver == 1) { + num_sub_bands = IWL_NUM_SUB_BANDS_V1; + gain = cmd->v1.gain[0]; + *cmd_size = sizeof(cmd->v1); + if (fwrt->ppag_ver >= 1) { + /* in this case FW supports revision 0 */ + IWL_DEBUG_RADIO(fwrt, + "PPAG table rev is %d, send truncated table\n", + fwrt->ppag_ver); + } + } else if (cmd_ver >= 2 && cmd_ver <= 6) { + num_sub_bands = IWL_NUM_SUB_BANDS_V2; + gain = cmd->v2.gain[0]; + *cmd_size = sizeof(cmd->v2); + if (fwrt->ppag_ver == 0) { + /* in this case FW supports revisions 1,2 or 3 */ + IWL_DEBUG_RADIO(fwrt, + "PPAG table rev is 0, send padded table\n"); + } + } else { + IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n"); + return -EINVAL; + } + + /* ppag mode */ + IWL_DEBUG_RADIO(fwrt, + "PPAG MODE bits were read from bios: %d\n", + le32_to_cpu(cmd->v1.flags)); + + if (cmd_ver == 5) + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V5_MASK); + else if (cmd_ver < 5) + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_CMD_V4_MASK); + + if ((cmd_ver == 1 && + !fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) || + (cmd_ver == 2 && fwrt->ppag_ver >= 2)) { + cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK); + IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n"); + } else { + IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n"); + } + + IWL_DEBUG_RADIO(fwrt, + "PPAG MODE bits going to be sent: %d\n", + le32_to_cpu(cmd->v1.flags)); + + for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) { + for (j = 0; j < num_sub_bands; j++) { + if (!send_ppag_always && + !iwl_ppag_value_valid(fwrt, i, j)) + return -EINVAL; + + gain[i * num_sub_bands + j] = + fwrt->ppag_chains[i].subbands[j]; + IWL_DEBUG_RADIO(fwrt, + "PPAG table: chain[%d] band[%d]: gain = %d\n", + i, j, gain[i * num_sub_bands + j]); + } + } + + return 0; +} +IWL_EXPORT_SYMBOL(iwl_fill_ppag_table); + +bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt) +{ + if (!dmi_check_system(dmi_ppag_approved_list)) { + IWL_DEBUG_RADIO(fwrt, + "System vendor '%s' is not in the approved list, disabling PPAG.\n", + dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>"); + fwrt->ppag_flags = 0; + return false; + } + + return true; +} +IWL_EXPORT_SYMBOL(iwl_is_ppag_approved); + +bool iwl_is_tas_approved(void) +{ + return dmi_check_system(dmi_tas_approved_list); +} +IWL_EXPORT_SYMBOL(iwl_is_tas_approved); + +int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *tas_data, + const u32 tas_selection) +{ + u8 override_iec = u32_get_bits(tas_selection, + IWL_WTAS_OVERRIDE_IEC_MSK); + u8 enabled_iec = u32_get_bits(tas_selection, IWL_WTAS_ENABLE_IEC_MSK); + u8 usa_tas_uhb = u32_get_bits(tas_selection, IWL_WTAS_USA_UHB_MSK); + int enabled = tas_selection & IWL_WTAS_ENABLED_MSK; + + IWL_DEBUG_RADIO(fwrt, "TAS selection as read from BIOS: 0x%x\n", + tas_selection); + + tas_data->usa_tas_uhb_allowed = usa_tas_uhb; + tas_data->override_tas_iec = override_iec; + tas_data->enable_tas_iec = enabled_iec; + + return enabled; +} + +static __le32 iwl_get_lari_config_bitmap(struct iwl_fw_runtime *fwrt) +{ + int ret; + u32 val; + __le32 config_bitmap = 0; + + switch (CSR_HW_RFID_TYPE(fwrt->trans->hw_rf_id)) { + case IWL_CFG_RF_TYPE_HR1: + case IWL_CFG_RF_TYPE_HR2: + case IWL_CFG_RF_TYPE_JF1: + case IWL_CFG_RF_TYPE_JF2: + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_INDONESIA_5G2, + &val); + + if (!ret && val == DSM_VALUE_INDONESIA_ENABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_ENABLE_5G2_IN_INDONESIA_MSK); + break; + default: + break; + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_DISABLE_SRD, &val); + if (!ret) { + if (val == DSM_VALUE_SRD_PASSIVE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_PASSIVE_MSK); + else if (val == DSM_VALUE_SRD_DISABLE) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_CHANGE_ETSI_TO_DISABLED_MSK); + } + + if (fw_has_capa(&fwrt->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_CHINA_22_REG_SUPPORT)) { + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_REGULATORY_CONFIG, + &val); + /* + * China 2022 enable if the BIOS object does not exist or + * if it is enabled in BIOS. + */ + if (ret < 0 || val & DSM_MASK_CHINA_22_REG) + config_bitmap |= + cpu_to_le32(LARI_CONFIG_ENABLE_CHINA_22_REG_SUPPORT_MSK); + } + + return config_bitmap; +} + +static size_t iwl_get_lari_config_cmd_size(u8 cmd_ver) +{ + size_t cmd_size; + + switch (cmd_ver) { + case 12: + case 11: + cmd_size = sizeof(struct iwl_lari_config_change_cmd); + break; + case 10: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v10); + break; + case 9: + case 8: + case 7: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v7); + break; + case 6: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6); + break; + case 5: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v5); + break; + case 4: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4); + break; + case 3: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3); + break; + case 2: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2); + break; + default: + cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); + break; + } + return cmd_size; +} + +int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, + struct iwl_lari_config_change_cmd *cmd, + size_t *cmd_size) +{ + int ret; + u32 value; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw, + WIDE_ID(REGULATORY_AND_NVM_GROUP, + LARI_CONFIG_CHANGE), 1); + + memset(cmd, 0, sizeof(*cmd)); + *cmd_size = iwl_get_lari_config_cmd_size(cmd_ver); + + cmd->config_bitmap = iwl_get_lari_config_bitmap(fwrt); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_11AX_ENABLEMENT, &value); + if (!ret) + cmd->oem_11ax_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_UNII4_CHAN, &value); + if (!ret) { + if (cmd_ver < 9) + value &= DSM_UNII4_ALLOW_BITMAP_CMD_V8; + else + value &= DSM_UNII4_ALLOW_BITMAP; + + cmd->oem_unii4_allow_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ACTIVATE_CHANNEL, &value); + if (!ret) { + if (cmd_ver < 8) + value &= ~ACTIVATE_5G2_IN_WW_MASK; + if (cmd_ver < 12) + value &= CHAN_STATE_ACTIVE_BITMAP_CMD_V11; + + cmd->chan_state_active_bitmap = cpu_to_le32(value); + } + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_6E, &value); + if (!ret) + cmd->oem_uhb_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_FORCE_DISABLE_CHANNELS, &value); + if (!ret) + cmd->force_disable_channels_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENERGY_DETECTION_THRESHOLD, + &value); + if (!ret) + cmd->edt_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_wbem(fwrt, &value); + if (!ret) + cmd->oem_320mhz_allow_bitmap = cpu_to_le32(value); + + ret = iwl_bios_get_dsm(fwrt, DSM_FUNC_ENABLE_11BE, &value); + if (!ret) + cmd->oem_11be_allow_bitmap = cpu_to_le32(value); + + if (cmd->config_bitmap || + cmd->oem_uhb_allow_bitmap || + cmd->oem_11ax_allow_bitmap || + cmd->oem_unii4_allow_bitmap || + cmd->chan_state_active_bitmap || + cmd->force_disable_channels_bitmap || + cmd->edt_bitmap || + cmd->oem_320mhz_allow_bitmap || + cmd->oem_11be_allow_bitmap) { + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->config_bitmap), + le32_to_cpu(cmd->oem_11ax_allow_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n", + le32_to_cpu(cmd->oem_unii4_allow_bitmap), + le32_to_cpu(cmd->chan_state_active_bitmap), + cmd_ver); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n", + le32_to_cpu(cmd->oem_uhb_allow_bitmap), + le32_to_cpu(cmd->force_disable_channels_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, edt_bitmap=0x%x, oem_320mhz_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->edt_bitmap), + le32_to_cpu(cmd->oem_320mhz_allow_bitmap)); + IWL_DEBUG_RADIO(fwrt, + "sending LARI_CONFIG_CHANGE, oem_11be_allow_bitmap=0x%x\n", + le32_to_cpu(cmd->oem_11be_allow_bitmap)); + } else { + return 1; + } + + return 0; +} +IWL_EXPORT_SYMBOL(iwl_fill_lari_config); + +int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value) +{ + GET_BIOS_TABLE(dsm, fwrt, func, value); +} +IWL_EXPORT_SYMBOL(iwl_bios_get_dsm); diff --git a/sys/contrib/dev/iwlwifi/fw/regulatory.h b/sys/contrib/dev/iwlwifi/fw/regulatory.h new file mode 100644 index 000000000000..e2c056f483c1 --- /dev/null +++ b/sys/contrib/dev/iwlwifi/fw/regulatory.h @@ -0,0 +1,220 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * Copyright (C) 2023-2024 Intel Corporation + */ + +#ifndef __fw_regulatory_h__ +#define __fw_regulatory_h__ + +#include "fw/img.h" +#include "fw/api/commands.h" +#include "fw/api/power.h" +#include "fw/api/phy.h" +#include "fw/api/config.h" +#include "fw/api/nvm-reg.h" +#include "fw/img.h" +#include "iwl-trans.h" + +#define BIOS_SAR_MAX_PROFILE_NUM 4 +/* + * Each SAR profile has (up to, depends on the table revision) 4 chains: + * chain A, chain B, chain A when in CDB, chain B when in CDB + */ +#define BIOS_SAR_MAX_CHAINS_PER_PROFILE 4 +#define BIOS_SAR_NUM_CHAINS 2 +#define BIOS_SAR_MAX_SUB_BANDS_NUM 11 + +#define BIOS_GEO_NUM_CHAINS 2 +#define BIOS_GEO_MAX_NUM_BANDS 3 +#define BIOS_GEO_MAX_PROFILE_NUM 8 +#define BIOS_GEO_MIN_PROFILE_NUM 3 + +#define IWL_SAR_ENABLE_MSK BIT(0) + +/* PPAG gain value bounds in 1/8 dBm */ +#define IWL_PPAG_MIN_LB -16 +#define IWL_PPAG_MAX_LB 24 +#define IWL_PPAG_MIN_HB -16 +#define IWL_PPAG_MAX_HB 40 + +#define IWL_PPAG_ETSI_CHINA_MASK 3 +#define IWL_PPAG_REV3_MASK 0x7FF + +#define IWL_WTAS_ENABLED_MSK 0x1 +#define IWL_WTAS_OVERRIDE_IEC_MSK 0x2 +#define IWL_WTAS_ENABLE_IEC_MSK 0x4 +#define IWL_WTAS_USA_UHB_MSK BIT(16) + +/* + * The profile for revision 2 is a superset of revision 1, which is in + * turn a superset of revision 0. So we can store all revisions + * inside revision 2, which is what we represent here. + */ + +/* + * struct iwl_sar_profile_chain - per-chain values of a SAR profile + * @subbands: the SAR value for each subband + */ +struct iwl_sar_profile_chain { + u8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM]; +}; + +/* + * struct iwl_sar_profile - SAR profile from SAR tables + * @enabled: whether the profile is enabled or not + * @chains: per-chain SAR values + */ +struct iwl_sar_profile { + bool enabled; + struct iwl_sar_profile_chain chains[BIOS_SAR_MAX_CHAINS_PER_PROFILE]; +}; + +/* Same thing as with SAR, all revisions fit in revision 2 */ + +/* + * struct iwl_geo_profile_band - per-band geo SAR offsets + * @max: the max tx power allowed for the band + * @chains: SAR offsets values for each chain + */ +struct iwl_geo_profile_band { + u8 max; + u8 chains[BIOS_GEO_NUM_CHAINS]; +}; + +/* + * struct iwl_geo_profile - geo profile + * @bands: per-band table of the SAR offsets + */ +struct iwl_geo_profile { + struct iwl_geo_profile_band bands[BIOS_GEO_MAX_NUM_BANDS]; +}; + +/* Same thing as with SAR, all revisions fit in revision 2 */ +struct iwl_ppag_chain { + s8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM]; +}; + +struct iwl_tas_data { + __le32 block_list_size; + __le32 block_list_array[IWL_WTAS_BLACK_LIST_MAX]; + u8 override_tas_iec; + u8 enable_tas_iec; + u8 usa_tas_uhb_allowed; +}; + +/* For DSM revision 0 and 4 */ +enum iwl_dsm_funcs { + DSM_FUNC_QUERY = 0, + DSM_FUNC_DISABLE_SRD = 1, + DSM_FUNC_ENABLE_INDONESIA_5G2 = 2, + DSM_FUNC_ENABLE_6E = 3, + DSM_FUNC_REGULATORY_CONFIG = 4, + DSM_FUNC_11AX_ENABLEMENT = 6, + DSM_FUNC_ENABLE_UNII4_CHAN = 7, + DSM_FUNC_ACTIVATE_CHANNEL = 8, + DSM_FUNC_FORCE_DISABLE_CHANNELS = 9, + DSM_FUNC_ENERGY_DETECTION_THRESHOLD = 10, + DSM_FUNC_RFI_CONFIG = 11, + DSM_FUNC_ENABLE_11BE = 12, + DSM_FUNC_NUM_FUNCS = 13, +}; + +enum iwl_dsm_values_srd { + DSM_VALUE_SRD_ACTIVE, + DSM_VALUE_SRD_PASSIVE, + DSM_VALUE_SRD_DISABLE, + DSM_VALUE_SRD_MAX +}; + +enum iwl_dsm_values_indonesia { + DSM_VALUE_INDONESIA_DISABLE, + DSM_VALUE_INDONESIA_ENABLE, + DSM_VALUE_INDONESIA_RESERVED, + DSM_VALUE_INDONESIA_MAX +}; + +enum iwl_dsm_unii4_bitmap { + DSM_VALUE_UNII4_US_OVERRIDE_MSK = BIT(0), + DSM_VALUE_UNII4_US_EN_MSK = BIT(1), + DSM_VALUE_UNII4_ETSI_OVERRIDE_MSK = BIT(2), + DSM_VALUE_UNII4_ETSI_EN_MSK = BIT(3), + DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK = BIT(4), + DSM_VALUE_UNII4_CANADA_EN_MSK = BIT(5), +}; + +#define DSM_UNII4_ALLOW_BITMAP_CMD_V8 (DSM_VALUE_UNII4_US_OVERRIDE_MSK | \ + DSM_VALUE_UNII4_US_EN_MSK | \ + DSM_VALUE_UNII4_ETSI_OVERRIDE_MSK | \ + DSM_VALUE_UNII4_ETSI_EN_MSK) +#define DSM_UNII4_ALLOW_BITMAP (DSM_UNII4_ALLOW_BITMAP_CMD_V8 | \ + DSM_VALUE_UNII4_CANADA_OVERRIDE_MSK | \ + DSM_VALUE_UNII4_CANADA_EN_MSK) + +enum iwl_dsm_values_rfi { + DSM_VALUE_RFI_DLVR_DISABLE = BIT(0), + DSM_VALUE_RFI_DDR_DISABLE = BIT(1), +}; + +#define DSM_VALUE_RFI_DISABLE (DSM_VALUE_RFI_DLVR_DISABLE |\ + DSM_VALUE_RFI_DDR_DISABLE) + +enum iwl_dsm_masks_reg { + DSM_MASK_CHINA_22_REG = BIT(2) +}; + +struct iwl_fw_runtime; + +bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt); + +int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt, + struct iwl_per_chain_offset *table, + u32 n_bands, u32 n_profiles); + +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 iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt, + union iwl_ppag_table_cmd *cmd, + int *cmd_size); + +bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt); + +bool iwl_is_tas_approved(void); + +int iwl_parse_tas_selection(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *tas_data, + const u32 tas_selection); + +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_wgds_table(struct iwl_fw_runtime *fwrt); + +int iwl_bios_get_ppag_table(struct iwl_fw_runtime *fwrt); + +int iwl_bios_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data); + +int iwl_bios_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit); + +int iwl_bios_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); +int iwl_bios_get_eckv(struct iwl_fw_runtime *fwrt, u32 *ext_clk); +int iwl_bios_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value); + +int iwl_fill_lari_config(struct iwl_fw_runtime *fwrt, + struct iwl_lari_config_change_cmd *cmd, + size_t *cmd_size); + +int iwl_bios_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value); + +static inline u32 iwl_bios_get_ppag_flags(const u32 ppag_modes, + const u8 ppag_ver) +{ + return ppag_modes & (ppag_ver < 3 ? IWL_PPAG_ETSI_CHINA_MASK : + IWL_PPAG_REV3_MASK); +} +#endif /* __fw_regulatory_h__ */ diff --git a/sys/contrib/dev/iwlwifi/fw/rs.c b/sys/contrib/dev/iwlwifi/fw/rs.c index b09e68dbf5a9..8f99e501629e 100644 --- a/sys/contrib/dev/iwlwifi/fw/rs.c +++ b/sys/contrib/dev/iwlwifi/fw/rs.c @@ -208,7 +208,6 @@ int rs_pretty_print_rate(char *buf, int bufsz, const u32 rate) return scnprintf(buf, bufsz, "Legacy | ANT: %s Rate: %s Mbps", iwl_rs_pretty_ant(ant), - index == IWL_RATE_INVALID ? "BAD" : iwl_rate_mcs(index)->mbps); } diff --git a/sys/contrib/dev/iwlwifi/fw/runtime.h b/sys/contrib/dev/iwlwifi/fw/runtime.h index 702586945533..048877fa7c71 100644 --- a/sys/contrib/dev/iwlwifi/fw/runtime.h +++ b/sys/contrib/dev/iwlwifi/fw/runtime.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef __iwl_fw_runtime_h__ #define __iwl_fw_runtime_h__ @@ -12,13 +12,13 @@ #include "fw/api/debug.h" #include "fw/api/paging.h" #include "fw/api/power.h" -#include "iwl-eeprom-parse.h" +#include "iwl-nvm-utils.h" #include "fw/acpi.h" +#include "fw/regulatory.h" struct iwl_fw_runtime_ops { void (*dump_start)(void *ctx); void (*dump_end)(void *ctx); - bool (*fw_running)(void *ctx); int (*send_hcmd)(void *ctx, struct iwl_host_cmd *host_cmd); bool (*d3_debug_enable)(void *ctx); }; @@ -45,6 +45,10 @@ struct iwl_fwrt_shared_mem_cfg { * struct iwl_fwrt_dump_data - dump data * @trig: trigger the worker was scheduled upon * @fw_pkt: packet received from FW + * + * Note that the decision which part of the union is used + * is based on iwl_trans_dbg_ini_valid(): the 'trig' part + * is used if it is %true, the 'desc' part otherwise. */ struct iwl_fwrt_dump_data { union { @@ -53,6 +57,7 @@ struct iwl_fwrt_dump_data { struct iwl_rx_packet *fw_pkt; }; struct { + /* must be first to be same as 'trig' */ const struct iwl_fw_dump_desc *desc; bool monitor_only; }; @@ -98,6 +103,12 @@ struct iwl_txf_iter_data { * @cur_fw_img: current firmware image, must be maintained by * the driver by calling &iwl_fw_set_current_image() * @dump: debug dump data + * @uats_table: AP type table + * @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. + * @sar_profiles: sar profiles as read from WRDS/EWRD BIOS tables + * @geo_profiles: geographic profiles as read from WGDS BIOS table */ struct iwl_fw_runtime { struct iwl_trans *trans; @@ -156,22 +167,21 @@ struct iwl_fw_runtime { #ifdef CONFIG_IWLWIFI_DEBUGFS bool tpc_enabled; #endif /* CONFIG_IWLWIFI_DEBUGFS */ -#ifdef CONFIG_ACPI - struct iwl_sar_profile sar_profiles[ACPI_SAR_PROFILE_NUM]; + struct iwl_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM]; u8 sar_chain_a_profile; u8 sar_chain_b_profile; - struct iwl_geo_profile geo_profiles[ACPI_NUM_GEO_PROFILES_REV3]; + u8 reduced_power_flags; + struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; u32 geo_rev; u32 geo_num_profiles; bool geo_enabled; struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; u32 ppag_flags; - u32 ppag_ver; - bool ppag_table_valid; + u8 ppag_ver; struct iwl_sar_offset_mapping_cmd sgom_table; bool sgom_enabled; - u8 reduced_power_flags; -#endif + struct iwl_mcc_allowed_ap_type_cmd uats_table; + u8 uefi_tables_lock_status; }; void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans, diff --git a/sys/contrib/dev/iwlwifi/fw/uefi.c b/sys/contrib/dev/iwlwifi/fw/uefi.c index 9877988db0d2..fb982d4fe851 100644 --- a/sys/contrib/dev/iwlwifi/fw/uefi.c +++ b/sys/contrib/dev/iwlwifi/fw/uefi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright(c) 2021-2023 Intel Corporation + * Copyright(c) 2021-2024 Intel Corporation */ #include "iwl-drv.h" @@ -76,6 +76,42 @@ void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) return data; } +static +void *iwl_uefi_get_verified_variable(struct iwl_trans *trans, + efi_char16_t *uefi_var_name, + char *var_name, + unsigned int expected_size, + unsigned long *size) +{ + void *var; + unsigned long var_size; + + var = iwl_uefi_get_variable(uefi_var_name, &IWL_EFI_VAR_GUID, + &var_size); + + if (IS_ERR(var)) { + IWL_DEBUG_RADIO(trans, + "%s UEFI variable not found 0x%lx\n", var_name, + PTR_ERR(var)); + return var; + } + + if (var_size < expected_size) { + IWL_DEBUG_RADIO(trans, + "Invalid %s UEFI variable len (%lu)\n", + var_name, var_size); + kfree(var); + return ERR_PTR(-EINVAL); + } + + IWL_DEBUG_RADIO(trans, "%s from UEFI with size %lu\n", var_name, + var_size); + + if (size) + *size = var_size; + return var; +} + int iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, u32 tlv_len, struct iwl_pnvm_image *pnvm_data) { @@ -230,26 +266,13 @@ u8 *iwl_uefi_get_reduced_power(struct iwl_trans *trans, size_t *len) unsigned long package_size; u8 *data; - package = iwl_uefi_get_variable(IWL_UEFI_REDUCED_POWER_NAME, - &IWL_EFI_VAR_GUID, &package_size); - - if (IS_ERR(package)) { - IWL_DEBUG_FW(trans, - "Reduced Power UEFI variable not found 0x%lx (len %lu)\n", - PTR_ERR(package), package_size); + package = iwl_uefi_get_verified_variable(trans, + IWL_UEFI_REDUCED_POWER_NAME, + "Reduced Power", + sizeof(*package), + &package_size); + if (IS_ERR(package)) return ERR_CAST(package); - } - - if (package_size < sizeof(*package)) { - IWL_DEBUG_FW(trans, - "Invalid Reduced Power UEFI variable len (%lu)\n", - package_size); - kfree(package); - return ERR_PTR(-EINVAL); - } - - IWL_DEBUG_FW(trans, "Read reduced power from UEFI with size %lu\n", - package_size); IWL_DEBUG_FW(trans, "rev %d, total_size %d, n_skus %d\n", package->rev, package->total_size, package->n_skus); @@ -283,32 +306,15 @@ static int iwl_uefi_step_parse(struct uefi_cnv_common_step_data *common_step_dat void iwl_uefi_get_step_table(struct iwl_trans *trans) { struct uefi_cnv_common_step_data *data; - unsigned long package_size; int ret; if (trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) return; - data = iwl_uefi_get_variable(IWL_UEFI_STEP_NAME, &IWL_EFI_VAR_GUID, - &package_size); - - if (IS_ERR(data)) { - IWL_DEBUG_FW(trans, - "STEP UEFI variable not found 0x%lx\n", - PTR_ERR(data)); + data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_STEP_NAME, + "STEP", sizeof(*data), NULL); + if (IS_ERR(data)) return; - } - - if (package_size < sizeof(*data)) { - IWL_DEBUG_FW(trans, - "Invalid STEP table UEFI variable len (%lu)\n", - package_size); - kfree(data); - return; - } - - IWL_DEBUG_FW(trans, "Read STEP from UEFI with size %lu\n", - package_size); ret = iwl_uefi_step_parse(data, trans); if (ret < 0) @@ -318,7 +324,6 @@ void iwl_uefi_get_step_table(struct iwl_trans *trans) } IWL_EXPORT_SYMBOL(iwl_uefi_get_step_table); -#ifdef CONFIG_ACPI static int iwl_uefi_sgom_parse(struct uefi_cnv_wlan_sgom_data *sgom_data, struct iwl_fw_runtime *fwrt) { @@ -355,31 +360,15 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) { struct uefi_cnv_wlan_sgom_data *data; - unsigned long package_size; int ret; if (!fwrt->geo_enabled) return; - data = iwl_uefi_get_variable(IWL_UEFI_SGOM_NAME, &IWL_EFI_VAR_GUID, - &package_size); - if (IS_ERR(data)) { - IWL_DEBUG_FW(trans, - "SGOM UEFI variable not found 0x%lx\n", - PTR_ERR(data)); - return; - } - - if (package_size < sizeof(*data)) { - IWL_DEBUG_FW(trans, - "Invalid SGOM table UEFI variable len (%lu)\n", - package_size); - kfree(data); + data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_SGOM_NAME, + "SGOM", sizeof(*data), NULL); + if (IS_ERR(data)) return; - } - - IWL_DEBUG_FW(trans, "Read SGOM from UEFI with size %lu\n", - package_size); ret = iwl_uefi_sgom_parse(data, fwrt); if (ret < 0) @@ -388,4 +377,355 @@ void iwl_uefi_get_sgom_table(struct iwl_trans *trans, kfree(data); } IWL_EXPORT_SYMBOL(iwl_uefi_get_sgom_table); -#endif /* CONFIG_ACPI */ + +static int iwl_uefi_uats_parse(struct uefi_cnv_wlan_uats_data *uats_data, + struct iwl_fw_runtime *fwrt) +{ + if (uats_data->revision != 1) + return -EINVAL; + + memcpy(fwrt->uats_table.offset_map, uats_data->offset_map, + sizeof(fwrt->uats_table.offset_map)); + return 0; +} + +int iwl_uefi_get_uats_table(struct iwl_trans *trans, + struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_wlan_uats_data *data; + int ret; + + data = iwl_uefi_get_verified_variable(trans, IWL_UEFI_UATS_NAME, + "UATS", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + ret = iwl_uefi_uats_parse(data, fwrt); + if (ret < 0) { + IWL_DEBUG_FW(trans, "Cannot read UATS table. rev is invalid\n"); + kfree(data); + return ret; + } + + kfree(data); + return 0; +} +IWL_EXPORT_SYMBOL(iwl_uefi_get_uats_table); + +static void iwl_uefi_set_sar_profile(struct iwl_fw_runtime *fwrt, + struct uefi_sar_profile *uefi_sar_prof, + u8 prof_index, bool enabled) +{ + memcpy(&fwrt->sar_profiles[prof_index].chains, uefi_sar_prof, + sizeof(struct uefi_sar_profile)); + + fwrt->sar_profiles[prof_index].enabled = enabled & IWL_SAR_ENABLE_MSK; +} + +int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_wrds *data; + int ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WRDS_NAME, + "WRDS", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_WRDS_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDS revision:%d\n", + data->revision); + goto out; + } + + /* 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->sar_profile, 0, data->mode); +out: + kfree(data); + return ret; +} + +int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_ewrd *data; + int i, ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_EWRD_NAME, + "EWRD", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_EWRD_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI EWRD revision:%d\n", + data->revision); + goto out; + } + + if (data->num_profiles >= BIOS_SAR_MAX_PROFILE_NUM) { + ret = -EINVAL; + goto out; + } + + for (i = 0; i < data->num_profiles; i++) + /* 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. + */ + iwl_uefi_set_sar_profile(fwrt, &data->sar_profiles[i], i + 1, + data->mode); + +out: + kfree(data); + return ret; +} + +int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_wgds *data; + int i, ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WGDS_NAME, + "WGDS", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_WGDS_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WGDS revision:%d\n", + data->revision); + goto out; + } + + if (data->num_profiles < BIOS_GEO_MIN_PROFILE_NUM || + data->num_profiles > BIOS_GEO_MAX_PROFILE_NUM) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Invalid number of profiles in WGDS: %d\n", + data->num_profiles); + goto out; + } + + fwrt->geo_rev = data->revision; + for (i = 0; i < data->num_profiles; i++) + memcpy(&fwrt->geo_profiles[i], &data->geo_profiles[i], + sizeof(struct iwl_geo_profile)); + + fwrt->geo_num_profiles = data->num_profiles; + fwrt->geo_enabled = true; +out: + kfree(data); + return ret; +} + +int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) +{ + struct uefi_cnv_var_ppag *data; + int ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME, + "PPAG", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision < IWL_UEFI_MIN_PPAG_REV || + data->revision > IWL_UEFI_MAX_PPAG_REV) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI PPAG revision:%d\n", + data->revision); + goto out; + } + + fwrt->ppag_ver = data->revision; + fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes, + fwrt->ppag_ver); + + BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains)); + memcpy(&fwrt->ppag_chains, &data->ppag_chains, + sizeof(data->ppag_chains)); +out: + kfree(data); + return ret; +} + +int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *tas_data) +{ + struct uefi_cnv_var_wtas *uefi_tas; + int ret = 0, enabled, i; + + uefi_tas = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_WTAS_NAME, + "WTAS", sizeof(*uefi_tas), NULL); + if (IS_ERR(uefi_tas)) + return -EINVAL; + + if (uefi_tas->revision != IWL_UEFI_WTAS_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WTAS revision:%d\n", + uefi_tas->revision); + goto out; + } + + enabled = iwl_parse_tas_selection(fwrt, tas_data, + uefi_tas->tas_selection); + if (!enabled) { + IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n"); + ret = 0; + goto out; + } + + IWL_DEBUG_RADIO(fwrt, "Reading TAS table revision %d\n", + uefi_tas->revision); + if (uefi_tas->black_list_size > IWL_WTAS_BLACK_LIST_MAX) { + IWL_DEBUG_RADIO(fwrt, "TAS invalid array size %d\n", + uefi_tas->black_list_size); + ret = -EINVAL; + goto out; + } + tas_data->block_list_size = cpu_to_le32(uefi_tas->black_list_size); + IWL_DEBUG_RADIO(fwrt, "TAS array size %u\n", uefi_tas->black_list_size); + + for (i = 0; i < uefi_tas->black_list_size; i++) { + tas_data->block_list_array[i] = + cpu_to_le32(uefi_tas->black_list[i]); + IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", + uefi_tas->black_list[i]); + } +out: + kfree(uefi_tas); + return ret; +} + +int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit) +{ + struct uefi_cnv_var_splc *data; + int ret = 0; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_SPLC_NAME, + "SPLC", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_SPLC_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI SPLC revision:%d\n", + data->revision); + goto out; + } + *dflt_pwr_limit = data->default_pwr_limit; +out: + kfree(data); + return ret; +} + +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); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_WRDD_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n", + data->revision); + goto out; + } + + if (data->mcc != UEFI_MCC_CHINA) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "UEFI WRDD is supported only for CN\n"); + goto out; + } + + mcc[0] = (data->mcc >> 8) & 0xff; + mcc[1] = data->mcc & 0xff; + mcc[2] = '\0'; +out: + kfree(data); + return ret; +} + +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(fwrt->trans, IWL_UEFI_ECKV_NAME, + "ECKV", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_ECKV_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WRDD revision:%d\n", + data->revision); + goto out; + } + *extl_clk = data->ext_clock_valid; +out: + kfree(data); + return ret; +} + +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); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_WBEM_REVISION) { + ret = -EINVAL; + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI WBEM revision:%d\n", + data->revision); + goto out; + } + *value = data->wbem_320mhz_per_mcc & IWL_UEFI_WBEM_REV0_MASK; + IWL_DEBUG_RADIO(fwrt, "Loaded WBEM config from UEFI\n"); +out: + kfree(data); + return ret; +} + +int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value) +{ + struct uefi_cnv_var_general_cfg *data; + int ret = -EINVAL; + + /* Not supported function index */ + if (func >= DSM_FUNC_NUM_FUNCS || func == 5) + return -EOPNOTSUPP; + + data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_DSM_NAME, + "DSM", sizeof(*data), NULL); + if (IS_ERR(data)) + return -EINVAL; + + if (data->revision != IWL_UEFI_DSM_REVISION) { + IWL_DEBUG_RADIO(fwrt, "Unsupported UEFI DSM revision:%d\n", + data->revision); + goto out; + } + + if (ARRAY_SIZE(data->functions) != UEFI_MAX_DSM_FUNCS) { + IWL_DEBUG_RADIO(fwrt, "Invalid size of DSM functions array\n"); + goto out; + } + + *value = data->functions[func]; + ret = 0; +out: + kfree(data); + return ret; +} diff --git a/sys/contrib/dev/iwlwifi/fw/uefi.h b/sys/contrib/dev/iwlwifi/fw/uefi.h index 1369cc4855c3..1f8884ca8997 100644 --- a/sys/contrib/dev/iwlwifi/fw/uefi.h +++ b/sys/contrib/dev/iwlwifi/fw/uefi.h @@ -1,16 +1,43 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright(c) 2021-2023 Intel Corporation + * Copyright(c) 2021-2024 Intel Corporation */ #ifndef __iwl_fw_uefi__ #define __iwl_fw_uefi__ +#include "fw/regulatory.h" + #define IWL_UEFI_OEM_PNVM_NAME L"UefiCnvWlanOemSignedPnvm" #define IWL_UEFI_REDUCED_POWER_NAME L"UefiCnvWlanReducedPower" #define IWL_UEFI_SGOM_NAME L"UefiCnvWlanSarGeoOffsetMapping" #define IWL_UEFI_STEP_NAME L"UefiCnvCommonSTEP" +#define IWL_UEFI_UATS_NAME L"CnvUefiWlanUATS" +#define IWL_UEFI_WRDS_NAME L"UefiCnvWlanWRDS" +#define IWL_UEFI_EWRD_NAME L"UefiCnvWlanEWRD" +#define IWL_UEFI_WGDS_NAME L"UefiCnvWlanWGDS" +#define IWL_UEFI_PPAG_NAME L"UefiCnvWlanPPAG" +#define IWL_UEFI_WTAS_NAME L"UefiCnvWlanWTAS" +#define IWL_UEFI_SPLC_NAME L"UefiCnvWlanSPLC" +#define IWL_UEFI_WRDD_NAME L"UefiCnvWlanWRDD" +#define IWL_UEFI_ECKV_NAME L"UefiCnvWlanECKV" +#define IWL_UEFI_DSM_NAME L"UefiCnvWlanGeneralCfg" +#define IWL_UEFI_WBEM_NAME L"UefiCnvWlanWBEM" + #define IWL_SGOM_MAP_SIZE 339 +#define IWL_UATS_MAP_SIZE 339 + +#define IWL_UEFI_WRDS_REVISION 2 +#define IWL_UEFI_EWRD_REVISION 2 +#define IWL_UEFI_WGDS_REVISION 3 +#define IWL_UEFI_MIN_PPAG_REV 1 +#define IWL_UEFI_MAX_PPAG_REV 3 +#define IWL_UEFI_WTAS_REVISION 1 +#define IWL_UEFI_SPLC_REVISION 0 +#define IWL_UEFI_WRDD_REVISION 0 +#define IWL_UEFI_ECKV_REVISION 0 +#define IWL_UEFI_WBEM_REVISION 0 +#define IWL_UEFI_DSM_REVISION 4 struct pnvm_sku_package { u8 rev; @@ -25,6 +52,11 @@ struct uefi_cnv_wlan_sgom_data { u8 offset_map[IWL_SGOM_MAP_SIZE - 1]; } __packed; +struct uefi_cnv_wlan_uats_data { + u8 revision; + u8 offset_map[IWL_UATS_MAP_SIZE - 1]; +} __packed; + struct uefi_cnv_common_step_data { u8 revision; u8 step_mode; @@ -35,6 +67,134 @@ struct uefi_cnv_common_step_data { } __packed; /* + * struct uefi_sar_profile - a SAR profile as defined in UEFI + * + * @chains: a per-chain table of SAR values + */ +struct uefi_sar_profile { + struct iwl_sar_profile_chain chains[BIOS_SAR_MAX_CHAINS_PER_PROFILE]; +} __packed; + +/* + * struct uefi_cnv_var_wrds - WRDS table as defined in UEFI + * + * @revision: the revision of the table + * @mode: is WRDS enbaled/disabled + * @sar_profile: sar profile #1 + */ +struct uefi_cnv_var_wrds { + u8 revision; + u32 mode; + struct uefi_sar_profile sar_profile; +} __packed; + +/* + * struct uefi_cnv_var_ewrd - EWRD table as defined in UEFI + * @revision: the revision of the table + * @mode: is WRDS enbaled/disabled + * @num_profiles: how many additional profiles we have in this table (0-3) + * @sar_profiles: the additional SAR profiles (#2-#4) + */ +struct uefi_cnv_var_ewrd { + u8 revision; + u32 mode; + u32 num_profiles; + struct uefi_sar_profile sar_profiles[BIOS_SAR_MAX_PROFILE_NUM - 1]; +} __packed; + +/* + * struct uefi_cnv_var_wgds - WGDS table as defined in UEFI + * @revision: the revision of the table + * @num_profiles: the number of geo profiles we have in the table. + * The first 3 are mandatory, and can have up to 8. + * @geo_profiles: a per-profile table of the offsets to add to SAR values. + */ +struct uefi_cnv_var_wgds { + u8 revision; + u8 num_profiles; + struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM]; +} __packed; + +/* + * struct uefi_cnv_var_ppag - PPAG table as defined in UEFI + * @revision: the revision of the table + * @ppag_modes: values from &enum iwl_ppag_flags + * @ppag_chains: the PPAG values per chain and band + */ +struct uefi_cnv_var_ppag { + u8 revision; + u32 ppag_modes; + struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS]; +} __packed; + +/* struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI + * @revision: the revision of the table + * @tas_selection: different options of TAS enablement. + * @black_list_size: the number of defined entried in the black list + * @black_list: a list of countries that are not allowed to use the TAS feature + */ +struct uefi_cnv_var_wtas { + u8 revision; + u32 tas_selection; + u8 black_list_size; + u16 black_list[IWL_WTAS_BLACK_LIST_MAX]; +} __packed; + +/* struct uefi_cnv_var_splc - SPLC tabled as defined in UEFI + * @revision: the revision of the table + * @default_pwr_limit: The default maximum power per device + */ +struct uefi_cnv_var_splc { + u8 revision; + u32 default_pwr_limit; +} __packed; + +#define UEFI_MCC_CHINA 0x434e + +/* struct uefi_cnv_var_wrdd - WRDD table as defined in UEFI + * @revision: the revision of the table + * @mcc: country identifier as defined in ISO/IEC 3166-1 Alpha 2 code + */ +struct uefi_cnv_var_wrdd { + u8 revision; + u32 mcc; +} __packed; + +/* struct uefi_cnv_var_eckv - ECKV table as defined in UEFI + * @revision: the revision of the table + * @ext_clock_valid: indicates if external 32KHz clock is valid + */ +struct uefi_cnv_var_eckv { + u8 revision; + u32 ext_clock_valid; +} __packed; + +#define UEFI_MAX_DSM_FUNCS 32 + +/* struct uefi_cnv_var_general_cfg - DSM-like table as defined in UEFI + * @revision: the revision of the table + * @functions: payload of the different DSM functions + */ +struct uefi_cnv_var_general_cfg { + u8 revision; + u32 functions[UEFI_MAX_DSM_FUNCS]; +} __packed; + +#define IWL_UEFI_WBEM_REV0_MASK (BIT(0) | BIT(1)) +/* struct uefi_cnv_wlan_wbem_data - Bandwidth enablement per MCC as defined + * in UEFI + * @revision: the revision of the table + * @wbem_320mhz_per_mcc: enablement of 320MHz bandwidth per MCC + * bit 0 - if set, 320MHz is enabled for Japan + * bit 1 - if set, 320MHz is enabled for South Korea + * bit 2- 31, Reserved + */ +struct uefi_cnv_wlan_wbem_data { + u8 revision; + u32 wbem_320mhz_per_mcc; +} __packed; + +/* * This is known to be broken on v4.19 and to work on v5.4. Until we * figure out why this is the case and how to make it work, simply * disable the feature in old kernels. @@ -48,6 +208,22 @@ int iwl_uefi_reduce_power_parse(struct iwl_trans *trans, void iwl_uefi_get_step_table(struct iwl_trans *trans); 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_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, + struct iwl_tas_data *data); +int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit); +int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc); +int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk); +int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value); +int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func, + u32 *value); +void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); +int iwl_uefi_get_uats_table(struct iwl_trans *trans, + struct iwl_fw_runtime *fwrt); #else /* CONFIG_EFI */ static inline void *iwl_uefi_get_pnvm(struct iwl_trans *trans, size_t *len) { @@ -78,14 +254,71 @@ iwl_uefi_handle_tlv_mem_desc(struct iwl_trans *trans, const u8 *data, { return 0; } -#endif /* CONFIG_EFI */ -#if defined(CONFIG_EFI) && defined(CONFIG_ACPI) -void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt); -#else +static inline int iwl_uefi_get_wrds_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_ewrd_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_wgds_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_tas_table(struct iwl_fw_runtime *fwrt, + struct iwl_tas_data *data) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_pwr_limit(struct iwl_fw_runtime *fwrt, + u64 *dflt_pwr_limit) +{ + *dflt_pwr_limit = 0; + return 0; +} + +static inline int iwl_uefi_get_mcc(struct iwl_fw_runtime *fwrt, char *mcc) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_eckv(struct iwl_fw_runtime *fwrt, u32 *extl_clk) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_wbem(struct iwl_fw_runtime *fwrt, u32 *value) +{ + return -ENOENT; +} + +static inline int iwl_uefi_get_dsm(struct iwl_fw_runtime *fwrt, + enum iwl_dsm_funcs func, u32 *value) +{ + return -ENOENT; +} + static inline void iwl_uefi_get_sgom_table(struct iwl_trans *trans, struct iwl_fw_runtime *fwrt) { } -#endif + +static inline +int iwl_uefi_get_uats_table(struct iwl_trans *trans, + struct iwl_fw_runtime *fwrt) +{ + return 0; +} +#endif /* CONFIG_EFI */ #endif /* __iwl_fw_uefi__ */ diff --git a/sys/contrib/dev/iwlwifi/iwl-config.h b/sys/contrib/dev/iwlwifi/iwl-config.h index 4ea322595925..52026554f2a2 100644 --- a/sys/contrib/dev/iwlwifi/iwl-config.h +++ b/sys/contrib/dev/iwlwifi/iwl-config.h @@ -2,7 +2,7 @@ /* * Copyright (C) 2005-2014, 2018-2021 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #ifndef __IWL_CONFIG_H__ #define __IWL_CONFIG_H__ @@ -11,7 +11,9 @@ #include <linux/netdevice.h> #include <linux/ieee80211.h> #include <linux/nl80211.h> +#include <linux/mod_devicetable.h> #include "iwl-csr.h" +#include "iwl-drv.h" enum iwl_device_family { IWL_DEVICE_FAMILY_UNDEFINED, @@ -122,10 +124,7 @@ enum iwl_nvm_type { #define IWL_DEFAULT_MAX_TX_POWER 22 #define IWL_TX_CSUM_NETIF_FLAGS (NETIF_F_IPV6_CSUM | NETIF_F_IP_CSUM |\ NETIF_F_TSO | NETIF_F_TSO6) -#define IWL_TX_CSUM_NETIF_FLAGS_BZ (NETIF_F_HW_CSUM | NETIF_F_TSO | NETIF_F_TSO6) -#define IWL_CSUM_NETIF_FLAGS_MASK (IWL_TX_CSUM_NETIF_FLAGS | \ - IWL_TX_CSUM_NETIF_FLAGS_BZ | \ - NETIF_F_RXCSUM) +#define IWL_CSUM_NETIF_FLAGS_MASK (IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM) /* Antenna presence definitions */ #define ANT_NONE 0x0 @@ -278,7 +277,7 @@ enum iwl_cfg_trans_ltr_delay { }; /** - * struct iwl_cfg_trans - information needed to start the trans + * struct iwl_cfg_trans_params - information needed to start the trans * * These values are specific to the device ID and do not change when * multiple configs are used for a single device ID. They values are @@ -286,7 +285,6 @@ enum iwl_cfg_trans_ltr_delay { * RFID can be read before deciding the remaining parameters to use. * * @base_params: pointer to basic parameters - * @csr: csr flags and addresses that are different across devices * @device_family: the device family * @umac_prph_offset: offset to add to UMAC periphery address * @xtal_latency: power up latency to get the xtal stabilized @@ -296,6 +294,7 @@ enum iwl_cfg_trans_ltr_delay { * @mq_rx_supported: multi-queue rx support * @integrated: discrete or integrated * @low_latency_xtal: use the low latency xtal if supported + * @bisr_workaround: BISR hardware workaround (for 22260 series devices) * @ltr_delay: LTR delay parameter, &enum iwl_cfg_trans_ltr_delay. * @imr_enabled: use the IMR if supported. */ @@ -355,7 +354,6 @@ struct iwl_fw_mon_regs { * @non_shared_ant: the antenna that is for WiFi only * @nvm_ver: NVM version * @nvm_calib_ver: NVM calibration version - * @lib: pointer to the lib ops * @ht_params: point to ht parameters * @led_mode: 0=blinking, 1=On(RF On)/Off(RF Off) * @rx_with_siso_diversity: 1x1 device with rx antenna diversity @@ -380,15 +378,12 @@ struct iwl_fw_mon_regs { * @nvm_type: see &enum iwl_nvm_type * @d3_debug_data_base_addr: base address where D3 debug data is stored * @d3_debug_data_length: length of the D3 debug data - * @bisr_workaround: BISR hardware workaround (for 22260 series devices) * @min_txq_size: minimum number of slots required in a TX queue * @uhb_supported: ultra high band channels supported * @min_ba_txq_size: minimum number of slots required in a TX queue which * based on hardware support (HE - 256, EHT - 1K). * @num_rbds: number of receive buffer descriptors to use * (only used for multi-queue capable devices) - * @mac_addr_csr_base: CSR base register for MAC address access, if not set - * assume 0x380 * * We enable the driver to be backward compatible wrt. hardware features. * API differences in uCode shouldn't be handled here but through TLVs @@ -421,7 +416,6 @@ struct iwl_cfg { u16 nvm_calib_ver; u32 rx_with_siso_diversity:1, tx_with_siso_diversity:1, - bt_shared_single_ant:1, internal_wimax_coex:1, host_interrupt_operation_mode:1, high_temp:1, @@ -463,6 +457,9 @@ struct iwl_cfg { #define IWL_CFG_MAC_TYPE_BZ 0x46 #define IWL_CFG_MAC_TYPE_GL 0x47 #define IWL_CFG_MAC_TYPE_SC 0x48 +#define IWL_CFG_MAC_TYPE_SC2 0x49 +#define IWL_CFG_MAC_TYPE_SC2F 0x4A +#define IWL_CFG_MAC_TYPE_BZ_W 0x4B #define IWL_CFG_RF_TYPE_TH 0x105 #define IWL_CFG_RF_TYPE_TH1 0x108 @@ -471,8 +468,6 @@ struct iwl_cfg { #define IWL_CFG_RF_TYPE_HR2 0x10A #define IWL_CFG_RF_TYPE_HR1 0x10C #define IWL_CFG_RF_TYPE_GF 0x10D -#define IWL_CFG_RF_TYPE_MR 0x110 -#define IWL_CFG_RF_TYPE_MS 0x111 #define IWL_CFG_RF_TYPE_FM 0x112 #define IWL_CFG_RF_TYPE_WH 0x113 @@ -487,6 +482,9 @@ struct iwl_cfg { #define IWL_CFG_NO_160 0x1 #define IWL_CFG_160 0x0 +#define IWL_CFG_NO_320 0x1 +#define IWL_CFG_320 0x0 + #define IWL_CFG_CORES_BT 0x0 #define IWL_CFG_CORES_BT_GNSS 0x5 @@ -516,6 +514,16 @@ struct iwl_dev_info { const char *name; }; +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +extern const struct iwl_dev_info iwl_dev_info_table[]; +extern const unsigned int iwl_dev_info_table_size; +const struct iwl_dev_info * +iwl_pci_find_dev_info(u16 device, u16 subsystem_device, + u16 mac_type, u8 mac_step, u16 rf_type, u8 cdb, + u8 jacket, u8 rf_id, u8 no_160, u8 cores, u8 rf_step); +extern const struct pci_device_id iwl_hw_card_ids[]; +#endif + /* * This list declares the config structures for all devices. */ @@ -571,7 +579,12 @@ extern const char iwl_ax221_name[]; extern const char iwl_ax231_name[]; extern const char iwl_ax411_name[]; extern const char iwl_bz_name[]; +extern const char iwl_fm_name[]; +extern const char iwl_gl_name[]; +extern const char iwl_mtp_name[]; extern const char iwl_sc_name[]; +extern const char iwl_sc2_name[]; +extern const char iwl_sc2f_name[]; #if IS_ENABLED(CONFIG_IWLDVM) extern const struct iwl_cfg iwl5300_agn_cfg; extern const struct iwl_cfg iwl5100_agn_cfg; @@ -677,6 +690,8 @@ extern const struct iwl_cfg iwl_cfg_bz; extern const struct iwl_cfg iwl_cfg_gl; extern const struct iwl_cfg iwl_cfg_sc; +extern const struct iwl_cfg iwl_cfg_sc2; +extern const struct iwl_cfg iwl_cfg_sc2f; #endif /* CONFIG_IWLMVM */ #endif /* __IWL_CONFIG_H__ */ diff --git a/sys/contrib/dev/iwlwifi/iwl-context-info-gen3.h b/sys/contrib/dev/iwlwifi/iwl-context-info-gen3.h index 96bf353469b8..5b62933134cf 100644 --- a/sys/contrib/dev/iwlwifi/iwl-context-info-gen3.h +++ b/sys/contrib/dev/iwlwifi/iwl-context-info-gen3.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018, 2020-2022 Intel Corporation + * Copyright (C) 2018, 2020-2024 Intel Corporation */ #ifndef __iwl_context_info_file_gen3_h__ #define __iwl_context_info_file_gen3_h__ @@ -44,7 +44,7 @@ enum iwl_prph_scratch_mtr_format { * @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_SCTATCH_RB_SIZE_4K: Use 4K RB size (the default is 2K) + * @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. @@ -56,6 +56,8 @@ enum iwl_prph_scratch_mtr_format { * @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. */ enum iwl_prph_scratch_flags { IWL_PRPH_SCRATCH_IMR_DEBUG_EN = BIT(1), @@ -71,6 +73,7 @@ enum iwl_prph_scratch_flags { 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), }; /* @@ -187,11 +190,15 @@ struct iwl_prph_scratch_ctrl_cfg { * 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 reserved[10]; + __le32 fseq_override; + __le32 step_analog_params; + __le32 reserved[8]; struct iwl_context_info_dram dram; } __packed; /* PERIPH_SCRATCH_S */ diff --git a/sys/contrib/dev/iwlwifi/iwl-csr.h b/sys/contrib/dev/iwlwifi/iwl-csr.h index 587368a0ad4a..98563757ce2c 100644 --- a/sys/contrib/dev/iwlwifi/iwl-csr.h +++ b/sys/contrib/dev/iwlwifi/iwl-csr.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2022 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -304,15 +304,14 @@ #define CSR_HW_RFID_IS_CDB(_val) (((_val) & 0x10000000) >> 28) #define CSR_HW_RFID_IS_JACKET(_val) (((_val) & 0x20000000) >> 29) -/** - * hw_rev values - */ +/* hw_rev values */ enum { SILICON_A_STEP = 0, SILICON_B_STEP, SILICON_C_STEP, SILICON_D_STEP, SILICON_E_STEP, + SILICON_TC_STEP = 0xe, SILICON_Z_STEP = 0xf, }; @@ -353,6 +352,8 @@ enum { #define CSR_HW_RF_ID_TYPE_GF (0x0010D000) #define CSR_HW_RF_ID_TYPE_GF4 (0x0010E000) #define CSR_HW_RF_ID_TYPE_MS (0x00111000) +#define CSR_HW_RF_ID_TYPE_FM (0x00112000) +#define CSR_HW_RF_ID_TYPE_WP (0x00113000) /* HW_RF CHIP STEP */ #define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF) @@ -618,6 +619,7 @@ enum msix_hw_int_causes { MSIX_HW_INT_CAUSES_REG_WAKEUP = BIT(1), MSIX_HW_INT_CAUSES_REG_IML = BIT(1), MSIX_HW_INT_CAUSES_REG_RESET_DONE = BIT(2), + MSIX_HW_INT_CAUSES_REG_TOP_FATAL_ERR = BIT(3), MSIX_HW_INT_CAUSES_REG_SW_ERR_BZ = BIT(5), MSIX_HW_INT_CAUSES_REG_CT_KILL = BIT(6), MSIX_HW_INT_CAUSES_REG_RF_KILL = BIT(7), diff --git a/sys/contrib/dev/iwlwifi/iwl-dbg-tlv.c b/sys/contrib/dev/iwlwifi/iwl-dbg-tlv.c index ef5baee6c9c5..08d990ba8a79 100644 --- a/sys/contrib/dev/iwlwifi/iwl-dbg-tlv.c +++ b/sys/contrib/dev/iwlwifi/iwl-dbg-tlv.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2018-2023 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/firmware.h> #include "iwl-drv.h" @@ -64,21 +64,22 @@ dbg_ver_table[IWL_DBG_TLV_TYPE_NUM] = { [IWL_DBG_TLV_TYPE_CONF_SET] = {.min_ver = 1, .max_ver = 1,}, }; -static int iwl_dbg_tlv_add(const struct iwl_ucode_tlv *tlv, - struct list_head *list) +/* add a new TLV node, returning it so it can be modified */ +static struct iwl_ucode_tlv *iwl_dbg_tlv_add(const struct iwl_ucode_tlv *tlv, + struct list_head *list) { u32 len = le32_to_cpu(tlv->length); struct iwl_dbg_tlv_node *node; - node = kzalloc(sizeof(*node) + len, GFP_KERNEL); + node = kzalloc(struct_size(node, tlv.data, len), GFP_KERNEL); if (!node) - return -ENOMEM; + return NULL; memcpy(&node->tlv, tlv, sizeof(node->tlv)); memcpy(node->tlv.data, tlv->data, len); list_add_tail(&node->list, list); - return 0; + return &node->tlv; } static bool iwl_dbg_tlv_ver_support(const struct iwl_ucode_tlv *tlv) @@ -103,10 +104,18 @@ static int iwl_dbg_tlv_alloc_debug_info(struct iwl_trans *trans, if (le32_to_cpu(tlv->length) != sizeof(*debug_info)) return -EINVAL; + /* we use this as a string, ensure input was NUL terminated */ + if (strnlen(debug_info->debug_cfg_name, + sizeof(debug_info->debug_cfg_name)) == + sizeof(debug_info->debug_cfg_name)) + return -EINVAL; + IWL_DEBUG_FW(trans, "WRT: Loading debug cfg: %s\n", debug_info->debug_cfg_name); - return iwl_dbg_tlv_add(tlv, &trans->dbg.debug_info_tlv_list); + if (!iwl_dbg_tlv_add(tlv, &trans->dbg.debug_info_tlv_list)) + return -ENOMEM; + return 0; } static int iwl_dbg_tlv_alloc_buf_alloc(struct iwl_trans *trans, @@ -175,7 +184,9 @@ static int iwl_dbg_tlv_alloc_hcmd(struct iwl_trans *trans, return -EINVAL; } - return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].hcmd_list); + if (!iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].hcmd_list)) + return -ENOMEM; + return 0; } static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, @@ -212,12 +223,6 @@ static int iwl_dbg_tlv_alloc_region(struct iwl_trans *trans, return -EINVAL; } - if (type == IWL_FW_INI_REGION_PCI_IOSF_CONFIG && - !trans->ops->read_config32) { - IWL_ERR(trans, "WRT: Unsupported region type %u\n", type); - return -EOPNOTSUPP; - } - if (type == IWL_FW_INI_REGION_INTERNAL_BUFFER) { trans->dbg.imr_data.sram_addr = le32_to_cpu(reg->internal_buffer.base_addr); @@ -246,11 +251,9 @@ 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; - struct iwl_fw_ini_trigger_tlv *dup_trig; u32 tp = le32_to_cpu(trig->time_point); u32 rf = le32_to_cpu(trig->reset_fw); - struct iwl_ucode_tlv *dup = NULL; - int ret; + struct iwl_ucode_tlv *new_tlv; if (le32_to_cpu(tlv->length) < sizeof(*trig)) return -EINVAL; @@ -267,20 +270,18 @@ static int iwl_dbg_tlv_alloc_trigger(struct iwl_trans *trans, "WRT: time point %u for trigger TLV with reset_fw %u\n", tp, rf); trans->dbg.last_tp_resetfw = 0xFF; + + new_tlv = iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list); + if (!new_tlv) + return -ENOMEM; + if (!le32_to_cpu(trig->occurrences)) { - dup = kmemdup(tlv, sizeof(*tlv) + le32_to_cpu(tlv->length), - GFP_KERNEL); - if (!dup) - return -ENOMEM; - dup_trig = (void *)dup->data; - dup_trig->occurrences = cpu_to_le32(-1); - tlv = dup; - } + struct iwl_fw_ini_trigger_tlv *new_trig = (void *)new_tlv->data; - ret = iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].trig_list); - kfree(dup); + new_trig->occurrences = cpu_to_le32(-1); + } - return ret; + return 0; } static int iwl_dbg_tlv_config_set(struct iwl_trans *trans, @@ -304,7 +305,9 @@ static int iwl_dbg_tlv_config_set(struct iwl_trans *trans, return -EINVAL; } - return iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].config_list); + if (!iwl_dbg_tlv_add(tlv, &trans->dbg.time_point[tp].config_list)) + return -ENOMEM; + return 0; } static int (*dbg_tlv_alloc[])(struct iwl_trans *trans, @@ -509,6 +512,8 @@ void iwl_dbg_tlv_load_bin(struct device *dev, struct iwl_trans *trans) if (res) return; + trans->dbg.yoyo_bin_loaded = true; + iwl_dbg_tlv_parse_bin(trans, fw->data, fw->size); release_firmware(fw); @@ -1094,7 +1099,7 @@ static int iwl_dbg_tlv_override_trig_node(struct iwl_fw_runtime *fwrt, node_trig = (void *)node_tlv->data; } - memcpy(node_trig->data + offset, trig->data, trig_data_len); + memcpy((u8 *)node_trig->data + offset, trig->data, trig_data_len); node_tlv->length = cpu_to_le32(size); if (policy & IWL_FW_INI_APPLY_POLICY_OVERRIDE_CFG) { @@ -1146,7 +1151,9 @@ iwl_dbg_tlv_add_active_trigger(struct iwl_fw_runtime *fwrt, if (!match) { IWL_DEBUG_FW(fwrt, "WRT: Enabling trigger (time point %u)\n", le32_to_cpu(trig->time_point)); - return iwl_dbg_tlv_add(trig_tlv, trig_list); + if (!iwl_dbg_tlv_add(trig_tlv, trig_list)) + return -ENOMEM; + return 0; } return iwl_dbg_tlv_override_trig_node(fwrt, trig_tlv, match); @@ -1232,38 +1239,27 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, } } - fwrt->trans->dbg.restart_required = FALSE; - IWL_DEBUG_FW(fwrt, "WRT: tp %d, reset_fw %d\n", - tp, dump_data.trig->reset_fw); - IWL_DEBUG_FW(fwrt, - "WRT: restart_required %d, last_tp_resetfw %d\n", - fwrt->trans->dbg.restart_required, - fwrt->trans->dbg.last_tp_resetfw); + fwrt->trans->dbg.restart_required = false; if (fwrt->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_9000) { - fwrt->trans->dbg.restart_required = TRUE; + fwrt->trans->dbg.restart_required = true; } else if (tp == IWL_FW_INI_TIME_POINT_FW_ASSERT && fwrt->trans->dbg.last_tp_resetfw == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) { - fwrt->trans->dbg.restart_required = FALSE; + fwrt->trans->dbg.restart_required = false; fwrt->trans->dbg.last_tp_resetfw = 0xFF; - IWL_DEBUG_FW(fwrt, "WRT: FW_ASSERT due to reset_fw_mode-no restart\n"); } else if (le32_to_cpu(dump_data.trig->reset_fw) == IWL_FW_INI_RESET_FW_MODE_STOP_AND_RELOAD_FW) { - IWL_DEBUG_FW(fwrt, "WRT: stop and reload firmware\n"); - fwrt->trans->dbg.restart_required = TRUE; + fwrt->trans->dbg.restart_required = true; } else if (le32_to_cpu(dump_data.trig->reset_fw) == IWL_FW_INI_RESET_FW_MODE_STOP_FW_ONLY) { - IWL_DEBUG_FW(fwrt, - "WRT: stop only and no reload firmware\n"); - fwrt->trans->dbg.restart_required = FALSE; + fwrt->trans->dbg.restart_required = false; fwrt->trans->dbg.last_tp_resetfw = le32_to_cpu(dump_data.trig->reset_fw); } else if (le32_to_cpu(dump_data.trig->reset_fw) == IWL_FW_INI_RESET_FW_MODE_NOTHING) { - IWL_DEBUG_FW(fwrt, - "WRT: nothing need to be done after debug collection\n"); + /* nothing */ } else { IWL_ERR(fwrt, "WRT: wrong resetfw %d\n", le32_to_cpu(dump_data.trig->reset_fw)); @@ -1272,7 +1268,7 @@ iwl_dbg_tlv_tp_trigger(struct iwl_fw_runtime *fwrt, bool sync, return 0; } -static void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) +void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt) { enum iwl_fw_ini_buffer_location *ini_dest = &fwrt->trans->dbg.ini_dest; int ret, i; diff --git a/sys/contrib/dev/iwlwifi/iwl-dbg-tlv.h b/sys/contrib/dev/iwlwifi/iwl-dbg-tlv.h index 128059ca77e6..7ed6329fd8ca 100644 --- a/sys/contrib/dev/iwlwifi/iwl-dbg-tlv.h +++ b/sys/contrib/dev/iwlwifi/iwl-dbg-tlv.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2023 Intel Corporation */ #ifndef __iwl_dbg_tlv_h__ #define __iwl_dbg_tlv_h__ @@ -10,7 +10,8 @@ #include <fw/file.h> #include <fw/api/dbg-tlv.h> -#define IWL_DBG_TLV_MAX_PRESET 15 +#define IWL_DBG_TLV_MAX_PRESET 15 +#define ENABLE_INI (IWL_DBG_TLV_MAX_PRESET + 1) /** * struct iwl_dbg_tlv_node - debug TLV node @@ -56,6 +57,7 @@ void _iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data, bool sync); +void iwl_dbg_tlv_init_cfg(struct iwl_fw_runtime *fwrt); static inline void iwl_dbg_tlv_time_point(struct iwl_fw_runtime *fwrt, enum iwl_fw_ini_time_point tp_id, diff --git a/sys/contrib/dev/iwlwifi/iwl-debug.c b/sys/contrib/dev/iwlwifi/iwl-debug.c index ac61b464e51d..0659e43368f6 100644 --- a/sys/contrib/dev/iwlwifi/iwl-debug.c +++ b/sys/contrib/dev/iwlwifi/iwl-debug.c @@ -150,17 +150,18 @@ void __iwl_dbg(struct device *dev, vaf.va = &args; #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_have_debug_level(level) && - (!limit || net_ratelimit())) { + (!limit || net_ratelimit())) #if defined(__linux_) dev_printk(KERN_DEBUG, dev, "%s %pV", function, &vaf); #elif defined(__FreeBSD__) + { char *str; vasprintf(&str, M_KMALLOC, vaf.fmt, args); dev_printk(KERN_DEBUG, dev, "%d %u %s %s", curthread->td_tid, (unsigned int)ticks, function, str); free(str, M_KMALLOC); -#endif } +#endif #endif trace_iwlwifi_dbg(level, function, &vaf); diff --git a/sys/contrib/dev/iwlwifi/iwl-devtrace.h b/sys/contrib/dev/iwlwifi/iwl-devtrace.h index 1a0d6a242b24..e37c380fdb5b 100644 --- a/sys/contrib/dev/iwlwifi/iwl-devtrace.h +++ b/sys/contrib/dev/iwlwifi/iwl-devtrace.h @@ -61,6 +61,8 @@ void trace_iwlwifi_dev_rx_data(const struct device *, #define trace_iwlwifi_dev_tx(...) #define trace_iwlwifi_dev_tx_tb(...) +#define maybe_trace_iwlwifi_dev_rx(...) + #define trace_iwlwifi_crit(...) #define trace_iwlwifi_dbg(...) #define trace_iwlwifi_err(...) diff --git a/sys/contrib/dev/iwlwifi/iwl-drv.c b/sys/contrib/dev/iwlwifi/iwl-drv.c index be89566b98ab..7f4746e5591e 100644 --- a/sys/contrib/dev/iwlwifi/iwl-drv.c +++ b/sys/contrib/dev/iwlwifi/iwl-drv.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2005-2014, 2018-2021 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -34,9 +34,11 @@ #if defined(__linux__) #define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux" +MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_LICENSE("GPL"); #elif defined(__FreeBSD__) #define DRV_DESCRIPTION "Intel(R) Wireless WiFi based driver for FreeBSD" +MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_LICENSE("BSD"); MODULE_VERSION(if_iwlwifi, 1); MODULE_DEPEND(if_iwlwifi, linuxkpi, 1, 1, 1); @@ -45,7 +47,6 @@ MODULE_DEPEND(if_iwlwifi, linuxkpi_wlan, 1, 1, 1); MODULE_DEPEND(if_iwlwifi, lindebugfs, 1, 1, 1); #endif #endif -MODULE_DESCRIPTION(DRV_DESCRIPTION); #ifdef CONFIG_IWLWIFI_DEBUGFS static struct dentry *iwl_dbgfs_root; @@ -145,6 +146,7 @@ static void iwl_dealloc_ucode(struct iwl_drv *drv) kfree(drv->fw.ucode_capa.cmd_versions); kfree(drv->fw.phy_integration_ver); kfree(drv->trans->dbg.pc_data); + drv->trans->dbg.pc_data = NULL; for (i = 0; i < IWL_UCODE_TYPE_MAX; i++) iwl_free_fw_img(drv, drv->fw.img + i); @@ -179,6 +181,8 @@ static inline char iwl_drv_get_step(int step) { if (step == SILICON_Z_STEP) return 'z'; + if (step == SILICON_TC_STEP) + return 'a'; return 'a' + step; } @@ -195,25 +199,28 @@ const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) mac_step = iwl_drv_get_step(trans->hw_rev_step); + rf_step = iwl_drv_get_step(CSR_HW_RFID_STEP(trans->hw_rf_id)); + switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { case IWL_CFG_RF_TYPE_HR1: case IWL_CFG_RF_TYPE_HR2: rf = "hr"; + rf_step = 'b'; break; case IWL_CFG_RF_TYPE_GF: rf = "gf"; break; - case IWL_CFG_RF_TYPE_MR: - rf = "mr"; - break; - case IWL_CFG_RF_TYPE_MS: - rf = "ms"; - break; case IWL_CFG_RF_TYPE_FM: rf = "fm"; break; case IWL_CFG_RF_TYPE_WH: - rf = "wh"; + if (SILICON_Z_STEP == + CSR_HW_RFID_STEP(trans->hw_rf_id)) { + rf = "whtc"; + rf_step = 'a'; + } else { + rf = "wh"; + } break; default: return "unknown-rf"; @@ -221,8 +228,6 @@ const char *iwl_drv_get_fwname_pre(struct iwl_trans *trans, char *buf) cdb = CSR_HW_RFID_IS_CDB(trans->hw_rf_id) ? "4" : ""; - rf_step = iwl_drv_get_step(CSR_HW_RFID_STEP(trans->hw_rf_id)); - scnprintf(buf, FW_NAME_PRE_BUFSIZE, "iwlwifi-%s-%c0-%s%s-%c0", trans->cfg->fw_name_mac, mac_step, @@ -995,16 +1000,10 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, minor = le32_to_cpup(ptr++); local_comp = le32_to_cpup(ptr); - if (major >= 35) - snprintf(drv->fw.fw_version, - sizeof(drv->fw.fw_version), - "%u.%08x.%u %s", major, minor, - local_comp, iwl_reduced_fw_name(drv)); - else - snprintf(drv->fw.fw_version, - sizeof(drv->fw.fw_version), - "%u.%u.%u %s", major, minor, - local_comp, iwl_reduced_fw_name(drv)); + snprintf(drv->fw.fw_version, + sizeof(drv->fw.fw_version), + "%u.%08x.%u %s", major, minor, + local_comp, iwl_reduced_fw_name(drv)); break; } case IWL_UCODE_TLV_FW_DBG_DEST: { @@ -1320,10 +1319,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv, case IWL_UCODE_TLV_CURRENT_PC: if (tlv_len < sizeof(struct iwl_pc_data)) goto invalid_tlv_len; - drv->trans->dbg.num_pc = - tlv_len / sizeof(struct iwl_pc_data); drv->trans->dbg.pc_data = kmemdup(tlv_data, tlv_len, GFP_KERNEL); + if (!drv->trans->dbg.pc_data) + return -ENOMEM; + drv->trans->dbg.num_pc = + tlv_len / sizeof(struct iwl_pc_data); break; default: IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type); @@ -1442,35 +1443,34 @@ _iwl_op_mode_start(struct iwl_drv *drv, struct iwlwifi_opmode_table *op) const struct iwl_op_mode_ops *ops = op->ops; struct dentry *dbgfs_dir = NULL; struct iwl_op_mode *op_mode = NULL; - int retry, max_retry = !!iwlwifi_mod_params.fw_restart * IWL_MAX_INIT_RETRY; - for (retry = 0; retry <= max_retry; retry++) { + /* also protects start/stop from racing against each other */ + lockdep_assert_held(&iwlwifi_opmode_table_mtx); #ifdef CONFIG_IWLWIFI_DEBUGFS - drv->dbgfs_op_mode = debugfs_create_dir(op->name, - drv->dbgfs_drv); - dbgfs_dir = drv->dbgfs_op_mode; + drv->dbgfs_op_mode = debugfs_create_dir(op->name, + drv->dbgfs_drv); + dbgfs_dir = drv->dbgfs_op_mode; #endif - op_mode = ops->start(drv->trans, drv->trans->cfg, - &drv->fw, dbgfs_dir); - - if (op_mode) - return op_mode; - - IWL_ERR(drv, "retry init count %d\n", retry); + op_mode = ops->start(drv->trans, drv->trans->cfg, + &drv->fw, dbgfs_dir); + if (op_mode) + return op_mode; #ifdef CONFIG_IWLWIFI_DEBUGFS - debugfs_remove_recursive(drv->dbgfs_op_mode); - drv->dbgfs_op_mode = NULL; + debugfs_remove_recursive(drv->dbgfs_op_mode); + drv->dbgfs_op_mode = NULL; #endif - } return NULL; } static void _iwl_op_mode_stop(struct iwl_drv *drv) { + /* also protects start/stop from racing against each other */ + lockdep_assert_held(&iwlwifi_opmode_table_mtx); + /* op_mode can be NULL if its start failed */ if (drv->op_mode) { iwl_op_mode_stop(drv->op_mode); @@ -1502,7 +1502,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) size_t trigger_tlv_sz[FW_DBG_TRIGGER_MAX]; u32 api_ver; int i; - bool load_module = false; bool usniffer_images = false; bool failure = true; @@ -1750,24 +1749,12 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context) goto out_unbind; } } else { - load_module = true; + request_module_nowait("%s", op->name); } mutex_unlock(&iwlwifi_opmode_table_mtx); - /* - * Complete the firmware request last so that - * a driver unbind (stop) doesn't run while we - * are doing the start() above. - */ complete(&drv->request_firmware_complete); - /* - * Load the module last so we don't block anything - * else from proceeding if the module fails to load - * or hangs loading. - */ - if (load_module) - request_module("%s", op->name); failure = false; goto free; @@ -1827,6 +1814,22 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) #endif drv->trans->dbg.domains_bitmap = IWL_TRANS_FW_DBG_DOMAIN(drv->trans); + if (iwlwifi_mod_params.enable_ini != ENABLE_INI) { + /* We have a non-default value in the module parameter, + * take its value + */ + drv->trans->dbg.domains_bitmap &= 0xffff; + if (iwlwifi_mod_params.enable_ini != IWL_FW_INI_PRESET_DISABLE) { + if (iwlwifi_mod_params.enable_ini > ENABLE_INI) { + IWL_ERR(trans, + "invalid enable_ini module parameter value: max = %d, using 0 instead\n", + ENABLE_INI); + iwlwifi_mod_params.enable_ini = 0; + } + drv->trans->dbg.domains_bitmap = + BIT(IWL_FW_DBG_DOMAIN_POS + iwlwifi_mod_params.enable_ini); + } + } ret = iwl_request_firmware(drv, true); if (ret) { @@ -1850,8 +1853,8 @@ struct iwl_drv *iwl_drv_start(struct iwl_trans *trans) err_fw: #ifdef CONFIG_IWLWIFI_DEBUGFS debugfs_remove_recursive(drv->dbgfs_drv); - iwl_dbg_tlv_free(drv->trans); #endif + iwl_dbg_tlv_free(drv->trans); kfree(drv); err: return ERR_PTR(ret); @@ -1865,11 +1868,12 @@ void iwl_drv_stop(struct iwl_drv *drv) wait_for_completion(&drv->drv_start_complete); #endif + mutex_lock(&iwlwifi_opmode_table_mtx); + _iwl_op_mode_stop(drv); iwl_dealloc_ucode(drv); - mutex_lock(&iwlwifi_opmode_table_mtx); /* * List is empty (this item wasn't added) * when firmware loading failed -- in that @@ -1880,7 +1884,7 @@ void iwl_drv_stop(struct iwl_drv *drv) mutex_unlock(&iwlwifi_opmode_table_mtx); #ifdef CONFIG_IWLWIFI_DEBUGFS - drv->trans->ops->debugfs_cleanup(drv->trans); + iwl_trans_debugfs_cleanup(drv->trans); debugfs_remove_recursive(drv->dbgfs_drv); #endif @@ -1890,8 +1894,6 @@ void iwl_drv_stop(struct iwl_drv *drv) kfree(drv); } -#define ENABLE_INI (IWL_DBG_TLV_MAX_PRESET + 1) - /* shared module parameters */ struct iwl_mod_params iwlwifi_mod_params = { .fw_restart = true, @@ -2017,43 +2019,10 @@ module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable, uint, 0644); MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality bitmap 1: BSS 2: P2P Client (default: 3)"); -#if defined(__linux__) -static int enable_ini_set(const char *arg, const struct kernel_param *kp) -{ - int ret = 0; - bool res; - __u32 new_enable_ini; - - /* in case the argument type is a number */ - ret = kstrtou32(arg, 0, &new_enable_ini); - if (!ret) { - if (new_enable_ini > ENABLE_INI) { - pr_err("enable_ini cannot be %d, in range 0-16\n", new_enable_ini); - return -EINVAL; - } - goto out; - } - - /* in case the argument type is boolean */ - ret = kstrtobool(arg, &res); - if (ret) - return ret; - new_enable_ini = (res ? ENABLE_INI : 0); - -out: - iwlwifi_mod_params.enable_ini = new_enable_ini; - return 0; -} - -static const struct kernel_param_ops enable_ini_ops = { - .set = enable_ini_set -}; - -module_param_cb(enable_ini, &enable_ini_ops, &iwlwifi_mod_params.enable_ini, 0644); +module_param_named(enable_ini, iwlwifi_mod_params.enable_ini, uint, 0444); MODULE_PARM_DESC(enable_ini, "0:disable, 1-15:FW_DBG_PRESET Values, 16:enabled without preset value defined," "Debug INI TLV FW debug infrastructure (default: 16)"); -#endif /* * set bt_coex_active to true, uCode will do kill/defer diff --git a/sys/contrib/dev/iwlwifi/iwl-drv.h b/sys/contrib/dev/iwlwifi/iwl-drv.h index 6c19989e4ab7..1549ff429549 100644 --- a/sys/contrib/dev/iwlwifi/iwl-drv.h +++ b/sys/contrib/dev/iwlwifi/iwl-drv.h @@ -6,6 +6,7 @@ #ifndef __iwl_drv_h__ #define __iwl_drv_h__ #include <linux/export.h> +#include <kunit/visibility.h> /* for all modules */ #define DRV_NAME "iwlwifi" @@ -56,7 +57,7 @@ struct iwl_cfg; /** * iwl_drv_start - start the drv * - * @trans_ops: the ops of the transport + * @trans: the transport * * starts the driver: fetches the firmware. This should be called by bus * specific system flows implementations. For example, the bus specific probe @@ -89,8 +90,13 @@ void iwl_drv_stop(struct iwl_drv *drv); #define IWL_EXPORT_SYMBOL(sym) #endif -/* max retry for init flow */ -#define IWL_MAX_INIT_RETRY 2 +#if IS_ENABLED(CONFIG_IWLWIFI_KUNIT_TESTS) +#define EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(sym) EXPORT_SYMBOL_IF_KUNIT(sym) +#define VISIBLE_IF_IWLWIFI_KUNIT +#else +#define EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(sym) +#define VISIBLE_IF_IWLWIFI_KUNIT static +#endif #define FW_NAME_PRE_BUFSIZE 64 struct iwl_trans; diff --git a/sys/contrib/dev/iwlwifi/iwl-eeprom-parse.c b/sys/contrib/dev/iwlwifi/iwl-eeprom-parse.c deleted file mode 100644 index d7a7835b935c..000000000000 --- a/sys/contrib/dev/iwlwifi/iwl-eeprom-parse.c +++ /dev/null @@ -1,879 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* - * Copyright (C) 2005-2014, 2018-2020 Intel Corporation - * Copyright (C) 2015 Intel Mobile Communications GmbH - */ -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/export.h> -#include "iwl-drv.h" -#include "iwl-modparams.h" -#include "iwl-eeprom-parse.h" - -#if IS_ENABLED(CONFIG_IWLDVM) -/* EEPROM offset definitions */ - -/* indirect access definitions */ -#define ADDRESS_MSK 0x0000FFFF -#define INDIRECT_TYPE_MSK 0x000F0000 -#define INDIRECT_HOST 0x00010000 -#define INDIRECT_GENERAL 0x00020000 -#define INDIRECT_REGULATORY 0x00030000 -#define INDIRECT_CALIBRATION 0x00040000 -#define INDIRECT_PROCESS_ADJST 0x00050000 -#define INDIRECT_OTHERS 0x00060000 -#define INDIRECT_TXP_LIMIT 0x00070000 -#define INDIRECT_TXP_LIMIT_SIZE 0x00080000 -#define INDIRECT_ADDRESS 0x00100000 - -/* corresponding link offsets in EEPROM */ -#define EEPROM_LINK_HOST (2*0x64) -#define EEPROM_LINK_GENERAL (2*0x65) -#define EEPROM_LINK_REGULATORY (2*0x66) -#define EEPROM_LINK_CALIBRATION (2*0x67) -#define EEPROM_LINK_PROCESS_ADJST (2*0x68) -#define EEPROM_LINK_OTHERS (2*0x69) -#define EEPROM_LINK_TXP_LIMIT (2*0x6a) -#define EEPROM_LINK_TXP_LIMIT_SIZE (2*0x6b) - -/* General */ -#define EEPROM_DEVICE_ID (2*0x08) /* 2 bytes */ -#define EEPROM_SUBSYSTEM_ID (2*0x0A) /* 2 bytes */ -#define EEPROM_MAC_ADDRESS (2*0x15) /* 6 bytes */ -#define EEPROM_BOARD_REVISION (2*0x35) /* 2 bytes */ -#define EEPROM_BOARD_PBA_NUMBER (2*0x3B+1) /* 9 bytes */ -#define EEPROM_VERSION (2*0x44) /* 2 bytes */ -#define EEPROM_SKU_CAP (2*0x45) /* 2 bytes */ -#define EEPROM_OEM_MODE (2*0x46) /* 2 bytes */ -#define EEPROM_RADIO_CONFIG (2*0x48) /* 2 bytes */ -#define EEPROM_NUM_MAC_ADDRESS (2*0x4C) /* 2 bytes */ - -/* calibration */ -struct iwl_eeprom_calib_hdr { - u8 version; - u8 pa_type; - __le16 voltage; -} __packed; - -#define EEPROM_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) -#define EEPROM_XTAL ((2*0x128) | EEPROM_CALIB_ALL) - -/* temperature */ -#define EEPROM_KELVIN_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL) -#define EEPROM_RAW_TEMPERATURE ((2*0x12B) | EEPROM_CALIB_ALL) - -/* SKU Capabilities (actual values from EEPROM definition) */ -enum eeprom_sku_bits { - EEPROM_SKU_CAP_BAND_24GHZ = BIT(4), - EEPROM_SKU_CAP_BAND_52GHZ = BIT(5), - EEPROM_SKU_CAP_11N_ENABLE = BIT(6), - EEPROM_SKU_CAP_AMT_ENABLE = BIT(7), - EEPROM_SKU_CAP_IPAN_ENABLE = BIT(8) -}; - -/* radio config bits (actual values from EEPROM definition) */ -#define EEPROM_RF_CFG_TYPE_MSK(x) (x & 0x3) /* bits 0-1 */ -#define EEPROM_RF_CFG_STEP_MSK(x) ((x >> 2) & 0x3) /* bits 2-3 */ -#define EEPROM_RF_CFG_DASH_MSK(x) ((x >> 4) & 0x3) /* bits 4-5 */ -#define EEPROM_RF_CFG_PNUM_MSK(x) ((x >> 6) & 0x3) /* bits 6-7 */ -#define EEPROM_RF_CFG_TX_ANT_MSK(x) ((x >> 8) & 0xF) /* bits 8-11 */ -#define EEPROM_RF_CFG_RX_ANT_MSK(x) ((x >> 12) & 0xF) /* bits 12-15 */ - - -/* - * EEPROM bands - * These are the channel numbers from each band in the order - * that they are stored in the EEPROM band information. Note - * that EEPROM bands aren't the same as mac80211 bands, and - * there are even special "ht40 bands" in the EEPROM. - */ -static const u8 iwl_eeprom_band_1[14] = { /* 2.4 GHz */ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 -}; - -static const u8 iwl_eeprom_band_2[] = { /* 4915-5080MHz */ - 183, 184, 185, 187, 188, 189, 192, 196, 7, 8, 11, 12, 16 -}; - -static const u8 iwl_eeprom_band_3[] = { /* 5170-5320MHz */ - 34, 36, 38, 40, 42, 44, 46, 48, 52, 56, 60, 64 -}; - -static const u8 iwl_eeprom_band_4[] = { /* 5500-5700MHz */ - 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140 -}; - -static const u8 iwl_eeprom_band_5[] = { /* 5725-5825MHz */ - 145, 149, 153, 157, 161, 165 -}; - -static const u8 iwl_eeprom_band_6[] = { /* 2.4 ht40 channel */ - 1, 2, 3, 4, 5, 6, 7 -}; - -static const u8 iwl_eeprom_band_7[] = { /* 5.2 ht40 channel */ - 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157 -}; - -#define IWL_NUM_CHANNELS (ARRAY_SIZE(iwl_eeprom_band_1) + \ - ARRAY_SIZE(iwl_eeprom_band_2) + \ - ARRAY_SIZE(iwl_eeprom_band_3) + \ - ARRAY_SIZE(iwl_eeprom_band_4) + \ - ARRAY_SIZE(iwl_eeprom_band_5)) - -/* rate data (static) */ -static struct ieee80211_rate iwl_cfg80211_rates[] = { - { .bitrate = 1 * 10, .hw_value = 0, .hw_value_short = 0, }, - { .bitrate = 2 * 10, .hw_value = 1, .hw_value_short = 1, - .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, - { .bitrate = 5.5 * 10, .hw_value = 2, .hw_value_short = 2, - .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, - { .bitrate = 11 * 10, .hw_value = 3, .hw_value_short = 3, - .flags = IEEE80211_RATE_SHORT_PREAMBLE, }, - { .bitrate = 6 * 10, .hw_value = 4, .hw_value_short = 4, }, - { .bitrate = 9 * 10, .hw_value = 5, .hw_value_short = 5, }, - { .bitrate = 12 * 10, .hw_value = 6, .hw_value_short = 6, }, - { .bitrate = 18 * 10, .hw_value = 7, .hw_value_short = 7, }, - { .bitrate = 24 * 10, .hw_value = 8, .hw_value_short = 8, }, - { .bitrate = 36 * 10, .hw_value = 9, .hw_value_short = 9, }, - { .bitrate = 48 * 10, .hw_value = 10, .hw_value_short = 10, }, - { .bitrate = 54 * 10, .hw_value = 11, .hw_value_short = 11, }, -}; -#define RATES_24_OFFS 0 -#define N_RATES_24 ARRAY_SIZE(iwl_cfg80211_rates) -#define RATES_52_OFFS 4 -#define N_RATES_52 (N_RATES_24 - RATES_52_OFFS) - -/* EEPROM reading functions */ - -static u16 iwl_eeprom_query16(const u8 *eeprom, size_t eeprom_size, int offset) -{ - if (WARN_ON(offset + sizeof(u16) > eeprom_size)) - return 0; - return le16_to_cpup((__le16 *)(eeprom + offset)); -} - -static u32 eeprom_indirect_address(const u8 *eeprom, size_t eeprom_size, - u32 address) -{ - u16 offset = 0; - - if ((address & INDIRECT_ADDRESS) == 0) - return address; - - switch (address & INDIRECT_TYPE_MSK) { - case INDIRECT_HOST: - offset = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_LINK_HOST); - break; - case INDIRECT_GENERAL: - offset = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_LINK_GENERAL); - break; - case INDIRECT_REGULATORY: - offset = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_LINK_REGULATORY); - break; - case INDIRECT_TXP_LIMIT: - offset = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_LINK_TXP_LIMIT); - break; - case INDIRECT_TXP_LIMIT_SIZE: - offset = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_LINK_TXP_LIMIT_SIZE); - break; - case INDIRECT_CALIBRATION: - offset = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_LINK_CALIBRATION); - break; - case INDIRECT_PROCESS_ADJST: - offset = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_LINK_PROCESS_ADJST); - break; - case INDIRECT_OTHERS: - offset = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_LINK_OTHERS); - break; - default: - WARN_ON(1); - break; - } - - /* translate the offset from words to byte */ - return (address & ADDRESS_MSK) + (offset << 1); -} - -static const u8 *iwl_eeprom_query_addr(const u8 *eeprom, size_t eeprom_size, - u32 offset) -{ - u32 address = eeprom_indirect_address(eeprom, eeprom_size, offset); - - if (WARN_ON(address >= eeprom_size)) - return NULL; - - return &eeprom[address]; -} - -static int iwl_eeprom_read_calib(const u8 *eeprom, size_t eeprom_size, - struct iwl_nvm_data *data) -{ - struct iwl_eeprom_calib_hdr *hdr; - - hdr = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size, - EEPROM_CALIB_ALL); - if (!hdr) - return -ENODATA; - data->calib_version = hdr->version; - data->calib_voltage = hdr->voltage; - - return 0; -} - -/** - * enum iwl_eeprom_channel_flags - channel flags in EEPROM - * @EEPROM_CHANNEL_VALID: channel is usable for this SKU/geo - * @EEPROM_CHANNEL_IBSS: usable as an IBSS channel - * @EEPROM_CHANNEL_ACTIVE: active scanning allowed - * @EEPROM_CHANNEL_RADAR: radar detection required - * @EEPROM_CHANNEL_WIDE: 20 MHz channel okay (?) - * @EEPROM_CHANNEL_DFS: dynamic freq selection candidate - */ -enum iwl_eeprom_channel_flags { - EEPROM_CHANNEL_VALID = BIT(0), - EEPROM_CHANNEL_IBSS = BIT(1), - EEPROM_CHANNEL_ACTIVE = BIT(3), - EEPROM_CHANNEL_RADAR = BIT(4), - EEPROM_CHANNEL_WIDE = BIT(5), - EEPROM_CHANNEL_DFS = BIT(7), -}; - -/** - * struct iwl_eeprom_channel - EEPROM channel data - * @flags: %EEPROM_CHANNEL_* flags - * @max_power_avg: max power (in dBm) on this channel, at most 31 dBm - */ -struct iwl_eeprom_channel { - u8 flags; - s8 max_power_avg; -} __packed; - - -enum iwl_eeprom_enhanced_txpwr_flags { - IWL_EEPROM_ENH_TXP_FL_VALID = BIT(0), - IWL_EEPROM_ENH_TXP_FL_BAND_52G = BIT(1), - IWL_EEPROM_ENH_TXP_FL_OFDM = BIT(2), - IWL_EEPROM_ENH_TXP_FL_40MHZ = BIT(3), - IWL_EEPROM_ENH_TXP_FL_HT_AP = BIT(4), - IWL_EEPROM_ENH_TXP_FL_RES1 = BIT(5), - IWL_EEPROM_ENH_TXP_FL_RES2 = BIT(6), - IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE = BIT(7), -}; - -/** - * struct iwl_eeprom_enhanced_txpwr - * @flags: entry flags - * @channel: channel number - * @chain_a_max: chain a max power in 1/2 dBm - * @chain_b_max: chain b max power in 1/2 dBm - * @chain_c_max: chain c max power in 1/2 dBm - * @delta_20_in_40: 20-in-40 deltas (hi/lo) - * @mimo2_max: mimo2 max power in 1/2 dBm - * @mimo3_max: mimo3 max power in 1/2 dBm - * - * This structure presents the enhanced regulatory tx power limit layout - * in an EEPROM image. - */ -struct iwl_eeprom_enhanced_txpwr { - u8 flags; - u8 channel; - s8 chain_a_max; - s8 chain_b_max; - s8 chain_c_max; - u8 delta_20_in_40; - s8 mimo2_max; - s8 mimo3_max; -} __packed; - -static s8 iwl_get_max_txpwr_half_dbm(const struct iwl_nvm_data *data, - struct iwl_eeprom_enhanced_txpwr *txp) -{ - s8 result = 0; /* (.5 dBm) */ - - /* Take the highest tx power from any valid chains */ - if (data->valid_tx_ant & ANT_A && txp->chain_a_max > result) - result = txp->chain_a_max; - - if (data->valid_tx_ant & ANT_B && txp->chain_b_max > result) - result = txp->chain_b_max; - - if (data->valid_tx_ant & ANT_C && txp->chain_c_max > result) - result = txp->chain_c_max; - - if ((data->valid_tx_ant == ANT_AB || - data->valid_tx_ant == ANT_BC || - data->valid_tx_ant == ANT_AC) && txp->mimo2_max > result) - result = txp->mimo2_max; - - if (data->valid_tx_ant == ANT_ABC && txp->mimo3_max > result) - result = txp->mimo3_max; - - return result; -} - -#define EEPROM_TXP_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT) -#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr) -#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE) - -#define TXP_CHECK_AND_PRINT(x) \ - ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) ? # x " " : "") - -static void -iwl_eeprom_enh_txp_read_element(struct iwl_nvm_data *data, - struct iwl_eeprom_enhanced_txpwr *txp, - int n_channels, s8 max_txpower_avg) -{ - int ch_idx; - enum nl80211_band band; - - band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ? - NL80211_BAND_5GHZ : NL80211_BAND_2GHZ; - - for (ch_idx = 0; ch_idx < n_channels; ch_idx++) { - struct ieee80211_channel *chan = &data->channels[ch_idx]; - - /* update matching channel or from common data only */ - if (txp->channel != 0 && chan->hw_value != txp->channel) - continue; - - /* update matching band only */ - if (band != chan->band) - continue; - - if (chan->max_power < max_txpower_avg && - !(txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ)) - chan->max_power = max_txpower_avg; - } -} - -static void iwl_eeprom_enhanced_txpower(struct device *dev, - struct iwl_nvm_data *data, - const u8 *eeprom, size_t eeprom_size, - int n_channels) -{ - struct iwl_eeprom_enhanced_txpwr *txp_array, *txp; - int idx, entries; - __le16 *txp_len; - s8 max_txp_avg_halfdbm; - - BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8); - - /* the length is in 16-bit words, but we want entries */ - txp_len = (__le16 *)iwl_eeprom_query_addr(eeprom, eeprom_size, - EEPROM_TXP_SZ_OFFS); - entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN; - - txp_array = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size, - EEPROM_TXP_OFFS); - - for (idx = 0; idx < entries; idx++) { - txp = &txp_array[idx]; - /* skip invalid entries */ - if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID)) - continue; - - IWL_DEBUG_EEPROM(dev, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n", - (txp->channel && (txp->flags & - IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ? - "Common " : (txp->channel) ? - "Channel" : "Common", - (txp->channel), - TXP_CHECK_AND_PRINT(VALID), - TXP_CHECK_AND_PRINT(BAND_52G), - TXP_CHECK_AND_PRINT(OFDM), - TXP_CHECK_AND_PRINT(40MHZ), - TXP_CHECK_AND_PRINT(HT_AP), - TXP_CHECK_AND_PRINT(RES1), - TXP_CHECK_AND_PRINT(RES2), - TXP_CHECK_AND_PRINT(COMMON_TYPE), - txp->flags); - IWL_DEBUG_EEPROM(dev, - "\t\t chain_A: %d chain_B: %d chain_C: %d\n", - txp->chain_a_max, txp->chain_b_max, - txp->chain_c_max); - IWL_DEBUG_EEPROM(dev, - "\t\t MIMO2: %d MIMO3: %d High 20_on_40: 0x%02x Low 20_on_40: 0x%02x\n", - txp->mimo2_max, txp->mimo3_max, - ((txp->delta_20_in_40 & 0xf0) >> 4), - (txp->delta_20_in_40 & 0x0f)); - - max_txp_avg_halfdbm = iwl_get_max_txpwr_half_dbm(data, txp); - - iwl_eeprom_enh_txp_read_element(data, txp, n_channels, - DIV_ROUND_UP(max_txp_avg_halfdbm, 2)); - - if (max_txp_avg_halfdbm > data->max_tx_pwr_half_dbm) - data->max_tx_pwr_half_dbm = max_txp_avg_halfdbm; - } -} - -static void iwl_init_band_reference(const struct iwl_cfg *cfg, - const u8 *eeprom, size_t eeprom_size, - int eeprom_band, int *eeprom_ch_count, - const struct iwl_eeprom_channel **ch_info, - const u8 **eeprom_ch_array) -{ - u32 offset = cfg->eeprom_params->regulatory_bands[eeprom_band - 1]; - - offset |= INDIRECT_ADDRESS | INDIRECT_REGULATORY; - - *ch_info = (void *)iwl_eeprom_query_addr(eeprom, eeprom_size, offset); - - switch (eeprom_band) { - case 1: /* 2.4GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_1); - *eeprom_ch_array = iwl_eeprom_band_1; - break; - case 2: /* 4.9GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_2); - *eeprom_ch_array = iwl_eeprom_band_2; - break; - case 3: /* 5.2GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_3); - *eeprom_ch_array = iwl_eeprom_band_3; - break; - case 4: /* 5.5GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_4); - *eeprom_ch_array = iwl_eeprom_band_4; - break; - case 5: /* 5.7GHz band */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_5); - *eeprom_ch_array = iwl_eeprom_band_5; - break; - case 6: /* 2.4GHz ht40 channels */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_6); - *eeprom_ch_array = iwl_eeprom_band_6; - break; - case 7: /* 5 GHz ht40 channels */ - *eeprom_ch_count = ARRAY_SIZE(iwl_eeprom_band_7); - *eeprom_ch_array = iwl_eeprom_band_7; - break; - default: - *eeprom_ch_count = 0; - *eeprom_ch_array = NULL; - WARN_ON(1); - } -} - -#define CHECK_AND_PRINT(x) \ - ((eeprom_ch->flags & EEPROM_CHANNEL_##x) ? # x " " : "") - -static void iwl_mod_ht40_chan_info(struct device *dev, - struct iwl_nvm_data *data, int n_channels, - enum nl80211_band band, u16 channel, - const struct iwl_eeprom_channel *eeprom_ch, - u8 clear_ht40_extension_channel) -{ - struct ieee80211_channel *chan = NULL; - int i; - - for (i = 0; i < n_channels; i++) { - if (data->channels[i].band != band) - continue; - if (data->channels[i].hw_value != channel) - continue; - chan = &data->channels[i]; - break; - } - - if (!chan) - return; - - IWL_DEBUG_EEPROM(dev, - "HT40 Ch. %d [%sGHz] %s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", - channel, - band == NL80211_BAND_5GHZ ? "5.2" : "2.4", - CHECK_AND_PRINT(IBSS), - CHECK_AND_PRINT(ACTIVE), - CHECK_AND_PRINT(RADAR), - CHECK_AND_PRINT(WIDE), - CHECK_AND_PRINT(DFS), - eeprom_ch->flags, - eeprom_ch->max_power_avg, - ((eeprom_ch->flags & EEPROM_CHANNEL_IBSS) && - !(eeprom_ch->flags & EEPROM_CHANNEL_RADAR)) ? "" - : "not "); - - if (eeprom_ch->flags & EEPROM_CHANNEL_VALID) - chan->flags &= ~clear_ht40_extension_channel; -} - -#define CHECK_AND_PRINT_I(x) \ - ((eeprom_ch_info[ch_idx].flags & EEPROM_CHANNEL_##x) ? # x " " : "") - -static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, - const u8 *eeprom, size_t eeprom_size) -{ - int band, ch_idx; - const struct iwl_eeprom_channel *eeprom_ch_info; - const u8 *eeprom_ch_array; - int eeprom_ch_count; - int n_channels = 0; - - /* - * Loop through the 5 EEPROM bands and add them to the parse list - */ - for (band = 1; band <= 5; band++) { - struct ieee80211_channel *channel; - - iwl_init_band_reference(cfg, eeprom, eeprom_size, band, - &eeprom_ch_count, &eeprom_ch_info, - &eeprom_ch_array); - - /* Loop through each band adding each of the channels */ - for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) { - const struct iwl_eeprom_channel *eeprom_ch; - - eeprom_ch = &eeprom_ch_info[ch_idx]; - - if (!(eeprom_ch->flags & EEPROM_CHANNEL_VALID)) { - IWL_DEBUG_EEPROM(dev, - "Ch. %d Flags %x [%sGHz] - No traffic\n", - eeprom_ch_array[ch_idx], - eeprom_ch_info[ch_idx].flags, - (band != 1) ? "5.2" : "2.4"); - continue; - } - - channel = &data->channels[n_channels]; - n_channels++; - - channel->hw_value = eeprom_ch_array[ch_idx]; - channel->band = (band == 1) ? NL80211_BAND_2GHZ - : NL80211_BAND_5GHZ; - channel->center_freq = - ieee80211_channel_to_frequency( - channel->hw_value, channel->band); - - /* set no-HT40, will enable as appropriate later */ - channel->flags = IEEE80211_CHAN_NO_HT40; - - if (!(eeprom_ch->flags & EEPROM_CHANNEL_IBSS)) - channel->flags |= IEEE80211_CHAN_NO_IR; - - if (!(eeprom_ch->flags & EEPROM_CHANNEL_ACTIVE)) - channel->flags |= IEEE80211_CHAN_NO_IR; - - if (eeprom_ch->flags & EEPROM_CHANNEL_RADAR) - channel->flags |= IEEE80211_CHAN_RADAR; - - /* Initialize regulatory-based run-time data */ - channel->max_power = - eeprom_ch_info[ch_idx].max_power_avg; - IWL_DEBUG_EEPROM(dev, - "Ch. %d [%sGHz] %s%s%s%s%s%s(0x%02x %ddBm): Ad-Hoc %ssupported\n", - channel->hw_value, - (band != 1) ? "5.2" : "2.4", - CHECK_AND_PRINT_I(VALID), - CHECK_AND_PRINT_I(IBSS), - CHECK_AND_PRINT_I(ACTIVE), - CHECK_AND_PRINT_I(RADAR), - CHECK_AND_PRINT_I(WIDE), - CHECK_AND_PRINT_I(DFS), - eeprom_ch_info[ch_idx].flags, - eeprom_ch_info[ch_idx].max_power_avg, - ((eeprom_ch_info[ch_idx].flags & - EEPROM_CHANNEL_IBSS) && - !(eeprom_ch_info[ch_idx].flags & - EEPROM_CHANNEL_RADAR)) - ? "" : "not "); - } - } - - if (cfg->eeprom_params->enhanced_txpower) { - /* - * for newer device (6000 series and up) - * EEPROM contain enhanced tx power information - * driver need to process addition information - * to determine the max channel tx power limits - */ - iwl_eeprom_enhanced_txpower(dev, data, eeprom, eeprom_size, - n_channels); - } else { - /* All others use data from channel map */ - int i; - - data->max_tx_pwr_half_dbm = -128; - - for (i = 0; i < n_channels; i++) - data->max_tx_pwr_half_dbm = - max_t(s8, data->max_tx_pwr_half_dbm, - data->channels[i].max_power * 2); - } - - /* Check if we do have HT40 channels */ - if (cfg->eeprom_params->regulatory_bands[5] == - EEPROM_REGULATORY_BAND_NO_HT40 && - cfg->eeprom_params->regulatory_bands[6] == - EEPROM_REGULATORY_BAND_NO_HT40) - return n_channels; - - /* Two additional EEPROM bands for 2.4 and 5 GHz HT40 channels */ - for (band = 6; band <= 7; band++) { - enum nl80211_band ieeeband; - - iwl_init_band_reference(cfg, eeprom, eeprom_size, band, - &eeprom_ch_count, &eeprom_ch_info, - &eeprom_ch_array); - - /* EEPROM band 6 is 2.4, band 7 is 5 GHz */ - ieeeband = (band == 6) ? NL80211_BAND_2GHZ - : NL80211_BAND_5GHZ; - - /* Loop through each band adding each of the channels */ - for (ch_idx = 0; ch_idx < eeprom_ch_count; ch_idx++) { - /* Set up driver's info for lower half */ - iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband, - eeprom_ch_array[ch_idx], - &eeprom_ch_info[ch_idx], - IEEE80211_CHAN_NO_HT40PLUS); - - /* Set up driver's info for upper half */ - iwl_mod_ht40_chan_info(dev, data, n_channels, ieeeband, - eeprom_ch_array[ch_idx] + 4, - &eeprom_ch_info[ch_idx], - IEEE80211_CHAN_NO_HT40MINUS); - } - } - - return n_channels; -} -#endif - -int iwl_init_sband_channels(struct iwl_nvm_data *data, - struct ieee80211_supported_band *sband, - int n_channels, enum nl80211_band band) -{ - struct ieee80211_channel *chan = &data->channels[0]; - int n = 0, idx = 0; - - while (idx < n_channels && chan->band != band) - chan = &data->channels[++idx]; - - sband->channels = &data->channels[idx]; - - while (idx < n_channels && chan->band == band) { - chan = &data->channels[++idx]; - n++; - } - - sband->n_channels = n; - - return n; -} - -#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ -#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ - -void iwl_init_ht_hw_capab(struct iwl_trans *trans, - struct iwl_nvm_data *data, - struct ieee80211_sta_ht_cap *ht_info, - enum nl80211_band band, - u8 tx_chains, u8 rx_chains) -{ - const struct iwl_cfg *cfg = trans->cfg; - int max_bit_rate = 0; - - tx_chains = hweight8(tx_chains); - if (cfg->rx_with_siso_diversity) - rx_chains = 1; - else - rx_chains = hweight8(rx_chains); - - if (!(data->sku_cap_11n_enable) || - (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) || - !cfg->ht_params) { - ht_info->ht_supported = false; - return; - } - - if (data->sku_cap_mimo_disabled) - rx_chains = 1; - - ht_info->ht_supported = true; - ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40; - - if (cfg->ht_params->stbc) { - ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); - - if (tx_chains > 1) - ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; - } - - if (cfg->ht_params->ldpc) - ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; - - if (trans->trans_cfg->mq_rx_supported || - iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K) - ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; - - ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; - ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; - - ht_info->mcs.rx_mask[0] = 0xFF; - if (rx_chains >= 2) - ht_info->mcs.rx_mask[1] = 0xFF; - if (rx_chains >= 3) - ht_info->mcs.rx_mask[2] = 0xFF; - - if (cfg->ht_params->ht_greenfield_support) - ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= IEEE80211_HT_CAP_SGI_20; - - max_bit_rate = MAX_BIT_RATE_20_MHZ; - - if (cfg->ht_params->ht40_bands & BIT(band)) { - ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; - ht_info->cap |= IEEE80211_HT_CAP_SGI_40; - max_bit_rate = MAX_BIT_RATE_40_MHZ; - } - - /* Highest supported Rx data rate */ - max_bit_rate *= rx_chains; - WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); - ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); - - /* Tx MCS capabilities */ - ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; - if (tx_chains != rx_chains) { - ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; - ht_info->mcs.tx_params |= ((tx_chains - 1) << - IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); - } -} - -#if IS_ENABLED(CONFIG_IWLDVM) -static void iwl_init_sbands(struct iwl_trans *trans, const struct iwl_cfg *cfg, - struct iwl_nvm_data *data, - const u8 *eeprom, size_t eeprom_size) -{ - struct device *dev = trans->dev; - int n_channels = iwl_init_channel_map(dev, cfg, data, - eeprom, eeprom_size); - int n_used = 0; - struct ieee80211_supported_band *sband; - - sband = &data->bands[NL80211_BAND_2GHZ]; - sband->band = NL80211_BAND_2GHZ; - sband->bitrates = &iwl_cfg80211_rates[RATES_24_OFFS]; - sband->n_bitrates = N_RATES_24; - n_used += iwl_init_sband_channels(data, sband, n_channels, - NL80211_BAND_2GHZ); - iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_2GHZ, - data->valid_tx_ant, data->valid_rx_ant); - - sband = &data->bands[NL80211_BAND_5GHZ]; - sband->band = NL80211_BAND_5GHZ; - sband->bitrates = &iwl_cfg80211_rates[RATES_52_OFFS]; - sband->n_bitrates = N_RATES_52; - n_used += iwl_init_sband_channels(data, sband, n_channels, - NL80211_BAND_5GHZ); - iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_5GHZ, - data->valid_tx_ant, data->valid_rx_ant); - - if (n_channels != n_used) - IWL_ERR_DEV(dev, "EEPROM: used only %d of %d channels\n", - n_used, n_channels); -} - -/* EEPROM data functions */ - -struct iwl_nvm_data * -iwl_parse_eeprom_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, - const u8 *eeprom, size_t eeprom_size) -{ - struct iwl_nvm_data *data; - struct device *dev = trans->dev; - const void *tmp; - u16 radio_cfg, sku; - - if (WARN_ON(!cfg || !cfg->eeprom_params)) - return NULL; - - data = kzalloc(struct_size(data, channels, IWL_NUM_CHANNELS), - GFP_KERNEL); - if (!data) - return NULL; - - /* get MAC address(es) */ - tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_MAC_ADDRESS); - if (!tmp) - goto err_free; - memcpy(data->hw_addr, tmp, ETH_ALEN); - data->n_hw_addrs = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_NUM_MAC_ADDRESS); - - if (iwl_eeprom_read_calib(eeprom, eeprom_size, data)) - goto err_free; - - tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, EEPROM_XTAL); - if (!tmp) - goto err_free; - memcpy(data->xtal_calib, tmp, sizeof(data->xtal_calib)); - - tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, - EEPROM_RAW_TEMPERATURE); - if (!tmp) - goto err_free; - data->raw_temperature = *(__le16 *)tmp; - - tmp = iwl_eeprom_query_addr(eeprom, eeprom_size, - EEPROM_KELVIN_TEMPERATURE); - if (!tmp) - goto err_free; - data->kelvin_temperature = *(__le16 *)tmp; - data->kelvin_voltage = *((__le16 *)tmp + 1); - - radio_cfg = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_RADIO_CONFIG); - data->radio_cfg_dash = EEPROM_RF_CFG_DASH_MSK(radio_cfg); - data->radio_cfg_pnum = EEPROM_RF_CFG_PNUM_MSK(radio_cfg); - data->radio_cfg_step = EEPROM_RF_CFG_STEP_MSK(radio_cfg); - data->radio_cfg_type = EEPROM_RF_CFG_TYPE_MSK(radio_cfg); - data->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg); - data->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg); - - sku = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_SKU_CAP); - data->sku_cap_11n_enable = sku & EEPROM_SKU_CAP_11N_ENABLE; - data->sku_cap_amt_enable = sku & EEPROM_SKU_CAP_AMT_ENABLE; - data->sku_cap_band_24ghz_enable = sku & EEPROM_SKU_CAP_BAND_24GHZ; - data->sku_cap_band_52ghz_enable = sku & EEPROM_SKU_CAP_BAND_52GHZ; - data->sku_cap_ipan_enable = sku & EEPROM_SKU_CAP_IPAN_ENABLE; - if (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) - data->sku_cap_11n_enable = false; - - data->nvm_version = iwl_eeprom_query16(eeprom, eeprom_size, - EEPROM_VERSION); - - /* check overrides (some devices have wrong EEPROM) */ - if (cfg->valid_tx_ant) - data->valid_tx_ant = cfg->valid_tx_ant; - if (cfg->valid_rx_ant) - data->valid_rx_ant = cfg->valid_rx_ant; - - if (!data->valid_tx_ant || !data->valid_rx_ant) { - IWL_ERR_DEV(dev, "invalid antennas (0x%x, 0x%x)\n", - data->valid_tx_ant, data->valid_rx_ant); - goto err_free; - } - - iwl_init_sbands(trans, cfg, data, eeprom, eeprom_size); - - return data; - err_free: - kfree(data); - return NULL; -} -IWL_EXPORT_SYMBOL(iwl_parse_eeprom_data); -#endif diff --git a/sys/contrib/dev/iwlwifi/iwl-eeprom-read.c b/sys/contrib/dev/iwlwifi/iwl-eeprom-read.c deleted file mode 100644 index 20759c32b47b..000000000000 --- a/sys/contrib/dev/iwlwifi/iwl-eeprom-read.c +++ /dev/null @@ -1,397 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause -/* - * Copyright (C) 2005-2014, 2018-2019, 2021 Intel Corporation - */ -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/export.h> -#if defined(__FreeBSD__) -#include <linux/delay.h> -#endif - -#include "iwl-drv.h" -#include "iwl-debug.h" -#include "iwl-eeprom-read.h" -#include "iwl-io.h" -#include "iwl-prph.h" -#include "iwl-csr.h" - -/* - * EEPROM access time values: - * - * Driver initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG. - * Driver then polls CSR_EEPROM_REG for CSR_EEPROM_REG_READ_VALID_MSK (0x1). - * When polling, wait 10 uSec between polling loops, up to a maximum 5000 uSec. - * Driver reads 16-bit value from bits 31-16 of CSR_EEPROM_REG. - */ -#define IWL_EEPROM_ACCESS_TIMEOUT 5000 /* uSec */ - -/* - * The device's EEPROM semaphore prevents conflicts between driver and uCode - * when accessing the EEPROM; each access is a series of pulses to/from the - * EEPROM chip, not a single event, so even reads could conflict if they - * weren't arbitrated by the semaphore. - */ -#define IWL_EEPROM_SEM_TIMEOUT 10 /* microseconds */ -#define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ - - -static int iwl_eeprom_acquire_semaphore(struct iwl_trans *trans) -{ - u16 count; - int ret; - - 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_BIT_EEPROM_OWN_SEM); - - /* See if we got it */ - ret = iwl_poll_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM, - IWL_EEPROM_SEM_TIMEOUT); - if (ret >= 0) { - IWL_DEBUG_EEPROM(trans->dev, - "Acquired semaphore after %d tries.\n", - count+1); - return ret; - } - } - - return ret; -} - -static void iwl_eeprom_release_semaphore(struct iwl_trans *trans) -{ - iwl_clear_bit(trans, CSR_HW_IF_CONFIG_REG, - CSR_HW_IF_CONFIG_REG_BIT_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; - - IWL_DEBUG_EEPROM(trans->dev, "EEPROM signature=0x%08x\n", gp); - - switch (gp) { - case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP: - if (!nvm_is_otp) { - IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n", - gp); - return -ENOENT; - } - return 0; - case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K: - case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K: - if (nvm_is_otp) { - IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp); - return -ENOENT; - } - return 0; - case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP: - default: - IWL_ERR(trans, - "bad EEPROM/OTP signature, type=%s, EEPROM_GP=0x%08x\n", - nvm_is_otp ? "OTP" : "EEPROM", gp); - return -ENOENT; - } -} - -/****************************************************************************** - * - * OTP related functions - * -******************************************************************************/ - -static void iwl_set_otp_access_absolute(struct iwl_trans *trans) -{ - iwl_read32(trans, CSR_OTP_GP_REG); - - iwl_clear_bit(trans, CSR_OTP_GP_REG, - CSR_OTP_GP_REG_OTP_ACCESS_MODE); -} - -static int iwl_nvm_is_otp(struct iwl_trans *trans) -{ - u32 otpgp; - - /* OTP only valid for CP/PP and after */ - switch (trans->hw_rev & CSR_HW_REV_TYPE_MSK) { - case CSR_HW_REV_TYPE_NONE: - IWL_ERR(trans, "Unknown hardware type\n"); - return -EIO; - case CSR_HW_REV_TYPE_5300: - case CSR_HW_REV_TYPE_5350: - case CSR_HW_REV_TYPE_5100: - case CSR_HW_REV_TYPE_5150: - return 0; - default: - otpgp = iwl_read32(trans, CSR_OTP_GP_REG); - if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT) - return 1; - return 0; - } -} - -static int iwl_init_otp_access(struct iwl_trans *trans) -{ - int ret; - - ret = iwl_finish_nic_init(trans); - if (ret) - return ret; - - iwl_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); - - /* - * CSR auto clock gate disable bit - - * this is only applicable for HW with OTP shadow RAM - */ - if (trans->trans_cfg->base_params->shadow_ram_support) - iwl_set_bit(trans, CSR_DBG_LINK_PWR_MGMT_REG, - CSR_RESET_LINK_PWR_MGMT_DISABLED); - - return 0; -} - -static int iwl_read_otp_word(struct iwl_trans *trans, u16 addr, - __le16 *eeprom_data) -{ - int ret = 0; - u32 r; - u32 otpgp; - - iwl_write32(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - ret = iwl_poll_bit(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { - IWL_ERR(trans, "Time out reading OTP[%d]\n", addr); - return ret; - } - r = iwl_read32(trans, CSR_EEPROM_REG); - /* check for ECC errors: */ - otpgp = iwl_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_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_ERR(trans, "Correctable OTP ECC error, continue read\n"); - } - *eeprom_data = cpu_to_le16(r >> 16); - return 0; -} - -/* - * iwl_is_otp_empty: check for empty OTP - */ -static bool iwl_is_otp_empty(struct iwl_trans *trans) -{ - u16 next_link_addr = 0; - __le16 link_value; - bool is_empty = false; - - /* locate the beginning of OTP link list */ - if (!iwl_read_otp_word(trans, next_link_addr, &link_value)) { - if (!link_value) { - IWL_ERR(trans, "OTP is empty\n"); - is_empty = true; - } - } else { - IWL_ERR(trans, "Unable to read first block of OTP list.\n"); - is_empty = true; - } - - return is_empty; -} - - -/* - * iwl_find_otp_image: find EEPROM image in OTP - * finding the OTP block that contains the EEPROM image. - * the last valid block on the link list (the block _before_ the last block) - * is the block we should read and used to configure the device. - * If all the available OTP blocks are full, the last block will be the block - * we should read and used to configure the device. - * only perform this operation if shadow RAM is disabled - */ -static int iwl_find_otp_image(struct iwl_trans *trans, - u16 *validblockaddr) -{ - u16 next_link_addr = 0, valid_addr; - __le16 link_value = 0; - int usedblocks = 0; - - /* set addressing mode to absolute to traverse the link list */ - iwl_set_otp_access_absolute(trans); - - /* checking for empty OTP or error */ - if (iwl_is_otp_empty(trans)) - return -EINVAL; - - /* - * start traverse link list - * until reach the max number of OTP blocks - * different devices have different number of OTP blocks - */ - do { - /* save current valid block address - * check for more block on the link list - */ - valid_addr = next_link_addr; - next_link_addr = le16_to_cpu(link_value) * sizeof(u16); - IWL_DEBUG_EEPROM(trans->dev, "OTP blocks %d addr 0x%x\n", - usedblocks, next_link_addr); - if (iwl_read_otp_word(trans, next_link_addr, &link_value)) - return -EINVAL; - if (!link_value) { - /* - * reach the end of link list, return success and - * set address point to the starting address - * of the image - */ - *validblockaddr = valid_addr; - /* skip first 2 bytes (link list pointer) */ - *validblockaddr += 2; - return 0; - } - /* more in the link list, continue */ - usedblocks++; - } while (usedblocks <= trans->trans_cfg->base_params->max_ll_items); - - /* OTP has no valid blocks */ - IWL_DEBUG_EEPROM(trans->dev, "OTP has no valid blocks\n"); - return -EINVAL; -} - -/* - * iwl_read_eeprom - read EEPROM contents - * - * Load the EEPROM contents from adapter and return it - * and its size. - * - * NOTE: This routine uses the non-debug IO access functions. - */ -int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size) -{ - __le16 *e; - u32 gp = iwl_read32(trans, CSR_EEPROM_GP); - int sz; - int ret; - u16 addr; - u16 validblockaddr = 0; - u16 cache_addr = 0; - int nvm_is_otp; - - if (!eeprom || !eeprom_size) - return -EINVAL; - - nvm_is_otp = iwl_nvm_is_otp(trans); - if (nvm_is_otp < 0) - return nvm_is_otp; - - sz = trans->trans_cfg->base_params->eeprom_size; - IWL_DEBUG_EEPROM(trans->dev, "NVM size = %d\n", sz); - - e = kmalloc(sz, GFP_KERNEL); - if (!e) - return -ENOMEM; - - ret = iwl_eeprom_verify_signature(trans, nvm_is_otp); - if (ret < 0) { - IWL_ERR(trans, "EEPROM not found, EEPROM_GP=0x%08x\n", gp); - goto err_free; - } - - /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - ret = iwl_eeprom_acquire_semaphore(trans); - if (ret < 0) { - IWL_ERR(trans, "Failed to acquire EEPROM semaphore.\n"); - goto err_free; - } - - if (nvm_is_otp) { - ret = iwl_init_otp_access(trans); - if (ret) { - IWL_ERR(trans, "Failed to initialize OTP access.\n"); - goto err_unlock; - } - - iwl_write32(trans, CSR_EEPROM_GP, - iwl_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); - /* traversing the linked list if no shadow ram supported */ - if (!trans->trans_cfg->base_params->shadow_ram_support) { - ret = iwl_find_otp_image(trans, &validblockaddr); - if (ret) - goto err_unlock; - } - for (addr = validblockaddr; addr < validblockaddr + sz; - addr += sizeof(u16)) { - __le16 eeprom_data; - - ret = iwl_read_otp_word(trans, addr, &eeprom_data); - if (ret) - goto err_unlock; - e[cache_addr / 2] = eeprom_data; - cache_addr += sizeof(u16); - } - } else { - /* eeprom is an array of 16bit values */ - for (addr = 0; addr < sz; addr += sizeof(u16)) { - u32 r; - - iwl_write32(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - - ret = iwl_poll_bit(trans, CSR_EEPROM_REG, - CSR_EEPROM_REG_READ_VALID_MSK, - CSR_EEPROM_REG_READ_VALID_MSK, - IWL_EEPROM_ACCESS_TIMEOUT); - if (ret < 0) { - IWL_ERR(trans, - "Time out reading EEPROM[%d]\n", addr); - goto err_unlock; - } - r = iwl_read32(trans, CSR_EEPROM_REG); - e[addr / 2] = cpu_to_le16(r >> 16); - } - } - - IWL_DEBUG_EEPROM(trans->dev, "NVM Type: %s\n", - nvm_is_otp ? "OTP" : "EEPROM"); - - iwl_eeprom_release_semaphore(trans); - - *eeprom_size = sz; - *eeprom = (u8 *)e; - return 0; - - err_unlock: - iwl_eeprom_release_semaphore(trans); - err_free: - kfree(e); - - return ret; -} -IWL_EXPORT_SYMBOL(iwl_read_eeprom); diff --git a/sys/contrib/dev/iwlwifi/iwl-eeprom-read.h b/sys/contrib/dev/iwlwifi/iwl-eeprom-read.h deleted file mode 100644 index 63b8e6c6659b..000000000000 --- a/sys/contrib/dev/iwlwifi/iwl-eeprom-read.h +++ /dev/null @@ -1,12 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ -/* - * Copyright (C) 2005-2014 Intel Corporation - */ -#ifndef __iwl_eeprom_h__ -#define __iwl_eeprom_h__ - -#include "iwl-trans.h" - -int iwl_read_eeprom(struct iwl_trans *trans, u8 **eeprom, size_t *eeprom_size); - -#endif /* __iwl_eeprom_h__ */ diff --git a/sys/contrib/dev/iwlwifi/iwl-fh.h b/sys/contrib/dev/iwlwifi/iwl-fh.h index 4e4a60ddf9b2..5c8f1868db64 100644 --- a/sys/contrib/dev/iwlwifi/iwl-fh.h +++ b/sys/contrib/dev/iwlwifi/iwl-fh.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2021, 2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021, 2023-2024 Intel Corporation * Copyright (C) 2015-2017 Intel Deutschland GmbH */ #ifndef __iwl_fh_h__ @@ -15,7 +15,7 @@ /* Flow Handler Definitions */ /****************************/ -/** +/* * This I/O area is directly read/writable by driver (e.g. Linux uses writel()) * Addresses are offsets from device's PCI hardware base address. */ @@ -24,7 +24,7 @@ #define FH_MEM_LOWER_BOUND_GEN2 (0xa06000) #define FH_MEM_UPPER_BOUND_GEN2 (0xa08000) -/** +/* * Keep-Warm (KW) buffer base address. * * Driver must allocate a 4KByte buffer that is for keeping the @@ -44,7 +44,7 @@ #define FH_KW_MEM_ADDR_REG (FH_MEM_LOWER_BOUND + 0x97C) -/** +/* * TFD Circular Buffers Base (CBBC) addresses * * Device has 16 base pointer registers, one for each of 16 host-DRAM-resident @@ -143,7 +143,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, */ #define TFH_SRV_DMA_CHNL0_BC (0x1F70) -/** +/* * Rx SRAM Control and Status Registers (RSCSR) * * These registers provide handshake between driver and device for the Rx queue @@ -216,21 +216,21 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define FH_MEM_RSCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xC00) #define FH_MEM_RSCSR_CHNL0 (FH_MEM_RSCSR_LOWER_BOUND) -/** +/* * Physical base address of 8-byte Rx Status buffer. * Bit fields: * 31-0: Rx status buffer physical base address [35:4], must 16-byte aligned. */ #define FH_RSCSR_CHNL0_STTS_WPTR_REG (FH_MEM_RSCSR_CHNL0) -/** +/* * Physical base address of Rx Buffer Descriptor Circular Buffer. * Bit fields: * 27-0: RBD CD physical base address [35:8], must be 256-byte aligned. */ #define FH_RSCSR_CHNL0_RBDCB_BASE_REG (FH_MEM_RSCSR_CHNL0 + 0x004) -/** +/* * Rx write pointer (index, really!). * Bit fields: * 11-0: Index of driver's most recent prepared-to-be-filled RBD, + 1. @@ -242,7 +242,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define FW_RSCSR_CHNL0_RXDCB_RDPTR_REG (FH_MEM_RSCSR_CHNL0 + 0x00c) #define FH_RSCSR_CHNL0_RDPTR FW_RSCSR_CHNL0_RXDCB_RDPTR_REG -/** +/* * Rx Config/Status Registers (RCSR) * Rx Config Reg for channel 0 (only channel used) * @@ -300,7 +300,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) -/** +/* * Rx Shared Status Registers (RSSR) * * After stopping Rx DMA channel (writing 0 to @@ -356,7 +356,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define RFH_RBDBUF_RBD0_LSB 0xA08300 #define RFH_RBDBUF_RBD_LSB(q) (RFH_RBDBUF_RBD0_LSB + (q) * 8) -/** +/* * RFH Status Register * * Bit fields: @@ -440,7 +440,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) #define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) -/** +/* * Transmit DMA Channel Control/Status Registers (TCSR) * * Device has one configuration register for each of 8 Tx DMA/FIFO channels @@ -501,7 +501,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) #define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) -/** +/* * Tx Shared Status Registers (TSSR) * * After stopping Tx DMA channel (writing 0 to @@ -518,7 +518,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) -/** +/* * Bit fields for TSSR(Tx Shared Status & Control) error status register: * 31: Indicates an address error when accessed to internal memory * uCode/driver must write "1" in order to clear this flag @@ -565,21 +565,24 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(struct iwl_trans *trans, #define RX_QUEUE_MASK 255 #define RX_QUEUE_SIZE_LOG 8 +#define IWL_DEFAULT_RX_QUEUE 0 + /** * struct iwl_rb_status - reserve buffer status * host memory mapped FH registers - * @closed_rb_num [0:11] - Indicates the index of the RB which was closed - * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed - * @finished_rb_num [0:11] - Indicates the index of the current RB + * @closed_rb_num: [0:11] Indicates the index of the RB which was closed + * @closed_fr_num: [0:11] Indicates the index of the RX Frame which was closed + * @finished_rb_num: [0:11] Indicates the index of the current RB * in which the last frame was written to - * @finished_fr_num [0:11] - Indicates the index of the RX Frame + * @finished_fr_num: [0:11] Indicates the index of the RX Frame * which was transferred + * @__spare: reserved */ struct iwl_rb_status { __le16 closed_rb_num; __le16 closed_fr_num; __le16 finished_rb_num; - __le16 finished_fr_nam; + __le16 finished_fr_num; __le32 __spare; } __packed; @@ -631,7 +634,7 @@ enum iwl_tfd_tb_hi_n_len { }; /** - * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor + * struct iwl_tfd_tb - transmit buffer descriptor within transmit frame descriptor * * This structure contains dma address and length of transmission address * @@ -645,19 +648,19 @@ struct iwl_tfd_tb { } __packed; /** - * struct iwl_tfh_tb transmit buffer descriptor within transmit frame descriptor + * struct iwl_tfh_tb - transmit buffer descriptor within transmit frame descriptor * * This structure contains dma address and length of transmission address * - * @tb_len length of the tx buffer - * @addr 64 bits dma address + * @tb_len: length of the tx buffer + * @addr: 64 bits dma address */ struct iwl_tfh_tb { __le16 tb_len; __le64 addr; } __packed; -/** +/* * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. * Both driver and device share these circular buffers, each of which must be * contiguous 256 TFDs. @@ -679,12 +682,13 @@ struct iwl_tfh_tb { /** * struct iwl_tfd - Transmit Frame Descriptor (TFD) - * @ __reserved1[3] reserved - * @ num_tbs 0-4 number of active tbs - * 5 reserved - * 6-7 padding (not used) - * @ tbs[20] transmit frame buffer descriptors - * @ __pad padding + * @__reserved1: reserved + * @num_tbs: + * 0-4 number of active tbs + * 5 reserved + * 6-7 padding (not used) + * @tbs: transmit frame buffer descriptors + * @__pad: padding */ struct iwl_tfd { u8 __reserved1[3]; @@ -695,10 +699,11 @@ struct iwl_tfd { /** * struct iwl_tfh_tfd - Transmit Frame Descriptor (TFD) - * @ num_tbs 0-4 number of active tbs - * 5 -15 reserved - * @ tbs[25] transmit frame buffer descriptors - * @ __pad padding + * @num_tbs: + * 0-4 number of active tbs + * 5-15 reserved + * @tbs: transmit frame buffer descriptors + * @__pad: padding */ struct iwl_tfh_tfd { __le16 num_tbs; @@ -712,13 +717,15 @@ struct iwl_tfh_tfd { /* Fixed (non-configurable) rx data from phy */ /** - * struct iwlagn_schedq_bc_tbl scheduler byte count table + * struct iwlagn_scd_bc_tbl - scheduler byte count table * base physical address provided by SCD_DRAM_BASE_ADDR * For devices up to 22000: - * @tfd_offset 0-12 - tx command byte count + * @tfd_offset: + * For devices up to 22000: + * 0-12 - tx command byte count * 12-16 - station index - * For 22000: - * @tfd_offset 0-12 - tx command byte count + * For 22000: + * 0-12 - tx command byte count * 12-13 - number of 64 byte chunks * 14-16 - reserved */ @@ -727,7 +734,7 @@ struct iwlagn_scd_bc_tbl { } __packed; /** - * struct iwl_gen3_bc_tbl_entry scheduler byte count table entry gen3 + * struct iwl_gen3_bc_tbl_entry - scheduler byte count table entry gen3 * For AX210 and on: * @tfd_offset: 0-12 - tx command byte count * 12-13 - number of 64 byte chunks diff --git a/sys/contrib/dev/iwlwifi/iwl-io.c b/sys/contrib/dev/iwlwifi/iwl-io.c index c60f9466c5fd..060becfd64f3 100644 --- a/sys/contrib/dev/iwlwifi/iwl-io.c +++ b/sys/contrib/dev/iwlwifi/iwl-io.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2003-2014, 2018-2022 Intel Corporation + * Copyright (C) 2003-2014, 2018-2022, 2024 Intel Corporation * Copyright (C) 2015-2016 Intel Deutschland GmbH */ #include <linux/delay.h> @@ -460,7 +460,7 @@ int iwl_finish_nic_init(struct iwl_trans *trans) */ if (cfg_trans->device_family >= IWL_DEVICE_FAMILY_BZ) { iwl_set_bit(trans, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_BZ_MAC_ACCESS_REQ | CSR_GP_CNTRL_REG_FLAG_MAC_INIT); poll_ready = CSR_GP_CNTRL_REG_FLAG_MAC_STATUS; } else { diff --git a/sys/contrib/dev/iwlwifi/iwl-modparams.h b/sys/contrib/dev/iwlwifi/iwl-modparams.h index 9d8c018c725e..b67fe353d202 100644 --- a/sys/contrib/dev/iwlwifi/iwl-modparams.h +++ b/sys/contrib/dev/iwlwifi/iwl-modparams.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2022 Intel Corporation + * Copyright (C) 2005-2014, 2018-2022, 2024 Intel Corporation */ #ifndef __iwl_modparams_h__ #define __iwl_modparams_h__ @@ -113,4 +113,23 @@ static inline bool iwl_enable_tx_ampdu(void) return true; } +/* Verify amsdu_size module parameter and convert it to a rxb size */ +static inline enum iwl_amsdu_size +iwl_amsdu_size_to_rxb_size(void) +{ + switch (iwlwifi_mod_params.amsdu_size) { + case IWL_AMSDU_8K: + return IWL_AMSDU_8K; + case IWL_AMSDU_12K: + return IWL_AMSDU_12K; + default: + pr_err("%s: Unsupported amsdu_size: %d\n", KBUILD_MODNAME, + iwlwifi_mod_params.amsdu_size); + fallthrough; + case IWL_AMSDU_DEF: + case IWL_AMSDU_4K: + return IWL_AMSDU_4K; + } +} + #endif /* #__iwl_modparams_h__ */ diff --git a/sys/contrib/dev/iwlwifi/iwl-nvm-parse.c b/sys/contrib/dev/iwlwifi/iwl-nvm-parse.c index d20a6019dbca..384082e20af8 100644 --- a/sys/contrib/dev/iwlwifi/iwl-nvm-parse.c +++ b/sys/contrib/dev/iwlwifi/iwl-nvm-parse.c @@ -38,16 +38,13 @@ enum nvm_offsets { N_HW_ADDRS = 3, NVM_CHANNELS = 0x1E0 - NVM_SW_SECTION, - /* NVM calibration section offset (in words) definitions */ - NVM_CALIB_SECTION = 0x2B8, - XTAL_CALIB = 0x316 - NVM_CALIB_SECTION, - /* NVM REGULATORY -Section offset (in words) definitions */ NVM_CHANNELS_SDP = 0, }; enum ext_nvm_offsets { /* NVM HW-Section offset (in words) definitions */ + MAC_ADDRESS_OVERRIDE_EXT_NVM = 1, /* NVM SW-Section offset (in words) definitions */ @@ -156,6 +153,8 @@ static struct ieee80211_rate iwl_cfg80211_rates[] = { * @NVM_CHANNEL_80MHZ: 80 MHz channel okay * @NVM_CHANNEL_160MHZ: 160 MHz channel okay * @NVM_CHANNEL_DC_HIGH: DC HIGH required/allowed (?) + * @NVM_CHANNEL_VLP: client support connection to UHB VLP AP + * @NVM_CHANNEL_AFC: client support connection to UHB AFC AP */ enum iwl_nvm_channel_flags { NVM_CHANNEL_VALID = BIT(0), @@ -170,6 +169,8 @@ enum iwl_nvm_channel_flags { NVM_CHANNEL_80MHZ = BIT(10), NVM_CHANNEL_160MHZ = BIT(11), NVM_CHANNEL_DC_HIGH = BIT(12), + NVM_CHANNEL_VLP = BIT(13), + NVM_CHANNEL_AFC = BIT(14), }; /** @@ -309,7 +310,7 @@ static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, /* Note: already can print up to 101 characters, 110 is the limit! */ IWL_DEBUG_DEV(dev, level, - "Ch. %d: 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s\n", + "Ch. %d: 0x%x:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", chan, flags, CHECK_AND_PRINT_I(VALID), CHECK_AND_PRINT_I(IBSS), @@ -322,7 +323,9 @@ static inline void iwl_nvm_print_channel_flags(struct device *dev, u32 level, CHECK_AND_PRINT_I(40MHZ), CHECK_AND_PRINT_I(80MHZ), CHECK_AND_PRINT_I(160MHZ), - CHECK_AND_PRINT_I(DC_HIGH)); + CHECK_AND_PRINT_I(DC_HIGH), + CHECK_AND_PRINT_I(VLP), + CHECK_AND_PRINT_I(AFC)); #undef CHECK_AND_PRINT_I } @@ -366,6 +369,14 @@ static u32 iwl_get_channel_flags(u8 ch_num, int ch_idx, enum nl80211_band band, (flags & IEEE80211_CHAN_NO_IR)) flags |= IEEE80211_CHAN_IR_CONCURRENT; + /* Set the AP type for the UHB case. */ + if (nvm_flags & NVM_CHANNEL_VLP) + flags |= IEEE80211_CHAN_ALLOW_6GHZ_VLP_AP; + else + flags |= IEEE80211_CHAN_NO_6GHZ_VLP_CLIENT; + if (!(nvm_flags & NVM_CHANNEL_AFC)) + flags |= IEEE80211_CHAN_NO_6GHZ_AFC_CLIENT; + return flags; } @@ -380,11 +391,14 @@ static enum nl80211_band iwl_nl80211_band_from_channel_idx(int ch_idx) return NL80211_BAND_2GHZ; } -static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, +static int iwl_init_channel_map(struct iwl_trans *trans, + const struct iwl_fw *fw, struct iwl_nvm_data *data, const void * const nvm_ch_flags, u32 sbands_flags, bool v4) { + const struct iwl_cfg *cfg = trans->cfg; + struct device *dev = trans->dev; int ch_idx; int n_channels = 0; struct ieee80211_channel *channel; @@ -466,11 +480,10 @@ static int iwl_init_channel_map(struct device *dev, const struct iwl_cfg *cfg, else channel->flags = 0; - /* TODO: Don't put limitations on UHB devices as we still don't - * have NVM for them - */ - if (cfg->uhb_supported) - channel->flags = 0; + if (fw_has_capa(&fw->ucode_capa, + IWL_UCODE_TLV_CAPA_MONITOR_PASSIVE_CHANS)) + channel->flags |= IEEE80211_CHAN_CAN_MONITOR; + iwl_nvm_print_channel_flags(dev, IWL_DL_EEPROM, channel->hw_value, ch_flags); IWL_DEBUG_EEPROM(dev, "Ch. %d: %ddBm\n", @@ -585,7 +598,8 @@ static const u8 iwl_vendor_caps[] = { static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { { - .types_mask = BIT(NL80211_IFTYPE_STATION), + .types_mask = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_P2P_CLIENT), .he_cap = { .has_he = true, .he_cap_elem = { @@ -668,10 +682,10 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { .has_eht = true, .eht_cap_elem = { .mac_cap_info[0] = - IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | IEEE80211_EHT_MAC_CAP0_OM_CONTROL | IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | - IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2, + IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2 | + IEEE80211_EHT_MAC_CAP0_SCS_TRAFFIC_DESC, .phy_cap_info[0] = IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI | @@ -695,10 +709,11 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP | IEEE80211_EHT_PHY_CAP4_EHT_MU_PPDU_4_EHT_LTF_08_GI, .phy_cap_info[5] = + FIELD_PREP_CONST(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK, + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US) | IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK | IEEE80211_EHT_PHY_CAP5_TX_LESS_242_TONE_RU_SUPP | - IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP | - IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT, + IEEE80211_EHT_PHY_CAP5_RX_LESS_242_TONE_RU_SUPP, .phy_cap_info[6] = IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK | IEEE80211_EHT_PHY_CAP6_EHT_DUP_6GHZ_SUPP, @@ -732,19 +747,22 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { /* * PPE thresholds for NSS = 2, and RU index bitmap set * to 0xc. + * Note: just for stating what we want, not present in + * the transmitted data due to not including + * IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT. */ .eht_ppe_thres = {0xc1, 0x0e, 0xe0 } }, }, { - .types_mask = BIT(NL80211_IFTYPE_AP), + .types_mask = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO), .he_cap = { .has_he = true, .he_cap_elem = { .mac_cap_info[0] = IEEE80211_HE_MAC_CAP0_HTC_HE, .mac_cap_info[1] = - IEEE80211_HE_MAC_CAP1_TF_MAC_PAD_DUR_16US | IEEE80211_HE_MAC_CAP1_MULTI_TID_AGG_RX_QOS_8, .mac_cap_info[3] = IEEE80211_HE_MAC_CAP3_OMI_CONTROL, @@ -792,7 +810,6 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { .has_eht = true, .eht_cap_elem = { .mac_cap_info[0] = - IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | IEEE80211_EHT_MAC_CAP0_OM_CONTROL | IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2, @@ -800,7 +817,8 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { IEEE80211_EHT_PHY_CAP0_242_TONE_RU_GT20MHZ | IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI, .phy_cap_info[5] = - IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT, + FIELD_PREP_CONST(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK, + IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US), }, /* For all MCS and bandwidth, set 2 NSS for both Tx and @@ -828,6 +846,9 @@ static const struct ieee80211_sband_iftype_data iwl_he_eht_capa[] = { /* * PPE thresholds for NSS = 2, and RU index bitmap set * to 0xc. + * Note: just for stating what we want, not present in + * the transmitted data due to not including + * IEEE80211_EHT_PHY_CAP5_PPE_THRESHOLD_PRESENT. */ .eht_ppe_thres = {0xc1, 0x0e, 0xe0 } }, @@ -888,11 +909,13 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, u8 tx_chains, u8 rx_chains, const struct iwl_fw *fw) { - bool is_ap = iftype_data->types_mask & BIT(NL80211_IFTYPE_AP); + bool is_ap = iftype_data->types_mask & (BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO)); bool no_320; - no_320 = !trans->trans_cfg->integrated && - trans->pcie_link_speed < PCI_EXP_LNKSTA_CLS_8_0GB; + no_320 = (!trans->trans_cfg->integrated && + trans->pcie_link_speed < PCI_EXP_LNKSTA_CLS_8_0GB) || + trans->reduced_cap_sku; if (!data->sku_cap_11be_enable || iwlwifi_mod_params.disable_11be) iftype_data->eht_cap.has_eht = false; @@ -962,6 +985,9 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, } } } else { + struct ieee80211_he_mcs_nss_supp *he_mcs_nss_supp = + &iftype_data->he_cap.he_mcs_nss_supp; + if (iftype_data->eht_cap.has_eht) { struct ieee80211_eht_mcs_nss_supp *mcs_nss = &iftype_data->eht_cap.eht_mcs_nss_supp; @@ -980,6 +1006,19 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, iftype_data->he_cap.he_cap_elem.phy_cap_info[7] |= IEEE80211_HE_PHY_CAP7_MAX_NC_1; } + + he_mcs_nss_supp->rx_mcs_80 |= + cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); + he_mcs_nss_supp->tx_mcs_80 |= + cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); + he_mcs_nss_supp->rx_mcs_160 |= + cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); + he_mcs_nss_supp->tx_mcs_160 |= + cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); + he_mcs_nss_supp->rx_mcs_80p80 |= + cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); + he_mcs_nss_supp->tx_mcs_80p80 |= + cpu_to_le16(IEEE80211_HE_MCS_NOT_SUPPORTED << 2); } if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210 && !is_ap) @@ -988,8 +1027,8 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, switch (CSR_HW_RFID_TYPE(trans->hw_rf_id)) { case IWL_CFG_RF_TYPE_GF: - case IWL_CFG_RF_TYPE_MR: - case IWL_CFG_RF_TYPE_MS: + case IWL_CFG_RF_TYPE_FM: + case IWL_CFG_RF_TYPE_WH: iftype_data->he_cap.he_cap_elem.phy_cap_info[9] |= IEEE80211_HE_PHY_CAP9_TX_1024_QAM_LESS_THAN_242_TONE_RU; if (!is_ap) @@ -1001,8 +1040,7 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, if (CSR_HW_REV_TYPE(trans->hw_rev) == IWL_CFG_MAC_TYPE_GL && iftype_data->eht_cap.has_eht) { iftype_data->eht_cap.eht_cap_elem.mac_cap_info[0] &= - ~(IEEE80211_EHT_MAC_CAP0_EPCS_PRIO_ACCESS | - IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | + ~(IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE1 | IEEE80211_EHT_MAC_CAP0_TRIG_TXOP_SHARING_MODE2); iftype_data->eht_cap.eht_cap_elem.phy_cap_info[3] &= ~(IEEE80211_EHT_PHY_CAP0_PARTIAL_BW_UL_MU_MIMO | @@ -1010,7 +1048,8 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK | IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK | IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK | - IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK); + IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK | + IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK); iftype_data->eht_cap.eht_cap_elem.phy_cap_info[4] &= ~(IEEE80211_EHT_PHY_CAP4_PART_BW_DL_MU_MIMO | IEEE80211_EHT_PHY_CAP4_POWER_BOOST_FACT_SUPP); @@ -1039,6 +1078,26 @@ iwl_nvm_fixup_sband_iftd(struct iwl_trans *trans, iftype_data->he_cap.he_cap_elem.phy_cap_info[7] &= ~IEEE80211_HE_PHY_CAP7_STBC_RX_ABOVE_80MHZ; } + + if (trans->step_urm) { + iftype_data->eht_cap.eht_mcs_nss_supp.bw._320.rx_tx_mcs11_max_nss = 0; + iftype_data->eht_cap.eht_mcs_nss_supp.bw._320.rx_tx_mcs13_max_nss = 0; + } + + if (trans->no_160) + iftype_data->he_cap.he_cap_elem.phy_cap_info[0] &= + ~IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G; + + if (trans->reduced_cap_sku) { + memset(&iftype_data->eht_cap.eht_mcs_nss_supp.bw._320, 0, + sizeof(iftype_data->eht_cap.eht_mcs_nss_supp.bw._320)); + iftype_data->eht_cap.eht_mcs_nss_supp.bw._80.rx_tx_mcs13_max_nss = 0; + iftype_data->eht_cap.eht_mcs_nss_supp.bw._160.rx_tx_mcs13_max_nss = 0; + iftype_data->eht_cap.eht_cap_elem.phy_cap_info[8] &= + ~IEEE80211_EHT_PHY_CAP8_RX_4096QAM_WIDER_BW_DL_OFDMA; + iftype_data->eht_cap.eht_cap_elem.phy_cap_info[2] &= + ~IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK; + } } static void iwl_init_he_hw_capab(struct iwl_trans *trans, @@ -1050,10 +1109,6 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans, struct ieee80211_sband_iftype_data *iftype_data; int i; - /* should only initialize once */ - if (WARN_ON(sband->iftype_data)) - return; - BUILD_BUG_ON(sizeof(data->iftd.low) != sizeof(iwl_he_eht_capa)); BUILD_BUG_ON(sizeof(data->iftd.high) != sizeof(iwl_he_eht_capa)); BUILD_BUG_ON(sizeof(data->iftd.uhb) != sizeof(iwl_he_eht_capa)); @@ -1075,8 +1130,8 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans, memcpy(iftype_data, iwl_he_eht_capa, sizeof(iwl_he_eht_capa)); - sband->iftype_data = iftype_data; - sband->n_iftype_data = ARRAY_SIZE(iwl_he_eht_capa); + _ieee80211_set_sband_iftype_data(sband, iftype_data, + ARRAY_SIZE(iwl_he_eht_capa)); for (i = 0; i < sband->n_iftype_data; i++) iwl_nvm_fixup_sband_iftd(trans, data, sband, &iftype_data[i], @@ -1085,6 +1140,37 @@ static void iwl_init_he_hw_capab(struct iwl_trans *trans, iwl_init_he_6ghz_capa(trans, data, sband, tx_chains, rx_chains); } +void iwl_reinit_cab(struct iwl_trans *trans, struct iwl_nvm_data *data, + u8 tx_chains, u8 rx_chains, const struct iwl_fw *fw) +{ + struct ieee80211_supported_band *sband; + + sband = &data->bands[NL80211_BAND_2GHZ]; + iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_2GHZ, + tx_chains, rx_chains); + + if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); + + sband = &data->bands[NL80211_BAND_5GHZ]; + iwl_init_ht_hw_capab(trans, data, &sband->ht_cap, NL80211_BAND_5GHZ, + tx_chains, rx_chains); + if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac) + iwl_init_vht_hw_capab(trans, data, &sband->vht_cap, + tx_chains, rx_chains); + + if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); + + sband = &data->bands[NL80211_BAND_6GHZ]; + if (data->sku_cap_11ax_enable && !iwlwifi_mod_params.disable_11ax) + iwl_init_he_hw_capab(trans, data, sband, tx_chains, rx_chains, + fw); +} +IWL_EXPORT_SYMBOL(iwl_reinit_cab); + static void iwl_init_sbands(struct iwl_trans *trans, struct iwl_nvm_data *data, const void *nvm_ch_flags, u8 tx_chains, @@ -1092,12 +1178,11 @@ static void iwl_init_sbands(struct iwl_trans *trans, const struct iwl_fw *fw) { struct device *dev = trans->dev; - const struct iwl_cfg *cfg = trans->cfg; int n_channels; int n_used = 0; struct ieee80211_supported_band *sband; - n_channels = iwl_init_channel_map(dev, cfg, data, nvm_ch_flags, + n_channels = iwl_init_channel_map(trans, fw, data, nvm_ch_flags, sbands_flags, v4); sband = &data->bands[NL80211_BAND_2GHZ]; sband->band = NL80211_BAND_2GHZ; @@ -1368,7 +1453,7 @@ iwl_nvm_no_wide_in_5ghz(struct iwl_trans *trans, const struct iwl_cfg *cfg, struct iwl_nvm_data * iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_mei_nvm *mei_nvm, - const struct iwl_fw *fw) + const struct iwl_fw *fw, u8 tx_ant, u8 rx_ant) { struct iwl_nvm_data *data; u32 sbands_flags = 0; @@ -1395,6 +1480,10 @@ iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, tx_chains &= data->valid_tx_ant; if (data->valid_rx_ant) rx_chains &= data->valid_rx_ant; + if (tx_ant) + tx_chains &= tx_ant; + if (rx_ant) + rx_chains &= rx_ant; data->sku_cap_mimo_disabled = false; data->sku_cap_band_24ghz_enable = true; @@ -1489,9 +1578,6 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, ®ulatory[NVM_CHANNELS_SDP] : &nvm_sw[NVM_CHANNELS]; - /* in family 8000 Xtal calibration values moved to OTP */ - data->xtal_calib[0] = *(nvm_calib + XTAL_CALIB); - data->xtal_calib[1] = *(nvm_calib + XTAL_CALIB + 1); lar_enabled = true; } else { u16 lar_offset = data->nvm_version < 0xE39 ? @@ -1539,11 +1625,15 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, flags &= ~NL80211_RRF_NO_HT40PLUS; if (nvm_chan[ch_idx] >= FIRST_2GHZ_HT_MINUS) flags &= ~NL80211_RRF_NO_HT40MINUS; - } else if (nvm_flags & NVM_CHANNEL_40MHZ) { + } else if (ch_idx < NUM_2GHZ_CHANNELS + NUM_5GHZ_CHANNELS && + nvm_flags & NVM_CHANNEL_40MHZ) { if ((ch_idx - NUM_2GHZ_CHANNELS) % 2 == 0) flags &= ~NL80211_RRF_NO_HT40PLUS; else flags &= ~NL80211_RRF_NO_HT40MINUS; + } else if (nvm_flags & NVM_CHANNEL_40MHZ) { + flags &= ~NL80211_RRF_NO_HT40PLUS; + flags &= ~NL80211_RRF_NO_HT40MINUS; } if (!(nvm_flags & NVM_CHANNEL_80MHZ)) @@ -1563,9 +1653,26 @@ static u32 iwl_nvm_get_regdom_bw_flags(const u16 *nvm_chan, /* Set the GO concurrent flag only in case that NO_IR is set. * Otherwise it is meaningless */ - if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT) && - (flags & NL80211_RRF_NO_IR)) - flags |= NL80211_RRF_GO_CONCURRENT; + if ((nvm_flags & NVM_CHANNEL_GO_CONCURRENT)) { + if (flags & NL80211_RRF_NO_IR) + flags |= NL80211_RRF_GO_CONCURRENT; + if (flags & NL80211_RRF_DFS) { + flags |= NL80211_RRF_DFS_CONCURRENT; + /* Our device doesn't set active bit for DFS channels + * however, once marked as DFS no-ir is not needed. + */ + flags &= ~NL80211_RRF_NO_IR; + } + } + + /* Set the AP type for the UHB case. */ + if (nvm_flags & NVM_CHANNEL_VLP) + flags |= NL80211_RRF_ALLOW_6GHZ_VLP_AP; + else + flags |= NL80211_RRF_NO_6GHZ_VLP_CLIENT; + + if (!(nvm_flags & NVM_CHANNEL_AFC)) + flags |= NL80211_RRF_NO_6GHZ_AFC_CLIENT; /* * reg_capa is per regulatory domain so apply it for every channel @@ -1629,7 +1736,6 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, const u16 *nvm_chan; struct ieee80211_regdomain *regd, *copy_rd; struct ieee80211_reg_rule *rule; - enum nl80211_band band; int center_freq, prev_center_freq = 0; int valid_rules = 0; bool new_rule; @@ -1673,8 +1779,10 @@ iwl_parse_nvm_mcc_info(struct device *dev, const struct iwl_cfg *cfg, reg_capa = iwl_get_reg_capa(cap, resp_ver); for (ch_idx = 0; ch_idx < num_of_ch; ch_idx++) { + enum nl80211_band band = + iwl_nl80211_band_from_channel_idx(ch_idx); + ch_flags = (u16)__le32_to_cpup(channels + ch_idx); - band = iwl_nl80211_band_from_channel_idx(ch_idx); center_freq = ieee80211_channel_to_frequency(nvm_chan[ch_idx], band); new_rule = false; @@ -1960,7 +2068,8 @@ out: IWL_EXPORT_SYMBOL(iwl_read_external_nvm); struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, - const struct iwl_fw *fw) + const struct iwl_fw *fw, + u8 set_tx_ant, u8 set_rx_ant) { struct iwl_nvm_get_info cmd = {}; struct iwl_nvm_data *nvm; @@ -1974,6 +2083,9 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, bool empty_otp; u32 mac_flags; u32 sbands_flags = 0; + u8 tx_ant; + u8 rx_ant; + /* * All the values in iwl_nvm_get_info_rsp v4 are the same as * in v3, except for the channel profile part of the @@ -2047,7 +2159,7 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, !!(mac_flags & NVM_MAC_SKU_FLAGS_BAND_5_2_ENABLED); nvm->sku_cap_mimo_disabled = !!(mac_flags & NVM_MAC_SKU_FLAGS_MIMO_DISABLED); - if (CSR_HW_RFID_TYPE(trans->hw_rf_id) == IWL_CFG_RF_TYPE_FM) + if (CSR_HW_RFID_TYPE(trans->hw_rf_id) >= IWL_CFG_RF_TYPE_FM) nvm->sku_cap_11be_enable = true; /* Initialize PHY sku data */ @@ -2065,10 +2177,15 @@ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, channel_profile = v4 ? (void *)rsp->regulatory.channel_profile : (void *)rsp_v3->regulatory.channel_profile; - iwl_init_sbands(trans, nvm, - channel_profile, - nvm->valid_tx_ant & fw->valid_tx_ant, - nvm->valid_rx_ant & fw->valid_rx_ant, + tx_ant = nvm->valid_tx_ant & fw->valid_tx_ant; + rx_ant = nvm->valid_rx_ant & fw->valid_rx_ant; + + if (set_tx_ant) + tx_ant &= set_tx_ant; + if (set_rx_ant) + rx_ant &= set_rx_ant; + + iwl_init_sbands(trans, nvm, channel_profile, tx_ant, rx_ant, sbands_flags, v4, fw); iwl_free_resp(&hcmd); diff --git a/sys/contrib/dev/iwlwifi/iwl-nvm-parse.h b/sys/contrib/dev/iwlwifi/iwl-nvm-parse.h index c79f72d54482..0c6c3fb8c6dd 100644 --- a/sys/contrib/dev/iwlwifi/iwl-nvm-parse.h +++ b/sys/contrib/dev/iwlwifi/iwl-nvm-parse.h @@ -1,13 +1,13 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2015, 2018-2022 Intel Corporation + * Copyright (C) 2005-2015, 2018-2024 Intel Corporation * Copyright (C) 2016-2017 Intel Deutschland GmbH */ #ifndef __iwl_nvm_parse_h__ #define __iwl_nvm_parse_h__ #include <net/cfg80211.h> -#include "iwl-eeprom-parse.h" +#include "iwl-nvm-utils.h" #include "mei/iwl-mei.h" /** @@ -21,7 +21,7 @@ enum iwl_nvm_sbands_flags { IWL_NVM_SBANDS_FLAGS_NO_WIDE_IN_5GHZ = BIT(1), }; -/** +/* * iwl_parse_nvm_data - parse NVM data and return values * * This function parses all NVM values we need and then @@ -38,7 +38,7 @@ iwl_parse_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, u8 tx_chains, u8 rx_chains); /** - * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW + * iwl_parse_nvm_mcc_info - parse MCC (mobile country code) info coming from FW * * This function parses the regulatory channel data received as a * MCC_UPDATE_CMD command. It returns a newly allocation regulatory domain, @@ -73,21 +73,28 @@ int iwl_read_external_nvm(struct iwl_trans *trans, void iwl_nvm_fixups(u32 hw_id, unsigned int section, u8 *data, unsigned int len); -/** +/* * iwl_get_nvm - retrieve NVM data from firmware * * Allocates a new iwl_nvm_data structure, fills it with * NVM data, and returns it to caller. */ struct iwl_nvm_data *iwl_get_nvm(struct iwl_trans *trans, - const struct iwl_fw *fw); + const struct iwl_fw *fw, + u8 set_tx_ant, u8 set_rx_ant); -/** +/* * iwl_parse_mei_nvm_data - parse the mei_nvm_data and get an iwl_nvm_data */ struct iwl_nvm_data * iwl_parse_mei_nvm_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, const struct iwl_mei_nvm *mei_nvm, - const struct iwl_fw *fw); + const struct iwl_fw *fw, u8 set_tx_ant, u8 set_rx_ant); + +/* + * iwl_reinit_cab - to be called when the tx_chains or rx_chains are modified + */ +void iwl_reinit_cab(struct iwl_trans *trans, struct iwl_nvm_data *data, + u8 tx_chains, u8 rx_chains, const struct iwl_fw *fw); #endif /* __iwl_nvm_parse_h__ */ diff --git a/sys/contrib/dev/iwlwifi/iwl-nvm-utils.c b/sys/contrib/dev/iwlwifi/iwl-nvm-utils.c new file mode 100644 index 000000000000..b3c25acd3691 --- /dev/null +++ b/sys/contrib/dev/iwlwifi/iwl-nvm-utils.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2005-2014, 2018-2021, 2023 Intel Corporation + * Copyright (C) 2015 Intel Mobile Communications GmbH + */ +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/export.h> +#include "iwl-drv.h" +#include "iwl-modparams.h" +#include "iwl-nvm-utils.h" + +int iwl_init_sband_channels(struct iwl_nvm_data *data, + struct ieee80211_supported_band *sband, + int n_channels, enum nl80211_band band) +{ + struct ieee80211_channel *chan = &data->channels[0]; + int n = 0, idx = 0; + + while (idx < n_channels && chan->band != band) + chan = &data->channels[++idx]; + + sband->channels = &data->channels[idx]; + + while (idx < n_channels && chan->band == band) { + chan = &data->channels[++idx]; + n++; + } + + sband->n_channels = n; + + return n; +} +IWL_EXPORT_SYMBOL(iwl_init_sband_channels); + +#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ +#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ + +void iwl_init_ht_hw_capab(struct iwl_trans *trans, + struct iwl_nvm_data *data, + struct ieee80211_sta_ht_cap *ht_info, + enum nl80211_band band, + u8 tx_chains, u8 rx_chains) +{ + const struct iwl_cfg *cfg = trans->cfg; + int max_bit_rate = 0; + + tx_chains = hweight8(tx_chains); + if (cfg->rx_with_siso_diversity) + rx_chains = 1; + else + rx_chains = hweight8(rx_chains); + + if (!(data->sku_cap_11n_enable) || + (iwlwifi_mod_params.disable_11n & IWL_DISABLE_HT_ALL) || + !cfg->ht_params) { + ht_info->ht_supported = false; + return; + } + + if (data->sku_cap_mimo_disabled) + rx_chains = 1; + + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_DSSSCCK40; + + if (cfg->ht_params->stbc) { + ht_info->cap |= (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT); + + if (tx_chains > 1) + ht_info->cap |= IEEE80211_HT_CAP_TX_STBC; + } + + if (cfg->ht_params->ldpc) + ht_info->cap |= IEEE80211_HT_CAP_LDPC_CODING; + + if (trans->trans_cfg->mq_rx_supported || + iwlwifi_mod_params.amsdu_size >= IWL_AMSDU_8K) + ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; + + ht_info->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + ht_info->ampdu_density = IEEE80211_HT_MPDU_DENSITY_4; + + ht_info->mcs.rx_mask[0] = 0xFF; + ht_info->mcs.rx_mask[1] = 0x00; + ht_info->mcs.rx_mask[2] = 0x00; + + if (rx_chains >= 2) + ht_info->mcs.rx_mask[1] = 0xFF; + if (rx_chains >= 3) + ht_info->mcs.rx_mask[2] = 0xFF; + + if (cfg->ht_params->ht_greenfield_support) + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + + max_bit_rate = MAX_BIT_RATE_20_MHZ; + + if (cfg->ht_params->ht40_bands & BIT(band)) { + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + max_bit_rate = MAX_BIT_RATE_40_MHZ; + } + + /* Highest supported Rx data rate */ + max_bit_rate *= rx_chains; + WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); + ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); + + /* Tx MCS capabilities */ + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + if (tx_chains != rx_chains) { + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_chains - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); + } +} +IWL_EXPORT_SYMBOL(iwl_init_ht_hw_capab); diff --git a/sys/contrib/dev/iwlwifi/iwl-eeprom-parse.h b/sys/contrib/dev/iwlwifi/iwl-nvm-utils.h index 0e8ca761d24b..ac0a29a1c31f 100644 --- a/sys/contrib/dev/iwlwifi/iwl-eeprom-parse.h +++ b/sys/contrib/dev/iwlwifi/iwl-nvm-utils.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018, 2020-2022 Intel Corporation + * Copyright (C) 2005-2014, 2018, 2020-2023 Intel Corporation * Copyright (C) 2015 Intel Mobile Communications GmbH */ #ifndef __iwl_eeprom_parse_h__ @@ -58,23 +58,6 @@ struct iwl_nvm_data { struct ieee80211_channel channels[]; }; -/** - * iwl_parse_eeprom_data - parse EEPROM data and return values - * - * @dev: device pointer we're parsing for, for debug only - * @cfg: device configuration for parsing and overrides - * @eeprom: the EEPROM data - * @eeprom_size: length of the EEPROM data - * - * This function parses all EEPROM values we need and then - * returns a (newly allocated) struct containing all the - * relevant values for driver use. The struct must be freed - * later with iwl_free_nvm_data(). - */ -struct iwl_nvm_data * -iwl_parse_eeprom_data(struct iwl_trans *trans, const struct iwl_cfg *cfg, - const u8 *eeprom, size_t eeprom_size); - int iwl_init_sband_channels(struct iwl_nvm_data *data, struct ieee80211_supported_band *sband, int n_channels, enum nl80211_band band); diff --git a/sys/contrib/dev/iwlwifi/iwl-op-mode.h b/sys/contrib/dev/iwlwifi/iwl-op-mode.h index af5f9b210f22..8ef5ed2db051 100644 --- a/sys/contrib/dev/iwlwifi/iwl-op-mode.h +++ b/sys/contrib/dev/iwlwifi/iwl-op-mode.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2021 Intel Corporation + * Copyright (C) 2005-2014, 2018-2021, 2024 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH * Copyright (C) 2015 Intel Deutschland GmbH */ @@ -64,15 +64,15 @@ struct iwl_cfg; * received on the RSS queue(s). The queue parameter indicates which of the * RSS queues received this frame; it will always be non-zero. * This method must not sleep. - * @async_cb: called when an ASYNC command with CMD_WANT_ASYNC_CALLBACK set - * completes. Must be atomic. * @queue_full: notifies that a HW queue is full. * Must be atomic and called with BH disabled. * @queue_not_full: notifies that a HW queue is not full any more. * Must be atomic and called with BH disabled. - * @hw_rf_kill:notifies of a change in the HW rf kill switch. True means that + * @hw_rf_kill: notifies of a change in the HW rf kill switch. True means that * the radio is killed. Return %true if the device should be stopped by * the transport immediately after the call. May sleep. + * Note that this must not return %true for newer devices using gen2 PCIe + * transport. * @free_skb: allows the transport layer to free skbs that haven't been * reclaimed by the op_mode. This can happen when the driver is freed and * there are Tx packets pending in the transport layer. @@ -85,6 +85,10 @@ struct iwl_cfg; * May sleep * @wimax_active: invoked when WiMax becomes active. May sleep * @time_point: called when transport layer wants to collect debug data + * @device_powered_off: called upon resume from hibernation but not only. + * Op_mode needs to reset its internal state because the device did not + * survive the system state transition. The firmware is no longer running, + * etc... */ struct iwl_op_mode_ops { struct iwl_op_mode *(*start)(struct iwl_trans *trans, @@ -96,8 +100,6 @@ struct iwl_op_mode_ops { struct iwl_rx_cmd_buffer *rxb); void (*rx_rss)(struct iwl_op_mode *op_mode, struct napi_struct *napi, struct iwl_rx_cmd_buffer *rxb, unsigned int queue); - void (*async_cb)(struct iwl_op_mode *op_mode, - const struct iwl_device_cmd *cmd); void (*queue_full)(struct iwl_op_mode *op_mode, int queue); void (*queue_not_full)(struct iwl_op_mode *op_mode, int queue); bool (*hw_rf_kill)(struct iwl_op_mode *op_mode, bool state); @@ -109,6 +111,7 @@ struct iwl_op_mode_ops { void (*time_point)(struct iwl_op_mode *op_mode, enum iwl_fw_ini_time_point tp_id, union iwl_dbg_tlv_tp_data *tp_data); + void (*device_powered_off)(struct iwl_op_mode *op_mode); }; int iwl_opmode_register(const char *name, const struct iwl_op_mode_ops *ops); @@ -147,13 +150,6 @@ static inline void iwl_op_mode_rx_rss(struct iwl_op_mode *op_mode, op_mode->ops->rx_rss(op_mode, napi, rxb, queue); } -static inline void iwl_op_mode_async_cb(struct iwl_op_mode *op_mode, - const struct iwl_device_cmd *cmd) -{ - if (op_mode->ops->async_cb) - op_mode->ops->async_cb(op_mode, cmd); -} - static inline void iwl_op_mode_queue_full(struct iwl_op_mode *op_mode, int queue) { @@ -194,7 +190,8 @@ static inline void iwl_op_mode_cmd_queue_full(struct iwl_op_mode *op_mode) static inline void iwl_op_mode_nic_config(struct iwl_op_mode *op_mode) { might_sleep(); - op_mode->ops->nic_config(op_mode); + if (op_mode->ops->nic_config) + op_mode->ops->nic_config(op_mode); } static inline void iwl_op_mode_wimax_active(struct iwl_op_mode *op_mode) @@ -212,4 +209,11 @@ static inline void iwl_op_mode_time_point(struct iwl_op_mode *op_mode, op_mode->ops->time_point(op_mode, tp_id, tp_data); } +static inline void iwl_op_mode_device_powered_off(struct iwl_op_mode *op_mode) +{ + if (!op_mode || !op_mode->ops || !op_mode->ops->device_powered_off) + return; + op_mode->ops->device_powered_off(op_mode); +} + #endif /* __iwl_op_mode_h__ */ diff --git a/sys/contrib/dev/iwlwifi/iwl-prph.h b/sys/contrib/dev/iwlwifi/iwl-prph.h index 6dd381ff0f9e..dc171c29eb7b 100644 --- a/sys/contrib/dev/iwlwifi/iwl-prph.h +++ b/sys/contrib/dev/iwlwifi/iwl-prph.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2023 Intel Corporation + * Copyright (C) 2005-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016 Intel Deutschland GmbH */ @@ -96,7 +96,7 @@ #define DTSC_PTAT_AVG (0x00a10650) -/** +/* * Tx Scheduler * * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs @@ -169,7 +169,7 @@ */ #define SCD_MEM_LOWER_BOUND (0x0000) -/** +/* * Max Tx window size is the max number of contiguous TFDs that the scheduler * can keep track of at one time when creating block-ack chains of frames. * Note that "64" matches the number of ack bits in a block-ack packet. @@ -348,8 +348,8 @@ #define RFIC_REG_RD 0xAD0470 #define WFPM_CTRL_REG 0xA03030 #define WFPM_OTP_CFG1_ADDR 0x00a03098 -#define WFPM_OTP_CFG1_IS_JACKET_BIT BIT(4) -#define WFPM_OTP_CFG1_IS_CDB_BIT BIT(5) +#define WFPM_OTP_CFG1_IS_JACKET_BIT BIT(5) +#define WFPM_OTP_CFG1_IS_CDB_BIT BIT(4) #define WFPM_OTP_BZ_BNJ_JACKET_BIT 5 #define WFPM_OTP_BZ_BNJ_CDB_BIT 4 #define WFPM_OTP_CFG1_IS_JACKET(_val) (((_val) & 0x00000020) >> WFPM_OTP_BZ_BNJ_JACKET_BIT) @@ -365,16 +365,25 @@ #define DBGI_SRAM_FIFO_POINTERS_WR_PTR_MSK 0x00000FFF enum { - ENABLE_WFPM = BIT(31), WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK = 0x80000000, }; -#define CNVI_AUX_MISC_CHIP 0xA200B0 +#define CNVI_AUX_MISC_CHIP 0xA200B0 +#define CNVI_AUX_MISC_CHIP_MAC_STEP(_val) (((_val) & 0xf000000) >> 24) +#define CNVI_AUX_MISC_CHIP_PROD_TYPE(_val) ((_val) & 0xfff) +#define CNVI_AUX_MISC_CHIP_PROD_TYPE_GL 0x910 +#define CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_U 0x930 +#define CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_I 0x900 +#define CNVI_AUX_MISC_CHIP_PROD_TYPE_BZ_W 0x901 + #define CNVR_AUX_MISC_CHIP 0xA2B800 #define CNVR_SCU_SD_REGS_SD_REG_DIG_DCDC_VTRIM 0xA29890 #define CNVR_SCU_SD_REGS_SD_REG_ACTIVE_VDIG_MIRROR 0xA29938 #define CNVI_SCU_SEQ_DATA_DW9 0xA27488 +#define CNVI_PMU_STEP_FLOW 0xA2D588 +#define CNVI_PMU_STEP_FLOW_FORCE_URM BIT(2) + #define PREG_AUX_BUS_WPROT_0 0xA04CC0 /* device family 9000 WPROT register */ @@ -383,7 +392,7 @@ enum { #define PREG_PRPH_WPROT_22000 0xA04D00 #define SB_MODIFY_CFG_FLAG 0xA03088 -#define SB_CFG_RESIDES_IN_OTP_MASK 0x10 +#define SB_CFG_RESIDES_IN_ROM 0x80 #define SB_CPU_1_STATUS 0xA01E30 #define SB_CPU_2_STATUS 0xA01E34 #define UMAG_SB_CPU_1_STATUS 0xA038C0 @@ -424,14 +433,14 @@ enum { * reserved: bits 12-18 * slave_exist: bit 19 * dash: bits 20-23 - * step: bits 24-26 - * flavor: bits 27-31 + * step: bits 24-27 + * flavor: bits 28-31 */ #define REG_CRF_ID_TYPE(val) (((val) & 0x00000FFF) >> 0) #define REG_CRF_ID_SLAVE(val) (((val) & 0x00080000) >> 19) #define REG_CRF_ID_DASH(val) (((val) & 0x00F00000) >> 20) -#define REG_CRF_ID_STEP(val) (((val) & 0x07000000) >> 24) -#define REG_CRF_ID_FLAVOR(val) (((val) & 0xF8000000) >> 27) +#define REG_CRF_ID_STEP(val) (((val) & 0x0F000000) >> 24) +#define REG_CRF_ID_FLAVOR(val) (((val) & 0xF0000000) >> 28) #define UREG_CHICK (0xA05C00) #define UREG_CHICK_MSI_ENABLE BIT(24) @@ -447,11 +456,8 @@ enum { #define REG_CRF_ID_TYPE_HR_NONE_CDB_1X1 0x501 #define REG_CRF_ID_TYPE_HR_NONE_CDB_CCP 0x532 #define REG_CRF_ID_TYPE_GF 0x410 -#define REG_CRF_ID_TYPE_GF_TC 0xF08 -#define REG_CRF_ID_TYPE_MR 0x810 #define REG_CRF_ID_TYPE_FM 0x910 -#define REG_CRF_ID_TYPE_FMI 0x930 -#define REG_CRF_ID_TYPE_FMR 0x900 +#define REG_CRF_ID_TYPE_WHP 0xA10 #define HPM_DEBUG 0xA03440 #define PERSISTENCE_BIT BIT(12) @@ -516,4 +522,8 @@ enum { #define WFPM_LMAC2_PD_NOTIFICATION 0xA033CC #define WFPM_LMAC2_PD_RE_READ BIT(31) +#define DPHYIP_INDIRECT 0xA2D800 +#define DPHYIP_INDIRECT_RD_MSK 0xFF000000 +#define DPHYIP_INDIRECT_RD_SHIFT 24 + #endif /* __iwl_prph_h__ */ diff --git a/sys/contrib/dev/iwlwifi/iwl-trans.c b/sys/contrib/dev/iwlwifi/iwl-trans.c index c49e1d8e0ca1..3c9d91496c82 100644 --- a/sys/contrib/dev/iwlwifi/iwl-trans.c +++ b/sys/contrib/dev/iwlwifi/iwl-trans.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH - * Copyright (C) 2019-2021, 2023 Intel Corporation + * Copyright (C) 2019-2021, 2023-2024 Intel Corporation */ #include <linux/kernel.h> #include <linux/bsearch.h> @@ -11,13 +11,13 @@ #include "iwl-trans.h" #include "iwl-drv.h" #include "iwl-fh.h" -#include "queue/tx.h" #include <linux/dmapool.h> #include "fw/api/commands.h" +#include "pcie/internal.h" +#include "iwl-context-info-gen3.h" struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, - const struct iwl_trans_ops *ops, const struct iwl_cfg_trans_params *cfg_trans) { struct iwl_trans *trans; @@ -37,22 +37,8 @@ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, #endif trans->dev = dev; - trans->ops = ops; trans->num_rx_queues = 1; - WARN_ON(!ops->wait_txq_empty && !ops->wait_tx_queues_empty); - - if (trans->trans_cfg->gen2) { - trans->txqs.tfd.addr_size = 64; - trans->txqs.tfd.max_tbs = IWL_TFH_NUM_TBS; - trans->txqs.tfd.size = sizeof(struct iwl_tfh_tfd); - } else { - trans->txqs.tfd.addr_size = 36; - trans->txqs.tfd.max_tbs = IWL_NUM_OF_TBS; - trans->txqs.tfd.size = sizeof(struct iwl_tfd); - } - trans->max_skb_frags = IWL_TRANS_MAX_FRAGS(trans); - return trans; } @@ -78,31 +64,6 @@ int iwl_trans_init(struct iwl_trans *trans) if (WARN_ON(trans->trans_cfg->gen2 && txcmd_size >= txcmd_align)) return -EINVAL; - if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) - trans->txqs.bc_tbl_size = - sizeof(struct iwl_gen3_bc_tbl_entry) * TFD_QUEUE_BC_SIZE_GEN3_BZ; - else if (trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) - trans->txqs.bc_tbl_size = - sizeof(struct iwl_gen3_bc_tbl_entry) * TFD_QUEUE_BC_SIZE_GEN3_AX210; - else - trans->txqs.bc_tbl_size = sizeof(struct iwlagn_scd_bc_tbl); - /* - * For gen2 devices, we use a single allocation for each byte-count - * table, but they're pretty small (1k) so use a DMA pool that we - * allocate here. - */ - if (trans->trans_cfg->gen2) { - trans->txqs.bc_pool = dmam_pool_create("iwlwifi:bc", trans->dev, - trans->txqs.bc_tbl_size, - 256, 0); - if (!trans->txqs.bc_pool) - return -ENOMEM; - } - - /* Some things must not change even if the config does */ - WARN_ON(trans->txqs.tfd.addr_size != - (trans->trans_cfg->gen2 ? 64 : 36)); - snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), "iwl_cmd_pool:%s", dev_name(trans->dev)); trans->dev_cmd_pool = @@ -112,14 +73,6 @@ int iwl_trans_init(struct iwl_trans *trans) if (!trans->dev_cmd_pool) return -ENOMEM; -#ifdef CONFIG_INET - trans->txqs.tso_hdr_page = alloc_percpu(struct iwl_tso_hdr_page); - if (!trans->txqs.tso_hdr_page) { - kmem_cache_destroy(trans->dev_cmd_pool); - return -ENOMEM; - } -#endif - /* Initialize the wait queue for commands */ init_waitqueue_head(&trans->wait_command_queue); @@ -128,22 +81,6 @@ int iwl_trans_init(struct iwl_trans *trans) void iwl_trans_free(struct iwl_trans *trans) { -#ifdef CONFIG_INET - int i; - - if (trans->txqs.tso_hdr_page) { - for_each_possible_cpu(i) { - struct iwl_tso_hdr_page *p = - per_cpu_ptr(trans->txqs.tso_hdr_page, i); - - if (p && p->page) - __free_page(p->page); - } - - free_percpu(trans->txqs.tso_hdr_page); - } -#endif - kmem_cache_destroy(trans->dev_cmd_pool); } @@ -171,14 +108,9 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) return -EIO; - if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); + if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, + "bad state = %d\n", trans->state)) return -EIO; - } - - if (WARN_ON((cmd->flags & CMD_WANT_ASYNC_CALLBACK) && - !(cmd->flags & CMD_ASYNC))) - return -EINVAL; if (!(cmd->flags & CMD_ASYNC)) lock_map_acquire_read(&trans->sync_cmd_lockdep_map); @@ -188,7 +120,7 @@ int iwl_trans_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd) cmd->id = DEF_ID(cmd->id); } - ret = iwl_trans_txq_send_hcmd(trans, cmd); + ret = iwl_trans_pcie_send_hcmd(trans, cmd); if (!(cmd->flags & CMD_ASYNC)) lock_map_release(&trans->sync_cmd_lockdep_map); @@ -255,3 +187,379 @@ int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans) return 0; } IWL_EXPORT_SYMBOL(iwl_cmd_groups_verify_sorted); + +void iwl_trans_configure(struct iwl_trans *trans, + const struct iwl_trans_config *trans_cfg) +{ + trans->op_mode = trans_cfg->op_mode; + + iwl_trans_pcie_configure(trans, trans_cfg); + WARN_ON(iwl_cmd_groups_verify_sorted(trans_cfg)); +} +IWL_EXPORT_SYMBOL(iwl_trans_configure); + +int iwl_trans_start_hw(struct iwl_trans *trans) +{ + might_sleep(); + + return iwl_trans_pcie_start_hw(trans); +} +IWL_EXPORT_SYMBOL(iwl_trans_start_hw); + +void iwl_trans_op_mode_leave(struct iwl_trans *trans) +{ + might_sleep(); + + iwl_trans_pcie_op_mode_leave(trans); + + trans->op_mode = NULL; + + trans->state = IWL_TRANS_NO_FW; +} +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); +} +IWL_EXPORT_SYMBOL(iwl_trans_write8); + +void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val) +{ + iwl_trans_pcie_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); +} +IWL_EXPORT_SYMBOL(iwl_trans_read32); + +u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs) +{ + return iwl_trans_pcie_read_prph(trans, ofs); +} +IWL_EXPORT_SYMBOL(iwl_trans_read_prph); + +void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val) +{ + return iwl_trans_pcie_write_prph(trans, ofs, val); +} +IWL_EXPORT_SYMBOL(iwl_trans_write_prph); + +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); +} +IWL_EXPORT_SYMBOL(iwl_trans_read_mem); + +int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, + const void *buf, int dwords) +{ + return iwl_trans_pcie_write_mem(trans, addr, buf, dwords); +} +IWL_EXPORT_SYMBOL(iwl_trans_write_mem); + +void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) +{ + if (state) + set_bit(STATUS_TPOWER_PMI, &trans->status); + else + clear_bit(STATUS_TPOWER_PMI, &trans->status); +} +IWL_EXPORT_SYMBOL(iwl_trans_set_pmi); + +int iwl_trans_sw_reset(struct iwl_trans *trans, bool retake_ownership) +{ + return iwl_trans_pcie_sw_reset(trans, retake_ownership); +} +IWL_EXPORT_SYMBOL(iwl_trans_sw_reset); + +struct iwl_trans_dump_data * +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); +} +IWL_EXPORT_SYMBOL(iwl_trans_dump_data); + +int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, bool reset) +{ + might_sleep(); + + return iwl_trans_pcie_d3_suspend(trans, test, reset); +} +IWL_EXPORT_SYMBOL(iwl_trans_d3_suspend); + +int iwl_trans_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, + bool test, bool reset) +{ + might_sleep(); + + return iwl_trans_pcie_d3_resume(trans, status, test, reset); +} +IWL_EXPORT_SYMBOL(iwl_trans_d3_resume); + +void iwl_trans_interrupts(struct iwl_trans *trans, bool enable) +{ + iwl_trans_pci_interrupts(trans, enable); +} +IWL_EXPORT_SYMBOL(iwl_trans_interrupts); + +void iwl_trans_sync_nmi(struct iwl_trans *trans) +{ + iwl_trans_pcie_sync_nmi(trans); +} +IWL_EXPORT_SYMBOL(iwl_trans_sync_nmi); + +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); +} +IWL_EXPORT_SYMBOL(iwl_trans_write_imr_mem); + +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); +} +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); +} +IWL_EXPORT_SYMBOL(iwl_trans_read_config32); + +bool _iwl_trans_grab_nic_access(struct iwl_trans *trans) +{ + return iwl_trans_pcie_grab_nic_access(trans); +} +IWL_EXPORT_SYMBOL(_iwl_trans_grab_nic_access); + +void __releases(nic_access) +iwl_trans_release_nic_access(struct iwl_trans *trans) +{ + iwl_trans_pcie_release_nic_access(trans); + __release(nic_access); +} +IWL_EXPORT_SYMBOL(iwl_trans_release_nic_access); + +void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr) +{ + might_sleep(); + + trans->state = IWL_TRANS_FW_ALIVE; + + if (trans->trans_cfg->gen2) + iwl_trans_pcie_gen2_fw_alive(trans); + else + iwl_trans_pcie_fw_alive(trans, scd_addr); +} +IWL_EXPORT_SYMBOL(iwl_trans_fw_alive); + +int iwl_trans_start_fw(struct iwl_trans *trans, const struct fw_img *fw, + bool run_in_rfkill) +{ + int ret; + + might_sleep(); + + WARN_ON_ONCE(!trans->rx_mpdu_cmd); + + clear_bit(STATUS_FW_ERROR, &trans->status); + + if (trans->trans_cfg->gen2) + ret = iwl_trans_pcie_gen2_start_fw(trans, fw, run_in_rfkill); + else + ret = iwl_trans_pcie_start_fw(trans, fw, run_in_rfkill); + + if (ret == 0) + trans->state = IWL_TRANS_FW_STARTED; + + return ret; +} +IWL_EXPORT_SYMBOL(iwl_trans_start_fw); + +void iwl_trans_stop_device(struct iwl_trans *trans) +{ + might_sleep(); + + if (trans->trans_cfg->gen2) + iwl_trans_pcie_gen2_stop_device(trans); + else + iwl_trans_pcie_stop_device(trans); + + trans->state = IWL_TRANS_NO_FW; +} +IWL_EXPORT_SYMBOL(iwl_trans_stop_device); + +int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_tx_cmd *dev_cmd, int queue) +{ + if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) + return -EIO; + + if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, + "bad state = %d\n", trans->state)) + return -EIO; + + if (trans->trans_cfg->gen2) + return iwl_txq_gen2_tx(trans, skb, dev_cmd, queue); + + return iwl_trans_pcie_tx(trans, skb, dev_cmd, queue); +} +IWL_EXPORT_SYMBOL(iwl_trans_tx); + +void iwl_trans_reclaim(struct iwl_trans *trans, int queue, int ssn, + struct sk_buff_head *skbs, bool is_flush) +{ + if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, + "bad state = %d\n", trans->state)) + return; + + iwl_pcie_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); +} +IWL_EXPORT_SYMBOL(iwl_trans_txq_disable); + +bool iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int queue_wdg_timeout) +{ + might_sleep(); + + if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, + "bad state = %d\n", trans->state)) + return false; + + return iwl_trans_pcie_txq_enable(trans, queue, ssn, + cfg, queue_wdg_timeout); +} +IWL_EXPORT_SYMBOL(iwl_trans_txq_enable_cfg); + +int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue) +{ + if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, + "bad state = %d\n", trans->state)) + return -EIO; + + return iwl_trans_pcie_wait_txq_empty(trans, queue); +} +IWL_EXPORT_SYMBOL(iwl_trans_wait_txq_empty); + +int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, u32 txqs) +{ + if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, + "bad state = %d\n", trans->state)) + return -EIO; + + return iwl_trans_pcie_wait_txqs_empty(trans, txqs); +} +IWL_EXPORT_SYMBOL(iwl_trans_wait_tx_queues_empty); + +void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, + unsigned long txqs, bool freeze) +{ + if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, + "bad state = %d\n", trans->state)) + return; + + iwl_pcie_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); +} +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); +} +IWL_EXPORT_SYMBOL(iwl_trans_debugfs_cleanup); +#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); +} +IWL_EXPORT_SYMBOL(iwl_trans_set_q_ptrs); + +int iwl_trans_txq_alloc(struct iwl_trans *trans, u32 flags, u32 sta_mask, + u8 tid, int size, unsigned int wdg_timeout) +{ + might_sleep(); + + if (WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, + "bad state = %d\n", trans->state)) + return -EIO; + + return iwl_txq_dyn_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); +} +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); +} +IWL_EXPORT_SYMBOL(iwl_trans_get_rxq_dma_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_gen3_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_gen3_set_pnvm(trans, capa); +} +IWL_EXPORT_SYMBOL(iwl_trans_set_pnvm); + +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_gen3_load_reduce_power(trans, payloads, + capa); +} +IWL_EXPORT_SYMBOL(iwl_trans_load_reduce_power); + +void iwl_trans_set_reduce_power(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa) +{ + iwl_trans_pcie_ctx_info_gen3_set_reduce_power(trans, capa); +} +IWL_EXPORT_SYMBOL(iwl_trans_set_reduce_power); diff --git a/sys/contrib/dev/iwlwifi/iwl-trans.h b/sys/contrib/dev/iwlwifi/iwl-trans.h index 88d09041b19a..7430d1b37541 100644 --- a/sys/contrib/dev/iwlwifi/iwl-trans.h +++ b/sys/contrib/dev/iwlwifi/iwl-trans.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* - * Copyright (C) 2005-2014, 2018-2022 Intel Corporation + * Copyright (C) 2005-2014, 2018-2023 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -30,11 +30,9 @@ * DOC: Transport layer - what is it ? * * The transport layer is the layer that deals with the HW directly. It provides - * an abstraction of the underlying HW to the upper layer. The transport layer - * doesn't provide any policy, algorithm or anything of this kind, but only - * mechanisms to make the HW do something. It is not completely stateless but - * close to it. - * We will have an implementation for each different supported bus. + * the PCIe access to the underlying hardwarwe. The transport layer doesn't + * provide any policy, algorithm or anything of this kind, but only mechanisms + * to make the HW do something. It is not completely stateless but close to it. */ /** @@ -60,6 +58,10 @@ * 6) Eventually, the free function will be called. */ +/* default preset 0 (start from bit 16)*/ +#define IWL_FW_DBG_DOMAIN_POS 16 +#define IWL_FW_DBG_DOMAIN BIT(IWL_FW_DBG_DOMAIN_POS) + #define IWL_TRANS_FW_DBG_DOMAIN(trans) IWL_FW_INI_DOMAIN_ALWAYS_ON #define FH_RSCSR_FRAME_SIZE_MSK 0x00003FFF /* bits 0-13 */ @@ -109,8 +111,8 @@ static inline u32 iwl_rx_packet_payload_len(const struct iwl_rx_packet *pkt) * @CMD_ASYNC: Return right away and don't wait for the response * @CMD_WANT_SKB: Not valid with CMD_ASYNC. The caller needs the buffer of * the response. The caller needs to call iwl_free_resp when done. - * @CMD_WANT_ASYNC_CALLBACK: the op_mode's async callback function must be - * called after this command completes. Valid only with CMD_ASYNC. + * @CMD_SEND_IN_RFKILL: Send the command even if the NIC is in RF-kill. + * @CMD_BLOCK_TXQS: Block TXQs while the comment is executing. * @CMD_SEND_IN_D3: Allow the command to be sent in D3 mode, relevant to * SUSPEND and RESUME commands. We are in D3 mode when we set * trans->system_pm_mode to IWL_PLAT_PM_MODE_D3. @@ -119,9 +121,10 @@ enum CMD_MODE { CMD_ASYNC = BIT(0), CMD_WANT_SKB = BIT(1), CMD_SEND_IN_RFKILL = BIT(2), - CMD_WANT_ASYNC_CALLBACK = BIT(3), + CMD_BLOCK_TXQS = BIT(3), CMD_SEND_IN_D3 = BIT(4), }; +#define CMD_MODE_BITS 5 #define DEF_CMD_PAYLOAD_SIZE 320 @@ -131,6 +134,11 @@ enum CMD_MODE { * For allocation of the command and tx queues, this establishes the overall * size of the largest command we send to uCode, except for commands that * aren't fully copied and use other TFD space. + * + * @hdr: command header + * @payload: payload for the command + * @hdr_wide: wide command header + * @payload_wide: payload for the wide command */ struct iwl_device_cmd { union { @@ -167,12 +175,6 @@ struct iwl_device_tx_cmd { */ #define IWL_MAX_CMD_TBS_PER_TFD 2 -/* We need 2 entries for the TX command and header, and another one might - * be needed for potential data in the SKB's head. The remaining ones can - * be used for frags. - */ -#define IWL_TRANS_MAX_FRAGS(trans) ((trans)->txqs.tfd.max_tbs - 3) - /** * enum iwl_hcmd_dataflag - flag for each one of the chunks of the command * @@ -208,8 +210,8 @@ enum iwl_error_event_table_status { * * @data: array of chunks that composes the data of the host command * @resp_pkt: response packet, if %CMD_WANT_SKB was set - * @_rx_page_order: (internally used to free response packet); - * FreeBSD uses _page instead. + * @_rx_page_order: (internally used to free response packet) + * [ FreeBSD uses _page instead ] * @_rx_page_addr: (internally used to free response packet) * @flags: can be CMD_* * @len: array of the lengths of the chunks in data @@ -287,10 +289,10 @@ static inline void iwl_free_rxb(struct iwl_rx_cmd_buffer *r) #define IWL_MGMT_TID 15 #define IWL_FRAME_LIMIT 64 #define IWL_MAX_RX_HW_QUEUES 16 -#define IWL_9000_MAX_RX_HW_QUEUES 6 +#define IWL_9000_MAX_RX_HW_QUEUES 1 /** - * enum iwl_wowlan_status - WoWLAN image/device status + * enum iwl_d3_status - WoWLAN image/device status * @IWL_D3_STATUS_ALIVE: firmware is still running after resume * @IWL_D3_STATUS_RESET: device was reset while suspended */ @@ -308,9 +310,6 @@ enum iwl_d3_status { * @STATUS_RFKILL_HW: the actual HW state of the RF-kill switch * @STATUS_RFKILL_OPMODE: RF-kill state reported to opmode * @STATUS_FW_ERROR: the fw is in error state - * @STATUS_TRANS_GOING_IDLE: shutting down the trans, only special commands - * are sent - * @STATUS_TRANS_IDLE: the trans is idle - general commands are not to be sent * @STATUS_TRANS_DEAD: trans is dead - avoid any read/write operation * @STATUS_SUPPRESS_CMD_ERROR_ONCE: suppress "FW error in SYNC CMD" once, * e.g. for testing @@ -323,8 +322,6 @@ enum iwl_trans_status { STATUS_RFKILL_HW, STATUS_RFKILL_OPMODE, STATUS_FW_ERROR, - STATUS_TRANS_GOING_IDLE, - STATUS_TRANS_IDLE, STATUS_TRANS_DEAD, STATUS_SUPPRESS_CMD_ERROR_ONCE, }; @@ -491,182 +488,6 @@ struct iwl_pnvm_image { }; /** - * struct iwl_trans_ops - transport specific operations - * - * All the handlers MUST be implemented - * - * @start_hw: starts the HW. From that point on, the HW can send interrupts. - * May sleep. - * @op_mode_leave: Turn off the HW RF kill indication if on - * May sleep - * @start_fw: allocates and inits all the resources for the transport - * layer. Also kick a fw image. - * May sleep - * @fw_alive: called when the fw sends alive notification. If the fw provides - * the SCD base address in SRAM, then provide it here, or 0 otherwise. - * May sleep - * @stop_device: stops the whole device (embedded CPU put to reset) and stops - * the HW. From that point on, the HW will be stopped but will still issue - * an interrupt if the HW RF kill switch is triggered. - * This callback must do the right thing and not crash even if %start_hw() - * was called but not &start_fw(). May sleep. - * @d3_suspend: put the device into the correct mode for WoWLAN during - * suspend. This is optional, if not implemented WoWLAN will not be - * supported. This callback may sleep. - * @d3_resume: resume the device after WoWLAN, enabling the opmode to - * talk to the WoWLAN image to get its status. This is optional, if not - * implemented WoWLAN will not be supported. This callback may sleep. - * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted. - * If RFkill is asserted in the middle of a SYNC host command, it must - * return -ERFKILL straight away. - * May sleep only if CMD_ASYNC is not set - * @tx: send an skb. The transport relies on the op_mode to zero the - * the ieee80211_tx_info->driver_data. If the MPDU is an A-MSDU, all - * the CSUM will be taken care of (TCP CSUM and IP header in case of - * IPv4). If the MPDU is a single MSDU, the op_mode must compute the IP - * header if it is IPv4. - * Must be atomic - * @reclaim: free packet until ssn. Returns a list of freed packets. - * Must be atomic - * @txq_enable: setup a queue. To setup an AC queue, use the - * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before - * this one. The op_mode must not configure the HCMD queue. The scheduler - * configuration may be %NULL, in which case the hardware will not be - * configured. If true is returned, the operation mode needs to increment - * the sequence number of the packets routed to this queue because of a - * hardware scheduler bug. May sleep. - * @txq_disable: de-configure a Tx queue to send AMPDUs - * Must be atomic - * @txq_set_shared_mode: change Tx queue shared/unshared marking - * @wait_tx_queues_empty: wait until tx queues are empty. May sleep. - * @wait_txq_empty: wait until specific tx queue is empty. May sleep. - * @freeze_txq_timer: prevents the timer of the queue from firing until the - * queue is set to awake. Must be atomic. - * @block_txq_ptrs: stop updating the write pointers of the Tx queues. Note - * that the transport needs to refcount the calls since this function - * will be called several times with block = true, and then the queues - * need to be unblocked only after the same number of calls with - * block = false. - * @write8: write a u8 to a register at offset ofs from the BAR - * @write32: write a u32 to a register at offset ofs from the BAR - * @read32: read a u32 register at offset ofs from the BAR - * @read_prph: read a DWORD from a periphery register - * @write_prph: write a DWORD to a periphery register - * @read_mem: read device's SRAM in DWORD - * @write_mem: write device's SRAM in DWORD. If %buf is %NULL, then the memory - * will be zeroed. - * @read_config32: read a u32 value from the device's config space at - * the given offset. - * @configure: configure parameters required by the transport layer from - * the op_mode. May be called several times before start_fw, can't be - * called after that. - * @set_pmi: set the power pmi state - * @grab_nic_access: wake the NIC to be able to access non-HBUS regs. - * Sleeping is not allowed between grab_nic_access and - * release_nic_access. - * @release_nic_access: let the NIC go to sleep. The "flags" parameter - * must be the same one that was sent before to the grab_nic_access. - * @set_bits_mask - set SRAM register according to value and mask. - * @dump_data: return a vmalloc'ed buffer with debug data, maybe containing last - * TX'ed commands and similar. The buffer will be vfree'd by the caller. - * Note that the transport must fill in the proper file headers. - * @debugfs_cleanup: used in the driver unload flow to make a proper cleanup - * of the trans debugfs - * @load_pnvm: save the pnvm data in DRAM - * @set_pnvm: set the pnvm data in the prph scratch buffer, inside the - * context info. - * @load_reduce_power: copy reduce power table to the corresponding DRAM memory - * @set_reduce_power: set reduce power table addresses in the sratch buffer - * @interrupts: disable/enable interrupts to transport - */ -struct iwl_trans_ops { - - int (*start_hw)(struct iwl_trans *iwl_trans); - void (*op_mode_leave)(struct iwl_trans *iwl_trans); - int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw, - bool run_in_rfkill); - void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr); - void (*stop_device)(struct iwl_trans *trans); - - int (*d3_suspend)(struct iwl_trans *trans, bool test, bool reset); - int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status, - bool test, bool reset); - - int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd); - - 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); - - void (*set_q_ptrs)(struct iwl_trans *trans, int queue, int ptr); - - bool (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg, - unsigned int queue_wdg_timeout); - void (*txq_disable)(struct iwl_trans *trans, int queue, - bool configure_scd); - /* 22000 functions */ - int (*txq_alloc)(struct iwl_trans *trans, u32 flags, - u32 sta_mask, u8 tid, - int size, unsigned int queue_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); - - void (*txq_set_shared_mode)(struct iwl_trans *trans, u32 txq_id, - bool shared); - - int (*wait_tx_queues_empty)(struct iwl_trans *trans, u32 txq_bm); - int (*wait_txq_empty)(struct iwl_trans *trans, int queue); - void (*freeze_txq_timer)(struct iwl_trans *trans, unsigned long txqs, - bool freeze); - void (*block_txq_ptrs)(struct iwl_trans *trans, bool block); - - void (*write8)(struct iwl_trans *trans, u32 ofs, u8 val); - 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 (*write_mem)(struct iwl_trans *trans, u32 addr, - const void *buf, int dwords); - int (*read_config32)(struct iwl_trans *trans, u32 ofs, u32 *val); - void (*configure)(struct iwl_trans *trans, - const struct iwl_trans_config *trans_cfg); - void (*set_pmi)(struct iwl_trans *trans, bool state); - int (*sw_reset)(struct iwl_trans *trans, bool retake_ownership); - bool (*grab_nic_access)(struct iwl_trans *trans); - void (*release_nic_access)(struct iwl_trans *trans); - void (*set_bits_mask)(struct iwl_trans *trans, u32 reg, u32 mask, - u32 value); - - 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); - void (*debugfs_cleanup)(struct iwl_trans *trans); - void (*sync_nmi)(struct iwl_trans *trans); - int (*load_pnvm)(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_payloads, - 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); - - void (*interrupts)(struct iwl_trans *trans, bool enable); - int (*imr_dma_data)(struct iwl_trans *trans, - u32 dst_addr, u64 src_addr, - u32 byte_cnt); - -}; - -/** * enum iwl_trans_state - state of the transport layer * * @IWL_TRANS_NO_FW: firmware wasn't started yet, or crashed @@ -747,6 +568,7 @@ struct iwl_dram_data { }; /** + * struct iwl_dram_regions - DRAM regions container structure * @drams: array of several DRAM areas that contains the pnvm and power * reduction table payloads. * @n_regions: number of DRAM regions that were allocated @@ -789,7 +611,7 @@ struct iwl_self_init_dram { * @imr_size: imr dram size received from fw * @sram_addr: sram address from debug tlv * @sram_size: sram size from debug tlv - * @imr2sram_remainbyte`: size remained after each dma transfer + * @imr2sram_remainbyte: size remained after each dma transfer * @imr_curr_addr: current dst address used during dma transfer * @imr_base_addr: imr address received from fw */ @@ -836,16 +658,21 @@ struct iwl_pc_data { * @fw_mon: DRAM buffer for firmware monitor * @hw_error: equals true if hw error interrupt was received from the FW * @ini_dest: debug monitor destination uses &enum iwl_fw_ini_buffer_location + * @unsupported_region_msk: unsupported regions out of active_regions * @active_regions: active regions * @debug_info_tlv_list: list of debug info TLVs * @time_point: array of debug time points * @periodic_trig_list: periodic triggers list * @domains_bitmap: bitmap of active domains other than &IWL_FW_INI_DOMAIN_ALWAYS_ON * @ucode_preset: preset based on ucode + * @restart_required: indicates debug restart is required + * @last_tp_resetfw: last handling of reset during debug timepoint + * @imr_data: IMR debug data allocation * @dump_file_name_ext: dump file name extension * @dump_file_name_ext_valid: dump file name extension if valid or not * @num_pc: number of program counter for cpu * @pc_data: details of the program counter + * @yoyo_bin_loaded: tells if a yoyo debug file has been loaded */ struct iwl_trans_debug { u8 n_dest_reg; @@ -875,8 +702,7 @@ struct iwl_trans_debug { u64 unsupported_region_msk; struct iwl_ucode_tlv *active_regions[IWL_FW_INI_MAX_REGION_ID]; struct list_head debug_info_tlv_list; - struct iwl_dbg_tlv_time_point_data - time_point[IWL_FW_INI_TIME_POINT_NUM]; + struct iwl_dbg_tlv_time_point_data time_point[IWL_FW_INI_TIME_POINT_NUM]; struct list_head periodic_trig_list; u32 domains_bitmap; @@ -888,6 +714,7 @@ struct iwl_trans_debug { bool dump_file_name_ext_valid; u32 num_pc; struct iwl_pc_data *pc_data; + bool yoyo_bin_loaded; }; struct iwl_dma_ptr { @@ -899,7 +726,9 @@ struct iwl_dma_ptr { struct iwl_cmd_meta { /* only for SYNC commands, iff the reply skb is wanted */ struct iwl_host_cmd *source; - u32 flags; + u32 flags: CMD_MODE_BITS; + /* sg_offset is valid if it is non-zero */ + u32 sg_offset: PAGE_SHIFT; u32 tbs; }; @@ -929,7 +758,6 @@ struct iwl_pcie_first_tb_buf { /** * struct iwl_txq - Tx Queue for DMA - * @q: generic Rx/Tx queue descriptor * @tfds: transmit frame descriptors (DMA memory) * @first_tb_bufs: start of command headers, including scratch buffers, for * the writeback -- this is DMA memory and an array holding one buffer @@ -937,6 +765,7 @@ struct iwl_pcie_first_tb_buf { * @first_tb_dma: DMA address for the first_tb_bufs start * @entries: transmit entries (driver state) * @lock: queue lock + * @reclaim_lock: reclaim lock * @stuck_timer: timer that fires if queue gets stuck * @trans: pointer back to transport (for timer) * @need_update: indicates need to update read/write index @@ -944,6 +773,7 @@ struct iwl_pcie_first_tb_buf { * @wd_timeout: queue watchdog timeout (jiffies) - per queue * @frozen: tx stuck queue timer is frozen * @frozen_expiry_remainder: remember how long until the timer fires + * @block: queue is blocked * @bc_tbl: byte count table of the queue (relevant only for gen2 transport) * @write_ptr: 1-st empty entry (index) host_w * @read_ptr: last used entry (index) host_r @@ -952,6 +782,8 @@ struct iwl_pcie_first_tb_buf { * @id: queue id * @low_mark: low watermark, resume queue if free space more than this * @high_mark: high watermark, stop queue if free space less than this + * @overflow_q: overflow queue for handling frames that didn't fit on HW queue + * @overflow_tx: need to transmit from overflow * * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame * descriptors) and required locking structures. @@ -976,6 +808,8 @@ struct iwl_txq { struct iwl_pcie_txq_entry *entries; /* lock for syncing changes on the queue */ spinlock_t lock; + /* lock to prevent concurrent reclaim */ + spinlock_t reclaim_lock; unsigned long frozen_expiry_remainder; struct timer_list stuck_timer; struct iwl_trans *trans; @@ -999,68 +833,36 @@ struct iwl_txq { }; /** - * struct iwl_trans_txqs - transport tx queues data - * - * @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes) - * @page_offs: offset from skb->cb to mac header page pointer - * @dev_cmd_offs: offset from skb->cb to iwl_device_tx_cmd pointer - * @queue_used - bit mask of used queues - * @queue_stopped - bit mask of stopped queues - * @scd_bc_tbls: gen1 pointer to the byte count table of the scheduler - * @queue_alloc_cmd_ver: queue allocation command version - */ -struct iwl_trans_txqs { - unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_TVQM_QUEUES)]; - unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_TVQM_QUEUES)]; - struct iwl_txq *txq[IWL_MAX_TVQM_QUEUES]; - struct dma_pool *bc_pool; - size_t bc_tbl_size; - bool bc_table_dword; - u8 page_offs; - u8 dev_cmd_offs; - struct iwl_tso_hdr_page __percpu *tso_hdr_page; - - struct { - u8 fifo; - u8 q_id; - unsigned int wdg_timeout; - } cmd; - - struct { - u8 max_tbs; - u16 size; - u8 addr_size; - } tfd; - - struct iwl_dma_ptr scd_bc_tbls; - - u8 queue_alloc_cmd_ver; -}; - -/** * struct iwl_trans - transport common data * - * @csme_own - true if we couldn't get ownership on the device - * @ops - pointer to iwl_trans_ops - * @op_mode - pointer to the op_mode + * @csme_own: true if we couldn't get ownership on the device + * @op_mode: pointer to the op_mode * @trans_cfg: the trans-specific configuration part - * @cfg - pointer to the configuration - * @drv - pointer to iwl_drv + * @cfg: pointer to the configuration + * @drv: pointer to iwl_drv + * @state: current device state * @status: a bit-mask of transport status flags - * @dev - pointer to struct device * that represents the device + * @dev: pointer to struct device * that represents the device * @max_skb_frags: maximum number of fragments an SKB can have when transmitted. * 0 indicates that frag SKBs (NETIF_F_SG) aren't supported. - * @hw_rf_id a u32 with the device RF ID - * @hw_crf_id a u32 with the device CRF ID - * @hw_wfpm_id a u32 with the device wfpm ID + * @hw_rf_id: a u32 with the device RF ID + * @hw_cnv_id: a u32 with the device CNV ID + * @hw_crf_id: a u32 with the device CRF ID + * @hw_wfpm_id: a u32 with the device wfpm ID * @hw_id: a u32 with the ID of the device / sub-device. * Set during transport allocation. * @hw_id_str: a string with info about HW ID. Set during transport allocation. + * @sku_id: the SKU identifier (for PNVM matching) + * @pnvm_loaded: indicates PNVM was loaded + * @hw_rev: the revision data of the HW * @hw_rev_step: The mac step of the HW * @pm_support: set to true in start_hw if link pm is supported * @ltr_enabled: set to true if the LTR is enabled * @fail_to_parse_pnvm_image: set to true if pnvm parsing failed + * @reduce_power_loaded: indicates reduced power section was loaded * @failed_to_load_reduce_power_image: set to true if pnvm loading failed + * @command_groups: pointer to command group name list array + * @command_groups_size: array size of @command_groups * @wide_cmd_header: true when ucode supports wide command header format * @wait_command_queue: wait queue for sync commands * @num_rx_queues: number of RX queues allocated by the transport; @@ -1069,23 +871,31 @@ struct iwl_trans_txqs { * @iml: a pointer to the image loader itself * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only. * The user should use iwl_trans_{alloc,free}_tx_cmd. + * @dev_cmd_pool_name: name for the TX command allocation pool + * @dbgfs_dir: iwlwifi debugfs base dir for this device + * @sync_cmd_lockdep_map: lockdep map for checking sync commands * @rx_mpdu_cmd: MPDU RX command ID, must be assigned by opmode before * starting the firmware, used for tracing * @rx_mpdu_cmd_hdr_size: used for tracing, amount of data before the * start of the 802.11 header in the @rx_mpdu_cmd - * @dflt_pwr_limit: default power limit fetched from the platform (ACPI) + * @dbg: additional debug data, see &struct iwl_trans_debug + * @init_dram: FW initialization DMA data * @system_pm_mode: the system-wide power management mode in use. * This mode is set dynamically, depending on the WoWLAN values * configured from the userspace at runtime. - * @iwl_trans_txqs: transport tx queues data. + * @name: the device name * @mbx_addr_0_step: step address data 0 * @mbx_addr_1_step: step address data 1 * @pcie_link_speed: current PCIe link speed (%PCI_EXP_LNKSTA_CLS_*), * only valid for discrete (not integrated) NICs + * @invalid_tx_cmd: invalid TX command buffer + * @reduced_cap_sku: reduced capability supported SKU + * @no_160: device not supporting 160 MHz + * @step_urm: STEP is in URM, no support for MCS>9 in 320 MHz + * @trans_specific: data for the specific transport this is allocated for/with */ struct iwl_trans { bool csme_own; - const struct iwl_trans_ops *ops; struct iwl_op_mode *op_mode; const struct iwl_cfg_trans_params *trans_cfg; const struct iwl_cfg *cfg; @@ -1104,6 +914,8 @@ struct iwl_trans { u32 hw_id; char hw_id_str[52]; u32 sku_id[3]; + bool reduced_cap_sku; + u8 no_160:1, step_urm:1; u8 rx_mpdu_cmd, rx_mpdu_cmd_hdr_size; @@ -1140,12 +952,13 @@ struct iwl_trans { enum iwl_plat_pm_mode system_pm_mode; const char *name; - struct iwl_trans_txqs txqs; u32 mbx_addr_0_step; u32 mbx_addr_1_step; u8 pcie_link_speed; + struct iwl_dma_ptr invalid_tx_cmd; + /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ char trans_specific[] __aligned(sizeof(void *)); @@ -1154,101 +967,29 @@ struct iwl_trans { const char *iwl_get_cmd_string(struct iwl_trans *trans, u32 id); int iwl_cmd_groups_verify_sorted(const struct iwl_trans_config *trans); -static inline void iwl_trans_configure(struct iwl_trans *trans, - const struct iwl_trans_config *trans_cfg) -{ - trans->op_mode = trans_cfg->op_mode; - - trans->ops->configure(trans, trans_cfg); - WARN_ON(iwl_cmd_groups_verify_sorted(trans_cfg)); -} - -static inline int iwl_trans_start_hw(struct iwl_trans *trans) -{ - might_sleep(); - - return trans->ops->start_hw(trans); -} - -static inline void iwl_trans_op_mode_leave(struct iwl_trans *trans) -{ - might_sleep(); - - if (trans->ops->op_mode_leave) - trans->ops->op_mode_leave(trans); - - trans->op_mode = NULL; - - trans->state = IWL_TRANS_NO_FW; -} - -static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr) -{ - might_sleep(); - - trans->state = IWL_TRANS_FW_ALIVE; - - trans->ops->fw_alive(trans, scd_addr); -} - -static inline int iwl_trans_start_fw(struct iwl_trans *trans, - const struct fw_img *fw, - bool run_in_rfkill) -{ - int ret; - - might_sleep(); - - WARN_ON_ONCE(!trans->rx_mpdu_cmd); - - clear_bit(STATUS_FW_ERROR, &trans->status); - ret = trans->ops->start_fw(trans, fw, run_in_rfkill); - if (ret == 0) - trans->state = IWL_TRANS_FW_STARTED; - - return ret; -} +void iwl_trans_configure(struct iwl_trans *trans, + const struct iwl_trans_config *trans_cfg); -static inline void iwl_trans_stop_device(struct iwl_trans *trans) -{ - might_sleep(); +int iwl_trans_start_hw(struct iwl_trans *trans); - trans->ops->stop_device(trans); +void iwl_trans_op_mode_leave(struct iwl_trans *trans); - trans->state = IWL_TRANS_NO_FW; -} +void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr); -static inline int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, - bool reset) -{ - might_sleep(); - if (!trans->ops->d3_suspend) - return -EOPNOTSUPP; +int iwl_trans_start_fw(struct iwl_trans *trans, const struct fw_img *fw, + bool run_in_rfkill); - return trans->ops->d3_suspend(trans, test, reset); -} +void iwl_trans_stop_device(struct iwl_trans *trans); -static inline int iwl_trans_d3_resume(struct iwl_trans *trans, - enum iwl_d3_status *status, - bool test, bool reset) -{ - might_sleep(); - if (!trans->ops->d3_resume) - return -EOPNOTSUPP; +int iwl_trans_d3_suspend(struct iwl_trans *trans, bool test, bool reset); - return trans->ops->d3_resume(trans, status, test, reset); -} +int iwl_trans_d3_resume(struct iwl_trans *trans, enum iwl_d3_status *status, + bool test, bool reset); -static inline struct iwl_trans_dump_data * +struct iwl_trans_dump_data * iwl_trans_dump_data(struct iwl_trans *trans, u32 dump_mask, const struct iwl_dump_sanitize_ops *sanitize_ops, - void *sanitize_ctx) -{ - if (!trans->ops->dump_data) - return NULL; - return trans->ops->dump_data(trans, dump_mask, - sanitize_ops, sanitize_ctx); -} + void *sanitize_ctx); static inline struct iwl_device_tx_cmd * iwl_trans_alloc_tx_cmd(struct iwl_trans *trans) @@ -1264,108 +1005,31 @@ static inline void iwl_trans_free_tx_cmd(struct iwl_trans *trans, kmem_cache_free(trans->dev_cmd_pool, dev_cmd); } -static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, - struct iwl_device_tx_cmd *dev_cmd, int queue) -{ - if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) - return -EIO; - - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return -EIO; - } - - return trans->ops->tx(trans, skb, dev_cmd, queue); -} - -static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue, - int ssn, struct sk_buff_head *skbs) -{ - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return; - } - - trans->ops->reclaim(trans, queue, ssn, skbs); -} - -static inline void iwl_trans_set_q_ptrs(struct iwl_trans *trans, int queue, - int ptr) -{ - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return; - } - - trans->ops->set_q_ptrs(trans, queue, ptr); -} - -static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, - bool configure_scd) -{ - trans->ops->txq_disable(trans, queue, configure_scd); -} - -static inline bool -iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, - const struct iwl_trans_txq_scd_cfg *cfg, - unsigned int queue_wdg_timeout) -{ - might_sleep(); - - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return false; - } - - return trans->ops->txq_enable(trans, queue, ssn, - cfg, queue_wdg_timeout); -} +int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb, + struct iwl_device_tx_cmd *dev_cmd, int queue); -static inline int -iwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue, - struct iwl_trans_rxq_dma_data *data) -{ - if (WARN_ON_ONCE(!trans->ops->rxq_dma_data)) - return -ENOTSUPP; +void iwl_trans_reclaim(struct iwl_trans *trans, int queue, int ssn, + struct sk_buff_head *skbs, bool is_flush); - return trans->ops->rxq_dma_data(trans, queue, data); -} - -static inline void -iwl_trans_txq_free(struct iwl_trans *trans, int queue) -{ - if (WARN_ON_ONCE(!trans->ops->txq_free)) - return; +void iwl_trans_set_q_ptrs(struct iwl_trans *trans, int queue, int ptr); - trans->ops->txq_free(trans, queue); -} +void iwl_trans_txq_disable(struct iwl_trans *trans, int queue, + bool configure_scd); -static inline int -iwl_trans_txq_alloc(struct iwl_trans *trans, - u32 flags, u32 sta_mask, u8 tid, - int size, unsigned int wdg_timeout) -{ - might_sleep(); +bool iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn, + const struct iwl_trans_txq_scd_cfg *cfg, + unsigned int queue_wdg_timeout); - if (WARN_ON_ONCE(!trans->ops->txq_alloc)) - return -ENOTSUPP; +int iwl_trans_get_rxq_dma_data(struct iwl_trans *trans, int queue, + struct iwl_trans_rxq_dma_data *data); - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return -EIO; - } +void iwl_trans_txq_free(struct iwl_trans *trans, int queue); - return trans->ops->txq_alloc(trans, flags, sta_mask, tid, - size, wdg_timeout); -} +int iwl_trans_txq_alloc(struct iwl_trans *trans, u32 flags, u32 sta_mask, + u8 tid, int size, unsigned int wdg_timeout); -static inline void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, - int queue, bool shared_mode) -{ - if (trans->ops->txq_set_shared_mode) - trans->ops->txq_set_shared_mode(trans, queue, shared_mode); -} +void iwl_trans_txq_set_shared_mode(struct iwl_trans *trans, + int txq_id, bool shared_mode); static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, int fifo, int sta_id, int tid, @@ -1398,90 +1062,32 @@ void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo, iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout); } -static inline void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, - unsigned long txqs, - bool freeze) -{ - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return; - } - - if (trans->ops->freeze_txq_timer) - trans->ops->freeze_txq_timer(trans, txqs, freeze); -} - -static inline void iwl_trans_block_txq_ptrs(struct iwl_trans *trans, - bool block) -{ - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return; - } - - if (trans->ops->block_txq_ptrs) - trans->ops->block_txq_ptrs(trans, block); -} - -static inline int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, - u32 txqs) -{ - if (WARN_ON_ONCE(!trans->ops->wait_tx_queues_empty)) - return -ENOTSUPP; +void iwl_trans_freeze_txq_timer(struct iwl_trans *trans, + unsigned long txqs, bool freeze); - /* No need to wait if the firmware is not alive */ - if (trans->state != IWL_TRANS_FW_ALIVE) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return -EIO; - } +int iwl_trans_wait_tx_queues_empty(struct iwl_trans *trans, u32 txqs); - return trans->ops->wait_tx_queues_empty(trans, txqs); -} - -static inline int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue) -{ - if (WARN_ON_ONCE(!trans->ops->wait_txq_empty)) - return -ENOTSUPP; +int iwl_trans_wait_txq_empty(struct iwl_trans *trans, int queue); - if (WARN_ON_ONCE(trans->state != IWL_TRANS_FW_ALIVE)) { - IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state); - return -EIO; - } +void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val); - return trans->ops->wait_txq_empty(trans, queue); -} +void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val); -static inline void iwl_trans_write8(struct iwl_trans *trans, u32 ofs, u8 val) -{ - trans->ops->write8(trans, ofs, val); -} +u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs); -static inline void iwl_trans_write32(struct iwl_trans *trans, u32 ofs, u32 val) -{ - trans->ops->write32(trans, ofs, val); -} +u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs); -static inline u32 iwl_trans_read32(struct iwl_trans *trans, u32 ofs) -{ - return trans->ops->read32(trans, ofs); -} +void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, u32 val); -static inline u32 iwl_trans_read_prph(struct iwl_trans *trans, u32 ofs) -{ - return trans->ops->read_prph(trans, ofs); -} +int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, + void *buf, int dwords); -static inline void iwl_trans_write_prph(struct iwl_trans *trans, u32 ofs, - u32 val) -{ - return trans->ops->write_prph(trans, ofs, val); -} +int iwl_trans_read_config32(struct iwl_trans *trans, u32 ofs, + u32 *val); -static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, - void *buf, int dwords) -{ - return trans->ops->read_mem(trans, addr, buf, dwords); -} +#ifdef CONFIG_IWLWIFI_DEBUGFS +void iwl_trans_debugfs_cleanup(struct iwl_trans *trans); +#endif #define iwl_trans_read_mem_bytes(trans, addr, buf, bufsize) \ do { \ @@ -1490,30 +1096,21 @@ static inline int iwl_trans_read_mem(struct iwl_trans *trans, u32 addr, iwl_trans_read_mem(trans, addr, buf, (bufsize) / sizeof(u32));\ } while (0) -static inline int iwl_trans_write_imr_mem(struct iwl_trans *trans, - u32 dst_addr, u64 src_addr, - u32 byte_cnt) -{ - if (trans->ops->imr_dma_data) - return trans->ops->imr_dma_data(trans, dst_addr, src_addr, byte_cnt); - return 0; -} +int iwl_trans_write_imr_mem(struct iwl_trans *trans, u32 dst_addr, + u64 src_addr, u32 byte_cnt); static inline u32 iwl_trans_read_mem32(struct iwl_trans *trans, u32 addr) { u32 value; - if (WARN_ON(iwl_trans_read_mem(trans, addr, &value, 1))) + if (iwl_trans_read_mem(trans, addr, &value, 1)) return 0xa5a5a5a5; return value; } -static inline int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, - const void *buf, int dwords) -{ - return trans->ops->write_mem(trans, addr, buf, dwords); -} +int iwl_trans_write_mem(struct iwl_trans *trans, u32 addr, + const void *buf, int dwords); static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr, u32 val) @@ -1521,36 +1118,21 @@ static inline u32 iwl_trans_write_mem32(struct iwl_trans *trans, u32 addr, return iwl_trans_write_mem(trans, addr, &val, 1); } -static inline void iwl_trans_set_pmi(struct iwl_trans *trans, bool state) -{ - if (trans->ops->set_pmi) - trans->ops->set_pmi(trans, state); -} +void iwl_trans_set_pmi(struct iwl_trans *trans, bool state); -static inline int iwl_trans_sw_reset(struct iwl_trans *trans, - bool retake_ownership) -{ - if (trans->ops->sw_reset) - return trans->ops->sw_reset(trans, retake_ownership); - return 0; -} +int iwl_trans_sw_reset(struct iwl_trans *trans, bool retake_ownership); -static inline void -iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value) -{ - trans->ops->set_bits_mask(trans, reg, mask, value); -} +void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, + u32 mask, u32 value); + +bool _iwl_trans_grab_nic_access(struct iwl_trans *trans); #define iwl_trans_grab_nic_access(trans) \ __cond_lock(nic_access, \ - likely((trans)->ops->grab_nic_access(trans))) + likely(_iwl_trans_grab_nic_access(trans))) -static inline void __releases(nic_access) -iwl_trans_release_nic_access(struct iwl_trans *trans) -{ - trans->ops->release_nic_access(trans); - __release(nic_access); -} +void __releases(nic_access) +iwl_trans_release_nic_access(struct iwl_trans *trans); static inline void iwl_trans_fw_error(struct iwl_trans *trans, bool sync) { @@ -1559,8 +1141,8 @@ static inline void iwl_trans_fw_error(struct iwl_trans *trans, bool sync) /* prevent double restarts due to the same erroneous FW */ if (!test_and_set_bit(STATUS_FW_ERROR, &trans->status)) { - iwl_op_mode_nic_error(trans->op_mode, sync); trans->state = IWL_TRANS_NO_FW; + iwl_op_mode_nic_error(trans->op_mode, sync); } } @@ -1569,44 +1151,24 @@ static inline bool iwl_trans_fw_running(struct iwl_trans *trans) return trans->state == IWL_TRANS_FW_ALIVE; } -static inline void iwl_trans_sync_nmi(struct iwl_trans *trans) -{ - if (trans->ops->sync_nmi) - trans->ops->sync_nmi(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); -static inline int iwl_trans_load_pnvm(struct iwl_trans *trans, - const struct iwl_pnvm_image *pnvm_data, - const struct iwl_ucode_capabilities *capa) -{ - return trans->ops->load_pnvm(trans, pnvm_data, capa); -} +int iwl_trans_load_pnvm(struct iwl_trans *trans, + const struct iwl_pnvm_image *pnvm_data, + const struct iwl_ucode_capabilities *capa); -static inline void iwl_trans_set_pnvm(struct iwl_trans *trans, - const struct iwl_ucode_capabilities *capa) -{ - if (trans->ops->set_pnvm) - trans->ops->set_pnvm(trans, capa); -} +void iwl_trans_set_pnvm(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa); -static inline int iwl_trans_load_reduce_power - (struct iwl_trans *trans, - const struct iwl_pnvm_image *payloads, - const struct iwl_ucode_capabilities *capa) -{ - return trans->ops->load_reduce_power(trans, payloads, capa); -} +int iwl_trans_load_reduce_power(struct iwl_trans *trans, + const struct iwl_pnvm_image *payloads, + const struct iwl_ucode_capabilities *capa); -static inline void -iwl_trans_set_reduce_power(struct iwl_trans *trans, - const struct iwl_ucode_capabilities *capa) -{ - if (trans->ops->set_reduce_power) - trans->ops->set_reduce_power(trans, capa); -} +void iwl_trans_set_reduce_power(struct iwl_trans *trans, + const struct iwl_ucode_capabilities *capa); static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans) { @@ -1614,18 +1176,13 @@ static inline bool iwl_trans_dbg_ini_valid(struct iwl_trans *trans) trans->dbg.external_ini_cfg != IWL_INI_CFG_STATE_NOT_LOADED; } -static inline void iwl_trans_interrupts(struct iwl_trans *trans, bool enable) -{ - if (trans->ops->interrupts) - trans->ops->interrupts(trans, enable); -} +void iwl_trans_interrupts(struct iwl_trans *trans, bool enable); /***************************************************** * transport helper functions *****************************************************/ struct iwl_trans *iwl_trans_alloc(unsigned int priv_size, struct device *dev, - const struct iwl_trans_ops *ops, const struct iwl_cfg_trans_params *cfg_trans); int iwl_trans_init(struct iwl_trans *trans); void iwl_trans_free(struct iwl_trans *trans); @@ -1636,10 +1193,13 @@ static inline bool iwl_trans_is_hw_error_value(u32 val) } /***************************************************** -* driver (transport) register/unregister functions -******************************************************/ + * PCIe handling + *****************************************************/ int __must_check iwl_pci_register_driver(void); void iwl_pci_unregister_driver(void); void iwl_trans_pcie_remove(struct iwl_trans *trans, bool rescan); +int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, + struct iwl_host_cmd *cmd); + #endif /* __iwl_trans_h__ */ diff --git a/sys/contrib/dev/iwlwifi/mei/iwl-mei.h b/sys/contrib/dev/iwlwifi/mei/iwl-mei.h index aec85c42d02a..ad60ce0acd86 100644 --- a/sys/contrib/dev/iwlwifi/mei/iwl-mei.h +++ b/sys/contrib/dev/iwlwifi/mei/iwl-mei.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2022 The FreeBSD Foundation + * Copyright (c) 2022-2024 The FreeBSD Foundation * * This software was developed by Björn Zeeb under sponsorship from * the FreeBSD Foundation. @@ -154,6 +154,11 @@ iwl_mei_pldr_req(void) { return (false); } + +static __inline void +iwl_mei_set_power_limit(__le16 *x __unused) +{ +} #endif #endif /* _IWL_MEI_IWL_MEI_H */ diff --git a/sys/contrib/dev/iwlwifi/mvm/coex.c b/sys/contrib/dev/iwlwifi/mvm/coex.c index 5a5b1128e75c..ad3e14a0d043 100644 --- a/sys/contrib/dev/iwlwifi/mvm/coex.c +++ b/sys/contrib/dev/iwlwifi/mvm/coex.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2013-2014, 2018-2020, 2022 Intel Corporation + * Copyright (C) 2013-2014, 2018-2020, 2022-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH */ #include <linux/ieee80211.h> @@ -116,11 +116,6 @@ iwl_get_coex_type(struct iwl_mvm *mvm, const struct ieee80211_vif *vif) ret = BT_COEX_TX_DIS_LUT; - if (mvm->cfg->bt_shared_single_ant) { - rcu_read_unlock(); - return ret; - } - phy_ctx_id = *((u16 *)chanctx_conf->drv_priv); primary_ch_phy_id = le32_to_cpu(mvm->last_bt_ci_cmd.primary_ch_phy_id); secondary_ch_phy_id = @@ -186,6 +181,9 @@ static int iwl_mvm_bt_coex_reduced_txp(struct iwl_mvm *mvm, u8 sta_id, struct iwl_mvm_sta *mvmsta; u32 value; + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) + return 0; + mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); if (!mvmsta) return 0; @@ -221,15 +219,13 @@ struct iwl_bt_iterator_data { static inline void iwl_mvm_bt_coex_enable_rssi_event(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, + struct iwl_mvm_vif_link_info *link_info, bool enable, int rssi) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - - mvmvif->bf_data.last_bt_coex_event = rssi; - mvmvif->bf_data.bt_coex_max_thold = + link_info->bf_data.last_bt_coex_event = rssi; + link_info->bf_data.bt_coex_max_thold = enable ? -IWL_MVM_BT_COEX_EN_RED_TXP_THRESH : 0; - mvmvif->bf_data.bt_coex_min_thold = + link_info->bf_data.bt_coex_min_thold = enable ? -IWL_MVM_BT_COEX_DIS_RED_TXP_THRESH : 0; } @@ -257,6 +253,77 @@ static void iwl_mvm_bt_coex_tcm_based_ci(struct iwl_mvm *mvm, swap(data->primary, data->secondary); } +/* + * This function receives the LB link id and checks if eSR should be + * enabled or disabled (due to BT coex) + */ +bool +iwl_mvm_bt_coex_calculate_esr_mode(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + s32 link_rssi, + bool primary) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + bool have_wifi_loss_rate = + iwl_fw_lookup_notif_ver(mvm->fw, LEGACY_GROUP, + BT_PROFILE_NOTIFICATION, 0) > 4; + u8 wifi_loss_rate; + + if (mvm->last_bt_notif.wifi_loss_low_rssi == BT_OFF) + return true; + + if (primary) + return false; + + /* The feature is not supported */ + if (!have_wifi_loss_rate) + return true; + + + /* + * In case we don't know the RSSI - take the lower wifi loss, + * so we will more likely enter eSR, and if RSSI is low - + * we will get an update on this and exit eSR. + */ + if (!link_rssi) + wifi_loss_rate = mvm->last_bt_notif.wifi_loss_mid_high_rssi; + + else if (mvmvif->esr_active) + /* RSSI needs to get really low to disable eSR... */ + wifi_loss_rate = + link_rssi <= -IWL_MVM_BT_COEX_DISABLE_ESR_THRESH ? + mvm->last_bt_notif.wifi_loss_low_rssi : + mvm->last_bt_notif.wifi_loss_mid_high_rssi; + else + /* ...And really high before we enable it back */ + wifi_loss_rate = + link_rssi <= -IWL_MVM_BT_COEX_ENABLE_ESR_THRESH ? + mvm->last_bt_notif.wifi_loss_low_rssi : + mvm->last_bt_notif.wifi_loss_mid_high_rssi; + + return wifi_loss_rate <= IWL_MVM_BT_COEX_WIFI_LOSS_THRESH; +} + +void iwl_mvm_bt_coex_update_link_esr(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + int link_id) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *link = mvmvif->link[link_id]; + + if (!ieee80211_vif_is_mld(vif) || + !iwl_mvm_vif_from_mac80211(vif)->authorized || + WARN_ON(!link)) + return; + + if (!iwl_mvm_bt_coex_calculate_esr_mode(mvm, vif, + (s8)link->beacon_stats.avg_signal, + link_id == iwl_mvm_get_primary_link(vif))) + /* In case we decided to exit eSR - stay with the primary */ + iwl_mvm_exit_esr(mvm, vif, IWL_MVM_ESR_EXIT_COEX, + iwl_mvm_get_primary_link(vif)); +} + static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_bt_iterator_data *data, @@ -296,12 +363,14 @@ static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, smps_mode, link_id); iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id, false); - /* FIXME: should this be per link? */ - iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); + iwl_mvm_bt_coex_enable_rssi_event(mvm, link_info, false, + 0); } return; } + iwl_mvm_bt_coex_update_link_esr(mvm, vif, link_id); + if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_COEX_SCHEMA_2)) min_ag_for_static_smps = BT_VERY_HIGH_TRAFFIC; else @@ -383,21 +452,19 @@ static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, /* * don't reduce the Tx power if one of these is true: * we are in LOOSE - * single share antenna product * BT is inactive * we are not associated */ if (iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT || - mvm->cfg->bt_shared_single_ant || !vif->cfg.assoc || - le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF) { + le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) == BT_OFF || + !vif->cfg.assoc) { iwl_mvm_bt_coex_reduced_txp(mvm, link_info->ap_sta_id, false); - /* FIXME: should this be per link? */ - iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, false, 0); + iwl_mvm_bt_coex_enable_rssi_event(mvm, link_info, false, 0); return; } /* try to get the avg rssi from fw */ - ave_rssi = mvmvif->bf_data.ave_beacon_signal; + ave_rssi = link_info->bf_data.ave_beacon_signal; /* if the RSSI isn't valid, fake it is very low */ if (!ave_rssi) @@ -413,7 +480,7 @@ static void iwl_mvm_bt_notif_per_link(struct iwl_mvm *mvm, } /* Begin to monitor the RSSI: it may influence the reduced Tx power */ - iwl_mvm_bt_coex_enable_rssi_event(mvm, vif, true, ave_rssi); + iwl_mvm_bt_coex_enable_rssi_event(mvm, link_info, true, ave_rssi); } /* must be called under rcu_read_lock */ @@ -460,6 +527,11 @@ static void iwl_mvm_bt_coex_notif_handle(struct iwl_mvm *mvm) mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_bt_notif_iterator, &data); + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_AX210) { + rcu_read_unlock(); + return; + } + iwl_mvm_bt_coex_tcm_based_ci(mvm, &data); if (data.primary) { @@ -570,7 +642,7 @@ void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * Check if rssi is good enough for reduced Tx power, but not in loose * scheme. */ - if (rssi_event == RSSI_EVENT_LOW || mvm->cfg->bt_shared_single_ant || + if (rssi_event == RSSI_EVENT_LOW || iwl_get_coex_type(mvm, vif) == BT_COEX_LOOSE_LUT) ret = iwl_mvm_bt_coex_reduced_txp(mvm, mvmvif->deflink.ap_sta_id, @@ -639,10 +711,6 @@ bool iwl_mvm_bt_coex_is_mimo_allowed(struct iwl_mvm *mvm, bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant) { - /* there is no other antenna, shared antenna is always available */ - if (mvm->cfg->bt_shared_single_ant) - return true; - if (ant & mvm->cfg->non_shared_ant) return true; @@ -652,10 +720,6 @@ bool iwl_mvm_bt_coex_is_ant_avail(struct iwl_mvm *mvm, u8 ant) bool iwl_mvm_bt_coex_is_shared_ant_avail(struct iwl_mvm *mvm) { - /* there is no other antenna, shared antenna is always available */ - if (mvm->cfg->bt_shared_single_ant) - return true; - return le32_to_cpu(mvm->last_bt_notif.bt_activity_grading) < BT_HIGH_TRAFFIC; } diff --git a/sys/contrib/dev/iwlwifi/mvm/constants.h b/sys/contrib/dev/iwlwifi/mvm/constants.h index 243eccc68cb0..c4c1e67b9ac7 100644 --- a/sys/contrib/dev/iwlwifi/mvm/constants.h +++ b/sys/contrib/dev/iwlwifi/mvm/constants.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* * Copyright (C) 2013-2015 Intel Mobile Communications GmbH - * Copyright (C) 2013-2014, 2018-2023 Intel Corporation + * Copyright (C) 2013-2014, 2018-2024 Intel Corporation * Copyright (C) 2015 Intel Deutschland GmbH */ #ifndef __MVM_CONSTANTS_H @@ -11,6 +11,11 @@ #include "fw-api.h" #define IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM 20 +#define IWL_MVM_BT_COEX_DISABLE_ESR_THRESH 69 +#define IWL_MVM_BT_COEX_ENABLE_ESR_THRESH 63 +#define IWL_MVM_BT_COEX_WIFI_LOSS_THRESH 0 +#define IWL_MVM_TRIGGER_LINK_SEL_TIME_SEC 30 +#define IWL_MVM_TPT_COUNT_WINDOW_SEC 5 #define IWL_MVM_DEFAULT_PS_TX_DATA_TIMEOUT (100 * USEC_PER_MSEC) #define IWL_MVM_DEFAULT_PS_RX_DATA_TIMEOUT (100 * USEC_PER_MSEC) @@ -18,7 +23,7 @@ #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT (10 * USEC_PER_MSEC) #define IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT (2 * 1024) /* defined in TU */ #define IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT (40 * 1024) /* defined in TU */ -#define IWL_MVM_P2P_LOWLATENCY_PS_ENABLE 0 +#define IWL_MVM_P2P_LOWLATENCY_PS_ENABLE 1 #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT (50 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT (50 * USEC_PER_MSEC) #define IWL_MVM_UAPSD_QUEUES (IEEE80211_WMM_IE_STA_QOSINFO_AC_VO |\ @@ -51,7 +56,6 @@ #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK 1 #define IWL_MVM_TOF_IS_RESPONDER 0 #define IWL_MVM_HW_CSUM_DISABLE 0 -#define IWL_MVM_PARSE_NVM 0 #define IWL_MVM_ADWELL_ENABLE 1 #define IWL_MVM_ADWELL_MAX_BUDGET 0 #define IWL_MVM_TCM_LOAD_MEDIUM_THRESH 10 /* percentage */ @@ -60,6 +64,7 @@ #define IWL_MVM_UAPSD_NONAGG_PERIOD 5000 /* msecs */ #define IWL_MVM_UAPSD_NOAGG_LIST_LEN IWL_MVM_UAPSD_NOAGG_BSSIDS_NUM #define IWL_MVM_NON_TRANSMITTING_AP 0 +#define IWL_MVM_CONN_LISTEN_INTERVAL 10 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1 @@ -94,6 +99,7 @@ #define IWL_MVM_FTM_INITIATOR_ALGO IWL_TOF_ALGO_TYPE_MAX_LIKE #define IWL_MVM_FTM_INITIATOR_DYNACK true #define IWL_MVM_FTM_LMR_FEEDBACK_TERMINATE false +#define IWL_MVM_FTM_TEST_INCORRECT_SAC false #define IWL_MVM_FTM_R2I_MAX_REP 7 #define IWL_MVM_FTM_I2R_MAX_REP 7 #define IWL_MVM_FTM_R2I_MAX_STS 1 @@ -108,7 +114,6 @@ #define IWL_MVM_D3_DEBUG false #define IWL_MVM_USE_TWT true #define IWL_MVM_AMPDU_CONSEC_DROPS_DELBA 20 -#define IWL_MVM_USE_NSSN_SYNC 0 #define IWL_MVM_FTM_INITIATOR_ENABLE_SMOOTH false #define IWL_MVM_FTM_INITIATOR_SMOOTH_ALPHA 40 /* 20016 pSec is 6 meter RTT, meaning 3 meter range */ @@ -118,5 +123,18 @@ #define IWL_MVM_DISABLE_AP_FILS false #define IWL_MVM_6GHZ_PASSIVE_SCAN_TIMEOUT 3000 /* in seconds */ #define IWL_MVM_6GHZ_PASSIVE_SCAN_ASSOC_TIMEOUT 60 /* in seconds */ +#define IWL_MVM_MIN_BEACON_INTERVAL_TU 16 +#define IWL_MVM_AUTO_EML_ENABLE true +#define IWL_MVM_MISSED_BEACONS_EXIT_ESR_THRESH 7 +#define IWL_MVM_HIGH_RSSI_THRESH_20MHZ -67 +#define IWL_MVM_LOW_RSSI_THRESH_20MHZ -71 +#define IWL_MVM_HIGH_RSSI_THRESH_40MHZ -64 +#define IWL_MVM_LOW_RSSI_THRESH_40MHZ -67 +#define IWL_MVM_HIGH_RSSI_THRESH_80MHZ -61 +#define IWL_MVM_LOW_RSSI_THRESH_80MHZ -74 +#define IWL_MVM_HIGH_RSSI_THRESH_160MHZ -58 +#define IWL_MVM_LOW_RSSI_THRESH_160MHZ -61 + +#define IWL_MVM_ENTER_ESR_TPT_THRESH 400 #endif /* __MVM_CONSTANTS_H */ diff --git a/sys/contrib/dev/iwlwifi/mvm/d3.c b/sys/contrib/dev/iwlwifi/mvm/d3.c index 17d74a771d13..0fbafd5f0dbb 100644 --- a/sys/contrib/dev/iwlwifi/mvm/d3.c +++ b/sys/contrib/dev/iwlwifi/mvm/d3.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -453,9 +453,9 @@ static void iwl_mvm_wowlan_get_rsc_v5_data(struct ieee80211_hw *hw, } static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct iwl_mvm_vif_link_info *mvm_link) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ver = iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_TSC_RSC_PARAM, IWL_FW_CMD_VER_UNKNOWN); int ret; @@ -464,16 +464,14 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, struct wowlan_key_rsc_v5_data data = {}; int i; - data.rsc = kmalloc(sizeof(*data.rsc), GFP_KERNEL); + data.rsc = kzalloc(sizeof(*data.rsc), GFP_KERNEL); if (!data.rsc) return -ENOMEM; - memset(data.rsc, 0xff, sizeof(*data.rsc)); - for (i = 0; i < ARRAY_SIZE(data.rsc->mcast_key_id_map); i++) data.rsc->mcast_key_id_map[i] = IWL_MCAST_KEY_MAP_INVALID; - data.rsc->sta_id = cpu_to_le32(mvmvif->deflink.ap_sta_id); + data.rsc->sta_id = cpu_to_le32(mvm_link->ap_sta_id); ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_wowlan_get_rsc_v5_data, @@ -497,7 +495,7 @@ static int iwl_mvm_wowlan_config_rsc_tsc(struct iwl_mvm *mvm, if (ver == 4) { size = sizeof(*data.rsc_tsc); data.rsc_tsc->sta_id = - cpu_to_le32(mvmvif->deflink.ap_sta_id); + cpu_to_le32(mvm_link->ap_sta_id); } else { /* ver == 2 || ver == IWL_FW_CMD_VER_UNKNOWN */ size = sizeof(data.rsc_tsc->params); @@ -600,6 +598,12 @@ static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw, void *_data) { struct wowlan_key_gtk_type_iter *data = _data; + __le32 *cipher = NULL; + + if (key->keyidx == 4 || key->keyidx == 5) + cipher = &data->kek_kck_cmd->igtk_cipher; + if (key->keyidx == 6 || key->keyidx == 7) + cipher = &data->kek_kck_cmd->bigtk_cipher; switch (key->cipher) { default: @@ -611,10 +615,13 @@ static void iwl_mvm_wowlan_gtk_type_iter(struct ieee80211_hw *hw, return; case WLAN_CIPHER_SUITE_BIP_GMAC_256: case WLAN_CIPHER_SUITE_BIP_GMAC_128: - data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_GCMP); + if (cipher) + *cipher = cpu_to_le32(STA_KEY_FLG_GCMP); return; case WLAN_CIPHER_SUITE_AES_CMAC: - data->kek_kck_cmd->igtk_cipher = cpu_to_le32(STA_KEY_FLG_CCM); + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + if (cipher) + *cipher = cpu_to_le32(STA_KEY_FLG_CCM); return; case WLAN_CIPHER_SUITE_CCMP: if (!sta) @@ -671,10 +678,9 @@ static int iwl_mvm_send_patterns_v1(struct iwl_mvm *mvm, } static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, - struct ieee80211_vif *vif, + struct iwl_mvm_vif_link_info *mvm_link, struct cfg80211_wowlan *wowlan) { - struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_wowlan_patterns_cmd *pattern_cmd; struct iwl_host_cmd cmd = { .id = WOWLAN_PATTERNS, @@ -696,7 +702,7 @@ static int iwl_mvm_send_patterns(struct iwl_mvm *mvm, pattern_cmd->n_patterns = wowlan->n_patterns; if (ver >= 3) - pattern_cmd->sta_id = mvmvif->deflink.ap_sta_id; + pattern_cmd->sta_id = mvm_link->ap_sta_id; for (i = 0; i < wowlan->n_patterns; i++) { int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); @@ -726,14 +732,15 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_chanctx_conf *ctx; u8 chains_static, chains_dynamic; - struct cfg80211_chan_def chandef; + struct cfg80211_chan_def chandef, ap_def; int ret, i; struct iwl_binding_cmd_v1 binding_cmd = {}; struct iwl_time_quota_cmd quota_cmd = {}; struct iwl_time_quota_data *quota; u32 status; - if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm))) + if (WARN_ON_ONCE(iwl_mvm_is_cdb_supported(mvm) || + ieee80211_vif_is_mld(vif))) return -EINVAL; /* add back the PHY */ @@ -747,12 +754,13 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return -EINVAL; } chandef = ctx->def; + ap_def = ctx->ap; chains_static = ctx->rx_chains_static; chains_dynamic = ctx->rx_chains_dynamic; rcu_read_unlock(); ret = iwl_mvm_phy_ctxt_add(mvm, mvmvif->deflink.phy_ctxt, &chandef, - chains_static, chains_dynamic); + &ap_def, chains_static, chains_dynamic); if (ret) return ret; @@ -821,7 +829,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (ret) IWL_ERR(mvm, "Failed to send quota: %d\n", ret); - if (iwl_mvm_is_lar_supported(mvm) && iwl_mvm_init_fw_regd(mvm)) + if (iwl_mvm_is_lar_supported(mvm) && iwl_mvm_init_fw_regd(mvm, false)) IWL_ERR(mvm, "Failed to initialize D3 LAR information\n"); return 0; @@ -930,6 +938,9 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, wowlan_config_cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING; + if (ap_sta->mfp) + wowlan_config_cmd->flags |= IS_11W_ASSOC; + if (iwl_fw_lookup_cmd_ver(mvm->fw, WOWLAN_CONFIGURATION, 0) < 6) { /* Query the last used seqno and set it */ int ret = iwl_mvm_get_last_nonqos_seq(mvm, vif); @@ -990,7 +1001,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm, } static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, - struct ieee80211_vif *vif) + struct ieee80211_vif *vif, + struct iwl_mvm_vif_link_info *mvm_link) { bool unified = fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); @@ -1019,7 +1031,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, return -EIO; } - ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif); + ret = iwl_mvm_wowlan_config_rsc_tsc(mvm, vif, mvm_link); if (ret) return ret; @@ -1033,7 +1045,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, if (ver == 2) { size = sizeof(tkip_data.tkip); tkip_data.tkip.sta_id = - cpu_to_le32(mvmvif->deflink.ap_sta_id); + cpu_to_le32(mvm_link->ap_sta_id); } else if (ver == 1 || ver == IWL_FW_CMD_VER_UNKNOWN) { size = sizeof(struct iwl_wowlan_tkip_params_cmd_ver_1); } else { @@ -1082,7 +1094,7 @@ static int iwl_mvm_wowlan_config_key_params(struct iwl_mvm *mvm, kek_kck_cmd.kek_len = cpu_to_le16(mvmvif->rekey_data.kek_len); kek_kck_cmd.replay_ctr = mvmvif->rekey_data.replay_ctr; kek_kck_cmd.akm = cpu_to_le32(mvmvif->rekey_data.akm); - kek_kck_cmd.sta_id = cpu_to_le32(mvmvif->deflink.ap_sta_id); + kek_kck_cmd.sta_id = cpu_to_le32(mvm_link->ap_sta_id); if (cmd_ver == 4) { cmd_size = sizeof(struct iwl_wowlan_kek_kck_material_cmd_v4); @@ -1115,6 +1127,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, struct cfg80211_wowlan *wowlan, struct iwl_wowlan_config_cmd *wowlan_config_cmd, struct ieee80211_vif *vif, struct iwl_mvm_vif *mvmvif, + struct iwl_mvm_vif_link_info *mvm_link, struct ieee80211_sta *ap_sta) { int ret; @@ -1133,14 +1146,7 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, return ret; } - /* - * This needs to be unlocked due to lock ordering - * constraints. Since we're in the suspend path - * that isn't really a problem though. - */ - mutex_unlock(&mvm->mutex); - ret = iwl_mvm_wowlan_config_key_params(mvm, vif); - mutex_lock(&mvm->mutex); + ret = iwl_mvm_wowlan_config_key_params(mvm, vif, mvm_link); if (ret) return ret; @@ -1152,13 +1158,14 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, if (fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WOWLAN_TCP_SYN_WAKE)) - ret = iwl_mvm_send_patterns(mvm, vif, wowlan); + ret = iwl_mvm_send_patterns(mvm, mvm_link, wowlan); else ret = iwl_mvm_send_patterns_v1(mvm, wowlan); if (ret) return ret; - return iwl_mvm_send_proto_offload(mvm, vif, false, true, 0); + return iwl_mvm_send_proto_offload(mvm, vif, false, true, 0, + mvm_link->ap_sta_id); } static int @@ -1233,6 +1240,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, struct ieee80211_vif *vif = NULL; struct iwl_mvm_vif *mvmvif = NULL; struct ieee80211_sta *ap_sta = NULL; + struct iwl_mvm_vif_link_info *mvm_link; struct iwl_d3_manager_config d3_cfg_cmd_data = { /* * Program the minimum sleep time to 10 seconds, as many @@ -1261,21 +1269,29 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, return -EINVAL; } + vif = iwl_mvm_get_bss_vif(mvm); + if (IS_ERR_OR_NULL(vif)) + return 1; + + ret = iwl_mvm_block_esr_sync(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN); + if (ret) + return ret; + mutex_lock(&mvm->mutex); set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); synchronize_net(); - vif = iwl_mvm_get_bss_vif(mvm); - if (IS_ERR_OR_NULL(vif)) { - ret = 1; + mvmvif = iwl_mvm_vif_from_mac80211(vif); + + mvm_link = mvmvif->link[iwl_mvm_get_primary_link(vif)]; + if (WARN_ON_ONCE(!mvm_link)) { + ret = -EINVAL; goto out_noreset; } - mvmvif = iwl_mvm_vif_from_mac80211(vif); - - if (mvmvif->deflink.ap_sta_id == IWL_MVM_INVALID_STA) { + if (mvm_link->ap_sta_id == IWL_MVM_INVALID_STA) { /* if we're not associated, this must be netdetect */ if (!wowlan->nd_config) { ret = 1; @@ -1289,24 +1305,31 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, mvm->net_detect = true; } else { - struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; + struct iwl_wowlan_config_cmd wowlan_config_cmd = { + .offloading_tid = 0, + }; - wowlan_config_cmd.sta_id = mvmvif->deflink.ap_sta_id; + wowlan_config_cmd.sta_id = mvm_link->ap_sta_id; ap_sta = rcu_dereference_protected( - mvm->fw_id_to_mac_id[mvmvif->deflink.ap_sta_id], + mvm->fw_id_to_mac_id[mvm_link->ap_sta_id], lockdep_is_held(&mvm->mutex)); if (IS_ERR_OR_NULL(ap_sta)) { ret = -EINVAL; goto out_noreset; } + ret = iwl_mvm_sta_ensure_queue( + mvm, ap_sta->txq[wowlan_config_cmd.offloading_tid]); + if (ret) + goto out_noreset; + ret = iwl_mvm_get_wowlan_config(mvm, wowlan, &wowlan_config_cmd, vif, mvmvif, ap_sta); if (ret) goto out_noreset; ret = iwl_mvm_wowlan_config(mvm, wowlan, &wowlan_config_cmd, - vif, mvmvif, ap_sta); + vif, mvmvif, mvm_link, ap_sta); if (ret) goto out; @@ -1441,6 +1464,10 @@ struct iwl_wowlan_status_data { } ptk; struct iwl_multicast_key_data igtk; + struct iwl_multicast_key_data bigtk[WOWLAN_BIGTK_KEYS_NUM]; + + int num_mlo_keys; + struct iwl_wowlan_mlo_gtk mlo_keys[WOWLAN_MAX_MLO_KEYS]; u8 *wake_packet; }; @@ -1471,7 +1498,8 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, status->pattern_number; if (reasons & (IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | - IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH)) + IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH | + IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE)) wakeup.disconnect = true; if (reasons & IWL_WOWLAN_WAKEUP_BY_GTK_REKEY_FAILURE) @@ -1495,6 +1523,9 @@ static void iwl_mvm_report_wakeup_reasons(struct iwl_mvm *mvm, if (reasons & IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET) wakeup.tcp_match = true; + if (reasons & IWL_WAKEUP_BY_11W_UNPROTECTED_DEAUTH_OR_DISASSOC) + wakeup.unprot_deauth_disassoc = true; + if (status->wake_packet) { int pktsize = status->wake_packet_bufsize; int pktlen = status->wake_packet_length; @@ -1784,8 +1815,8 @@ static void iwl_mvm_set_key_rx_seq(struct ieee80211_key_conf *key, struct iwl_mvm_d3_gtk_iter_data { struct iwl_mvm *mvm; struct iwl_wowlan_status_data *status; - u32 gtk_cipher, igtk_cipher; - bool unhandled_cipher, igtk_support; + u32 gtk_cipher, igtk_cipher, bigtk_cipher; + bool unhandled_cipher, igtk_support, bigtk_support; int num_keys; }; @@ -1796,6 +1827,10 @@ static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, void *_data) { struct iwl_mvm_d3_gtk_iter_data *data = _data; + int link_id = vif->active_links ? __ffs(vif->active_links) : -1; + + if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id) + return; if (data->unhandled_cipher) return; @@ -1820,6 +1855,9 @@ static void iwl_mvm_d3_find_last_keys(struct ieee80211_hw *hw, if (data->igtk_support && (key->keyidx == 4 || key->keyidx == 5)) { data->igtk_cipher = key->cipher; + } else if (data->bigtk_support && + (key->keyidx == 6 || key->keyidx == 7)) { + data->bigtk_cipher = key->cipher; } else { data->unhandled_cipher = true; return; @@ -1845,9 +1883,30 @@ iwl_mvm_d3_set_igtk_bigtk_ipn(const struct iwl_multicast_key_data *key, memcpy(seq->aes_gmac.pn, key->ipn, sizeof(seq->aes_gmac.pn)); break; case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_AES_CMAC: BUILD_BUG_ON(sizeof(seq->aes_cmac.pn) != sizeof(key->ipn)); memcpy(seq->aes_cmac.pn, key->ipn, sizeof(seq->aes_cmac.pn)); break; + default: + WARN_ON(1); + } +} + +static void +iwl_mvm_d3_update_igtk_bigtk(struct iwl_wowlan_status_data *status, + struct ieee80211_key_conf *key, + struct iwl_multicast_key_data *key_data) +{ + if (status->num_of_gtk_rekeys && key_data->len) { + /* remove rekeyed key */ + ieee80211_remove_key(key); + } else { + struct ieee80211_key_seq seq; + + iwl_mvm_d3_set_igtk_bigtk_ipn(key_data, + &seq, + key->cipher); + ieee80211_set_key_rx_seq(key, 0, &seq); } } @@ -1860,6 +1919,10 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, struct iwl_mvm_d3_gtk_iter_data *data = _data; struct iwl_wowlan_status_data *status = data->status; s8 keyidx; + int link_id = vif->active_links ? __ffs(vif->active_links) : -1; + + if (link_id >= 0 && key->link_id >= 0 && link_id != key->link_id) + return; if (data->unhandled_cipher) return; @@ -1903,26 +1966,186 @@ static void iwl_mvm_d3_update_keys(struct ieee80211_hw *hw, case WLAN_CIPHER_SUITE_BIP_CMAC_256: case WLAN_CIPHER_SUITE_AES_CMAC: if (key->keyidx == 4 || key->keyidx == 5) { - /* remove rekeyed key */ - if (status->num_of_gtk_rekeys) { - ieee80211_remove_key(key); - } else { - struct ieee80211_key_seq seq; + iwl_mvm_d3_update_igtk_bigtk(status, key, + &status->igtk); + } + if (key->keyidx == 6 || key->keyidx == 7) { + u8 idx = key->keyidx == status->bigtk[1].id; - iwl_mvm_d3_set_igtk_bigtk_ipn(&status->igtk, - &seq, - key->cipher); - ieee80211_set_key_rx_seq(key, 0, &seq); - } + iwl_mvm_d3_update_igtk_bigtk(status, key, + &status->bigtk[idx]); } } } +struct iwl_mvm_d3_mlo_old_keys { + u32 cipher[IEEE80211_MLD_MAX_NUM_LINKS][WOWLAN_MLO_GTK_KEY_NUM_TYPES]; + struct ieee80211_key_conf *key[IEEE80211_MLD_MAX_NUM_LINKS][8]; +}; + +static void iwl_mvm_mlo_key_ciphers(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_sta *sta, + struct ieee80211_key_conf *key, + void *data) +{ + struct iwl_mvm_d3_mlo_old_keys *old_keys = data; + enum iwl_wowlan_mlo_gtk_type key_type; + + if (key->link_id < 0) + return; + + if (WARN_ON(key->link_id >= IEEE80211_MLD_MAX_NUM_LINKS || + key->keyidx >= 8)) + return; + + if (WARN_ON(old_keys->key[key->link_id][key->keyidx])) + return; + + switch (key->cipher) { + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + case WLAN_CIPHER_SUITE_GCMP_256: + key_type = WOWLAN_MLO_GTK_KEY_TYPE_GTK; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + case WLAN_CIPHER_SUITE_AES_CMAC: + if (key->keyidx == 4 || key->keyidx == 5) { + key_type = WOWLAN_MLO_GTK_KEY_TYPE_IGTK; + break; + } else if (key->keyidx == 6 || key->keyidx == 7) { + key_type = WOWLAN_MLO_GTK_KEY_TYPE_BIGTK; + break; + } + return; + default: + /* ignore WEP/TKIP or unknown ciphers */ + return; + } + + old_keys->cipher[key->link_id][key_type] = key->cipher; + old_keys->key[key->link_id][key->keyidx] = key; +} + +static bool iwl_mvm_mlo_gtk_rekey(struct iwl_wowlan_status_data *status, + struct ieee80211_vif *vif, + struct iwl_mvm *mvm) +{ + int i; + struct iwl_mvm_d3_mlo_old_keys *old_keys; + bool ret = true; + + IWL_DEBUG_WOWLAN(mvm, "Num of MLO Keys: %d\n", status->num_mlo_keys); + if (!status->num_mlo_keys) + return true; + + old_keys = kzalloc(sizeof(*old_keys), GFP_KERNEL); + if (!old_keys) + return false; + + /* find the cipher for each mlo key */ + ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mlo_key_ciphers, old_keys); + + for (i = 0; i < status->num_mlo_keys; i++) { + struct iwl_wowlan_mlo_gtk *mlo_key = &status->mlo_keys[i]; + struct ieee80211_key_conf *key, *old_key; + struct ieee80211_key_seq seq; + struct { + struct ieee80211_key_conf conf; + u8 key[32]; + } conf = {}; + u16 flags = le16_to_cpu(mlo_key->flags); + int j, link_id, key_id, key_type; + + link_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_LINK_ID_MSK); + key_id = u16_get_bits(flags, WOWLAN_MLO_GTK_FLAG_KEY_ID_MSK); + key_type = u16_get_bits(flags, + WOWLAN_MLO_GTK_FLAG_KEY_TYPE_MSK); + + if (!(vif->valid_links & BIT(link_id))) + continue; + + if (WARN_ON(link_id >= IEEE80211_MLD_MAX_NUM_LINKS || + key_id >= 8 || + key_type >= WOWLAN_MLO_GTK_KEY_NUM_TYPES)) + continue; + + conf.conf.cipher = old_keys->cipher[link_id][key_type]; + /* WARN_ON? */ + if (!conf.conf.cipher) + continue; + + conf.conf.keylen = 0; + switch (conf.conf.cipher) { + case WLAN_CIPHER_SUITE_CCMP: + case WLAN_CIPHER_SUITE_GCMP: + conf.conf.keylen = WLAN_KEY_LEN_CCMP; + break; + case WLAN_CIPHER_SUITE_GCMP_256: + conf.conf.keylen = WLAN_KEY_LEN_GCMP_256; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_128: + conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_128; + break; + case WLAN_CIPHER_SUITE_BIP_GMAC_256: + conf.conf.keylen = WLAN_KEY_LEN_BIP_GMAC_256; + break; + case WLAN_CIPHER_SUITE_AES_CMAC: + conf.conf.keylen = WLAN_KEY_LEN_AES_CMAC; + break; + case WLAN_CIPHER_SUITE_BIP_CMAC_256: + conf.conf.keylen = WLAN_KEY_LEN_BIP_CMAC_256; + break; + } + + if (WARN_ON(!conf.conf.keylen || + conf.conf.keylen > sizeof(conf.key))) + continue; + + memcpy(conf.conf.key, mlo_key->key, conf.conf.keylen); + conf.conf.keyidx = key_id; + + old_key = old_keys->key[link_id][key_id]; + if (old_key) { + IWL_DEBUG_WOWLAN(mvm, + "Remove MLO key id %d, link id %d\n", + key_id, link_id); + ieee80211_remove_key(old_key); + } + + IWL_DEBUG_WOWLAN(mvm, "Add MLO key id %d, link id %d\n", + key_id, link_id); + key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); + if (WARN_ON(IS_ERR(key))) { + ret = false; + goto out; + } + + /* + * mac80211 expects the pn in big-endian + * also note that seq is a union of all cipher types + * (ccmp, gcmp, cmac, gmac), and they all have the same + * pn field (of length 6) so just copy it to ccmp.pn. + */ + for (j = 5; j >= 0; j--) + seq.ccmp.pn[5 - j] = mlo_key->pn[j]; + + /* group keys are non-QoS and use TID 0 */ + ieee80211_set_key_rx_seq(key, 0, &seq); + } + +out: + kfree(old_keys); + return ret; +} + static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, struct ieee80211_vif *vif, struct iwl_mvm *mvm, u32 gtk_cipher) { - int i; + int i, j; struct ieee80211_key_conf *key; struct { struct ieee80211_key_conf conf; @@ -1930,6 +2153,7 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, } conf = { .conf.cipher = gtk_cipher, }; + int link_id = vif->active_links ? __ffs(vif->active_links) : -1; BUILD_BUG_ON(WLAN_KEY_LEN_CCMP != WLAN_KEY_LEN_GCMP); BUILD_BUG_ON(sizeof(conf.key) < WLAN_KEY_LEN_CCMP); @@ -1963,10 +2187,18 @@ static bool iwl_mvm_gtk_rekey(struct iwl_wowlan_status_data *status, memcpy(conf.conf.key, status->gtk[i].key, sizeof(status->gtk[i].key)); - key = ieee80211_gtk_rekey_add(vif, &conf.conf); + key = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); if (IS_ERR(key)) return false; - iwl_mvm_set_key_rx_seq_idx(key, status, i); + + for (j = 0; j < ARRAY_SIZE(status->gtk_seq); j++) { + if (!status->gtk_seq[j].valid || + status->gtk_seq[j].key_id != key->keyidx) + continue; + iwl_mvm_set_key_rx_seq_idx(key, status, j); + break; + } + WARN_ON(j == ARRAY_SIZE(status->gtk_seq)); } return true; @@ -1986,6 +2218,7 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, .conf.keyidx = key_data->id, }; struct ieee80211_key_seq seq; + int link_id = vif->active_links ? __ffs(vif->active_links) : -1; if (!key_data->len) return true; @@ -2011,10 +2244,20 @@ iwl_mvm_d3_igtk_bigtk_rekey_add(struct iwl_wowlan_status_data *status, BUILD_BUG_ON(sizeof(conf.key) < sizeof(key_data->key)); memcpy(conf.conf.key, key_data->key, conf.conf.keylen); - key_config = ieee80211_gtk_rekey_add(vif, &conf.conf); + key_config = ieee80211_gtk_rekey_add(vif, &conf.conf, link_id); if (IS_ERR(key_config)) return false; ieee80211_set_key_rx_seq(key_config, 0, &seq); + + if (key_config->keyidx == 4 || key_config->keyidx == 5) { + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *mvm_link; + + link_id = link_id < 0 ? 0 : link_id; + mvm_link = mvmvif->link[link_id]; + mvm_link->igtk = key_config; + } + return true; } @@ -2045,6 +2288,7 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, .mvm = mvm, .status = status, }; + int i; u32 disconnection_reasons = IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; @@ -2052,15 +2296,17 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, if (!status || !vif->bss_conf.bssid) return false; - if (status->wakeup_reasons & disconnection_reasons) - return false; - if (iwl_mvm_lookup_wowlan_status_ver(mvm) > 6 || iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION, 0)) gtkdata.igtk_support = true; + if (iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, + WOWLAN_INFO_NOTIFICATION, + 0) >= 3) + gtkdata.bigtk_support = true; + /* find last GTK that we used initially, if any */ ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_d3_find_last_keys, >kdata); @@ -2091,18 +2337,32 @@ static bool iwl_mvm_setup_connection_keep(struct iwl_mvm *mvm, &status->igtk)) return false; + for (i = 0; i < ARRAY_SIZE(status->bigtk); i++) { + if (!iwl_mvm_d3_igtk_bigtk_rekey_add(status, vif, + gtkdata.bigtk_cipher, + &status->bigtk[i])) + return false; + } + + if (!iwl_mvm_mlo_gtk_rekey(status, vif, mvm)) + return false; + ieee80211_gtk_rekey_notify(vif, vif->bss_conf.bssid, (void *)&replay_ctr, GFP_KERNEL); } out: if (iwl_fw_lookup_notif_ver(mvm->fw, LONG_GROUP, - WOWLAN_GET_STATUSES, 0) < 10) { + WOWLAN_GET_STATUSES, + IWL_FW_CMD_VER_UNKNOWN) < 10) { mvmvif->seqno_valid = true; /* +0x10 because the set API expects next-to-use, not last-used */ mvmvif->seqno = status->non_qos_seq_ctr + 0x10; } + if (status->wakeup_reasons & disconnection_reasons) + return false; + return true; } @@ -2160,7 +2420,10 @@ static void iwl_mvm_convert_gtk_v3(struct iwl_wowlan_status_data *status, static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, struct iwl_wowlan_igtk_status *data) { + int i; + BUILD_BUG_ON(sizeof(status->igtk.key) < sizeof(data->key)); + BUILD_BUG_ON(sizeof(status->igtk.ipn) != sizeof(data->ipn)); if (!data->key_len) return; @@ -2172,15 +2435,50 @@ static void iwl_mvm_convert_igtk(struct iwl_wowlan_status_data *status, + WOWLAN_IGTK_MIN_INDEX; memcpy(status->igtk.key, data->key, sizeof(data->key)); - memcpy(status->igtk.ipn, data->ipn, sizeof(data->ipn)); + + /* mac80211 expects big endian for memcmp() to work, convert */ + for (i = 0; i < sizeof(data->ipn); i++) + status->igtk.ipn[i] = data->ipn[sizeof(data->ipn) - i - 1]; +} + +static void iwl_mvm_convert_bigtk(struct iwl_wowlan_status_data *status, + const struct iwl_wowlan_igtk_status *data) +{ + int data_idx, status_idx = 0; + + BUILD_BUG_ON(ARRAY_SIZE(status->bigtk) < WOWLAN_BIGTK_KEYS_NUM); + + for (data_idx = 0; data_idx < WOWLAN_BIGTK_KEYS_NUM; data_idx++) { + if (!data[data_idx].key_len) + continue; + + status->bigtk[status_idx].len = data[data_idx].key_len; + status->bigtk[status_idx].flags = data[data_idx].key_flags; + status->bigtk[status_idx].id = + u32_get_bits(data[data_idx].key_flags, + IWL_WOWLAN_IGTK_BIGTK_IDX_MASK) + + WOWLAN_BIGTK_MIN_INDEX; + + BUILD_BUG_ON(sizeof(status->bigtk[status_idx].key) < + sizeof(data[data_idx].key)); + BUILD_BUG_ON(sizeof(status->bigtk[status_idx].ipn) < + sizeof(data[data_idx].ipn)); + + memcpy(status->bigtk[status_idx].key, data[data_idx].key, + sizeof(data[data_idx].key)); + memcpy(status->bigtk[status_idx].ipn, data[data_idx].ipn, + sizeof(data[data_idx].ipn)); + status_idx++; + } } static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, struct iwl_wowlan_info_notif *data, struct iwl_wowlan_status_data *status, - u32 len) + u32 len, bool has_mlo_keys) { u32 i; + u32 expected_len = sizeof(*data); if (!data) { IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n"); @@ -2188,16 +2486,69 @@ static void iwl_mvm_parse_wowlan_info_notif(struct iwl_mvm *mvm, return; } - if (len < sizeof(*data)) { + if (has_mlo_keys) + expected_len += (data->num_mlo_link_keys * + sizeof(status->mlo_keys[0])); + + if (len < expected_len) { IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); status = NULL; return; } + if (mvm->fast_resume) + return; + iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc); iwl_mvm_convert_gtk_v3(status, data->gtk); iwl_mvm_convert_igtk(status, &data->igtk[0]); + iwl_mvm_convert_bigtk(status, data->bigtk); + status->replay_ctr = le64_to_cpu(data->replay_ctr); + status->pattern_number = le16_to_cpu(data->pattern_number); + for (i = 0; i < IWL_MAX_TID_COUNT; i++) + status->qos_seq_ctr[i] = + le16_to_cpu(data->qos_seq_ctr[i]); + status->wakeup_reasons = le32_to_cpu(data->wakeup_reasons); + status->num_of_gtk_rekeys = + le32_to_cpu(data->num_of_gtk_rekeys); + status->received_beacons = le32_to_cpu(data->received_beacons); + status->tid_tear_down = data->tid_tear_down; + if (has_mlo_keys && data->num_mlo_link_keys) { + status->num_mlo_keys = data->num_mlo_link_keys; + if (IWL_FW_CHECK(mvm, + status->num_mlo_keys > WOWLAN_MAX_MLO_KEYS, + "Too many mlo keys: %d, max %d\n", + status->num_mlo_keys, WOWLAN_MAX_MLO_KEYS)) + status->num_mlo_keys = WOWLAN_MAX_MLO_KEYS; + memcpy(status->mlo_keys, data->mlo_gtks, + status->num_mlo_keys * sizeof(status->mlo_keys[0])); + } +} + +static void +iwl_mvm_parse_wowlan_info_notif_v2(struct iwl_mvm *mvm, + struct iwl_wowlan_info_notif_v2 *data, + struct iwl_wowlan_status_data *status, + u32 len) +{ + u32 i; + + if (!data) { + IWL_ERR(mvm, "iwl_wowlan_info_notif data is NULL\n"); + status = NULL; + return; + } + + if (len < sizeof(*data)) { + IWL_ERR(mvm, "Invalid WoWLAN info notification!\n"); + status = NULL; + return; + } + + iwl_mvm_convert_key_counters_v5(status, &data->gtk[0].sc); + iwl_mvm_convert_gtk_v3(status, data->gtk); + iwl_mvm_convert_igtk(status, &data->igtk[0]); status->replay_ctr = le64_to_cpu(data->replay_ctr); status->pattern_number = le16_to_cpu(data->pattern_number); for (i = 0; i < IWL_MAX_TID_COUNT; i++) @@ -2391,8 +2742,14 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, struct iwl_wowlan_status_data *status) { int i; - bool keep; + bool keep = false; struct iwl_mvm_sta *mvm_ap_sta; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int link_id = vif->active_links ? __ffs(vif->active_links) : 0; + struct iwl_mvm_vif_link_info *mvm_link = mvmvif->link[link_id]; + + if (WARN_ON(!mvm_link)) + goto out_unlock; if (!status) goto out_unlock; @@ -2400,8 +2757,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, IWL_DEBUG_WOWLAN(mvm, "wakeup reason 0x%x\n", status->wakeup_reasons); - /* still at hard-coded place 0 for D3 image */ - mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, 0); + mvm_ap_sta = iwl_mvm_sta_from_staid_protected(mvm, mvm_link->ap_sta_id); if (!mvm_ap_sta) goto out_unlock; @@ -2419,18 +2775,12 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm, mvm_ap_sta->tid_data[i].seq_number >> 4); } - /* now we have all the data we need, unlock to avoid mac80211 issues */ - mutex_unlock(&mvm->mutex); - iwl_mvm_report_wakeup_reasons(mvm, vif, status); keep = iwl_mvm_setup_connection_keep(mvm, vif, status); - - return keep; - out_unlock: mutex_unlock(&mvm->mutex); - return false; + return keep; } #define ND_QUERY_BUF_LEN (sizeof(struct iwl_scan_offload_profile_match) * \ @@ -2705,7 +3055,7 @@ static bool iwl_mvm_check_rt_status(struct iwl_mvm *mvm, if (iwl_mvm_rt_status(mvm->trans, mvm->trans->dbg.lmac_error_event_table[0], &err_id)) { - if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN) { + if (err_id == RF_KILL_INDICATOR_FOR_WOWLAN && vif) { struct cfg80211_wowlan_wakeup wakeup = { .rfkill_release = true, }; @@ -2746,6 +3096,9 @@ iwl_mvm_choose_query_wakeup_reasons(struct iwl_mvm *mvm, u8 sta_id = mvm->net_detect ? IWL_MVM_INVALID_STA : mvmvif->deflink.ap_sta_id; + /* bug - FW with MLO has status notification */ + WARN_ON(ieee80211_vif_is_mld(vif)); + d3_data->status = iwl_mvm_send_wowlan_get_status(mvm, sta_id); } @@ -2854,7 +3207,7 @@ static void iwl_mvm_nd_match_info_handler(struct iwl_mvm *mvm, if (results->matched_profiles) { memcpy(results->matches, notif->matches, matches_len); - d3_data->nd_results_valid = TRUE; + d3_data->nd_results_valid = true; } /* no scan should be active at this point */ @@ -2869,7 +3222,7 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, struct iwl_mvm *mvm = container_of(notif_wait, struct iwl_mvm, notif_wait); struct iwl_d3_data *d3_data = data; - u32 len; + u32 len = iwl_rx_packet_payload_len(pkt); int ret; int wowlan_info_ver = iwl_fw_lookup_notif_ver(mvm->fw, PROT_OFFLOAD_GROUP, @@ -2879,7 +3232,6 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, switch (WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd)) { case WIDE_ID(PROT_OFFLOAD_GROUP, WOWLAN_INFO_NOTIFICATION): { - struct iwl_wowlan_info_notif *notif; if (d3_data->notif_received & IWL_D3_NOTIF_WOWLAN_INFO) { /* We might get two notifications due to dual bss */ @@ -2889,26 +3241,40 @@ static bool iwl_mvm_wait_d3_notif(struct iwl_notif_wait_data *notif_wait, } if (wowlan_info_ver < 2) { - struct iwl_wowlan_info_notif_v1 *notif_v1 = (void *)pkt->data; + struct iwl_wowlan_info_notif_v1 *notif_v1 = + (void *)pkt->data; + struct iwl_wowlan_info_notif_v2 *notif_v2; - notif = kmemdup(notif_v1, sizeof(*notif), GFP_ATOMIC); - if (!notif) + notif_v2 = kmemdup(notif_v1, sizeof(*notif_v2), GFP_ATOMIC); + + if (!notif_v2) return false; - notif->tid_tear_down = notif_v1->tid_tear_down; - notif->station_id = notif_v1->station_id; - memset_after(notif, 0, station_id); + notif_v2->tid_tear_down = notif_v1->tid_tear_down; + notif_v2->station_id = notif_v1->station_id; + memset_after(notif_v2, 0, station_id); + iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, + d3_data->status, + len); + kfree(notif_v2); + + } else if (wowlan_info_ver == 2) { + struct iwl_wowlan_info_notif_v2 *notif_v2 = + (void *)pkt->data; + + iwl_mvm_parse_wowlan_info_notif_v2(mvm, notif_v2, + d3_data->status, + len); } else { - notif = (void *)pkt->data; + struct iwl_wowlan_info_notif *notif = + (void *)pkt->data; + + iwl_mvm_parse_wowlan_info_notif(mvm, notif, + d3_data->status, len, + wowlan_info_ver > 3); } d3_data->notif_received |= IWL_D3_NOTIF_WOWLAN_INFO; - len = iwl_rx_packet_payload_len(pkt); - iwl_mvm_parse_wowlan_info_notif(mvm, notif, d3_data->status, - len); - - if (wowlan_info_ver < 2) - kfree(notif); if (d3_data->status && d3_data->status->wakeup_reasons & IWL_WOWLAN_WAKEUP_REASON_HAS_WAKEUP_PKT) @@ -3006,7 +3372,7 @@ static int iwl_mvm_resume_firmware(struct iwl_mvm *mvm, bool test) return ret; } -#define IWL_MVM_D3_NOTIF_TIMEOUT (HZ / 5) +#define IWL_MVM_D3_NOTIF_TIMEOUT (HZ / 3) static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm, struct iwl_d3_data *d3_data) @@ -3017,12 +3383,22 @@ static int iwl_mvm_d3_notif_wait(struct iwl_mvm *mvm, WIDE_ID(SCAN_GROUP, OFFLOAD_MATCH_INFO_NOTIF), WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION) }; + static const u16 d3_fast_resume_notif[] = { + WIDE_ID(PROT_OFFLOAD_GROUP, D3_END_NOTIFICATION) + }; struct iwl_notification_wait wait_d3_notif; int ret; - iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif, - d3_resume_notif, ARRAY_SIZE(d3_resume_notif), - iwl_mvm_wait_d3_notif, d3_data); + if (mvm->fast_resume) + iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif, + d3_fast_resume_notif, + ARRAY_SIZE(d3_fast_resume_notif), + iwl_mvm_wait_d3_notif, d3_data); + else + iwl_init_notification_wait(&mvm->notif_wait, &wait_d3_notif, + d3_resume_notif, + ARRAY_SIZE(d3_resume_notif), + iwl_mvm_wait_d3_notif, d3_data); ret = iwl_mvm_resume_firmware(mvm, d3_data->test); if (ret) { @@ -3066,6 +3442,16 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) mutex_lock(&mvm->mutex); + /* Apparently, the device went away and device_powered_off() was called, + * don't even try to read the rt_status, the device is currently + * inaccessible. + */ + if (!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status)) { + IWL_INFO(mvm, + "Can't resume, device_powered_off() was called during wowlan\n"); + goto err; + } + mvm->last_reset_or_resume_time_jiffies = jiffies; /* get the BSS vif pointer again */ @@ -3103,6 +3489,8 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) goto err; } + iwl_mvm_unblock_esr(mvm, vif, IWL_MVM_ESR_BLOCKED_WOWLAN); + /* after the successful handshake, we're out of D3 */ mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; @@ -3205,6 +3593,68 @@ void iwl_mvm_set_wakeup(struct ieee80211_hw *hw, bool enabled) device_set_wakeup_enable(mvm->trans->dev, enabled); } +void iwl_mvm_fast_suspend(struct iwl_mvm *mvm) +{ + struct iwl_d3_manager_config d3_cfg_cmd_data = {}; + int ret; + + lockdep_assert_held(&mvm->mutex); + + IWL_DEBUG_WOWLAN(mvm, "Starting fast suspend flow\n"); + + mvm->fast_resume = true; + set_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); + + WARN_ON(iwl_mvm_power_update_device(mvm)); + mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_D3; + ret = iwl_mvm_send_cmd_pdu(mvm, D3_CONFIG_CMD, CMD_SEND_IN_D3, + sizeof(d3_cfg_cmd_data), &d3_cfg_cmd_data); + if (ret) + IWL_ERR(mvm, + "fast suspend: couldn't send D3_CONFIG_CMD %d\n", ret); + + WARN_ON(iwl_mvm_power_update_mac(mvm)); + + ret = iwl_trans_d3_suspend(mvm->trans, false, false); + if (ret) + IWL_ERR(mvm, "fast suspend: trans_d3_suspend failed %d\n", ret); +} + +int iwl_mvm_fast_resume(struct iwl_mvm *mvm) +{ + struct iwl_d3_data d3_data = { + .notif_expected = + IWL_D3_NOTIF_D3_END_NOTIF, + }; + int ret; + + lockdep_assert_held(&mvm->mutex); + + IWL_DEBUG_WOWLAN(mvm, "Starting the fast resume flow\n"); + + mvm->last_reset_or_resume_time_jiffies = jiffies; + iwl_fw_dbg_read_d3_debug_data(&mvm->fwrt); + + if (iwl_mvm_check_rt_status(mvm, NULL)) { + set_bit(STATUS_FW_ERROR, &mvm->trans->status); + iwl_mvm_dump_nic_error_log(mvm); + iwl_dbg_tlv_time_point(&mvm->fwrt, + IWL_FW_INI_TIME_POINT_FW_ASSERT, NULL); + iwl_fw_dbg_collect_desc(&mvm->fwrt, &iwl_dump_desc_assert, + false, 0); + return -ENODEV; + } + ret = iwl_mvm_d3_notif_wait(mvm, &d3_data); + clear_bit(IWL_MVM_STATUS_IN_D3, &mvm->status); + mvm->trans->system_pm_mode = IWL_PLAT_PM_MODE_DISABLED; + mvm->fast_resume = false; + + if (ret) + IWL_ERR(mvm, "Couldn't get the d3 notif %d\n", ret); + + return ret; +} + #ifdef CONFIG_IWLWIFI_DEBUGFS static int iwl_mvm_d3_test_open(struct inode *inode, struct file *file) { @@ -3240,6 +3690,7 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; + unsigned long end = jiffies + 60 * HZ; u32 pme_asserted; while (true) { @@ -3253,6 +3704,12 @@ static ssize_t iwl_mvm_d3_test_read(struct file *file, char __user *user_buf, if (msleep_interruptible(100)) break; + + if (time_is_before_jiffies(end)) { + IWL_ERR(mvm, + "ending pseudo-D3 with timeout after ~60 seconds\n"); + return -ETIMEDOUT; + } } return 0; diff --git a/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c b/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c index e03951c843a8..aa5058955323 100644 --- a/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c +++ b/sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -384,9 +384,9 @@ static ssize_t iwl_dbgfs_bf_params_write(struct ieee80211_vif *vif, char *buf, mutex_lock(&mvm->mutex); iwl_dbgfs_update_bf(vif, param, value); if (param == MVM_DEBUGFS_BF_ENABLE_BEACON_FILTER && !value) - ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0); + ret = iwl_mvm_disable_beacon_filter(mvm, vif); else - ret = iwl_mvm_enable_beacon_filter(mvm, vif, 0); + ret = iwl_mvm_enable_beacon_filter(mvm, vif); mutex_unlock(&mvm->mutex); return ret ?: count; @@ -410,7 +410,7 @@ static ssize_t iwl_dbgfs_bf_params_read(struct file *file, }; iwl_mvm_beacon_filter_debugfs_parameters(vif, &cmd); - if (mvmvif->bf_data.bf_enabled) + if (mvmvif->bf_enabled) cmd.bf_enable_beacon_filter = cpu_to_le32(1); else cmd.bf_enable_beacon_filter = 0; @@ -585,34 +585,47 @@ static ssize_t iwl_dbgfs_rx_phyinfo_write(struct ieee80211_vif *vif, char *buf, { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct iwl_mvm *mvm = mvmvif->mvm; - struct ieee80211_chanctx_conf *chanctx_conf; - struct iwl_mvm_phy_ctxt *phy_ctxt; + struct ieee80211_bss_conf *link_conf; u16 value; - int ret; + int link_id, ret = -EINVAL; ret = kstrtou16(buf, 0, &value); if (ret) return ret; mutex_lock(&mvm->mutex); - rcu_read_lock(); - chanctx_conf = rcu_dereference(vif->bss_conf.chanctx_conf); - /* make sure the channel context is assigned */ - if (!chanctx_conf) { + mvm->dbgfs_rx_phyinfo = value; + + for_each_vif_active_link(vif, link_conf, link_id) { + struct ieee80211_chanctx_conf *chanctx_conf; + struct cfg80211_chan_def min_def, ap_def; + struct iwl_mvm_phy_ctxt *phy_ctxt; + u8 chains_static, chains_dynamic; + + rcu_read_lock(); + chanctx_conf = rcu_dereference(link_conf->chanctx_conf); + if (!chanctx_conf) { + rcu_read_unlock(); + continue; + } + /* A command can't be sent with RCU lock held, so copy + * everything here and use it after unlocking + */ + min_def = chanctx_conf->min_def; + ap_def = chanctx_conf->ap; + chains_static = chanctx_conf->rx_chains_static; + chains_dynamic = chanctx_conf->rx_chains_dynamic; rcu_read_unlock(); - mutex_unlock(&mvm->mutex); - return -EINVAL; - } - phy_ctxt = &mvm->phy_ctxts[*(u16 *)chanctx_conf->drv_priv]; - rcu_read_unlock(); + phy_ctxt = mvmvif->link[link_id]->phy_ctxt; + if (!phy_ctxt) + continue; - mvm->dbgfs_rx_phyinfo = value; + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &min_def, &ap_def, + chains_static, chains_dynamic); + } - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &chanctx_conf->min_def, - chanctx_conf->rx_chains_static, - chanctx_conf->rx_chains_dynamic); mutex_unlock(&mvm->mutex); return ret ?: count; @@ -686,6 +699,132 @@ static ssize_t iwl_dbgfs_quota_min_read(struct file *file, return simple_read_from_buffer(user_buf, count, ppos, buf, len); } +static ssize_t iwl_dbgfs_max_tx_op_write(struct ieee80211_vif *vif, char *buf, + size_t count, loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + u16 value; + int ret; + + ret = kstrtou16(buf, 0, &value); + if (ret) + return ret; + + mutex_lock(&mvm->mutex); + mvmvif->max_tx_op = value; + mutex_unlock(&mvm->mutex); + + return count; +} + +static ssize_t iwl_dbgfs_max_tx_op_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + char buf[10]; + int len; + + mutex_lock(&mvm->mutex); + len = scnprintf(buf, sizeof(buf), "%hu\n", mvmvif->max_tx_op); + mutex_unlock(&mvm->mutex); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static ssize_t iwl_dbgfs_int_mlo_scan_write(struct ieee80211_vif *vif, + char *buf, size_t count, + loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + u32 action; + int ret; + + if (!vif->cfg.assoc || !ieee80211_vif_is_mld(vif)) + return -EINVAL; + + if (kstrtou32(buf, 0, &action)) + return -EINVAL; + + mutex_lock(&mvm->mutex); + + if (!action) { + ret = iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_INT_MLO, false); + } else if (action == 1) { + ret = iwl_mvm_int_mlo_scan(mvm, vif); + } else { + ret = -EINVAL; + } + + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + +static ssize_t iwl_dbgfs_esr_disable_reason_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ieee80211_vif *vif = file->private_data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + unsigned long esr_mask; + char *buf; + int bufsz, pos, i; + ssize_t rv; + + mutex_lock(&mvm->mutex); + esr_mask = mvmvif->esr_disable_reason; + mutex_unlock(&mvm->mutex); + + bufsz = hweight32(esr_mask) * 32 + 40; + buf = kmalloc(bufsz, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + pos = scnprintf(buf, bufsz, "EMLSR state: '0x%lx'\nreasons:\n", + esr_mask); + for_each_set_bit(i, &esr_mask, BITS_PER_LONG) + pos += scnprintf(buf + pos, bufsz - pos, " - %s\n", + iwl_get_esr_state_string(BIT(i))); + + rv = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return rv; +} + +static ssize_t iwl_dbgfs_esr_disable_reason_write(struct ieee80211_vif *vif, + char *buf, size_t count, + loff_t *ppos) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + u32 reason; + u8 block; + int ret; + + ret = sscanf(buf, "%u %hhu", &reason, &block); + if (ret < 0) + return ret; + + if (hweight16(reason) != 1 || !(reason & IWL_MVM_BLOCK_ESR_REASONS)) + return -EINVAL; + + mutex_lock(&mvm->mutex); + if (block) + iwl_mvm_block_esr(mvm, vif, reason, + iwl_mvm_get_primary_link(vif)); + else + iwl_mvm_unblock_esr(mvm, vif, reason); + mutex_unlock(&mvm->mutex); + + return count; +} + #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \ _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif) #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \ @@ -705,22 +844,15 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20); MVM_DEBUGFS_READ_WRITE_FILE_OPS(rx_phyinfo, 10); MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32); MVM_DEBUGFS_READ_FILE_OPS(os_device_timediff); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(max_tx_op, 10); +MVM_DEBUGFS_WRITE_FILE_OPS(int_mlo_scan, 32); +MVM_DEBUGFS_READ_WRITE_FILE_OPS(esr_disable_reason, 32); - -void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +void iwl_mvm_vif_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif) { + struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); struct dentry *dbgfs_dir = vif->debugfs_dir; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); -#if defined(__linux__) - char buf[100]; -#endif - - /* - * Check if debugfs directory already exist before creating it. - * This may happen when, for example, resetting hw or suspend-resume - */ - if (!dbgfs_dir || mvmvif->dbgfs_dir) - return; mvmvif->dbgfs_dir = debugfs_create_dir("iwlmvm", dbgfs_dir); if (IS_ERR_OR_NULL(mvmvif->dbgfs_dir)) { @@ -742,10 +874,28 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir, 0600); MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir, 0600); MVM_DEBUGFS_ADD_FILE_VIF(os_device_timediff, mvmvif->dbgfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE_VIF(max_tx_op, mvmvif->dbgfs_dir, 0600); + debugfs_create_bool("ftm_unprotected", 0200, mvmvif->dbgfs_dir, + &mvmvif->ftm_unprotected); + MVM_DEBUGFS_ADD_FILE_VIF(int_mlo_scan, mvmvif->dbgfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE_VIF(esr_disable_reason, mvmvif->dbgfs_dir, 0600); if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p && mvmvif == mvm->bf_allowed_vif) MVM_DEBUGFS_ADD_FILE_VIF(bf_params, mvmvif->dbgfs_dir, 0600); +} + +void iwl_mvm_vif_dbgfs_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +{ + struct dentry *dbgfs_dir = vif->debugfs_dir; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + char buf[3 * 3 + 11 + (NL80211_WIPHY_NAME_MAXLEN + 1) + + (7 + IFNAMSIZ + 1) + 6 + 1]; + char name[7 + IFNAMSIZ + 1]; + + /* this will happen in monitor mode */ + if (!dbgfs_dir) + return; #if defined(__linux__) /* @@ -755,22 +905,64 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif) * find * netdev:wlan0 -> ../../../ieee80211/phy0/netdev:wlan0/iwlmvm/ */ - snprintf(buf, 100, "../../../%pd3/%pd", - dbgfs_dir, - mvmvif->dbgfs_dir); + snprintf(name, sizeof(name), "%pd", dbgfs_dir); + snprintf(buf, sizeof(buf), "../../../%pd3/iwlmvm", dbgfs_dir); - mvmvif->dbgfs_slink = debugfs_create_symlink(dbgfs_dir->d_name.name, - mvm->debugfs_dir, buf); + mvmvif->dbgfs_slink = + debugfs_create_symlink(name, mvm->debugfs_dir, buf); #endif } -void iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif) +void iwl_mvm_vif_dbgfs_rm_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); debugfs_remove(mvmvif->dbgfs_slink); mvmvif->dbgfs_slink = NULL; +} + +#define MVM_DEBUGFS_WRITE_LINK_FILE_OPS(name, bufsz) \ + _MVM_DEBUGFS_WRITE_FILE_OPS(link_##name, bufsz, \ + struct ieee80211_bss_conf) +#define MVM_DEBUGFS_READ_WRITE_LINK_FILE_OPS(name, bufsz) \ + _MVM_DEBUGFS_READ_WRITE_FILE_OPS(link_##name, bufsz, \ + struct ieee80211_bss_conf) +#define MVM_DEBUGFS_ADD_LINK_FILE(name, parent, mode) \ + debugfs_create_file(#name, mode, parent, link_conf, \ + &iwl_dbgfs_link_##name##_ops) + +static void iwl_mvm_debugfs_add_link_files(struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct dentry *mvm_dir) +{ + /* Add per-link files here*/ +} + +void iwl_mvm_link_add_debugfs(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf, + struct dentry *dir) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm *mvm = mvmvif->mvm; + unsigned int link_id = link_conf->link_id; + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; + struct dentry *mvm_dir; + + if (WARN_ON(!link_info) || !dir) + return; + + if (dir == vif->debugfs_dir) { + WARN_ON(!mvmvif->dbgfs_dir); + mvm_dir = mvmvif->dbgfs_dir; + } else { + mvm_dir = debugfs_create_dir("iwlmvm", dir); + if (IS_ERR_OR_NULL(mvm_dir)) { + IWL_ERR(mvm, "Failed to create debugfs directory under %pd\n", + dir); + return; + } + } - debugfs_remove_recursive(mvmvif->dbgfs_dir); - mvmvif->dbgfs_dir = NULL; + iwl_mvm_debugfs_add_link_files(vif, link_conf, mvm_dir); } diff --git a/sys/contrib/dev/iwlwifi/mvm/debugfs.c b/sys/contrib/dev/iwlwifi/mvm/debugfs.c index 2ba63198c70a..24bcffe67235 100644 --- a/sys/contrib/dev/iwlwifi/mvm/debugfs.c +++ b/sys/contrib/dev/iwlwifi/mvm/debugfs.c @@ -50,8 +50,18 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { int ret; + bool force; - if (!iwl_mvm_is_ctdp_supported(mvm)) + if (!kstrtobool(buf, &force)) + IWL_DEBUG_INFO(mvm, + "force start is %d [0=disabled, 1=enabled]\n", + force); + + /* we allow skipping cap support check and force stop ctdp + * statistics collection and with guerantee that it is + * safe to use. + */ + if (!force && !iwl_mvm_is_ctdp_supported(mvm)) return -EOPNOTSUPP; if (!iwl_mvm_firmware_running(mvm) || @@ -65,6 +75,36 @@ static ssize_t iwl_dbgfs_stop_ctdp_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } +static ssize_t iwl_dbgfs_start_ctdp_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + int ret; + bool force; + + if (!kstrtobool(buf, &force)) + IWL_DEBUG_INFO(mvm, + "force start is %d [0=disabled, 1=enabled]\n", + force); + + /* we allow skipping cap support check and force enable ctdp + * for statistics collection and with guerantee that it is + * safe to use. + */ + if (!force && !iwl_mvm_is_ctdp_supported(mvm)) + return -EOPNOTSUPP; + + if (!iwl_mvm_firmware_running(mvm) || + mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) + return -EIO; + + mutex_lock(&mvm->mutex); + ret = iwl_mvm_ctdp_command(mvm, CTDP_CMD_OPERATION_START, 0); + mutex_unlock(&mvm->mutex); + + return ret ?: count; +} + static ssize_t iwl_dbgfs_force_ctkill_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { @@ -111,37 +151,6 @@ static ssize_t iwl_dbgfs_tx_flush_write(struct iwl_mvm *mvm, char *buf, return ret; } -static ssize_t iwl_dbgfs_sta_drain_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm_sta *mvmsta; - int sta_id, drain, ret; - - if (!iwl_mvm_firmware_running(mvm) || - mvm->fwrt.cur_fw_img != IWL_UCODE_REGULAR) - return -EIO; - - if (sscanf(buf, "%d %d", &sta_id, &drain) != 2) - return -EINVAL; - if (sta_id < 0 || sta_id >= mvm->fw->ucode_capa.num_stations) - return -EINVAL; - if (drain < 0 || drain > 1) - return -EINVAL; - - mutex_lock(&mvm->mutex); - - mvmsta = iwl_mvm_sta_from_staid_protected(mvm, sta_id); - - if (!mvmsta) - ret = -ENOENT; - else - ret = iwl_mvm_drain_sta(mvm, mvmsta, drain) ? : count; - - mutex_unlock(&mvm->mutex); - - return ret; -} - static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { @@ -351,9 +360,7 @@ static ssize_t iwl_dbgfs_wifi_6e_enable_read(struct file *file, char buf[12]; u32 value; - err = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ENABLE_6E, - &iwl_guid, &value); + err = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_ENABLE_6E, &value); if (err) return err; @@ -530,193 +537,12 @@ static ssize_t iwl_dbgfs_disable_power_off_write(struct iwl_mvm *mvm, char *buf, return ret ?: count; } -static -int iwl_mvm_coex_dump_mbox(struct iwl_bt_coex_profile_notif *notif, char *buf, - int pos, int bufsz) -{ - pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw0:\n"); - - BT_MBOX_PRINT(0, LE_SLAVE_LAT, false); - BT_MBOX_PRINT(0, LE_PROF1, false); - BT_MBOX_PRINT(0, LE_PROF2, false); - BT_MBOX_PRINT(0, LE_PROF_OTHER, false); - BT_MBOX_PRINT(0, CHL_SEQ_N, false); - BT_MBOX_PRINT(0, INBAND_S, false); - BT_MBOX_PRINT(0, LE_MIN_RSSI, false); - BT_MBOX_PRINT(0, LE_SCAN, false); - BT_MBOX_PRINT(0, LE_ADV, false); - BT_MBOX_PRINT(0, LE_MAX_TX_POWER, false); - BT_MBOX_PRINT(0, OPEN_CON_1, true); - - pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw1:\n"); - - BT_MBOX_PRINT(1, BR_MAX_TX_POWER, false); - BT_MBOX_PRINT(1, IP_SR, false); - BT_MBOX_PRINT(1, LE_MSTR, false); - BT_MBOX_PRINT(1, AGGR_TRFC_LD, false); - BT_MBOX_PRINT(1, MSG_TYPE, false); - BT_MBOX_PRINT(1, SSN, true); - - pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw2:\n"); - - BT_MBOX_PRINT(2, SNIFF_ACT, false); - BT_MBOX_PRINT(2, PAG, false); - BT_MBOX_PRINT(2, INQUIRY, false); - BT_MBOX_PRINT(2, CONN, false); - BT_MBOX_PRINT(2, SNIFF_INTERVAL, false); - BT_MBOX_PRINT(2, DISC, false); - BT_MBOX_PRINT(2, SCO_TX_ACT, false); - BT_MBOX_PRINT(2, SCO_RX_ACT, false); - BT_MBOX_PRINT(2, ESCO_RE_TX, false); - BT_MBOX_PRINT(2, SCO_DURATION, true); - - pos += scnprintf(buf+pos, bufsz-pos, "MBOX dw3:\n"); - - BT_MBOX_PRINT(3, SCO_STATE, false); - BT_MBOX_PRINT(3, SNIFF_STATE, false); - BT_MBOX_PRINT(3, A2DP_STATE, false); - BT_MBOX_PRINT(3, A2DP_SRC, false); - BT_MBOX_PRINT(3, ACL_STATE, false); - BT_MBOX_PRINT(3, MSTR_STATE, false); - BT_MBOX_PRINT(3, OBX_STATE, false); - BT_MBOX_PRINT(3, OPEN_CON_2, false); - BT_MBOX_PRINT(3, TRAFFIC_LOAD, false); - BT_MBOX_PRINT(3, CHL_SEQN_LSB, false); - BT_MBOX_PRINT(3, INBAND_P, false); - BT_MBOX_PRINT(3, MSG_TYPE_2, false); - BT_MBOX_PRINT(3, SSN_2, false); - BT_MBOX_PRINT(3, UPDATE_REQUEST, true); - - return pos; -} - -static ssize_t iwl_dbgfs_bt_notif_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_profile_notif *notif = &mvm->last_bt_notif; - char *buf; - int ret, pos = 0, bufsz = sizeof(char) * 1024; - - buf = kmalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - mutex_lock(&mvm->mutex); - - pos += iwl_mvm_coex_dump_mbox(notif, buf, pos, bufsz); - - pos += scnprintf(buf + pos, bufsz - pos, "bt_ci_compliance = %d\n", - notif->bt_ci_compliance); - pos += scnprintf(buf + pos, bufsz - pos, "primary_ch_lut = %d\n", - le32_to_cpu(notif->primary_ch_lut)); - pos += scnprintf(buf + pos, bufsz - pos, "secondary_ch_lut = %d\n", - le32_to_cpu(notif->secondary_ch_lut)); - pos += scnprintf(buf + pos, - bufsz - pos, "bt_activity_grading = %d\n", - le32_to_cpu(notif->bt_activity_grading)); - pos += scnprintf(buf + pos, bufsz - pos, "bt_rrc = %d\n", - notif->rrc_status & 0xF); - pos += scnprintf(buf + pos, bufsz - pos, "bt_ttc = %d\n", - notif->ttc_status & 0xF); - - pos += scnprintf(buf + pos, bufsz - pos, "sync_sco = %d\n", - IWL_MVM_BT_COEX_SYNC2SCO); - pos += scnprintf(buf + pos, bufsz - pos, "mplut = %d\n", - IWL_MVM_BT_COEX_MPLUT); - - mutex_unlock(&mvm->mutex); - - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); - kfree(buf); - - return ret; -} -#undef BT_MBOX_PRINT - -static ssize_t iwl_dbgfs_bt_cmd_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct iwl_mvm *mvm = file->private_data; - struct iwl_bt_coex_ci_cmd *cmd = &mvm->last_bt_ci_cmd; - char buf[256]; - int bufsz = sizeof(buf); - int pos = 0; - - mutex_lock(&mvm->mutex); - - pos += scnprintf(buf + pos, bufsz - pos, "Channel inhibition CMD\n"); - pos += scnprintf(buf + pos, bufsz - pos, - "\tPrimary Channel Bitmap 0x%016llx\n", - le64_to_cpu(cmd->bt_primary_ci)); - pos += scnprintf(buf + pos, bufsz - pos, - "\tSecondary Channel Bitmap 0x%016llx\n", - le64_to_cpu(cmd->bt_secondary_ci)); - - mutex_unlock(&mvm->mutex); - - return simple_read_from_buffer(user_buf, count, ppos, buf, pos); -} - -static ssize_t -iwl_dbgfs_bt_tx_prio_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - u32 bt_tx_prio; - - if (sscanf(buf, "%u", &bt_tx_prio) != 1) - return -EINVAL; - if (bt_tx_prio > 4) - return -EINVAL; - - mvm->bt_tx_prio = bt_tx_prio; - - return count; -} - -static ssize_t -iwl_dbgfs_bt_force_ant_write(struct iwl_mvm *mvm, char *buf, - size_t count, loff_t *ppos) -{ - static const char * const modes_str[BT_FORCE_ANT_MAX] = { - [BT_FORCE_ANT_DIS] = "dis", - [BT_FORCE_ANT_AUTO] = "auto", - [BT_FORCE_ANT_BT] = "bt", - [BT_FORCE_ANT_WIFI] = "wifi", - }; - int ret, bt_force_ant_mode; - - ret = match_string(modes_str, ARRAY_SIZE(modes_str), buf); - if (ret < 0) - return ret; - - bt_force_ant_mode = ret; - ret = 0; - mutex_lock(&mvm->mutex); - if (mvm->bt_force_ant_mode == bt_force_ant_mode) - goto out; - - mvm->bt_force_ant_mode = bt_force_ant_mode; - IWL_DEBUG_COEX(mvm, "Force mode: %s\n", - modes_str[mvm->bt_force_ant_mode]); - - if (iwl_mvm_firmware_running(mvm)) - ret = iwl_mvm_send_bt_init_conf(mvm); - else - ret = 0; - -out: - mutex_unlock(&mvm->mutex); - return ret ?: count; -} - static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct iwl_mvm *mvm = file->private_data; char *buff, *pos, *endpos; static const size_t bufsz = 1024; - char _fw_name_pre[FW_NAME_PRE_BUFSIZE]; int ret; buff = kmalloc(bufsz, GFP_KERNEL); @@ -726,8 +552,8 @@ static ssize_t iwl_dbgfs_fw_ver_read(struct file *file, char __user *user_buf, pos = buff; endpos = pos + bufsz; - pos += scnprintf(pos, endpos - pos, "FW prefix: %s\n", - iwl_drv_get_fwname_pre(mvm->trans, _fw_name_pre)); + pos += scnprintf(pos, endpos - pos, "FW id: %s\n", + mvm->fwrt.fw->fw_version); pos += scnprintf(pos, endpos - pos, "FW: %s\n", mvm->fwrt.fw->human_readable); pos += scnprintf(pos, endpos - pos, "Device: %s\n", @@ -841,14 +667,14 @@ static ssize_t iwl_dbgfs_tas_get_status_read(struct file *file, le16_to_cpu(rsp->curr_mcc)); pos += scnprintf(pos, endpos - pos, "Block list entries:"); - for (i = 0; i < APCI_WTAS_BLACK_LIST_MAX; i++) + for (i = 0; i < IWL_WTAS_BLACK_LIST_MAX; i++) pos += scnprintf(pos, endpos - pos, " 0x%x", le16_to_cpu(rsp->block_list[i])); pos += scnprintf(pos, endpos - pos, "\nOEM name: %s\n", - dmi_get_system_info(DMI_SYS_VENDOR)); + dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>"); pos += scnprintf(pos, endpos - pos, "\tVendor In Approved List: %s\n", - iwl_mvm_is_vendor_in_approved_list() ? "YES" : "NO"); + iwl_is_tas_approved() ? "YES" : "NO"); pos += scnprintf(pos, endpos - pos, "\tDo TAS Support Dual Radio?: %s\n", rsp->in_dual_radio ? "TRUE" : "FALSE"); @@ -969,6 +795,13 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, char *buf; int ret; size_t bufsz; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(SYSTEM_GROUP, + SYSTEM_STATISTICS_CMD), + IWL_FW_CMD_VER_UNKNOWN); + + if (cmd_ver != IWL_FW_CMD_VER_UNKNOWN) + return -EOPNOTSUPP; if (iwl_mvm_has_new_rx_stats_api(mvm)) bufsz = ((sizeof(struct mvm_statistics_rx) / @@ -1148,6 +981,101 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file, } #undef PRINT_STAT_LE32 +static ssize_t iwl_dbgfs_fw_system_stats_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + char *buff, *pos, *endpos; + int ret; + size_t bufsz; + int i; + struct iwl_mvm_vif *mvmvif; + struct ieee80211_vif *vif; + struct iwl_mvm *mvm = file->private_data; + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, + WIDE_ID(SYSTEM_GROUP, + SYSTEM_STATISTICS_CMD), + IWL_FW_CMD_VER_UNKNOWN); + + /* in case of a wrong cmd version, allocate buffer only for error msg */ + bufsz = (cmd_ver == 1) ? 4096 : 64; + + buff = kzalloc(bufsz, GFP_KERNEL); + if (!buff) + return -ENOMEM; + + pos = buff; + endpos = pos + bufsz; + + if (cmd_ver != 1) { + pos += scnprintf(pos, endpos - pos, + "System stats not supported:%d\n", cmd_ver); + goto send_out; + } + + mutex_lock(&mvm->mutex); + if (iwl_mvm_firmware_running(mvm)) + iwl_mvm_request_statistics(mvm, false); + + for (i = 0; i < NUM_MAC_INDEX_DRIVER; i++) { + vif = iwl_mvm_rcu_dereference_vif_id(mvm, i, false); + if (!vif) + continue; + + if (vif->type == NL80211_IFTYPE_STATION) + break; + } + + if (i == NUM_MAC_INDEX_DRIVER || !vif) { + pos += scnprintf(pos, endpos - pos, "vif is NULL\n"); + goto release_send_out; + } + + mvmvif = iwl_mvm_vif_from_mac80211(vif); + if (!mvmvif) { + pos += scnprintf(pos, endpos - pos, "mvmvif is NULL\n"); + goto release_send_out; + } + + for_each_mvm_vif_valid_link(mvmvif, i) { + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[i]; + + pos += scnprintf(pos, endpos - pos, + "link_id %d", i); + pos += scnprintf(pos, endpos - pos, + " num_beacons %d", + link_info->beacon_stats.num_beacons); + pos += scnprintf(pos, endpos - pos, + " accu_num_beacons %d", + link_info->beacon_stats.accu_num_beacons); + pos += scnprintf(pos, endpos - pos, + " avg_signal %d\n", + link_info->beacon_stats.avg_signal); + } + + pos += scnprintf(pos, endpos - pos, + "radio_stats.rx_time %lld\n", + mvm->radio_stats.rx_time); + pos += scnprintf(pos, endpos - pos, + "radio_stats.tx_time %lld\n", + mvm->radio_stats.tx_time); + pos += scnprintf(pos, endpos - pos, + "accu_radio_stats.rx_time %lld\n", + mvm->accu_radio_stats.rx_time); + pos += scnprintf(pos, endpos - pos, + "accu_radio_stats.tx_time %lld\n", + mvm->accu_radio_stats.tx_time); + +release_send_out: + mutex_unlock(&mvm->mutex); + +send_out: + ret = simple_read_from_buffer(user_buf, count, ppos, buff, pos - buff); + kfree(buff); + + return ret; +} + static ssize_t iwl_dbgfs_frame_stats_read(struct iwl_mvm *mvm, char __user *user_buf, size_t count, loff_t *ppos, @@ -1260,6 +1188,8 @@ static ssize_t iwl_dbgfs_fw_nmi_write(struct iwl_mvm *mvm, char *buf, if (!iwl_mvm_firmware_running(mvm)) return -EIO; + IWL_ERR(mvm, "Triggering an NMI from debugfs\n"); + if (count == 6 && !strcmp(buf, "nolog\n")) set_bit(IWL_MVM_STATUS_SUPPRESS_ERROR_LOG_ONCE, &mvm->status); @@ -1383,7 +1313,7 @@ static ssize_t iwl_dbgfs_inject_packet_write(struct iwl_mvm *mvm, /* supporting only MQ RX */ if (!mvm->trans->trans_cfg->mq_rx_supported) - return -ENOTSUPP; + return -EOPNOTSUPP; rxb._page = alloc_pages(GFP_ATOMIC, 0); if (!rxb._page) @@ -1481,6 +1411,15 @@ static int _iwl_dbgfs_inject_beacon_ie(struct iwl_mvm *mvm, char *bin, int len) &beacon_cmd.tim_size, beacon->data, beacon->len); + if (iwl_fw_lookup_cmd_ver(mvm->fw, + BEACON_TEMPLATE_CMD, 0) >= 14) { + u32 offset = iwl_mvm_find_ie_offset(beacon->data, + WLAN_EID_S1G_TWT, + beacon->len); + + beacon_cmd.btwt_offset = cpu_to_le32(offset); + } + iwl_mvm_mac_ctxt_send_beacon_cmd(mvm, beacon, &beacon_cmd, sizeof(beacon_cmd)); } @@ -1576,6 +1515,20 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm, return count; } +static ssize_t iwl_dbgfs_fw_dbg_clear_write(struct iwl_mvm *mvm, + char *buf, size_t count, + loff_t *ppos) +{ + if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_9000) + return -EOPNOTSUPP; + + mutex_lock(&mvm->mutex); + iwl_fw_dbg_clear_monitor_buf(&mvm->fwrt); + mutex_unlock(&mvm->mutex); + + return count; +} + static ssize_t iwl_dbgfs_dbg_time_point_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) @@ -1677,7 +1630,7 @@ static ssize_t _iwl_dbgfs_link_sta_##name##_write(struct file *file, \ char buf[buflen] = {}; \ size_t buf_size = min(count, sizeof(buf) - 1); \ \ - if (copy_from_user(buf, user_buf, sizeof(buf))) \ + if (copy_from_user(buf, user_buf, buf_size)) \ return -EFAULT; \ \ return _iwl_dbgfs_link_sta_wrap_write(iwl_dbgfs_##name##_write, \ @@ -2002,30 +1955,28 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64); /* Device wide debugfs entries */ MVM_DEBUGFS_READ_FILE_OPS(ctdp_budget); MVM_DEBUGFS_WRITE_FILE_OPS(stop_ctdp, 8); +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(sta_drain, 8); 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); MVM_DEBUGFS_READ_LINK_STA_FILE_OPS(rs_data); -MVM_DEBUGFS_READ_FILE_OPS(bt_notif); -MVM_DEBUGFS_READ_FILE_OPS(bt_cmd); MVM_DEBUGFS_READ_WRITE_FILE_OPS(disable_power_off, 64); MVM_DEBUGFS_READ_FILE_OPS(fw_rx_stats); MVM_DEBUGFS_READ_FILE_OPS(drv_rx_stats); +MVM_DEBUGFS_READ_FILE_OPS(fw_system_stats); MVM_DEBUGFS_READ_FILE_OPS(fw_ver); MVM_DEBUGFS_READ_FILE_OPS(phy_integration_ver); MVM_DEBUGFS_READ_FILE_OPS(tas_get_status); MVM_DEBUGFS_WRITE_FILE_OPS(fw_restart, 10); MVM_DEBUGFS_WRITE_FILE_OPS(fw_nmi, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10); -MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10); 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_collect, 64); +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)); @@ -2208,28 +2159,26 @@ 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(sta_drain, 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); MVM_DEBUGFS_ADD_FILE(stop_ctdp, mvm->debugfs_dir, 0200); + MVM_DEBUGFS_ADD_FILE(start_ctdp, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(force_ctkill, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(stations, mvm->debugfs_dir, 0400); - MVM_DEBUGFS_ADD_FILE(bt_notif, mvm->debugfs_dir, 0400); - MVM_DEBUGFS_ADD_FILE(bt_cmd, mvm->debugfs_dir, 0400); MVM_DEBUGFS_ADD_FILE(disable_power_off, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(fw_ver, mvm->debugfs_dir, 0400); MVM_DEBUGFS_ADD_FILE(fw_rx_stats, mvm->debugfs_dir, 0400); MVM_DEBUGFS_ADD_FILE(drv_rx_stats, mvm->debugfs_dir, 0400); + MVM_DEBUGFS_ADD_FILE(fw_system_stats, mvm->debugfs_dir, 0400); MVM_DEBUGFS_ADD_FILE(fw_restart, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(fw_nmi, mvm->debugfs_dir, 0200); - MVM_DEBUGFS_ADD_FILE(bt_tx_prio, mvm->debugfs_dir, 0200); - MVM_DEBUGFS_ADD_FILE(bt_force_ant, mvm->debugfs_dir, 0200); MVM_DEBUGFS_ADD_FILE(scan_ant_rxchain, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, 0600); MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, 0200); + 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); @@ -2283,6 +2232,9 @@ void iwl_mvm_dbgfs_register(struct iwl_mvm *mvm) debugfs_create_file("mem", 0600, mvm->debugfs_dir, mvm, &iwl_dbgfs_mem_ops); + debugfs_create_bool("rx_ts_ptp", 0600, mvm->debugfs_dir, + &mvm->rx_ts_ptp); + #if defined(__linux__) /* * Create a symlink with mac80211. It will be removed when mac80211 diff --git a/sys/contrib/dev/iwlwifi/mvm/debugfs.h b/sys/contrib/dev/iwlwifi/mvm/debugfs.h index 0711ab689c48..cc2c45b45ddc 100644 --- a/sys/contrib/dev/iwlwifi/mvm/debugfs.h +++ b/sys/contrib/dev/iwlwifi/mvm/debugfs.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ /* + * Copyright (C) 2023 Intel Corporation * Copyright (C) 2012-2014 Intel Corporation * Copyright (C) 2013-2014 Intel Mobile Communications GmbH */ diff --git a/sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c b/sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c index bc7451e77f25..b0371acb98ca 100644 --- a/sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c +++ b/sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <linux/etherdevice.h> #include <linux/math64.h> @@ -40,6 +40,12 @@ struct iwl_mvm_ftm_pasn_entry { u32 flags; }; +struct iwl_mvm_ftm_iter_data { + u8 *cipher; + u8 *bssid; + u8 *tk; +}; + int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, u8 *addr, u32 cipher, u8 *tk, u32 tk_len, u8 *hltk, u32 hltk_len) @@ -53,6 +59,8 @@ int iwl_mvm_ftm_add_pasn_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (!pasn) return -ENOBUFS; + iwl_mvm_ftm_remove_pasn_sta(mvm, addr); + pasn->cipher = iwl_mvm_cipher_to_location_cipher(cipher); switch (pasn->cipher) { @@ -433,47 +441,55 @@ iwl_mvm_ftm_put_target_v2(struct iwl_mvm *mvm, return 0; } -#define FTM_PUT_FLAG(flag) (target->initiator_ap_flags |= \ +#define FTM_SET_FLAG(flag) (*flags |= \ cpu_to_le32(IWL_INITIATOR_AP_FLAGS_##flag)) static void -iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm, - struct cfg80211_pmsr_request_peer *peer, - struct iwl_tof_range_req_ap_entry_v6 *target) +iwl_mvm_ftm_set_target_flags(struct iwl_mvm *mvm, + struct cfg80211_pmsr_request_peer *peer, + __le32 *flags) { - memcpy(target->bssid, peer->addr, ETH_ALEN); - target->burst_period = - cpu_to_le16(peer->ftm.burst_period); - target->samples_per_burst = peer->ftm.ftms_per_burst; - target->num_of_bursts = peer->ftm.num_bursts_exp; - target->ftmr_max_retries = peer->ftm.ftmr_retries; - target->initiator_ap_flags = cpu_to_le32(0); + *flags = cpu_to_le32(0); if (peer->ftm.asap) - FTM_PUT_FLAG(ASAP); + FTM_SET_FLAG(ASAP); if (peer->ftm.request_lci) - FTM_PUT_FLAG(LCI_REQUEST); + FTM_SET_FLAG(LCI_REQUEST); if (peer->ftm.request_civicloc) - FTM_PUT_FLAG(CIVIC_REQUEST); + FTM_SET_FLAG(CIVIC_REQUEST); if (IWL_MVM_FTM_INITIATOR_DYNACK) - FTM_PUT_FLAG(DYN_ACK); + FTM_SET_FLAG(DYN_ACK); if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_LINEAR_REG) - FTM_PUT_FLAG(ALGO_LR); + FTM_SET_FLAG(ALGO_LR); else if (IWL_MVM_FTM_INITIATOR_ALGO == IWL_TOF_ALGO_TYPE_FFT) - FTM_PUT_FLAG(ALGO_FFT); + FTM_SET_FLAG(ALGO_FFT); if (peer->ftm.trigger_based) - FTM_PUT_FLAG(TB); + FTM_SET_FLAG(TB); else if (peer->ftm.non_trigger_based) - FTM_PUT_FLAG(NON_TB); + FTM_SET_FLAG(NON_TB); if ((peer->ftm.trigger_based || peer->ftm.non_trigger_based) && peer->ftm.lmr_feedback) - FTM_PUT_FLAG(LMR_FEEDBACK); + FTM_SET_FLAG(LMR_FEEDBACK); +} + +static void +iwl_mvm_ftm_put_target_common(struct iwl_mvm *mvm, + struct cfg80211_pmsr_request_peer *peer, + struct iwl_tof_range_req_ap_entry_v6 *target) +{ + memcpy(target->bssid, peer->addr, ETH_ALEN); + target->burst_period = + cpu_to_le16(peer->ftm.burst_period); + target->samples_per_burst = peer->ftm.ftms_per_burst; + target->num_of_bursts = peer->ftm.num_bursts_exp; + target->ftmr_max_retries = peer->ftm.ftmr_retries; + iwl_mvm_ftm_set_target_flags(mvm, peer, &target->initiator_ap_flags); } static int @@ -516,21 +532,10 @@ iwl_mvm_ftm_put_target_v4(struct iwl_mvm *mvm, return 0; } -static int -iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct cfg80211_pmsr_request_peer *peer, - struct iwl_tof_range_req_ap_entry_v6 *target) +static int iwl_mvm_ftm_set_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request_peer *peer, + u8 *sta_id, __le32 *flags) { - int ret; - - ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num, - &target->format_bw, - &target->ctrl_ch_position); - if (ret) - return ret; - - iwl_mvm_ftm_put_target_common(mvm, peer, target); - if (vif->cfg.assoc) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); struct ieee80211_sta *sta; @@ -542,8 +547,8 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (memcmp(peer->addr, link_conf->bssid, ETH_ALEN)) continue; - target->sta_id = mvmvif->link[link_id]->ap_sta_id; - sta = rcu_dereference(mvm->fw_id_to_mac_id[target->sta_id]); + *sta_id = mvmvif->link[link_id]->ap_sta_id; + sta = rcu_dereference(mvm->fw_id_to_mac_id[*sta_id]); if (WARN_ON_ONCE(IS_ERR_OR_NULL(sta))) { rcu_read_unlock(); return PTR_ERR_OR_ZERO(sta); @@ -551,14 +556,42 @@ iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (sta->mfp && (peer->ftm.trigger_based || peer->ftm.non_trigger_based)) - FTM_PUT_FLAG(PMF); + FTM_SET_FLAG(PMF); break; } rcu_read_unlock(); + +#ifdef CONFIG_IWLWIFI_DEBUGFS + if (mvmvif->ftm_unprotected) { + *sta_id = IWL_MVM_INVALID_STA; + *flags &= ~cpu_to_le32(IWL_INITIATOR_AP_FLAGS_PMF); + } +#endif } else { - target->sta_id = IWL_MVM_INVALID_STA; + *sta_id = IWL_MVM_INVALID_STA; } + return 0; +} + +static int +iwl_mvm_ftm_put_target(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request_peer *peer, + struct iwl_tof_range_req_ap_entry_v6 *target) +{ + int ret; + + ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num, + &target->format_bw, + &target->ctrl_ch_position); + if (ret) + return ret; + + iwl_mvm_ftm_put_target_common(mvm, peer, target); + + iwl_mvm_ftm_set_sta(mvm, vif, peer, &target->sta_id, + &target->initiator_ap_flags); + /* * TODO: Beacon interval is currently unknown, so use the common value * of 100 TUs. @@ -696,57 +729,62 @@ static void iter(struct ieee80211_hw *hw, struct ieee80211_key_conf *key, void *data) { - struct iwl_tof_range_req_ap_entry_v6 *target = data; + struct iwl_mvm_ftm_iter_data *target = data; if (!sta || memcmp(sta->addr, target->bssid, ETH_ALEN)) return; WARN_ON(!sta->mfp); - if (WARN_ON(key->keylen > sizeof(target->tk))) - return; - - memcpy(target->tk, key->key, key->keylen); - target->cipher = iwl_mvm_cipher_to_location_cipher(key->cipher); - WARN_ON(target->cipher == IWL_LOCATION_CIPHER_INVALID); + target->tk = key->key; + *target->cipher = iwl_mvm_cipher_to_location_cipher(key->cipher); + WARN_ON(*target->cipher == IWL_LOCATION_CIPHER_INVALID); } static void iwl_mvm_ftm_set_secured_ranging(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct iwl_tof_range_req_ap_entry_v7 *target) + u8 *bssid, u8 *cipher, u8 *hltk, u8 *tk, + u8 *rx_pn, u8 *tx_pn, __le32 *flags) { struct iwl_mvm_ftm_pasn_entry *entry; - u32 flags = le32_to_cpu(target->initiator_ap_flags); +#ifdef CONFIG_IWLWIFI_DEBUGFS + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + + if (mvmvif->ftm_unprotected) + return; +#endif - if (!(flags & (IWL_INITIATOR_AP_FLAGS_NON_TB | + if (!(le32_to_cpu(*flags) & (IWL_INITIATOR_AP_FLAGS_NON_TB | IWL_INITIATOR_AP_FLAGS_TB))) return; lockdep_assert_held(&mvm->mutex); list_for_each_entry(entry, &mvm->ftm_initiator.pasn_list, list) { - if (memcmp(entry->addr, target->bssid, sizeof(entry->addr))) + if (memcmp(entry->addr, bssid, sizeof(entry->addr))) continue; - target->cipher = entry->cipher; + *cipher = entry->cipher; if (entry->flags & IWL_MVM_PASN_FLAG_HAS_HLTK) - memcpy(target->hltk, entry->hltk, sizeof(target->hltk)); + memcpy(hltk, entry->hltk, sizeof(entry->hltk)); else - memset(target->hltk, 0, sizeof(target->hltk)); + memset(hltk, 0, sizeof(entry->hltk)); if (vif->cfg.assoc && - !memcmp(vif->bss_conf.bssid, target->bssid, - sizeof(target->bssid))) - ieee80211_iter_keys(mvm->hw, vif, iter, target); - else - memcpy(target->tk, entry->tk, sizeof(target->tk)); + !memcmp(vif->bss_conf.bssid, bssid, ETH_ALEN)) { + struct iwl_mvm_ftm_iter_data target; - memcpy(target->rx_pn, entry->rx_pn, sizeof(target->rx_pn)); - memcpy(target->tx_pn, entry->tx_pn, sizeof(target->tx_pn)); + target.bssid = bssid; + ieee80211_iter_keys(mvm->hw, vif, iter, &target); + } else { + memcpy(tk, entry->tk, sizeof(entry->tk)); + } - target->initiator_ap_flags |= - cpu_to_le32(IWL_INITIATOR_AP_FLAGS_SECURED); + memcpy(rx_pn, entry->rx_pn, sizeof(entry->rx_pn)); + memcpy(tx_pn, entry->tx_pn, sizeof(entry->tx_pn)); + + FTM_SET_FLAG(SECURED); return; } } @@ -760,7 +798,11 @@ iwl_mvm_ftm_put_target_v7(struct iwl_mvm *mvm, struct ieee80211_vif *vif, if (err) return err; - iwl_mvm_ftm_set_secured_ranging(mvm, vif, target); + iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid, + &target->cipher, target->hltk, + target->tk, target->rx_pn, + target->tx_pn, + &target->initiator_ap_flags); return err; } @@ -825,9 +867,10 @@ iwl_mvm_ftm_put_target_v8(struct iwl_mvm *mvm, struct ieee80211_vif *vif, * If secure LTF is turned off, replace the flag with PMF only */ flags = le32_to_cpu(target->initiator_ap_flags); - if ((flags & IWL_INITIATOR_AP_FLAGS_SECURED) && - !IWL_MVM_FTM_INITIATOR_SECURE_LTF) { - flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; + if (flags & IWL_INITIATOR_AP_FLAGS_SECURED) { + if (!IWL_MVM_FTM_INITIATOR_SECURE_LTF) + flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; + flags |= IWL_INITIATOR_AP_FLAGS_PMF; target->initiator_ap_flags = cpu_to_le32(flags); } @@ -906,6 +949,105 @@ static int iwl_mvm_ftm_start_v13(struct iwl_mvm *mvm, return iwl_mvm_ftm_send_cmd(mvm, &hcmd); } +static int +iwl_mvm_ftm_put_target_v10(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct cfg80211_pmsr_request_peer *peer, + struct iwl_tof_range_req_ap_entry_v10 *target) +{ + u32 i2r_max_sts, flags; + int ret; + + ret = iwl_mvm_ftm_target_chandef_v2(mvm, peer, &target->channel_num, + &target->format_bw, + &target->ctrl_ch_position); + if (ret) + return ret; + + memcpy(target->bssid, peer->addr, ETH_ALEN); + target->burst_period = + cpu_to_le16(peer->ftm.burst_period); + target->samples_per_burst = peer->ftm.ftms_per_burst; + target->num_of_bursts = peer->ftm.num_bursts_exp; + iwl_mvm_ftm_set_target_flags(mvm, peer, &target->initiator_ap_flags); + iwl_mvm_ftm_set_sta(mvm, vif, peer, &target->sta_id, + &target->initiator_ap_flags); + iwl_mvm_ftm_set_secured_ranging(mvm, vif, target->bssid, + &target->cipher, target->hltk, + target->tk, target->rx_pn, + target->tx_pn, + &target->initiator_ap_flags); + + i2r_max_sts = IWL_MVM_FTM_I2R_MAX_STS > 1 ? 1 : + IWL_MVM_FTM_I2R_MAX_STS; + + target->r2i_ndp_params = IWL_MVM_FTM_R2I_MAX_REP | + (IWL_MVM_FTM_R2I_MAX_STS << IWL_LOCATION_MAX_STS_POS) | + (IWL_MVM_FTM_R2I_MAX_TOTAL_LTF << IWL_LOCATION_TOTAL_LTF_POS); + target->i2r_ndp_params = IWL_MVM_FTM_I2R_MAX_REP | + (i2r_max_sts << IWL_LOCATION_MAX_STS_POS) | + (IWL_MVM_FTM_I2R_MAX_TOTAL_LTF << IWL_LOCATION_TOTAL_LTF_POS); + + if (peer->ftm.non_trigger_based) { + target->min_time_between_msr = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MIN_TIME_BETWEEN_MSR); + target->burst_period = + cpu_to_le16(IWL_MVM_FTM_NON_TB_MAX_TIME_BETWEEN_MSR); + } else { + target->min_time_between_msr = cpu_to_le16(0); + } + + target->band = + iwl_mvm_phy_band_from_nl80211(peer->chandef.chan->band); + + /* + * TODO: Beacon interval is currently unknown, so use the common value + * of 100 TUs. + */ + target->beacon_interval = cpu_to_le16(100); + + /* + * If secure LTF is turned off, replace the flag with PMF only + */ + flags = le32_to_cpu(target->initiator_ap_flags); + if (flags & IWL_INITIATOR_AP_FLAGS_SECURED) { + if (!IWL_MVM_FTM_INITIATOR_SECURE_LTF) + flags &= ~IWL_INITIATOR_AP_FLAGS_SECURED; + + flags |= IWL_INITIATOR_AP_FLAGS_PMF; + target->initiator_ap_flags = cpu_to_le32(flags); + } + + return 0; +} + +static int iwl_mvm_ftm_start_v14(struct iwl_mvm *mvm, + struct ieee80211_vif *vif, + struct cfg80211_pmsr_request *req) +{ + struct iwl_tof_range_req_cmd_v14 cmd; + struct iwl_host_cmd hcmd = { + .id = WIDE_ID(LOCATION_GROUP, TOF_RANGE_REQ_CMD), + .dataflags[0] = IWL_HCMD_DFL_DUP, + .data[0] = &cmd, + .len[0] = sizeof(cmd), + }; + u8 i; + int err; + + iwl_mvm_ftm_cmd_common(mvm, vif, (void *)&cmd, req); + + for (i = 0; i < cmd.num_of_ap; i++) { + struct cfg80211_pmsr_request_peer *peer = &req->peers[i]; + struct iwl_tof_range_req_ap_entry_v10 *target = &cmd.ap[i]; + + err = iwl_mvm_ftm_put_target_v10(mvm, vif, peer, target); + if (err) + return err; + } + + return iwl_mvm_ftm_send_cmd(mvm, &hcmd); +} + int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct cfg80211_pmsr_request *req) { @@ -924,6 +1066,9 @@ int iwl_mvm_ftm_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif, IWL_FW_CMD_VER_UNKNOWN); switch (cmd_ver) { + case 14: + err = iwl_mvm_ftm_start_v14(mvm, vif, req); + break; case 13: err = iwl_mvm_ftm_start_v13(mvm, vif, req); break; diff --git a/sys/contrib/dev/iwlwifi/mvm/ftm-responder.c b/sys/contrib/dev/iwlwifi/mvm/ftm-responder.c index 769a344ced8e..3e989f3141b5 100644 --- a/sys/contrib/dev/iwlwifi/mvm/ftm-responder.c +++ b/sys/contrib/dev/iwlwifi/mvm/ftm-responder.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* * Copyright (C) 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2022 Intel Corporation + * Copyright (C) 2018-2024 Intel Corporation */ #include <net/cfg80211.h> #include <linux/etherdevice.h> @@ -12,6 +12,9 @@ struct iwl_mvm_pasn_sta { struct list_head list; struct iwl_mvm_int_sta int_sta; u8 addr[ETH_ALEN]; + + /* must be last as it followed by buffer holding the key */ + struct ieee80211_key_conf keyconf; }; struct iwl_mvm_pasn_hltk_data { @@ -39,7 +42,7 @@ static int iwl_mvm_ftm_responder_set_bw_v1(struct cfg80211_chan_def *chandef, *ctrl_ch_position = iwl_mvm_get_ctrl_pos(chandef); break; default: - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; @@ -77,7 +80,7 @@ static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, } fallthrough; default: - return -ENOTSUPP; + return -EOPNOTSUPP; } return 0; @@ -85,7 +88,7 @@ static int iwl_mvm_ftm_responder_set_bw_v2(struct cfg80211_chan_def *chandef, static void iwl_mvm_ftm_responder_set_ndp(struct iwl_mvm *mvm, - struct iwl_tof_responder_config_cmd_v9 *cmd) + struct iwl_tof_responder_config_cmd *cmd) { /* Up to 2 R2I STS are allowed on the responder */ u32 r2i_max_sts = IWL_MVM_FTM_R2I_MAX_STS < 2 ? @@ -114,7 +117,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, * field interpretation is different), so the same struct can be use * for all cases. */ - struct iwl_tof_responder_config_cmd_v9 cmd = { + struct iwl_tof_responder_config_cmd cmd = { .channel_num = chandef->chan->hw_value, .cmd_valid_fields = cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_CHAN_INFO | @@ -128,8 +131,13 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, lockdep_assert_held(&mvm->mutex); + if (cmd_ver == 10) { + cmd.band = + iwl_mvm_phy_band_from_nl80211(chandef->chan->band); + } + /* Use a default of bss_color=1 for now */ - if (cmd_ver == 9) { + if (cmd_ver >= 9) { cmd.cmd_valid_fields |= cpu_to_le32(IWL_TOF_RESPONDER_CMD_VALID_BSS_COLOR | IWL_TOF_RESPONDER_CMD_VALID_MIN_MAX_TIME_BETWEEN_MSR); @@ -145,7 +153,7 @@ iwl_mvm_ftm_responder_cmd(struct iwl_mvm *mvm, } if (cmd_ver >= 8) - iwl_mvm_ftm_responder_set_ndp(mvm, &cmd); + iwl_mvm_ftm_responder_set_ndp(mvm, (void *)&cmd); if (cmd_ver >= 7) err = iwl_mvm_ftm_responder_set_bw_v2(chandef, &cmd.format_bw, @@ -291,7 +299,7 @@ iwl_mvm_ftm_responder_dyn_cfg_cmd(struct iwl_mvm *mvm, default: IWL_ERR(mvm, "Unsupported DYN_CONFIG_CMD version %u\n", cmd_ver); - ret = -ENOTSUPP; + ret = -EOPNOTSUPP; } return ret; @@ -302,7 +310,16 @@ static void iwl_mvm_resp_del_pasn_sta(struct iwl_mvm *mvm, struct iwl_mvm_pasn_sta *sta) { list_del(&sta->list); - iwl_mvm_rm_sta_id(mvm, vif, sta->int_sta.sta_id); + + if (sta->keyconf.keylen) + iwl_mvm_sec_key_del_pasn(mvm, vif, BIT(sta->int_sta.sta_id), + &sta->keyconf); + + if (iwl_mvm_has_mld_api(mvm->fw)) + iwl_mvm_mld_rm_sta_id(mvm, sta->int_sta.sta_id); + else + iwl_mvm_rm_sta_id(mvm, vif, sta->int_sta.sta_id); + iwl_mvm_dealloc_int_sta(mvm, &sta->int_sta); kfree(sta); } @@ -329,7 +346,7 @@ int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, if (cmd_ver < 3) { IWL_ERR(mvm, "Adding PASN station not supported by FW\n"); - return -ENOTSUPP; + return -EOPNOTSUPP; } if ((!hltk || !hltk_len) && (!tk || !tk_len)) { @@ -338,6 +355,12 @@ int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, } if (hltk && hltk_len) { + if (!fw_has_capa(&mvm->fw->ucode_capa, + IWL_UCODE_TLV_CAPA_SECURE_LTF_SUPPORT)) { + IWL_ERR(mvm, "No support for secure LTF measurement\n"); + return -EINVAL; + } + hltk_data.cipher = iwl_mvm_cipher_to_location_cipher(cipher); if (hltk_data.cipher == IWL_LOCATION_CIPHER_INVALID) { IWL_ERR(mvm, "invalid cipher: %u\n", cipher); @@ -348,12 +371,12 @@ int iwl_mvm_ftm_respoder_add_pasn_sta(struct iwl_mvm *mvm, } if (tk && tk_len) { - sta = kzalloc(sizeof(*sta), GFP_KERNEL); + sta = kzalloc(sizeof(*sta) + tk_len, GFP_KERNEL); if (!sta) return -ENOBUFS; ret = iwl_mvm_add_pasn_sta(mvm, vif, &sta->int_sta, addr, - cipher, tk, tk_len); + cipher, tk, tk_len, &sta->keyconf); if (ret) { kfree(sta); return ret; @@ -422,7 +445,7 @@ int iwl_mvm_ftm_start_responder(struct iwl_mvm *mvm, struct ieee80211_vif *vif, rcu_read_unlock(); phy_ctxt = &mvm->phy_ctxts[*phy_ctxt_id]; - ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, + ret = iwl_mvm_phy_ctxt_changed(mvm, phy_ctxt, &ctx.def, &ctx.ap, ctx.rx_chains_static, ctx.rx_chains_dynamic); if (ret) diff --git a/sys/contrib/dev/iwlwifi/mvm/fw.c b/sys/contrib/dev/iwlwifi/mvm/fw.c index 1d5ee4330f29..08c4898c8f1a 100644 --- a/sys/contrib/dev/iwlwifi/mvm/fw.c +++ b/sys/contrib/dev/iwlwifi/mvm/fw.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2012-2014, 2018-2023 Intel Corporation + * Copyright (C) 2012-2014, 2018-2024 Intel Corporation * Copyright (C) 2013-2015 Intel Mobile Communications GmbH * Copyright (C) 2016-2017 Intel Deutschland GmbH */ @@ -15,6 +15,8 @@ #include "iwl-prph.h" #include "fw/acpi.h" #include "fw/pnvm.h" +#include "fw/uefi.h" +#include "fw/regulatory.h" #include "mvm.h" #include "fw/dbg.h" @@ -23,12 +25,9 @@ #include "iwl-nvm-parse.h" #include "time-sync.h" -#define MVM_UCODE_ALIVE_TIMEOUT (HZ) +#define MVM_UCODE_ALIVE_TIMEOUT (2 * HZ) #define MVM_UCODE_CALIB_TIMEOUT (2 * HZ) -#define IWL_TAS_US_MCC 0x5553 -#define IWL_TAS_CANADA_MCC 0x4341 - struct iwl_mvm_alive_data { bool valid; u32 scd_base_addr; @@ -92,20 +91,10 @@ void iwl_mvm_mfu_assert_dump_notif(struct iwl_mvm *mvm, { struct iwl_rx_packet *pkt = rxb_addr(rxb); struct iwl_mfu_assert_dump_notif *mfu_dump_notif = (void *)pkt->data; - __le32 *dump_data = mfu_dump_notif->data; - int n_words = le32_to_cpu(mfu_dump_notif->data_size) / sizeof(__le32); - int i; if (mfu_dump_notif->index_num == 0) IWL_INFO(mvm, "MFUART assert id 0x%x occurred\n", le32_to_cpu(mfu_dump_notif->assert_id)); - - for (i = 0; i < n_words; i++) - IWL_DEBUG_INFO(mvm, - "MFUART assert dump, dword %u: 0x%08x\n", - le16_to_cpu(mfu_dump_notif->index_num) * - n_words + i, - le32_to_cpu(dump_data[i])); } static bool iwl_alive_fn(struct iwl_notif_wait_data *notif_wait, @@ -416,7 +405,7 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, UREG_LMAC2_CURRENT_PC)); } - if (ret == -ETIMEDOUT && !mvm->pldr_sync) + if (ret == -ETIMEDOUT && !mvm->fw_product_reset) iwl_fw_dbg_error_collect(&mvm->fwrt, FW_DBG_TRIGGER_ALIVE_TIMEOUT); @@ -468,12 +457,14 @@ static int iwl_mvm_load_ucode_wait_alive(struct iwl_mvm *mvm, #endif /* + * For pre-MLD API (MLD API doesn't use the timestamps): * All the BSSes in the BSS table include the GP2 in the system * at the beacon Rx time, this is of course no longer relevant * since we are resetting the firmware. * Purge all the BSS table. */ - cfg80211_bss_flush(mvm->hw->wiphy); + if (!mvm->mld_api_is_used) + cfg80211_bss_flush(mvm->hw->wiphy); return 0; } @@ -486,7 +477,47 @@ static void iwl_mvm_phy_filter_init(struct iwl_mvm *mvm, #endif /* CONFIG_ACPI */ } -#if defined(CONFIG_ACPI) && defined(CONFIG_EFI) +static void iwl_mvm_uats_init(struct iwl_mvm *mvm) +{ + u8 cmd_ver; + int ret; + struct iwl_host_cmd cmd = { + .id = WIDE_ID(REGULATORY_AND_NVM_GROUP, + MCC_ALLOWED_AP_TYPE_CMD), + .flags = 0, + .data[0] = &mvm->fwrt.uats_table, + .len[0] = sizeof(mvm->fwrt.uats_table), + .dataflags[0] = IWL_HCMD_DFL_NOCOPY, + }; + + if (mvm->trans->trans_cfg->device_family < IWL_DEVICE_FAMILY_AX210) { + IWL_DEBUG_RADIO(mvm, "UATS feature is not supported\n"); + return; + } + + cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd.id, + IWL_FW_CMD_VER_UNKNOWN); + if (cmd_ver != 1) { + IWL_DEBUG_RADIO(mvm, + "MCC_ALLOWED_AP_TYPE_CMD ver %d not supported\n", + cmd_ver); + return; + } + + ret = iwl_uefi_get_uats_table(mvm->trans, &mvm->fwrt); + if (ret < 0) { + IWL_DEBUG_FW(mvm, "failed to read UATS table (%d)\n", ret); + return; + } + + ret = iwl_mvm_send_cmd(mvm, &cmd); + if (ret < 0) + IWL_ERR(mvm, "failed to send MCC_ALLOWED_AP_TYPE_CMD (%d)\n", + ret); + else + IWL_DEBUG_RADIO(mvm, "MCC_ALLOWED_AP_TYPE_CMD sent to FW\n"); +} + static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) { u8 cmd_ver; @@ -520,13 +551,6 @@ static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) return ret; } -#else - -static int iwl_mvm_sgom_init(struct iwl_mvm *mvm) -{ - return 0; -} -#endif static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm) { @@ -583,6 +607,7 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) static const u16 init_complete[] = { INIT_COMPLETE_NOTIF, }; + u32 sb_cfg; int ret; if (mvm->trans->cfg->tx_with_siso_diversity) @@ -592,6 +617,14 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) mvm->rfkill_safe_init_done = false; + if (mvm->trans->trans_cfg->device_family == IWL_DEVICE_FAMILY_AX210) { + sb_cfg = iwl_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()) + return -EBUSY; + } + iwl_init_notification_wait(&mvm->notif_wait, &init_wait, init_complete, @@ -605,11 +638,23 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) ret = iwl_mvm_load_ucode_wait_alive(mvm, IWL_UCODE_REGULAR); if (ret) { IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); + + /* if we needed reset then fail here, but notify and remove */ + if (mvm->fw_product_reset) { + iwl_mei_alive_notif(false); + iwl_trans_pcie_remove(mvm->trans, true); + } + goto error; } iwl_dbg_tlv_time_point(&mvm->fwrt, IWL_FW_INI_TIME_POINT_AFTER_ALIVE, NULL); + if (mvm->trans->trans_cfg->device_family >= IWL_DEVICE_FAMILY_BZ) + mvm->trans->step_urm = !!(iwl_read_umac_prph(mvm->trans, + CNVI_PMU_STEP_FLOW) & + CNVI_PMU_STEP_FLOW_FORCE_URM); + /* Send init config command to mark that we are sending NVM access * commands */ @@ -634,14 +679,6 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) goto error; } - if (IWL_MVM_PARSE_NVM && !mvm->nvm_data) { - ret = iwl_nvm_init(mvm); - if (ret) { - IWL_ERR(mvm, "Failed to read NVM: %d\n", ret); - goto error; - } - } - ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, NVM_ACCESS_COMPLETE), CMD_SEND_IN_RFKILL, @@ -666,8 +703,9 @@ static int iwl_run_unified_mvm_ucode(struct iwl_mvm *mvm) return ret; /* Read the NVM only at driver load time, no need to do this twice */ - if (!IWL_MVM_PARSE_NVM && !mvm->nvm_data) { - mvm->nvm_data = iwl_get_nvm(mvm->trans, mvm->fw); + if (!mvm->nvm_data) { + mvm->nvm_data = iwl_get_nvm(mvm->trans, mvm->fw, + mvm->set_tx_ant, mvm->set_rx_ant); if (IS_ERR(mvm->nvm_data)) { ret = PTR_ERR(mvm->nvm_data); mvm->nvm_data = NULL; @@ -790,7 +828,7 @@ remove_notif: iwl_remove_notification(&mvm->notif_wait, &calib_wait); out: mvm->rfkill_safe_init_done = false; - if (iwlmvm_mod_params.init_dbg && !mvm->nvm_data) { + if (!mvm->nvm_data) { /* we want to debug INIT and we have no NVM - fake */ mvm->nvm_data = kzalloc(sizeof(struct iwl_nvm_data) + sizeof(struct ieee80211_channel) + @@ -822,7 +860,6 @@ static int iwl_mvm_config_ltr(struct iwl_mvm *mvm) sizeof(cmd), &cmd); } -#ifdef CONFIG_ACPI int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) { u32 cmd_id = REDUCE_TX_POWER_CMD; @@ -833,13 +870,15 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) int ret; u16 len = 0; u32 n_subbands; - u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, - IWL_FW_CMD_VER_UNKNOWN); - if (cmd_ver == 7) { + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 3); + + if (cmd_ver >= 7) { len = sizeof(cmd.v7); n_subbands = IWL_NUM_SUB_BANDS_V2; per_chain = cmd.v7.per_chain[0][0]; cmd.v7.flags = cpu_to_le32(mvm->fwrt.reduced_power_flags); + if (cmd_ver == 8) + len = sizeof(cmd.v8); } else if (cmd_ver == 6) { len = sizeof(cmd.v6); n_subbands = IWL_NUM_SUB_BANDS_V2; @@ -863,9 +902,9 @@ int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, int prof_a, int prof_b) /* all structs have the same common part, add it */ len += sizeof(cmd.common); - ret = iwl_sar_select_profile(&mvm->fwrt, per_chain, - IWL_NUM_CHAIN_TABLES, - n_subbands, prof_a, prof_b); + ret = iwl_sar_fill_profile(&mvm->fwrt, per_chain, + IWL_NUM_CHAIN_TABLES, + n_subbands, prof_a, prof_b); /* return on error or if the profile is disabled (positive number) */ if (ret) @@ -921,7 +960,7 @@ int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) resp = (void *)cmd.resp_pkt->data; ret = le32_to_cpu(resp->profile_idx); - if (WARN_ON(ret > ACPI_NUM_GEO_PROFILES_REV3)) + if (WARN_ON(ret > BIOS_GEO_MAX_PROFILE_NUM)) ret = -EIO; iwl_free_resp(&cmd); @@ -935,7 +974,7 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) u16 len; u32 n_bands; u32 n_profiles; - u32 sk = 0; + __le32 sk = cpu_to_le32(0); int ret; u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, IWL_FW_CMD_VER_UNKNOWN); @@ -952,27 +991,35 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) /* the ops field is at the same spot for all versions, so set in v1 */ cmd.v1.ops = cpu_to_le32(IWL_PER_CHAIN_OFFSET_SET_TABLES); + /* Only set to South Korea if the table revision is 1 */ + if (mvm->fwrt.geo_rev == 1) + sk = cpu_to_le32(1); + if (cmd_ver == 5) { len = sizeof(cmd.v5); n_bands = ARRAY_SIZE(cmd.v5.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES_REV3; + n_profiles = BIOS_GEO_MAX_PROFILE_NUM; + cmd.v5.table_revision = sk; } else if (cmd_ver == 4) { len = sizeof(cmd.v4); n_bands = ARRAY_SIZE(cmd.v4.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES_REV3; + n_profiles = BIOS_GEO_MAX_PROFILE_NUM; + cmd.v4.table_revision = sk; } else if (cmd_ver == 3) { len = sizeof(cmd.v3); n_bands = ARRAY_SIZE(cmd.v3.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES; + n_profiles = BIOS_GEO_MIN_PROFILE_NUM; + cmd.v3.table_revision = sk; } else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, IWL_UCODE_TLV_API_SAR_TABLE_VER)) { len = sizeof(cmd.v2); n_bands = ARRAY_SIZE(cmd.v2.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES; + n_profiles = BIOS_GEO_MIN_PROFILE_NUM; + cmd.v2.table_revision = sk; } else { len = sizeof(cmd.v1); n_bands = ARRAY_SIZE(cmd.v1.table[0]); - n_profiles = ACPI_NUM_GEO_PROFILES; + n_profiles = BIOS_GEO_MIN_PROFILE_NUM; } BUILD_BUG_ON(offsetof(struct iwl_geo_tx_power_profiles_cmd_v1, table) != @@ -984,8 +1031,8 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) offsetof(struct iwl_geo_tx_power_profiles_cmd_v4, table) != offsetof(struct iwl_geo_tx_power_profiles_cmd_v5, table)); /* the table is at the same position for all versions, so set use v1 */ - ret = iwl_sar_geo_init(&mvm->fwrt, &cmd.v1.table[0][0], - n_bands, n_profiles); + ret = iwl_sar_geo_fill_table(&mvm->fwrt, &cmd.v1.table[0][0], + n_bands, n_profiles); /* * It is a valid scenario to not support SAR, or miss wgds table, @@ -994,27 +1041,6 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) if (ret) return 0; - /* Only set to South Korea if the table revision is 1 */ - if (mvm->fwrt.geo_rev == 1) - sk = 1; - - /* - * Set the table_revision to South Korea (1) or not (0). The - * element name is misleading, as it doesn't contain the table - * revision number, but whether the South Korea variation - * should be used. - * This must be done after calling iwl_sar_geo_init(). - */ - if (cmd_ver == 5) - cmd.v5.table_revision = cpu_to_le32(sk); - else if (cmd_ver == 4) - cmd.v4.table_revision = cpu_to_le32(sk); - else if (cmd_ver == 3) - cmd.v3.table_revision = cpu_to_le32(sk); - else if (fw_has_api(&mvm->fwrt.fw->ucode_capa, - IWL_UCODE_TLV_API_SAR_TABLE_VER)) - cmd.v2.table_revision = cpu_to_le32(sk); - return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd); } @@ -1023,7 +1049,7 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) union iwl_ppag_table_cmd cmd; int ret, cmd_size; - ret = iwl_read_ppag_table(&mvm->fwrt, &cmd, &cmd_size); + ret = iwl_fill_ppag_table(&mvm->fwrt, &cmd, &cmd_size); /* Not supporting PPAG table is a valid scenario */ if (ret < 0) return 0; @@ -1042,74 +1068,19 @@ int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) { /* no need to read the table, done in INIT stage */ - if (!(iwl_acpi_is_ppag_approved(&mvm->fwrt))) + if (!(iwl_is_ppag_approved(&mvm->fwrt))) return 0; return iwl_mvm_ppag_send_cmd(mvm); } -static const struct dmi_system_id dmi_tas_approved_list[] = { - { .ident = "HP", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HP"), - }, - }, - { .ident = "SAMSUNG", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD"), - }, - }, - { .ident = "LENOVO", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - }, - }, - { .ident = "DELL", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - }, - }, - { .ident = "MSFT", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), - }, - }, - { .ident = "Acer", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Acer"), - }, - }, - { .ident = "ASUS", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - }, - }, - { .ident = "MSI", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International Co., Ltd."), - }, - }, - { .ident = "Honor", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "HONOR"), - }, - }, - /* keep last */ - {} -}; - -bool iwl_mvm_is_vendor_in_approved_list(void) -{ - return dmi_check_system(dmi_tas_approved_list); -} - static bool iwl_mvm_add_to_tas_block_list(__le32 *list, __le32 *le_size, unsigned int mcc) { int i; u32 size = le32_to_cpu(*le_size); /* Verify that there is room for another country */ - if (size >= IWL_TAS_BLOCK_LIST_MAX) + if (size >= IWL_WTAS_BLACK_LIST_MAX) return false; for (i = 0; i < size; i++) { @@ -1126,21 +1097,21 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) { u32 cmd_id = WIDE_ID(REGULATORY_AND_NVM_GROUP, TAS_CONFIG); int ret; - union iwl_tas_config_cmd cmd = {}; + struct iwl_tas_data data = {}; + struct iwl_tas_config_cmd cmd = {}; int cmd_size, fw_ver; - BUILD_BUG_ON(ARRAY_SIZE(cmd.v3.block_list_array) < - APCI_WTAS_BLACK_LIST_MAX); + BUILD_BUG_ON(ARRAY_SIZE(data.block_list_array) != + IWL_WTAS_BLACK_LIST_MAX); + BUILD_BUG_ON(ARRAY_SIZE(cmd.common.block_list_array) != + IWL_WTAS_BLACK_LIST_MAX); if (!fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_TAS_CFG)) { IWL_DEBUG_RADIO(mvm, "TAS not enabled in FW\n"); return; } - fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, - IWL_FW_CMD_VER_UNKNOWN); - - ret = iwl_acpi_get_tas(&mvm->fwrt, &cmd, fw_ver); + ret = iwl_bios_get_tas_table(&mvm->fwrt, &data); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "TAS table invalid or unavailable. (%d)\n", @@ -1151,16 +1122,16 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) if (ret == 0) return; - if (!iwl_mvm_is_vendor_in_approved_list()) { + if (!iwl_is_tas_approved()) { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is not in the approved list, disabling TAS in US and Canada.\n", - dmi_get_system_info(DMI_SYS_VENDOR)); - if ((!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array, - &cmd.v4.block_list_size, - IWL_TAS_US_MCC)) || - (!iwl_mvm_add_to_tas_block_list(cmd.v4.block_list_array, - &cmd.v4.block_list_size, - IWL_TAS_CANADA_MCC))) { + dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>"); + if ((!iwl_mvm_add_to_tas_block_list(data.block_list_array, + &data.block_list_size, + IWL_MCC_US)) || + (!iwl_mvm_add_to_tas_block_list(data.block_list_array, + &data.block_list_size, + IWL_MCC_CANADA))) { IWL_DEBUG_RADIO(mvm, "Unable to add US/Canada to TAS block list, disabling TAS\n"); return; @@ -1168,125 +1139,74 @@ static void iwl_mvm_tas_init(struct iwl_mvm *mvm) } else { IWL_DEBUG_RADIO(mvm, "System vendor '%s' is in the approved list.\n", - dmi_get_system_info(DMI_SYS_VENDOR)); + dmi_get_system_info(DMI_SYS_VENDOR) ?: "<unknown>"); + } + + fw_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, + IWL_FW_CMD_VER_UNKNOWN); + + memcpy(&cmd.common, &data, sizeof(struct iwl_tas_config_cmd_common)); + + /* Set v3 or v4 specific parts. will be trunctated for fw_ver < 3 */ + if (fw_ver == 4) { + cmd.v4.override_tas_iec = data.override_tas_iec; + cmd.v4.enable_tas_iec = data.enable_tas_iec; + cmd.v4.usa_tas_uhb_allowed = data.usa_tas_uhb_allowed; + } else { + cmd.v3.override_tas_iec = cpu_to_le16(data.override_tas_iec); + cmd.v3.enable_tas_iec = cpu_to_le16(data.enable_tas_iec); } - /* v4 is the same size as v3, so no need to differentiate here */ - cmd_size = fw_ver < 3 ? - sizeof(struct iwl_tas_config_cmd_v2) : - sizeof(struct iwl_tas_config_cmd_v3); + cmd_size = sizeof(struct iwl_tas_config_cmd_common); + if (fw_ver >= 3) + /* v4 is the same size as v3 */ + cmd_size += sizeof(struct iwl_tas_config_cmd_v3); ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, cmd_size, &cmd); if (ret < 0) IWL_DEBUG_RADIO(mvm, "failed to send TAS_CONFIG (%d)\n", ret); } -static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) +static bool iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) { - u8 value; - int ret = iwl_acpi_get_dsm_u8(mvm->fwrt.dev, 0, DSM_RFI_FUNC_ENABLE, - &iwl_rfi_guid, &value); + u32 value = 0; + /* default behaviour is disabled */ + bool bios_enable_rfi = false; + int ret = iwl_bios_get_dsm(&mvm->fwrt, DSM_FUNC_RFI_CONFIG, &value); + if (ret < 0) { IWL_DEBUG_RADIO(mvm, "Failed to get DSM RFI, ret=%d\n", ret); + return bios_enable_rfi; + } - } else if (value >= DSM_VALUE_RFI_MAX) { - IWL_DEBUG_RADIO(mvm, "DSM RFI got invalid value, ret=%d\n", - value); - - } else if (value == DSM_VALUE_RFI_ENABLE) { + value &= DSM_VALUE_RFI_DISABLE; + /* RFI BIOS CONFIG value can be 0 or 3 only. + * i.e 0 means DDR and DLVR enabled. 3 means DDR and DLVR disabled. + * 1 and 2 are invalid BIOS configurations, So, it's not possible to + * disable ddr/dlvr separately. + */ + if (!value) { IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to enable\n"); - return DSM_VALUE_RFI_ENABLE; + bios_enable_rfi = true; + } else if (value == DSM_VALUE_RFI_DISABLE) { + IWL_DEBUG_RADIO(mvm, "DSM RFI is evaluated to disable\n"); + } else { + IWL_DEBUG_RADIO(mvm, + "DSM RFI got invalid value, value=%d\n", value); } - IWL_DEBUG_RADIO(mvm, "DSM RFI is disabled\n"); - - /* default behaviour is disabled */ - return DSM_VALUE_RFI_DISABLE; + return bios_enable_rfi; } static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) { + struct iwl_lari_config_change_cmd cmd; + size_t cmd_size; int ret; - u32 value; - struct iwl_lari_config_change_cmd_v6 cmd = {}; - - cmd.config_bitmap = iwl_acpi_get_lari_config_bitmap(&mvm->fwrt); - - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, DSM_FUNC_11AX_ENABLEMENT, - &iwl_guid, &value); - if (!ret) - cmd.oem_11ax_allow_bitmap = cpu_to_le32(value); - - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ENABLE_UNII4_CHAN, - &iwl_guid, &value); - if (!ret) - cmd.oem_unii4_allow_bitmap = cpu_to_le32(value); - - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ACTIVATE_CHANNEL, - &iwl_guid, &value); - if (!ret) - cmd.chan_state_active_bitmap = cpu_to_le32(value); - - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_ENABLE_6E, - &iwl_guid, &value); - if (!ret) - cmd.oem_uhb_allow_bitmap = cpu_to_le32(value); - - ret = iwl_acpi_get_dsm_u32(mvm->fwrt.dev, 0, - DSM_FUNC_FORCE_DISABLE_CHANNELS, - &iwl_guid, &value); - if (!ret) - cmd.force_disable_channels_bitmap = cpu_to_le32(value); - - if (cmd.config_bitmap || - cmd.oem_uhb_allow_bitmap || - cmd.oem_11ax_allow_bitmap || - cmd.oem_unii4_allow_bitmap || - cmd.chan_state_active_bitmap || - cmd.force_disable_channels_bitmap) { - size_t cmd_size; - u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, - WIDE_ID(REGULATORY_AND_NVM_GROUP, - LARI_CONFIG_CHANGE), - 1); - switch (cmd_ver) { - case 6: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v6); - break; - case 5: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v5); - break; - case 4: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v4); - break; - case 3: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v3); - break; - case 2: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v2); - break; - default: - cmd_size = sizeof(struct iwl_lari_config_change_cmd_v1); - break; - } - IWL_DEBUG_RADIO(mvm, - "sending LARI_CONFIG_CHANGE, config_bitmap=0x%x, oem_11ax_allow_bitmap=0x%x\n", - le32_to_cpu(cmd.config_bitmap), - le32_to_cpu(cmd.oem_11ax_allow_bitmap)); - IWL_DEBUG_RADIO(mvm, - "sending LARI_CONFIG_CHANGE, oem_unii4_allow_bitmap=0x%x, chan_state_active_bitmap=0x%x, cmd_ver=%d\n", - le32_to_cpu(cmd.oem_unii4_allow_bitmap), - le32_to_cpu(cmd.chan_state_active_bitmap), - cmd_ver); - IWL_DEBUG_RADIO(mvm, - "sending LARI_CONFIG_CHANGE, oem_uhb_allow_bitmap=0x%x, force_disable_channels_bitmap=0x%x\n", - le32_to_cpu(cmd.oem_uhb_allow_bitmap), - le32_to_cpu(cmd.force_disable_channels_bitmap)); + ret = iwl_fill_lari_config(&mvm->fwrt, &cmd, &cmd_size); + if (!ret) { ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(REGULATORY_AND_NVM_GROUP, LARI_CONFIG_CHANGE), @@ -1298,12 +1218,14 @@ static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) } } -void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) +void iwl_mvm_get_bios_tables(struct iwl_mvm *mvm) { int ret; + iwl_acpi_get_guid_lock_status(&mvm->fwrt); + /* read PPAG table */ - ret = iwl_acpi_get_ppag_table(&mvm->fwrt); + ret = iwl_bios_get_ppag_table(&mvm->fwrt); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "PPAG BIOS table invalid or unavailable. (%d)\n", @@ -1311,7 +1233,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) } /* read SAR tables */ - ret = iwl_sar_get_wrds_table(&mvm->fwrt); + ret = iwl_bios_get_wrds_table(&mvm->fwrt); if (ret < 0) { IWL_DEBUG_RADIO(mvm, "WRDS SAR BIOS table invalid or unavailable. (%d)\n", @@ -1320,7 +1242,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) * If not available, don't fail and don't bother with EWRD and * WGDS */ - if (!iwl_sar_get_wgds_table(&mvm->fwrt)) { + if (!iwl_bios_get_wgds_table(&mvm->fwrt)) { /* * If basic SAR is not available, we check for WGDS, * which should *not* be available either. If it is @@ -1331,7 +1253,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) } } else { - ret = iwl_sar_get_ewrd_table(&mvm->fwrt); + ret = iwl_bios_get_ewrd_table(&mvm->fwrt); /* if EWRD is not available, we can still use * WRDS, so don't fail */ if (ret < 0) @@ -1341,7 +1263,7 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) /* read geo SAR table */ if (iwl_sar_geo_support(&mvm->fwrt)) { - ret = iwl_sar_get_wgds_table(&mvm->fwrt); + ret = iwl_bios_get_wgds_table(&mvm->fwrt); if (ret < 0) IWL_DEBUG_RADIO(mvm, "Geo SAR BIOS table invalid or unavailable. (%d)\n", @@ -1351,59 +1273,18 @@ void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) } iwl_acpi_get_phy_filters(&mvm->fwrt, &mvm->phy_filters); -} -#else /* CONFIG_ACPI */ -inline int iwl_mvm_sar_select_profile(struct iwl_mvm *mvm, - int prof_a, int prof_b) -{ - return 1; -} - -inline int iwl_mvm_get_sar_geo_profile(struct iwl_mvm *mvm) -{ - return -ENOENT; + if (iwl_bios_get_eckv(&mvm->fwrt, &mvm->ext_clock_valid)) + IWL_DEBUG_RADIO(mvm, "ECKV table doesn't exist in BIOS\n"); } -static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm) +static void iwl_mvm_disconnect_iterator(void *data, u8 *mac, + struct ieee80211_vif *vif) { - return 0; + if (vif->type == NL80211_IFTYPE_STATION) + ieee80211_hw_restart_disconnect(vif); } -int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm) -{ - return -ENOENT; -} - -static int iwl_mvm_ppag_init(struct iwl_mvm *mvm) -{ - return 0; -} - -static void iwl_mvm_tas_init(struct iwl_mvm *mvm) -{ -} - -static void iwl_mvm_lari_cfg(struct iwl_mvm *mvm) -{ -} - -bool iwl_mvm_is_vendor_in_approved_list(void) -{ - return false; -} - -static u8 iwl_mvm_eval_dsm_rfi(struct iwl_mvm *mvm) -{ - return DSM_VALUE_RFI_DISABLE; -} - -void iwl_mvm_get_acpi_tables(struct iwl_mvm *mvm) -{ -} - -#endif /* CONFIG_ACPI */ - void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) { u32 error_log_size = mvm->fw->ucode_capa.error_log_size; @@ -1448,10 +1329,15 @@ void iwl_mvm_send_recovery_cmd(struct iwl_mvm *mvm, u32 flags) /* skb respond is only relevant in ERROR_RECOVERY_UPDATE_DB */ if (flags & ERROR_RECOVERY_UPDATE_DB) { resp = le32_to_cpu(*(__le32 *)host_cmd.resp_pkt->data); - if (resp) + if (resp) { IWL_ERR(mvm, "Failed to send recovery cmd blob was invalid %d\n", resp); + + ieee80211_iterate_interfaces(mvm->hw, 0, + iwl_mvm_disconnect_iterator, + mvm); + } } } @@ -1471,9 +1357,6 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) if (ret) { IWL_ERR(mvm, "Failed to run INIT ucode: %d\n", ret); - - if (iwlmvm_mod_params.init_dbg) - return 0; return ret; } @@ -1499,10 +1382,7 @@ static int iwl_mvm_load_rt_fw(struct iwl_mvm *mvm) int iwl_mvm_up(struct iwl_mvm *mvm) { int ret, i; - struct ieee80211_channel *chan; - struct cfg80211_chan_def chandef; struct ieee80211_supported_band *sband = NULL; - u32 sb_cfg; lockdep_assert_held(&mvm->mutex); @@ -1510,23 +1390,19 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (ret) return ret; - sb_cfg = iwl_read_umac_prph(mvm->trans, SB_MODIFY_CFG_FLAG); - mvm->pldr_sync = !(sb_cfg & SB_CFG_RESIDES_IN_OTP_MASK); - if (mvm->pldr_sync && iwl_mei_pldr_req()) - return -EBUSY; - ret = iwl_mvm_load_rt_fw(mvm); if (ret) { IWL_ERR(mvm, "Failed to start RT ucode: %d\n", ret); - if (ret != -ERFKILL && !mvm->pldr_sync) + if (ret != -ERFKILL && !mvm->fw_product_reset) iwl_fw_dbg_error_collect(&mvm->fwrt, FW_DBG_TRIGGER_DRIVER); goto error; } /* FW loaded successfully */ - mvm->pldr_sync = false; + mvm->fw_product_reset = false; + iwl_fw_disable_dbg_asserts(&mvm->fwrt); iwl_get_shared_mem_conf(&mvm->fwrt); ret = iwl_mvm_sf_update(mvm, NULL, false); @@ -1591,8 +1467,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) for (i = 0; i < IWL_MVM_FW_MAX_LINK_ID + 1; i++) RCU_INIT_POINTER(mvm->link_id_to_link_conf[i], NULL); - memset(&mvm->fw_link_ids_map, 0, sizeof(mvm->fw_link_ids_map)); - mvm->tdls_cs.peer.sta_id = IWL_MVM_INVALID_STA; /* reset quota debouncing buffer - 0xff will yield invalid data */ @@ -1630,21 +1504,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } - chan = &sband->channels[0]; - - cfg80211_chandef_create(&chandef, chan, NL80211_CHAN_NO_HT); - for (i = 0; i < NUM_PHY_CTX; i++) { - /* - * The channel used here isn't relevant as it's - * going to be overwritten in the other flows. - * For now use the first channel we have. - */ - ret = iwl_mvm_phy_ctxt_add(mvm, &mvm->phy_ctxts[i], - &chandef, 1, 1); - if (ret) - goto error; - } - if (iwl_mvm_is_tt_in_fw(mvm)) { /* in order to give the responsibility of ct-kill and * TX backoff to FW we need to send empty temperature reporting @@ -1708,9 +1567,6 @@ int iwl_mvm_up(struct iwl_mvm *mvm) if (!mvm->ptp_data.ptp_clock) iwl_mvm_ptp_init(mvm); - if (iwl_acpi_get_eckv(mvm->dev, &mvm->ext_clock_valid)) - IWL_DEBUG_INFO(mvm, "ECKV table doesn't exist in BIOS\n"); - ret = iwl_mvm_ppag_init(mvm); if (ret) goto error; @@ -1727,9 +1583,10 @@ int iwl_mvm_up(struct iwl_mvm *mvm) iwl_mvm_tas_init(mvm); iwl_mvm_leds_sync(mvm); + iwl_mvm_uats_init(mvm); if (iwl_rfi_supported(mvm)) { - if (iwl_mvm_eval_dsm_rfi(mvm) == DSM_VALUE_RFI_ENABLE) + if (iwl_mvm_eval_dsm_rfi(mvm)) iwl_rfi_send_config_cmd(mvm, NULL); } @@ -1738,8 +1595,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) IWL_DEBUG_INFO(mvm, "RT uCode started.\n"); return 0; error: - if (!iwlmvm_mod_params.init_dbg || !ret) - iwl_mvm_stop_device(mvm); + iwl_mvm_stop_device(mvm); return ret; } diff --git a/sys/contrib/dev/iwlwifi/mvm/link.c b/sys/contrib/dev/iwlwifi/mvm/link.c index ace82e2c5bd9..a9929aa49913 100644 --- a/sys/contrib/dev/iwlwifi/mvm/link.c +++ b/sys/contrib/dev/iwlwifi/mvm/link.c @@ -1,33 +1,65 @@ // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause /* - * Copyright (C) 2022 - 2023 Intel Corporation + * Copyright (C) 2022 - 2024 Intel Corporation */ #include "mvm.h" #include "time-event.h" -static u32 iwl_mvm_get_free_fw_link_id(struct iwl_mvm *mvm, - struct iwl_mvm_vif *mvm_vif) -{ - u32 link_id; +#define HANDLE_ESR_REASONS(HOW) \ + HOW(BLOCKED_PREVENTION) \ + HOW(BLOCKED_WOWLAN) \ + HOW(BLOCKED_TPT) \ + HOW(BLOCKED_FW) \ + HOW(BLOCKED_NON_BSS) \ + HOW(BLOCKED_ROC) \ + HOW(EXIT_MISSED_BEACON) \ + HOW(EXIT_LOW_RSSI) \ + HOW(EXIT_COEX) \ + HOW(EXIT_BANDWIDTH) \ + HOW(EXIT_CSA) \ + HOW(EXIT_LINK_USAGE) - lockdep_assert_held(&mvm->mutex); +static const char *const iwl_mvm_esr_states_names[] = { +#define NAME_ENTRY(x) [ilog2(IWL_MVM_ESR_##x)] = #x, + HANDLE_ESR_REASONS(NAME_ENTRY) +}; + +const char *iwl_get_esr_state_string(enum iwl_mvm_esr_state state) +{ + int offs = ilog2(state); - link_id = ffz(mvm->fw_link_ids_map); + if (offs >= ARRAY_SIZE(iwl_mvm_esr_states_names) || + !iwl_mvm_esr_states_names[offs]) + return "UNKNOWN"; - /* this case can happen if there're deactivated but not removed links */ - if (link_id > IWL_MVM_FW_MAX_LINK_ID) - return IWL_MVM_FW_LINK_ID_INVALID; + return iwl_mvm_esr_states_names[offs]; +} - mvm->fw_link_ids_map |= BIT(link_id); - return link_id; +static void iwl_mvm_print_esr_state(struct iwl_mvm *mvm, u32 mask) +{ +#define NAME_FMT(x) "%s" +#define NAME_PR(x) (mask & IWL_MVM_ESR_##x) ? "[" #x "]" : "", + IWL_DEBUG_INFO(mvm, + "EMLSR state = " HANDLE_ESR_REASONS(NAME_FMT) + " (0x%x)\n", + HANDLE_ESR_REASONS(NAME_PR) + mask); +#undef NAME_FMT +#undef NAME_PR } -static void iwl_mvm_release_fw_link_id(struct iwl_mvm *mvm, u32 link_id) +static u32 iwl_mvm_get_free_fw_link_id(struct iwl_mvm *mvm, + struct iwl_mvm_vif *mvm_vif) { + u32 i; + lockdep_assert_held(&mvm->mutex); - if (!WARN_ON(link_id > IWL_MVM_FW_MAX_LINK_ID)) - mvm->fw_link_ids_map &= ~BIT(link_id); + for (i = 0; i < ARRAY_SIZE(mvm->link_id_to_link_conf); i++) + if (!rcu_access_pointer(mvm->link_id_to_link_conf[i])) + return i; + + return IWL_MVM_FW_LINK_ID_INVALID; } static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm, @@ -46,28 +78,45 @@ static int iwl_mvm_link_cmd_send(struct iwl_mvm *mvm, return ret; } -int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, - struct ieee80211_bss_conf *link_conf) +int iwl_mvm_set_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) { struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - unsigned int link_id = link_conf->link_id; - struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; - struct iwl_link_config_cmd cmd = {}; - struct iwl_mvm_phy_ctxt *phyctxt; - - if (WARN_ON_ONCE(!link_info)) - return -EINVAL; + struct iwl_mvm_vif_link_info *link_info = + mvmvif->link[link_conf->link_id]; if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) { link_info->fw_link_id = iwl_mvm_get_free_fw_link_id(mvm, mvmvif); - if (link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID) + if (link_info->fw_link_id >= + ARRAY_SIZE(mvm->link_id_to_link_conf)) return -EINVAL; rcu_assign_pointer(mvm->link_id_to_link_conf[link_info->fw_link_id], link_conf); } + return 0; +} + +int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + unsigned int link_id = link_conf->link_id; + struct iwl_mvm_vif_link_info *link_info = mvmvif->link[link_id]; + struct iwl_link_config_cmd cmd = {}; + unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1); + int ret; + + if (WARN_ON_ONCE(!link_info)) + return -EINVAL; + + ret = iwl_mvm_set_link_mapping(mvm, vif, link_conf); + if (ret) + return ret; + /* Update SF - Disable if needed. if this fails, SF might still be on * while many macs are bound, which is forbidden - so fail the binding. */ @@ -77,23 +126,79 @@ int iwl_mvm_add_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, cmd.link_id = cpu_to_le32(link_info->fw_link_id); cmd.mac_id = cpu_to_le32(mvmvif->id); cmd.spec_link_id = link_conf->link_id; - /* P2P-Device already has a valid PHY context during add */ - phyctxt = link_info->phy_ctxt; - if (phyctxt) - cmd.phy_id = cpu_to_le32(phyctxt->id); - else - cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID); + WARN_ON_ONCE(link_info->phy_ctxt); + cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID); memcpy(cmd.local_link_addr, link_conf->addr, ETH_ALEN); if (vif->type == NL80211_IFTYPE_ADHOC && link_conf->bssid) memcpy(cmd.ibss_bssid_addr, link_conf->bssid, ETH_ALEN); - cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); + if (cmd_ver < 2) + cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); return iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_ADD); } +struct iwl_mvm_esr_iter_data { + struct ieee80211_vif *vif; + unsigned int link_id; + bool lift_block; +}; + +static void iwl_mvm_esr_vif_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_esr_iter_data *data = _data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + int link_id; + + if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_STATION) + return; + + for_each_mvm_vif_valid_link(mvmvif, link_id) { + struct iwl_mvm_vif_link_info *link_info = + mvmvif->link[link_id]; + if (vif == data->vif && link_id == data->link_id) + continue; + if (link_info->active) + data->lift_block = false; + } +} + +int iwl_mvm_esr_non_bss_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + unsigned int link_id, bool active) +{ + /* An active link of a non-station vif blocks EMLSR. Upon activation + * block EMLSR on the bss vif. Upon deactivation, check if this link + * was the last non-station link active, and if so unblock the bss vif + */ + struct ieee80211_vif *bss_vif = iwl_mvm_get_bss_vif(mvm); + struct iwl_mvm_esr_iter_data data = { + .vif = vif, + .link_id = link_id, + .lift_block = true, + }; + + if (IS_ERR_OR_NULL(bss_vif)) + return 0; + + if (active) + return iwl_mvm_block_esr_sync(mvm, bss_vif, + IWL_MVM_ESR_BLOCKED_NON_BSS); + + ieee80211_iterate_active_interfaces(mvm->hw, + IEEE80211_IFACE_ITER_NORMAL, + iwl_mvm_esr_vif_iterator, &data); + if (data.lift_block) { + mutex_lock(&mvm->mutex); + iwl_mvm_unblock_esr(mvm, bss_vif, IWL_MVM_ESR_BLOCKED_NON_BSS); + mutex_unlock(&mvm->mutex); + } + + return 0; +} + int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf, u32 changes, bool active) @@ -105,6 +210,8 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_link_config_cmd cmd = {}; u32 ht_flag, flags = 0, flags_mask = 0; int ret; + unsigned int cmd_id = WIDE_ID(MAC_CONF_GROUP, LINK_CONFIG_CMD); + u8 cmd_ver = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 1); if (WARN_ON_ONCE(!link_info || link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)) @@ -194,11 +301,23 @@ int iwl_mvm_link_changed(struct iwl_mvm *mvm, struct ieee80211_vif *vif, flags_mask |= LINK_FLG_MU_EDCA_CW; } - if (link_conf->eht_puncturing && !iwlwifi_mod_params.disable_11be) - cmd.puncture_mask = cpu_to_le16(link_conf->eht_puncturing); - else - /* This flag can be set only if the MAC has eht support */ - changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS; + if (changes & LINK_CONTEXT_MODIFY_EHT_PARAMS) { + struct ieee80211_chanctx_conf *ctx; + struct cfg80211_chan_def *def = NULL; + + rcu_read_lock(); + ctx = rcu_dereference(link_conf->chanctx_conf); + if (ctx) + def = iwl_mvm_chanctx_def(mvm, ctx); + + if (iwlwifi_mod_params.disable_11be || + !link_conf->eht_support || !def || + iwl_fw_lookup_cmd_ver(mvm->fw, PHY_CONTEXT_CMD, 1) >= 6) + changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS; + else + cmd.puncture_mask = cpu_to_le16(def->punctured); + rcu_read_unlock(); + } cmd.bss_color = link_conf->he_bss_color.color; @@ -226,7 +345,8 @@ send_cmd: cmd.flags = cpu_to_le32(flags); cmd.flags_mask = cpu_to_le32(flags_mask); cmd.spec_link_id = link_conf->link_id; - cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); + if (cmd_ver < 2) + cmd.listen_lmac = cpu_to_le32(link_info->listen_lmac); ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_MODIFY); if (!ret && (changes & LINK_CONTEXT_MODIFY_ACTIVE)) @@ -235,6 +355,24 @@ send_cmd: return ret; } +int iwl_mvm_unset_link_mapping(struct iwl_mvm *mvm, struct ieee80211_vif *vif, + struct ieee80211_bss_conf *link_conf) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_vif_link_info *link_info = + mvmvif->link[link_conf->link_id]; + + /* mac80211 thought we have the link, but it was never configured */ + if (WARN_ON(!link_info || + link_info->fw_link_id >= + ARRAY_SIZE(mvm->link_id_to_link_conf))) + return -EINVAL; + + RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id], + NULL); + return 0; +} + int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct ieee80211_bss_conf *link_conf) { @@ -244,16 +382,14 @@ int iwl_mvm_remove_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, struct iwl_link_config_cmd cmd = {}; int ret; - if (WARN_ON(!link_info || - link_info->fw_link_id == IWL_MVM_FW_LINK_ID_INVALID)) - return -EINVAL; + ret = iwl_mvm_unset_link_mapping(mvm, vif, link_conf); + if (ret) + return 0; - RCU_INIT_POINTER(mvm->link_id_to_link_conf[link_info->fw_link_id], - NULL); cmd.link_id = cpu_to_le32(link_info->fw_link_id); - iwl_mvm_release_fw_link_id(mvm, link_info->fw_link_id); link_info->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID; cmd.spec_link_id = link_conf->link_id; + cmd.phy_id = cpu_to_le32(FW_CTXT_INVALID); ret = iwl_mvm_link_cmd_send(mvm, &cmd, FW_CTXT_ACTION_REMOVE); @@ -283,3 +419,732 @@ int iwl_mvm_disable_link(struct iwl_mvm *mvm, struct ieee80211_vif *vif, return ret; } + +struct iwl_mvm_rssi_to_grade { + s8 rssi[2]; + u16 grade; +}; + +#define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \ + { \ + .rssi = {_lb, _hb_uhb}, \ + .grade = _grade \ + } + +/* + * This array must be sorted by increasing RSSI for proper functionality. + * The grades are actually estimated throughput, represented as fixed-point + * with a scale factor of 1/10. + */ +static const struct iwl_mvm_rssi_to_grade rssi_to_grade_map[] = { + RSSI_TO_GRADE_LINE(-85, -89, 177), + RSSI_TO_GRADE_LINE(-83, -86, 344), + RSSI_TO_GRADE_LINE(-82, -85, 516), + RSSI_TO_GRADE_LINE(-80, -83, 688), + RSSI_TO_GRADE_LINE(-77, -79, 1032), + RSSI_TO_GRADE_LINE(-73, -76, 1376), + RSSI_TO_GRADE_LINE(-70, -74, 1548), + RSSI_TO_GRADE_LINE(-69, -72, 1750), + RSSI_TO_GRADE_LINE(-65, -68, 2064), + RSSI_TO_GRADE_LINE(-61, -66, 2294), + RSSI_TO_GRADE_LINE(-58, -61, 2580), + RSSI_TO_GRADE_LINE(-55, -58, 2868), + RSSI_TO_GRADE_LINE(-46, -55, 3098), + RSSI_TO_GRADE_LINE(-43, -54, 3442) +}; + +#define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade) + +#define DEFAULT_CHAN_LOAD_LB 30 +#define DEFAULT_CHAN_LOAD_HB 15 +#define DEFAULT_CHAN_LOAD_UHB 0 + +/* Factors calculation is done with fixed-point with a scaling factor of 1/256 */ +#define SCALE_FACTOR 256 + +/* Convert a percentage from [0,100] to [0,255] */ +#define NORMALIZE_PERCENT_TO_255(percentage) ((percentage) * SCALE_FACTOR / 100) + +static unsigned int +iwl_mvm_get_puncturing_factor(const struct ieee80211_bss_conf *link_conf) +{ + enum nl80211_chan_width chan_width = + link_conf->chanreq.oper.width; + int mhz = nl80211_chan_width_to_mhz(chan_width); + unsigned int n_subchannels, n_punctured, puncturing_penalty; + + if (WARN_ONCE(mhz < 20 || mhz > 320, + "Invalid channel width : (%d)\n", mhz)) + return SCALE_FACTOR; + + /* No puncturing, no penalty */ + if (mhz < 80) + return SCALE_FACTOR; + + /* total number of subchannels */ + n_subchannels = mhz / 20; + /* how many of these are punctured */ + n_punctured = hweight16(link_conf->chanreq.oper.punctured); + + puncturing_penalty = n_punctured * SCALE_FACTOR / n_subchannels; + return SCALE_FACTOR - puncturing_penalty; +} + +static unsigned int +iwl_mvm_get_chan_load(struct ieee80211_bss_conf *link_conf) +{ + struct ieee80211_vif *vif = link_conf->vif; + struct iwl_mvm_vif_link_info *mvm_link = + iwl_mvm_vif_from_mac80211(link_conf->vif)->link[link_conf->link_id]; + const struct element *bss_load_elem; + const struct ieee80211_bss_load_elem *bss_load; + enum nl80211_band band = link_conf->chanreq.oper.chan->band; + const struct cfg80211_bss_ies *ies; + unsigned int chan_load; + u32 chan_load_by_us; + + rcu_read_lock(); + if (ieee80211_vif_link_active(vif, link_conf->link_id)) + ies = rcu_dereference(link_conf->bss->beacon_ies); + else + ies = rcu_dereference(link_conf->bss->ies); + + if (ies) + bss_load_elem = cfg80211_find_elem(WLAN_EID_QBSS_LOAD, + ies->data, ies->len); + else + bss_load_elem = NULL; + + /* If there isn't BSS Load element, take the defaults */ + if (!bss_load_elem || + bss_load_elem->datalen != sizeof(*bss_load)) { + rcu_read_unlock(); + switch (band) { + case NL80211_BAND_2GHZ: + chan_load = DEFAULT_CHAN_LOAD_LB; + break; + case NL80211_BAND_5GHZ: + chan_load = DEFAULT_CHAN_LOAD_HB; + break; + case NL80211_BAND_6GHZ: + chan_load = DEFAULT_CHAN_LOAD_UHB; + break; + default: + chan_load = 0; + break; + } + /* The defaults are given in percentage */ + return NORMALIZE_PERCENT_TO_255(chan_load); + } + + bss_load = (const void *)bss_load_elem->data; + /* Channel util is in range 0-255 */ + chan_load = bss_load->channel_util; + rcu_read_unlock(); + + if (!mvm_link || !mvm_link->active) + return chan_load; + + if (WARN_ONCE(!mvm_link->phy_ctxt, + "Active link (%u) without phy ctxt assigned!\n", + link_conf->link_id)) + return chan_load; + + /* channel load by us is given in percentage */ + chan_load_by_us = + NORMALIZE_PERCENT_TO_255(mvm_link->phy_ctxt->channel_load_by_us); + + /* Use only values that firmware sends that can possibly be valid */ + if (chan_load_by_us <= chan_load) + chan_load -= chan_load_by_us; + + return chan_load; +} + +static unsigned int +iwl_mvm_get_chan_load_factor(struct ieee80211_bss_conf *link_conf) +{ + return SCALE_FACTOR - iwl_mvm_get_chan_load(link_conf); +} + +/* This function calculates the grade of a link. Returns 0 in error case */ +VISIBLE_IF_IWLWIFI_KUNIT +unsigned int iwl_mvm_get_link_grade(struct ieee80211_bss_conf *link_conf) +{ + enum nl80211_band band; + int i, rssi_idx; + s32 link_rssi; + unsigned int grade = MAX_GRADE; + + if (WARN_ON_ONCE(!link_conf)) + return 0; + + band = link_conf->chanreq.oper.chan->band; + if (WARN_ONCE(band != NL80211_BAND_2GHZ && + band != NL80211_BAND_5GHZ && + band != NL80211_BAND_6GHZ, + "Invalid band (%u)\n", band)) + return 0; + + link_rssi = MBM_TO_DBM(link_conf->bss->signal); + /* + * For 6 GHz the RSSI of the beacons is lower than + * the RSSI of the data. + */ + if (band == NL80211_BAND_6GHZ) + link_rssi += 4; + + rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1; + + /* No valid RSSI - take the lowest grade */ + if (!link_rssi) + link_rssi = rssi_to_grade_map[0].rssi[rssi_idx]; + + /* Get grade based on RSSI */ + for (i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) { + const struct iwl_mvm_rssi_to_grade *line = + &rssi_to_grade_map[i]; + + if (link_rssi > line->rssi[rssi_idx]) + continue; + grade = line->grade; + break; + } + + /* apply the channel load and puncturing factors */ + grade = grade * iwl_mvm_get_chan_load_factor(link_conf) / SCALE_FACTOR; + grade = grade * iwl_mvm_get_puncturing_factor(link_conf) / SCALE_FACTOR; + return grade; +} +EXPORT_SYMBOL_IF_IWLWIFI_KUNIT(iwl_mvm_get_link_grade); + +static +u8 iwl_mvm_set_link_selection_data(struct ieee80211_vif *vif, + struct iwl_mvm_link_sel_data *data, + unsigned long usable_links, + u8 *best_link_idx) +{ + u8 n_data = 0; + u16 max_grade = 0; + unsigned long link_id; + + /* TODO: don't select links that weren't discovered in the last scan */ + for_each_set_bit(link_id, &usable_links, IEEE80211_MLD_MAX_NUM_LINKS) { + struct ieee80211_bss_conf *link_conf = + link_conf_dereference_protected(vif, link_id); + + if (WARN_ON_ONCE(!link_conf)) + continue; + + data[n_data].link_id = link_id; + data[n_data].chandef = &link_conf->chanreq.oper; + data[n_data].signal = link_conf->bss->signal / 100; + data[n_data].grade = iwl_mvm_get_link_grade(link_conf); + + if (data[n_data].grade > max_grade) { + max_grade = data[n_data].grade; + *best_link_idx = n_data; + } + n_data++; + } + + return n_data; +} + +struct iwl_mvm_bw_to_rssi_threshs { + s8 low; + s8 high; +}; + +#define BW_TO_RSSI_THRESHOLDS(_bw) \ + [IWL_PHY_CHANNEL_MODE ## _bw] = { \ + .low = IWL_ |