git: d2a50aafb6cc - stable/13 - iwlwifi: update from iwlwifi-next
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 27 Feb 2022 23:43:36 UTC
The branch stable/13 has been updated by bz: URL: https://cgit.FreeBSD.org/src/commit/?id=d2a50aafb6ccc9c72e878fb27b4cb3b8d3a9300d commit d2a50aafb6ccc9c72e878fb27b4cb3b8d3a9300d Author: Bjoern A. Zeeb <bz@FreeBSD.org> AuthorDate: 2022-02-24 21:34:13 +0000 Commit: Bjoern A. Zeeb <bz@FreeBSD.org> CommitDate: 2022-02-27 23:41:54 +0000 iwlwifi: update from iwlwifi-next Import new code from iwlwifi-next at cb0a1fb7fd86b0062692b5056ca8552906509512 (matching tag: iwlwifi-next-for-kalle-2022-02-18). Also add files not previously imported because we are not yet compiling them to ease updating and having them when needed. This adds MEI (Management Engine) support upstream which we cannot import (currently GPL-only) so we have stub functions for the missing bits. This also reduces the diff to upstream. Changes submitted to avoid problems with const and with void * arithmetics were merged. In the module build Makefile disable CONFIG_IWLWIFI_OPMODE_MODULAR as we are building iwlwifi as a single module. Sponsored by: The FreeBSD Foundation (cherry picked from commit d9836fb4b9380e2ed1c38455fb31a3832b452671) --- sys/contrib/dev/iwlwifi/cfg/22000.c | 117 +- sys/contrib/dev/iwlwifi/fw/acpi.c | 971 +++++++ sys/contrib/dev/iwlwifi/fw/acpi.h | 30 +- sys/contrib/dev/iwlwifi/fw/api/alive.h | 26 +- sys/contrib/dev/iwlwifi/fw/api/commands.h | 36 +- sys/contrib/dev/iwlwifi/fw/api/config.h | 33 - sys/contrib/dev/iwlwifi/fw/api/d3.h | 81 +- sys/contrib/dev/iwlwifi/fw/api/datapath.h | 210 +- sys/contrib/dev/iwlwifi/fw/api/dbg-tlv.h | 72 +- sys/contrib/dev/iwlwifi/fw/api/debug.h | 19 +- sys/contrib/dev/iwlwifi/fw/api/mac-cfg.h | 34 + sys/contrib/dev/iwlwifi/fw/api/mac.h | 127 +- sys/contrib/dev/iwlwifi/fw/api/nvm-reg.h | 82 +- sys/contrib/dev/iwlwifi/fw/api/phy-ctxt.h | 9 +- sys/contrib/dev/iwlwifi/fw/api/phy.h | 16 +- sys/contrib/dev/iwlwifi/fw/api/power.h | 22 +- sys/contrib/dev/iwlwifi/fw/api/rfi.h | 10 +- sys/contrib/dev/iwlwifi/fw/api/rs.h | 60 +- sys/contrib/dev/iwlwifi/fw/api/rx.h | 12 + sys/contrib/dev/iwlwifi/fw/api/scan.h | 93 +- sys/contrib/dev/iwlwifi/fw/api/stats.h | 92 +- sys/contrib/dev/iwlwifi/fw/api/{soc.h => system.h} | 16 +- sys/contrib/dev/iwlwifi/fw/api/tx.h | 30 +- sys/contrib/dev/iwlwifi/fw/api/txq.h | 4 +- sys/contrib/dev/iwlwifi/fw/dbg.c | 328 ++- sys/contrib/dev/iwlwifi/fw/dbg.h | 5 +- sys/contrib/dev/iwlwifi/fw/debugfs.c | 409 +++ sys/contrib/dev/iwlwifi/fw/dump.c | 153 +- sys/contrib/dev/iwlwifi/fw/error-dump.h | 18 + sys/contrib/dev/iwlwifi/fw/file.h | 9 +- sys/contrib/dev/iwlwifi/fw/img.c | 13 +- sys/contrib/dev/iwlwifi/fw/img.h | 6 +- sys/contrib/dev/iwlwifi/fw/init.c | 7 +- sys/contrib/dev/iwlwifi/fw/paging.c | 2 +- sys/contrib/dev/iwlwifi/fw/runtime.h | 9 +- sys/contrib/dev/iwlwifi/fw/smem.c | 4 +- sys/contrib/dev/iwlwifi/fw/uefi.c | 106 +- sys/contrib/dev/iwlwifi/fw/uefi.h | 20 + sys/contrib/dev/iwlwifi/iwl-config.h | 27 +- sys/contrib/dev/iwlwifi/iwl-csr.h | 27 +- sys/contrib/dev/iwlwifi/iwl-dbg-tlv.c | 136 +- sys/contrib/dev/iwlwifi/iwl-debug.c | 4 +- sys/contrib/dev/iwlwifi/iwl-drv.c | 137 +- sys/contrib/dev/iwlwifi/iwl-drv.h | 5 +- sys/contrib/dev/iwlwifi/iwl-eeprom-read.c | 12 +- sys/contrib/dev/iwlwifi/iwl-fh.h | 32 +- sys/contrib/dev/iwlwifi/iwl-io.c | 20 +- sys/contrib/dev/iwlwifi/iwl-modparams.h | 4 + sys/contrib/dev/iwlwifi/iwl-nvm-parse.c | 95 +- sys/contrib/dev/iwlwifi/iwl-nvm-parse.h | 11 +- sys/contrib/dev/iwlwifi/iwl-phy-db.c | 4 +- sys/contrib/dev/iwlwifi/iwl-prph.h | 22 +- sys/contrib/dev/iwlwifi/iwl-trans.c | 8 +- sys/contrib/dev/iwlwifi/iwl-trans.h | 87 +- sys/contrib/dev/iwlwifi/mei/iwl-mei.h | 138 + sys/contrib/dev/iwlwifi/mvm/constants.h | 2 +- sys/contrib/dev/iwlwifi/mvm/d3.c | 2797 ++++++++++++++++++++ sys/contrib/dev/iwlwifi/mvm/debugfs.c | 2145 +++++++++++++++ sys/contrib/dev/iwlwifi/mvm/ftm-initiator.c | 29 +- sys/contrib/dev/iwlwifi/mvm/ftm-responder.c | 24 +- sys/contrib/dev/iwlwifi/mvm/fw-api.h | 2 +- sys/contrib/dev/iwlwifi/mvm/fw.c | 384 ++- sys/contrib/dev/iwlwifi/mvm/mac-ctxt.c | 50 +- sys/contrib/dev/iwlwifi/mvm/mac80211.c | 504 +++- sys/contrib/dev/iwlwifi/mvm/mvm.h | 106 +- sys/contrib/dev/iwlwifi/mvm/offloading.c | 3 +- sys/contrib/dev/iwlwifi/mvm/ops.c | 300 ++- sys/contrib/dev/iwlwifi/mvm/phy-ctxt.c | 93 +- sys/contrib/dev/iwlwifi/mvm/quota.c | 2 +- sys/contrib/dev/iwlwifi/mvm/rfi.c | 61 +- sys/contrib/dev/iwlwifi/mvm/rs-fw.c | 129 +- sys/contrib/dev/iwlwifi/mvm/rs.h | 2 +- sys/contrib/dev/iwlwifi/mvm/rx.c | 266 +- sys/contrib/dev/iwlwifi/mvm/rxmq.c | 62 +- sys/contrib/dev/iwlwifi/mvm/scan.c | 386 ++- sys/contrib/dev/iwlwifi/mvm/sta.c | 332 ++- sys/contrib/dev/iwlwifi/mvm/sta.h | 7 +- sys/contrib/dev/iwlwifi/mvm/tdls.c | 5 +- sys/contrib/dev/iwlwifi/mvm/time-event.c | 44 +- sys/contrib/dev/iwlwifi/mvm/tt.c | 11 +- sys/contrib/dev/iwlwifi/mvm/tx.c | 123 +- sys/contrib/dev/iwlwifi/mvm/utils.c | 91 +- sys/contrib/dev/iwlwifi/pcie/drv.c | 388 +-- sys/contrib/dev/iwlwifi/pcie/internal.h | 46 +- sys/contrib/dev/iwlwifi/pcie/rx.c | 123 +- sys/contrib/dev/iwlwifi/pcie/trans-gen2.c | 13 +- sys/contrib/dev/iwlwifi/pcie/trans.c | 209 +- sys/contrib/dev/iwlwifi/pcie/tx.c | 8 +- sys/contrib/dev/iwlwifi/queue/tx.c | 104 +- sys/contrib/dev/iwlwifi/queue/tx.h | 19 +- sys/modules/iwlwifi/Makefile | 3 +- 91 files changed, 11379 insertions(+), 1554 deletions(-) diff --git a/sys/contrib/dev/iwlwifi/cfg/22000.c b/sys/contrib/dev/iwlwifi/cfg/22000.c index 1572097bccf1..918dd0f6f8b5 100644 --- a/sys/contrib/dev/iwlwifi/cfg/22000.c +++ b/sys/contrib/dev/iwlwifi/cfg/22000.c @@ -7,9 +7,10 @@ #include <linux/stringify.h> #include "iwl-config.h" #include "iwl-prph.h" +#include "fw/api/txq.h" /* Highest firmware API version supported */ -#define IWL_22000_UCODE_API_MAX 67 +#define IWL_22000_UCODE_API_MAX 70 /* Lowest firmware API version supported */ #define IWL_22000_UCODE_API_MIN 39 @@ -39,6 +40,7 @@ #define IWL_SO_A_GF_A_FW_PRE "iwlwifi-so-a0-gf-a0-" #define IWL_TY_A_GF_A_FW_PRE "iwlwifi-ty-a0-gf-a0-" #define IWL_SO_A_GF4_A_FW_PRE "iwlwifi-so-a0-gf4-a0-" +#define IWL_SO_A_MR_A_FW_PRE "iwlwifi-so-a0-mr-a0-" #define IWL_SNJ_A_GF4_A_FW_PRE "iwlwifi-SoSnj-a0-gf4-a0-" #define IWL_SNJ_A_GF_A_FW_PRE "iwlwifi-SoSnj-a0-gf-a0-" #define IWL_SNJ_A_HR_B_FW_PRE "iwlwifi-SoSnj-a0-hr-b0-" @@ -54,7 +56,13 @@ #define IWL_BZ_A_GF4_A_FW_PRE "iwlwifi-bz-a0-gf4-a0-" #define IWL_BZ_A_MR_A_FW_PRE "iwlwifi-bz-a0-mr-a0-" #define IWL_BZ_A_FM_A_FW_PRE "iwlwifi-bz-a0-fm-a0-" -#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm7-a0-" +#define IWL_GL_A_FM_A_FW_PRE "iwlwifi-gl-a0-fm-a0-" +#define IWL_BZ_Z_GF_A_FW_PRE "iwlwifi-bz-z0-gf-a0-" +#define IWL_BNJ_A_FM_A_FW_PRE "iwlwifi-BzBnj-a0-fm-a0-" +#define IWL_BNJ_A_FM4_A_FW_PRE "iwlwifi-BzBnj-a0-fm4-a0-" +#define IWL_BNJ_A_GF_A_FW_PRE "iwlwifi-BzBnj-a0-gf-a0-" +#define IWL_BNJ_A_GF4_A_FW_PRE "iwlwifi-BzBnj-a0-gf4-a0-" +#define IWL_BNJ_A_HR_B_FW_PRE "iwlwifi-BzBnj-a0-hr-b0-" #define IWL_QU_B_HR_B_MODULE_FIRMWARE(api) \ @@ -113,6 +121,16 @@ IWL_BZ_A_FM_A_FW_PRE __stringify(api) ".ucode" #define IWL_GL_A_FM_A_MODULE_FIRMWARE(api) \ IWL_GL_A_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_FM_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_FM_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_FM4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_GF_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_GF_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_GF4_A_FW_PRE __stringify(api) ".ucode" +#define IWL_BNJ_A_HR_B_MODULE_FIRMWARE(api) \ + IWL_BNJ_A_HR_B_FW_PRE __stringify(api) ".ucode" static const struct iwl_base_params iwl_22000_base_params = { .eeprom_size = OTP_LOW_IMAGE_SIZE_32K, @@ -206,7 +224,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .trans.base_params = &iwl_ax210_base_params, \ .min_txq_size = 128, \ .gp2_reg_addr = 0xd02c68, \ - .min_256_ba_txq_size = 1024, \ + .min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_HE, \ .mon_dram_regs = { \ .write_ptr = { \ .addr = DBGC_CUR_DBGBUF_STATUS, \ @@ -234,7 +252,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .dccm2_len = IWL_22000_DCCM2_LEN, \ .smem_offset = IWL_22000_SMEM_OFFSET, \ .smem_len = IWL_22000_SMEM_LEN, \ - .features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM, \ + .features = IWL_TX_CSUM_NETIF_FLAGS_BZ | NETIF_F_RXCSUM, \ .apmg_not_supported = true, \ .trans.mq_rx_supported = true, \ .vht_mu_mimo_supported = true, \ @@ -267,7 +285,7 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .trans.base_params = &iwl_ax210_base_params, \ .min_txq_size = 128, \ .gp2_reg_addr = 0xd02c68, \ - .min_256_ba_txq_size = 1024, \ + .min_ba_txq_size = IWL_DEFAULT_QUEUE_SIZE_EHT, \ .mon_dram_regs = { \ .write_ptr = { \ .addr = DBGC_CUR_DBGBUF_STATUS, \ @@ -281,6 +299,12 @@ static const struct iwl_ht_params iwl_22000_ht_params = { .addr = DBGC_CUR_DBGBUF_STATUS, \ .mask = DBGC_CUR_DBGBUF_STATUS_IDX_MSK, \ }, \ + }, \ + .mon_dbgi_regs = { \ + .write_ptr = { \ + .addr = DBGI_SRAM_FIFO_POINTERS, \ + .mask = DBGI_SRAM_FIFO_POINTERS_WR_PTR_MSK, \ + }, \ } const struct iwl_cfg_trans_params iwl_qnj_trans_cfg = { @@ -458,6 +482,7 @@ const char iwl_ax101_name[] = "Intel(R) Wi-Fi 6 AX101"; const char iwl_ax200_name[] = "Intel(R) Wi-Fi 6 AX200 160MHz"; const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz"; const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203"; +const char iwl_ax204_name[] = "Intel(R) Wi-Fi 6 AX204 160MHz"; const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz"; const char iwl_ax221_name[] = "Intel(R) Wi-Fi 6E AX221 160MHz"; const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6E AX231 160MHz"; @@ -626,7 +651,7 @@ const struct iwl_cfg iwl_ax200_cfg_cc = { }; const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", + .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201NGW)", .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -639,7 +664,7 @@ const struct iwl_cfg killer1650s_2ax_cfg_qu_b0_hr_b0 = { }; const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", + .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201D2W)", .fw_name_pre = IWL_QU_B_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -652,7 +677,7 @@ const struct iwl_cfg killer1650i_2ax_cfg_qu_b0_hr_b0 = { }; const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)", + .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201NGW)", .fw_name_pre = IWL_QU_C_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -665,7 +690,7 @@ const struct iwl_cfg killer1650s_2ax_cfg_qu_c0_hr_b0 = { }; const struct iwl_cfg killer1650i_2ax_cfg_qu_c0_hr_b0 = { - .name = "Killer(R) Wi-Fi 6 AX1650s 160MHz Wireless Network Adapter (201D2W)", + .name = "Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201D2W)", .fw_name_pre = IWL_QU_C_HR_B_FW_PRE, IWL_DEVICE_22500, /* @@ -696,13 +721,6 @@ const struct iwl_cfg iwlax210_2ax_cfg_so_jf_b0 = { .num_rbds = IWL_NUM_RBDS_NON_HE, }; -const struct iwl_cfg iwlax210_2ax_cfg_so_hr_a0 = { - .name = "Intel(R) Wi-Fi 6 AX210 160MHz", - .fw_name_pre = IWL_SO_A_HR_B_FW_PRE, - IWL_DEVICE_AX210, - .num_rbds = IWL_NUM_RBDS_AX210_HE, -}; - const struct iwl_cfg iwlax211_2ax_cfg_so_gf_a0 = { .name = iwl_ax211_name, .fw_name_pre = IWL_SO_A_GF_A_FW_PRE, @@ -805,6 +823,20 @@ const struct iwl_cfg iwl_cfg_ma_a0_mr_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_ma_a0_ms_a0 = { + .fw_name_pre = IWL_MA_A_MR_A_FW_PRE, + .uhb_supported = false, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_so_a0_ms_a0 = { + .fw_name_pre = IWL_SO_A_MR_A_FW_PRE, + .uhb_supported = false, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + const struct iwl_cfg iwl_cfg_ma_a0_fm_a0 = { .fw_name_pre = IWL_MA_A_FM_A_FW_PRE, .uhb_supported = true, @@ -819,6 +851,13 @@ const struct iwl_cfg iwl_cfg_snj_a0_mr_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_snj_a0_ms_a0 = { + .fw_name_pre = IWL_SNJ_A_MR_A_FW_PRE, + .uhb_supported = false, + IWL_DEVICE_AX210, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + const struct iwl_cfg iwl_cfg_so_a0_hr_a0 = { .fw_name_pre = IWL_SO_A_HR_B_FW_PRE, IWL_DEVICE_AX210, @@ -879,6 +918,47 @@ const struct iwl_cfg iwl_cfg_gl_a0_fm_a0 = { .num_rbds = IWL_NUM_RBDS_AX210_HE, }; +const struct iwl_cfg iwl_cfg_bz_z0_gf_a0 = { + .fw_name_pre = IWL_BZ_Z_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_fm_a0 = { + .fw_name_pre = IWL_BNJ_A_FM_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_fm4_a0 = { + .fw_name_pre = IWL_BNJ_A_FM4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_gf_a0 = { + .fw_name_pre = IWL_BNJ_A_GF_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_gf4_a0 = { + .fw_name_pre = IWL_BNJ_A_GF4_A_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; + +const struct iwl_cfg iwl_cfg_bnj_a0_hr_b0 = { + .fw_name_pre = IWL_BNJ_A_HR_B_FW_PRE, + .uhb_supported = true, + IWL_DEVICE_BZ, + .num_rbds = IWL_NUM_RBDS_AX210_HE, +}; MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QNJ_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); @@ -907,3 +987,8 @@ MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_MR_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_BZ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); MODULE_FIRMWARE(IWL_GL_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_FM_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_FM4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_GF_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_GF4_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL_BNJ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX)); diff --git a/sys/contrib/dev/iwlwifi/fw/acpi.c b/sys/contrib/dev/iwlwifi/fw/acpi.c new file mode 100644 index 000000000000..0e9e61508ae5 --- /dev/null +++ b/sys/contrib/dev/iwlwifi/fw/acpi.c @@ -0,0 +1,971 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * Copyright (C) 2017 Intel Deutschland GmbH + * Copyright (C) 2019-2021 Intel Corporation + */ +#include <linux/uuid.h> +#include "iwl-drv.h" +#include "iwl-debug.h" +#include "acpi.h" +#include "fw/runtime.h" + +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 int iwl_acpi_get_handle(struct device *dev, acpi_string method, + acpi_handle *ret_handle) +{ + acpi_handle root_handle; + acpi_status status; + + root_handle = ACPI_HANDLE(dev); + if (!root_handle) { + IWL_DEBUG_DEV_RADIO(dev, + "ACPI: Could not retrieve root port handle\n"); + return -ENOENT; + } + + status = acpi_get_handle(root_handle, method, ret_handle); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_DEV_RADIO(dev, + "ACPI: %s method not found\n", method); + return -ENOENT; + } + return 0; +} + +void *iwl_acpi_get_object(struct device *dev, acpi_string method) +{ + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_handle handle; + acpi_status status; + int ret; + + ret = iwl_acpi_get_handle(dev, method, &handle); + if (ret) + return ERR_PTR(-ENOENT); + + /* Call the method with no arguments */ + status = acpi_evaluate_object(handle, NULL, NULL, &buf); + if (ACPI_FAILURE(status)) { + IWL_DEBUG_DEV_RADIO(dev, + "ACPI: %s method invocation failed (status: 0x%x)\n", + method, status); + return ERR_PTR(-ENOENT); + } + return buf.pointer; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_object); + +/* + * Generic function for evaluating a method defined in the device specific + * method (DSM) interface. The returned acpi object must be freed by calling + * function. + */ +static void *iwl_acpi_get_dsm_object(struct device *dev, int rev, int func, + union acpi_object *args, + const guid_t *guid) +{ + union acpi_object *obj; + + obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), guid, rev, func, + args); + if (!obj) { + IWL_DEBUG_DEV_RADIO(dev, + "ACPI: DSM method invocation failed (rev: %d, func:%d)\n", + rev, func); + return ERR_PTR(-ENOENT); + } + return obj; +} + +/* + * Generic function to evaluate a DSM with no arguments + * and an integer return value, + * (as an integer object or inside a buffer object), + * verify and assign the value in the "value" parameter. + * return 0 in success and the appropriate errno otherwise. + */ +static int iwl_acpi_get_dsm_integer(struct device *dev, int rev, int func, + const guid_t *guid, u64 *value, + size_t expected_size) +{ + union acpi_object *obj; + int ret = 0; + + obj = iwl_acpi_get_dsm_object(dev, rev, func, NULL, guid); + if (IS_ERR(obj)) { + IWL_DEBUG_DEV_RADIO(dev, + "Failed to get DSM object. func= %d\n", + func); + return -ENOENT; + } + + if (obj->type == ACPI_TYPE_INTEGER) { + *value = obj->integer.value; + } else if (obj->type == ACPI_TYPE_BUFFER) { + __le64 le_value = 0; + + if (WARN_ON_ONCE(expected_size > sizeof(le_value))) + return -EINVAL; + + /* if the buffer size doesn't match the expected size */ + if (obj->buffer.length != expected_size) + IWL_DEBUG_DEV_RADIO(dev, + "ACPI: DSM invalid buffer size, padding or truncating (%d)\n", + obj->buffer.length); + + /* assuming LE from Intel BIOS spec */ + memcpy(&le_value, obj->buffer.pointer, + min_t(size_t, expected_size, (size_t)obj->buffer.length)); + *value = le64_to_cpu(le_value); + } else { + IWL_DEBUG_DEV_RADIO(dev, + "ACPI: DSM method did not return a valid object, type=%d\n", + obj->type); + ret = -EINVAL; + goto out; + } + + IWL_DEBUG_DEV_RADIO(dev, + "ACPI: DSM method evaluated: func=%d, ret=%d\n", + func, ret); +out: + ACPI_FREE(obj); + return ret; +} + +/* + * Evaluate a DSM with no arguments and a u8 return value, + */ +int iwl_acpi_get_dsm_u8(struct device *dev, int rev, int func, + const guid_t *guid, u8 *value) +{ + int ret; + u64 val; + + ret = iwl_acpi_get_dsm_integer(dev, rev, func, + guid, &val, sizeof(u8)); + + if (ret < 0) + return ret; + + /* cast val (u64) to be u8 */ + *value = (u8)val; + return 0; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u8); + +/* + * 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; + + ret = iwl_acpi_get_dsm_integer(dev, rev, func, + guid, &val, sizeof(u32)); + + if (ret < 0) + return ret; + + /* cast val (u64) to be u32 */ + *value = (u32)val; + return 0; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_dsm_u32); + +union acpi_object *iwl_acpi_get_wifi_pkg_range(struct device *dev, + union acpi_object *data, + int min_data_size, + int max_data_size, + int *tbl_rev) +{ + int i; + union acpi_object *wifi_pkg; + + /* + * We need at least one entry in the wifi package that + * describes the domain, and one more entry, otherwise there's + * no point in reading it. + */ + if (WARN_ON_ONCE(min_data_size < 2 || min_data_size > max_data_size)) + return ERR_PTR(-EINVAL); + + /* + * We need at least two packages, one for the revision and one + * for the data itself. Also check that the revision is valid + * (i.e. it is an integer (each caller has to check by itself + * if the returned revision is supported)). + */ + if (data->type != ACPI_TYPE_PACKAGE || + data->package.count < 2 || + data->package.elements[0].type != ACPI_TYPE_INTEGER) { + IWL_DEBUG_DEV_RADIO(dev, "Invalid packages structure\n"); + return ERR_PTR(-EINVAL); + } + + *tbl_rev = data->package.elements[0].integer.value; + + /* loop through all the packages to find the one for WiFi */ + for (i = 1; i < data->package.count; i++) { + union acpi_object *domain; + + wifi_pkg = &data->package.elements[i]; + + /* skip entries that are not a package with the right size */ + if (wifi_pkg->type != ACPI_TYPE_PACKAGE || + wifi_pkg->package.count < min_data_size || + wifi_pkg->package.count > max_data_size) + continue; + + domain = &wifi_pkg->package.elements[0]; + if (domain->type == ACPI_TYPE_INTEGER && + domain->integer.value == ACPI_WIFI_DOMAIN) + goto found; + } + + return ERR_PTR(-ENOENT); + +found: + return wifi_pkg; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_wifi_pkg_range); + +int iwl_acpi_get_tas(struct iwl_fw_runtime *fwrt, + union iwl_tas_config_cmd *cmd, int fw_ver) +{ + union acpi_object *wifi_pkg, *data; + int ret, tbl_rev, i, block_list_size, enabled; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_WTAS_METHOD); + if (IS_ERR(data)) + return PTR_ERR(data); + + /* try to read wtas table revision 1 or revision 0*/ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WTAS_WIFI_DATA_SIZE, + &tbl_rev); + if (IS_ERR(wifi_pkg)) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if (tbl_rev == 1 && wifi_pkg->package.elements[1].type == + 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; + } + + } else if (tbl_rev == 0 && + wifi_pkg->package.elements[1].type == ACPI_TYPE_INTEGER) { + enabled = !!wifi_pkg->package.elements[1].integer.value; + } else { + ret = -EINVAL; + goto out_free; + } + + if (!enabled) { + IWL_DEBUG_RADIO(fwrt, "TAS not enabled\n"); + ret = 0; + goto out_free; + } + + 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_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); + + 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; + + if (wifi_pkg->package.elements[3 + i].type != + ACPI_TYPE_INTEGER) { + IWL_DEBUG_RADIO(fwrt, + "TAS invalid array elem %d\n", 3 + i); + ret = -EINVAL; + goto out_free; + } + + country = wifi_pkg->package.elements[3 + i].integer.value; + cmd->v4.block_list_array[i] = cpu_to_le32(country); + IWL_DEBUG_RADIO(fwrt, "TAS block list country %d\n", country); + } + + ret = 1; +out_free: + kfree(data); + return ret; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_tas); + +int iwl_acpi_get_mcc(struct device *dev, char *mcc) +{ + union acpi_object *wifi_pkg, *data; + u32 mcc_val; + int ret, tbl_rev; + + data = iwl_acpi_get_object(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, + &tbl_rev); + if (IS_ERR(wifi_pkg)) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + tbl_rev != 0) { + ret = -EINVAL; + goto out_free; + } + + mcc_val = wifi_pkg->package.elements[1].integer.value; + + mcc[0] = (mcc_val >> 8) & 0xff; + mcc[1] = mcc_val & 0xff; + mcc[2] = '\0'; + + ret = 0; +out_free: + kfree(data); + return ret; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_mcc); + +u64 iwl_acpi_get_pwr_limit(struct device *dev) +{ + union acpi_object *data, *wifi_pkg; + u64 dflt_pwr_limit; + int tbl_rev; + + data = iwl_acpi_get_object(dev, ACPI_SPLC_METHOD); + if (IS_ERR(data)) { + dflt_pwr_limit = 0; + goto out; + } + + wifi_pkg = iwl_acpi_get_wifi_pkg(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; + goto out_free; + } + + dflt_pwr_limit = wifi_pkg->package.elements[1].integer.value; +out_free: + kfree(data); +out: + return dflt_pwr_limit; +} +IWL_EXPORT_SYMBOL(iwl_acpi_get_pwr_limit); + +int iwl_acpi_get_eckv(struct device *dev, u32 *extl_clk) +{ + union acpi_object *wifi_pkg, *data; + int ret, tbl_rev; + + data = iwl_acpi_get_object(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, + &tbl_rev); + if (IS_ERR(wifi_pkg)) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER || + tbl_rev != 0) { + ret = -EINVAL; + goto out_free; + } + + *extl_clk = wifi_pkg->package.elements[1].integer.value; + + ret = 0; + +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) +{ + int i, j, idx = 0; + + /* + * 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++) { + /* if we don't have the values, use the default */ + if (i >= num_chains || j >= num_sub_bands) { + profile->chains[i].subbands[j] = 0; + } else { + if (table[idx].type != ACPI_TYPE_INTEGER || + table[idx].integer.value > U8_MAX) + return -EINVAL; + + profile->chains[i].subbands[j] = + table[idx].integer.value; + + idx++; + } + } + } + + /* Only if all values were valid can the profile be enabled */ + profile->enabled = enabled; + + 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) +{ + union acpi_object *wifi_pkg, *table, *data; + bool enabled; + int ret, tbl_rev; + u8 num_chains, num_sub_bands; + + data = iwl_acpi_get_object(fwrt->dev, ACPI_WRDS_METHOD); + if (IS_ERR(data)) + return PTR_ERR(data); + + /* start by trying to read revision 2 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV2, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 2) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV2; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV2; + + goto read_table; + } + + /* then try revision 1 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV1, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 1) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV1; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV1; + + goto read_table; + } + + /* then finally revision 0 */ + wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data, + ACPI_WRDS_WIFI_DATA_SIZE_REV0, + &tbl_rev); + if (!IS_ERR(wifi_pkg)) { + if (tbl_rev != 0) { + ret = PTR_ERR(wifi_pkg); + goto out_free; + } + + num_chains = ACPI_SAR_NUM_CHAINS_REV0; + num_sub_bands = ACPI_SAR_NUM_SUB_BANDS_REV0; + + goto read_table; + } + + ret = PTR_ERR(wifi_pkg); + goto out_free; + +read_table: + if (wifi_pkg->package.elements[1].type != ACPI_TYPE_INTEGER) { + ret = -EINVAL; + goto out_free; + } + + IWL_DEBUG_RADIO(fwrt, "Reading WRDS tbl_rev=%d\n", tbl_rev); + + enabled = !!(wifi_pkg->package.elements[1].integer.value); + + /* position of the actual table */ + table = &wifi_pkg->package.elements[2]; + *** 18555 LINES SKIPPED ***