aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjoern A. Zeeb <bz@FreeBSD.org>2024-09-27 21:53:40 +0000
committerBjoern A. Zeeb <bz@FreeBSD.org>2024-10-28 14:42:25 +0000
commita4128aad8503277614f2d214011ef60a19447b83 (patch)
tree5442f1a66fbd0cb3746ef1f586c4c17b54acb1b0
parent7b43f4d064195bcf66816cb9fe350a1392fe24ce (diff)
parent5d6ad179ba1337044d054d06596e2169952660b6 (diff)
downloadsrc-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
-rw-r--r--share/man/man4/iwlwifi.440
-rw-r--r--share/man/man4/iwlwififw.4238
-rw-r--r--sys/contrib/dev/iwlwifi/cfg/22000.c4
-rw-r--r--sys/contrib/dev/iwlwifi/cfg/ax210.c12
-rw-r--r--sys/contrib/dev/iwlwifi/cfg/bz.c29
-rw-r--r--sys/contrib/dev/iwlwifi/cfg/sc.c48
-rw-r--r--sys/contrib/dev/iwlwifi/fw/acpi.c649
-rw-r--r--sys/contrib/dev/iwlwifi/fw/acpi.h220
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/alive.h6
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/binding.h4
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/coex.h81
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/commands.h30
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/config.h4
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/d3.h107
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/datapath.h36
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/dbg-tlv.h81
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/debug.h40
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/location.h160
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/mac-cfg.h60
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/mac.h17
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/nvm-reg.h198
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/offload.h8
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/phy-ctxt.h24
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/phy.h9
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/power.h134
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/rfi.h7
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/rs.h4
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/rx.h26
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/scan.h49
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/sta.h4
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/stats.h153
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/time-event.h80
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/tx.h23
-rw-r--r--sys/contrib/dev/iwlwifi/fw/api/txq.h14
-rw-r--r--sys/contrib/dev/iwlwifi/fw/dbg.c295
-rw-r--r--sys/contrib/dev/iwlwifi/fw/dbg.h4
-rw-r--r--sys/contrib/dev/iwlwifi/fw/debugfs.c17
-rw-r--r--sys/contrib/dev/iwlwifi/fw/dump.c3
-rw-r--r--sys/contrib/dev/iwlwifi/fw/error-dump.h33
-rw-r--r--sys/contrib/dev/iwlwifi/fw/file.h71
-rw-r--r--sys/contrib/dev/iwlwifi/fw/img.h4
-rw-r--r--sys/contrib/dev/iwlwifi/fw/init.c7
-rw-r--r--sys/contrib/dev/iwlwifi/fw/notif-wait.h3
-rw-r--r--sys/contrib/dev/iwlwifi/fw/pnvm.c49
-rw-r--r--sys/contrib/dev/iwlwifi/fw/regulatory.c639
-rw-r--r--sys/contrib/dev/iwlwifi/fw/regulatory.h220
-rw-r--r--sys/contrib/dev/iwlwifi/fw/rs.c1
-rw-r--r--sys/contrib/dev/iwlwifi/fw/runtime.h30
-rw-r--r--sys/contrib/dev/iwlwifi/fw/uefi.c462
-rw-r--r--sys/contrib/dev/iwlwifi/fw/uefi.h245
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-config.h43
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-context-info-gen3.h13
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-csr.h10
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-dbg-tlv.c94
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-dbg-tlv.h6
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-debug.c5
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-devtrace.h2
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-drv.c151
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-drv.h12
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-eeprom-parse.c879
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-eeprom-read.c397
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-eeprom-read.h12
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-fh.h85
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-io.c4
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-modparams.h21
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-nvm-parse.c223
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-nvm-parse.h23
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-nvm-utils.c118
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-nvm-utils.h (renamed from sys/contrib/dev/iwlwifi/iwl-eeprom-parse.h)19
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-op-mode.h32
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-prph.h42
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-trans.c456
-rw-r--r--sys/contrib/dev/iwlwifi/iwl-trans.h736
-rw-r--r--sys/contrib/dev/iwlwifi/mei/iwl-mei.h7
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/coex.c124
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/constants.h26
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/d3.c649
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/debugfs-vif.c272
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/debugfs.c418
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/debugfs.h1
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c277
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/ftm-responder.c49
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/fw.c522
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/link.c953
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/mac-ctxt.c117
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/mac80211.c1421
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/mld-key.c42
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/mld-mac.c11
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/mld-mac80211.c672
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/mld-sta.c98
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/mvm.h592
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/nvm.c19
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/offloading.c8
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/ops.c319
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/phy-ctxt.c115
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/power.c179
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/rfi.c8
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/rs-fw.c33
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/rx.c329
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/rxmq.c473
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/scan.c694
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/sf.c5
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/sta.c258
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/sta.h47
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/tdls.c39
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/testmode.h92
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/time-event.c470
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/time-event.h21
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/tt.c146
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/tx.c325
-rw-r--r--sys/contrib/dev/iwlwifi/mvm/utils.c99
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/ctxt-info-gen3.c42
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/ctxt-info.c6
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/drv.c211
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/internal.h362
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/rx.c47
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/trans-gen2.c29
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/trans.c482
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/tx-gen2.c1191
-rw-r--r--sys/contrib/dev/iwlwifi/pcie/tx.c1270
-rw-r--r--sys/contrib/dev/iwlwifi/queue/tx.c1903
-rw-r--r--sys/contrib/dev/iwlwifi/queue/tx.h183
-rw-r--r--sys/contrib/dev/iwlwifi/tests/Makefile7
-rw-r--r--sys/contrib/dev/iwlwifi/tests/devinfo.c78
-rw-r--r--sys/contrib/dev/iwlwifi/tests/module.c10
-rw-r--r--sys/modules/iwlwifi/Makefile7
-rw-r--r--usr.sbin/fwget/pci/pci_network_intel33
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, &params, 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, &params, 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,
&regulatory[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, &gtkdata);
@@ -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_