From 6778948f9de86c3cfaf36725a7c87dcff9ba247f Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 08:20:59 +0000 Subject: [PATCH] kernel_5.10 no rt --- kernel/drivers/net/wireless/ath/ath10k/core.c | 1812 +++++++++++++++++++++++++++++++++++++--------------------- 1 files changed, 1,148 insertions(+), 664 deletions(-) diff --git a/kernel/drivers/net/wireless/ath/ath10k/core.c b/kernel/drivers/net/wireless/ath/ath10k/core.c index 436eac3..d0967bb 100644 --- a/kernel/drivers/net/wireless/ath/ath10k/core.c +++ b/kernel/drivers/net/wireless/ath/ath10k/core.c @@ -1,26 +1,17 @@ +// SPDX-License-Identifier: ISC /* * Copyright (c) 2005-2011 Atheros Communications Inc. * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. - * Copyright (c) 2018, The Linux Foundation. All rights reserved. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. */ #include <linux/module.h> #include <linux/firmware.h> #include <linux/of.h> +#include <linux/property.h> #include <linux/dmi.h> #include <linux/ctype.h> +#include <linux/pm_qos.h> #include <asm/byteorder.h> #include "core.h" @@ -36,10 +27,13 @@ #include "coredump.h" unsigned int ath10k_debug_mask; +EXPORT_SYMBOL(ath10k_debug_mask); + static unsigned int ath10k_cryptmode_param; static bool uart_print; static bool skip_otp; static bool rawmode; +static bool fw_diag_log; unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) | BIT(ATH10K_FW_CRASH_DUMP_CE_DATA); @@ -50,6 +44,7 @@ module_param(uart_print, bool, 0644); module_param(skip_otp, bool, 0644); module_param(rawmode, bool, 0644); +module_param(fw_diag_log, bool, 0644); module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444); MODULE_PARM_DESC(debug_mask, "Debugging mask"); @@ -58,11 +53,13 @@ MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software"); MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath"); MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file"); +MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging"); static const struct ath10k_hw_params ath10k_hw_params_list[] = { { .id = QCA988X_HW_2_0_VERSION, .dev_id = QCA988X_2_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca988x hw2.0", .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -84,7 +81,6 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, @@ -92,6 +88,9 @@ .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = true, }, { .id = QCA988X_HW_2_0_VERSION, @@ -117,19 +116,21 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = true, }, { .id = QCA9887_HW_1_0_VERSION, .dev_id = QCA9887_1_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9887 hw1.0", .patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -151,19 +152,52 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, + }, + { + .id = QCA6174_HW_3_2_VERSION, + .dev_id = QCA6174_3_2_DEVICE_ID, + .bus = ATH10K_BUS_SDIO, + .name = "qca6174 hw3.2 sdio", + .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, + .uart_pin = 19, + .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, + .max_probe_resp_desc_thres = 0, + .cal_data_len = 0, + .fw = { + .dir = QCA6174_HW_3_0_FW_DIR, + .board = QCA6174_HW_3_0_BOARD_DATA_FILE, + .board_size = QCA6174_BOARD_DATA_SZ, + .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, + }, + .hw_ops = &qca6174_sdio_ops, + .hw_clk = qca6174_clk, + .target_cpu_freq = 176000000, + .decap_align_bytes = 4, + .n_cipher_suites = 8, + .num_peers = 10, + .ast_skid_limit = 0x10, + .num_wds_entries = 0x20, + .uart_pin_workaround = true, + .tx_stats_over_pktlog = false, + .credit_size_workaround = false, + .bmi_large_size_download = true, + .supports_peer_stats_info = true, }, { .id = QCA6174_HW_2_1_VERSION, .dev_id = QCA6164_2_1_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca6164 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -184,19 +218,21 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, { .id = QCA6174_HW_2_1_VERSION, .dev_id = QCA6174_2_1_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca6174 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -217,19 +253,21 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, { .id = QCA6174_HW_3_0_VERSION, .dev_id = QCA6174_2_1_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca6174 hw3.0", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -250,19 +288,21 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, { .id = QCA6174_HW_3_2_VERSION, .dev_id = QCA6174_2_1_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca6174 hw3.2", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -286,19 +326,22 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = true, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, + .supports_peer_stats_info = true, }, { .id = QCA99X0_HW_2_0_DEV_VERSION, .dev_id = QCA99X0_2_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca99x0 hw2.0", .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -325,19 +368,21 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 11, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, { .id = QCA9984_HW_1_0_DEV_VERSION, .dev_id = QCA9984_1_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9984/qca9994 hw1.0", .patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -354,8 +399,10 @@ .fw = { .dir = QCA9984_HW_1_0_FW_DIR, .board = QCA9984_HW_1_0_BOARD_DATA_FILE, + .eboard = QCA9984_HW_1_0_EBOARD_DATA_FILE, .board_size = QCA99X0_BOARD_DATA_SZ, .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + .ext_board_size = QCA99X0_EXT_BOARD_DATA_SZ, }, .sw_decrypt_mcast_mgmt = true, .hw_ops = &qca99x0_ops, @@ -369,19 +416,21 @@ .vht160_mcs_rx_highest = 1560, .vht160_mcs_tx_highest = 1560, .n_cipher_suites = 11, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, { .id = QCA9888_HW_2_0_DEV_VERSION, .dev_id = QCA9888_2_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9888 hw2.0", .patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -412,19 +461,21 @@ .vht160_mcs_rx_highest = 780, .vht160_mcs_tx_highest = 780, .n_cipher_suites = 11, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, { .id = QCA9377_HW_1_0_DEV_VERSION, .dev_id = QCA9377_1_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9377 hw1.0", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -445,19 +496,21 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, { .id = QCA9377_HW_1_1_DEV_VERSION, .dev_id = QCA9377_1_0_DEVICE_ID, + .bus = ATH10K_BUS_PCI, .name = "qca9377 hw1.1", .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 6, @@ -480,19 +533,49 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 8, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = true, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, + }, + { + .id = QCA9377_HW_1_1_DEV_VERSION, + .dev_id = QCA9377_1_0_DEVICE_ID, + .bus = ATH10K_BUS_SDIO, + .name = "qca9377 hw1.1 sdio", + .patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR, + .uart_pin = 19, + .otp_exe_param = 0, + .channel_counters_freq_hz = 88000, + .max_probe_resp_desc_thres = 0, + .cal_data_len = 8124, + .fw = { + .dir = QCA9377_HW_1_0_FW_DIR, + .board = QCA9377_HW_1_0_BOARD_DATA_FILE, + .board_size = QCA9377_BOARD_DATA_SZ, + .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ, + }, + .hw_ops = &qca6174_ops, + .hw_clk = qca6174_clk, + .target_cpu_freq = 176000000, + .decap_align_bytes = 4, + .n_cipher_suites = 8, + .num_peers = TARGET_QCA9377_HL_NUM_PEERS, + .ast_skid_limit = 0x10, + .num_wds_entries = 0x20, + .uart_pin_workaround = true, + .credit_size_workaround = true, }, { .id = QCA4019_HW_1_0_DEV_VERSION, .dev_id = 0, + .bus = ATH10K_BUS_AHB, .name = "qca4019 hw1.0", .patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, @@ -520,19 +603,21 @@ .vht160_mcs_rx_highest = 0, .vht160_mcs_tx_highest = 0, .n_cipher_suites = 11, - .num_peers = TARGET_TLV_NUM_PEERS, .ast_skid_limit = 0x10, .num_wds_entries = 0x20, .target_64bit = false, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL, - .per_ce_irq = false, .shadow_reg_support = false, .rri_on_ddr = false, .hw_filter_reset_required = true, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, { .id = WCN3990_HW_1_0_DEV_VERSION, .dev_id = 0, + .bus = ATH10K_BUS_SNOC, .name = "wcn3990 hw1.0", .continuous_frag_desc = true, .tx_chain_mask = 0x7, @@ -544,16 +629,18 @@ .sw_decrypt_mcast_mgmt = true, .hw_ops = &wcn3990_ops, .decap_align_bytes = 1, - .num_peers = TARGET_HL_10_TLV_NUM_PEERS, + .num_peers = TARGET_HL_TLV_NUM_PEERS, .n_cipher_suites = 11, - .ast_skid_limit = TARGET_HL_10_TLV_AST_SKID_LIMIT, - .num_wds_entries = TARGET_HL_10_TLV_NUM_WDS_ENTRIES, + .ast_skid_limit = TARGET_HL_TLV_AST_SKID_LIMIT, + .num_wds_entries = TARGET_HL_TLV_NUM_WDS_ENTRIES, .target_64bit = true, .rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC, - .per_ce_irq = true, .shadow_reg_support = true, .rri_on_ddr = true, .hw_filter_reset_required = false, + .fw_diag_ce_download = false, + .credit_size_workaround = false, + .tx_stats_over_pktlog = false, }, }; @@ -578,6 +665,8 @@ [ATH10K_FW_FEATURE_NO_PS] = "no-ps", [ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference", [ATH10K_FW_FEATURE_NON_BMI] = "non-bmi", + [ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL] = "single-chan-info-per-channel", + [ATH10K_FW_FEATURE_PEER_FIXED_RATE] = "peer-fixed-rate", }; static unsigned int ath10k_core_get_fw_feature_str(char *buf, @@ -622,19 +711,51 @@ complete(&ar->target_suspend); } -static void ath10k_init_sdio(struct ath10k *ar) +static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode) { + bool mtu_workaround = ar->hw_params.credit_size_workaround; + int ret; u32 param = 0; - ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256); - ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99); - ath10k_bmi_read32(ar, hi_acs_flags, ¶m); + ret = ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256); + if (ret) + return ret; - param |= (HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET | - HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET | - HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE); + ret = ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99); + if (ret) + return ret; - ath10k_bmi_write32(ar, hi_acs_flags, param); + ret = ath10k_bmi_read32(ar, hi_acs_flags, ¶m); + if (ret) + return ret; + + param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET; + + if (mode == ATH10K_FIRMWARE_MODE_NORMAL && !mtu_workaround) + param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE; + else + param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE; + + if (mode == ATH10K_FIRMWARE_MODE_UTF) + param &= ~HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET; + else + param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET; + + ret = ath10k_bmi_write32(ar, hi_acs_flags, param); + if (ret) + return ret; + + ret = ath10k_bmi_read32(ar, hi_option_flag2, ¶m); + if (ret) + return ret; + + param |= HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_HOST; + + ret = ath10k_bmi_write32(ar, hi_option_flag2, param); + if (ret) + return ret; + + return 0; } static int ath10k_init_configure_target(struct ath10k *ar) @@ -777,11 +898,714 @@ return 0; } +static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) +{ + u32 result, address; + u8 board_id, chip_id; + bool ext_bid_support; + int ret, bmi_board_id_param; + + address = ar->hw_params.patch_load_addr; + + if (!ar->normal_mode_fw.fw_file.otp_data || + !ar->normal_mode_fw.fw_file.otp_len) { + ath10k_warn(ar, + "failed to retrieve board id because of invalid otp\n"); + return -ENODATA; + } + + if (ar->id.bmi_ids_valid) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot already acquired valid otp board id,skip download, board_id %d chip_id %d\n", + ar->id.bmi_board_id, ar->id.bmi_chip_id); + goto skip_otp_download; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot upload otp to 0x%x len %zd for board id\n", + address, ar->normal_mode_fw.fw_file.otp_len); + + ret = ath10k_bmi_fast_download(ar, address, + ar->normal_mode_fw.fw_file.otp_data, + ar->normal_mode_fw.fw_file.otp_len); + if (ret) { + ath10k_err(ar, "could not write otp for board id check: %d\n", + ret); + return ret; + } + + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID; + else + bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID; + + ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result); + if (ret) { + ath10k_err(ar, "could not execute otp for board id check: %d\n", + ret); + return ret; + } + + board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP); + chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP); + ext_bid_support = (result & ATH10K_BMI_EXT_BOARD_ID_SUPPORT); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot get otp board id result 0x%08x board_id %d chip_id %d ext_bid_support %d\n", + result, board_id, chip_id, ext_bid_support); + + ar->id.ext_bid_supported = ext_bid_support; + + if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 || + (board_id == 0)) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "board id does not exist in otp, ignore it\n"); + return -EOPNOTSUPP; + } + + ar->id.bmi_ids_valid = true; + ar->id.bmi_board_id = board_id; + ar->id.bmi_chip_id = chip_id; + +skip_otp_download: + + return 0; +} + +static void ath10k_core_check_bdfext(const struct dmi_header *hdr, void *data) +{ + struct ath10k *ar = data; + const char *bdf_ext; + const char *magic = ATH10K_SMBIOS_BDF_EXT_MAGIC; + u8 bdf_enabled; + int i; + + if (hdr->type != ATH10K_SMBIOS_BDF_EXT_TYPE) + return; + + if (hdr->length != ATH10K_SMBIOS_BDF_EXT_LENGTH) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "wrong smbios bdf ext type length (%d).\n", + hdr->length); + return; + } + + bdf_enabled = *((u8 *)hdr + ATH10K_SMBIOS_BDF_EXT_OFFSET); + if (!bdf_enabled) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not found.\n"); + return; + } + + /* Only one string exists (per spec) */ + bdf_ext = (char *)hdr + hdr->length; + + if (memcmp(bdf_ext, magic, strlen(magic)) != 0) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "bdf variant magic does not match.\n"); + return; + } + + for (i = 0; i < strlen(bdf_ext); i++) { + if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "bdf variant name contains non ascii chars.\n"); + return; + } + } + + /* Copy extension name without magic suffix */ + if (strscpy(ar->id.bdf_ext, bdf_ext + strlen(magic), + sizeof(ar->id.bdf_ext)) < 0) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", + bdf_ext); + return; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "found and validated bdf variant smbios_type 0x%x bdf %s\n", + ATH10K_SMBIOS_BDF_EXT_TYPE, bdf_ext); +} + +static int ath10k_core_check_smbios(struct ath10k *ar) +{ + ar->id.bdf_ext[0] = '\0'; + dmi_walk(ath10k_core_check_bdfext, ar); + + if (ar->id.bdf_ext[0] == '\0') + return -ENODATA; + + return 0; +} + +int ath10k_core_check_dt(struct ath10k *ar) +{ + struct device_node *node; + const char *variant = NULL; + + node = ar->dev->of_node; + if (!node) + return -ENOENT; + + of_property_read_string(node, "qcom,ath10k-calibration-variant", + &variant); + if (!variant) + return -ENODATA; + + if (strscpy(ar->id.bdf_ext, variant, sizeof(ar->id.bdf_ext)) < 0) + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", + variant); + + return 0; +} +EXPORT_SYMBOL(ath10k_core_check_dt); + +static int ath10k_download_fw(struct ath10k *ar) +{ + u32 address, data_len; + const void *data; + int ret; + struct pm_qos_request latency_qos; + + address = ar->hw_params.patch_load_addr; + + data = ar->running_fw->fw_file.firmware_data; + data_len = ar->running_fw->fw_file.firmware_len; + + ret = ath10k_swap_code_seg_configure(ar, &ar->running_fw->fw_file); + if (ret) { + ath10k_err(ar, "failed to configure fw code swap: %d\n", + ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot uploading firmware image %pK len %d\n", + data, data_len); + + /* Check if device supports to download firmware via + * diag copy engine. Downloading firmware via diag CE + * greatly reduces the time to download firmware. + */ + if (ar->hw_params.fw_diag_ce_download) { + ret = ath10k_hw_diag_fast_download(ar, address, + data, data_len); + if (ret == 0) + /* firmware upload via diag ce was successful */ + return 0; + + ath10k_warn(ar, + "failed to upload firmware via diag ce, trying BMI: %d", + ret); + } + + memset(&latency_qos, 0, sizeof(latency_qos)); + cpu_latency_qos_add_request(&latency_qos, 0); + + ret = ath10k_bmi_fast_download(ar, address, data, data_len); + + cpu_latency_qos_remove_request(&latency_qos); + + return ret; +} + +void ath10k_core_free_board_files(struct ath10k *ar) +{ + if (!IS_ERR(ar->normal_mode_fw.board)) + release_firmware(ar->normal_mode_fw.board); + + if (!IS_ERR(ar->normal_mode_fw.ext_board)) + release_firmware(ar->normal_mode_fw.ext_board); + + ar->normal_mode_fw.board = NULL; + ar->normal_mode_fw.board_data = NULL; + ar->normal_mode_fw.board_len = 0; + ar->normal_mode_fw.ext_board = NULL; + ar->normal_mode_fw.ext_board_data = NULL; + ar->normal_mode_fw.ext_board_len = 0; +} +EXPORT_SYMBOL(ath10k_core_free_board_files); + +static void ath10k_core_free_firmware_files(struct ath10k *ar) +{ + if (!IS_ERR(ar->normal_mode_fw.fw_file.firmware)) + release_firmware(ar->normal_mode_fw.fw_file.firmware); + + if (!IS_ERR(ar->cal_file)) + release_firmware(ar->cal_file); + + if (!IS_ERR(ar->pre_cal_file)) + release_firmware(ar->pre_cal_file); + + ath10k_swap_code_seg_release(ar, &ar->normal_mode_fw.fw_file); + + ar->normal_mode_fw.fw_file.otp_data = NULL; + ar->normal_mode_fw.fw_file.otp_len = 0; + + ar->normal_mode_fw.fw_file.firmware = NULL; + ar->normal_mode_fw.fw_file.firmware_data = NULL; + ar->normal_mode_fw.fw_file.firmware_len = 0; + + ar->cal_file = NULL; + ar->pre_cal_file = NULL; +} + +static int ath10k_fetch_cal_file(struct ath10k *ar) +{ + char filename[100]; + + /* pre-cal-<bus>-<id>.bin */ + scnprintf(filename, sizeof(filename), "pre-cal-%s-%s.bin", + ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); + + ar->pre_cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename); + if (!IS_ERR(ar->pre_cal_file)) + goto success; + + /* cal-<bus>-<id>.bin */ + scnprintf(filename, sizeof(filename), "cal-%s-%s.bin", + ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); + + ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename); + if (IS_ERR(ar->cal_file)) + /* calibration file is optional, don't print any warnings */ + return PTR_ERR(ar->cal_file); +success: + ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n", + ATH10K_FW_DIR, filename); + + return 0; +} + +static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type) +{ + const struct firmware *fw; + + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + if (!ar->hw_params.fw.board) { + ath10k_err(ar, "failed to find board file fw entry\n"); + return -EINVAL; + } + + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + ar->hw_params.fw.board); + if (IS_ERR(ar->normal_mode_fw.board)) + return PTR_ERR(ar->normal_mode_fw.board); + + ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data; + ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size; + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + if (!ar->hw_params.fw.eboard) { + ath10k_err(ar, "failed to find eboard file fw entry\n"); + return -EINVAL; + } + + fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, + ar->hw_params.fw.eboard); + ar->normal_mode_fw.ext_board = fw; + if (IS_ERR(ar->normal_mode_fw.ext_board)) + return PTR_ERR(ar->normal_mode_fw.ext_board); + + ar->normal_mode_fw.ext_board_data = ar->normal_mode_fw.ext_board->data; + ar->normal_mode_fw.ext_board_len = ar->normal_mode_fw.ext_board->size; + } + + return 0; +} + +static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, + const void *buf, size_t buf_len, + const char *boardname, + int bd_ie_type) +{ + const struct ath10k_fw_ie *hdr; + bool name_match_found; + int ret, board_ie_id; + size_t board_ie_len; + const void *board_ie_data; + + name_match_found = false; + + /* go through ATH10K_BD_IE_BOARD_ elements */ + while (buf_len > sizeof(struct ath10k_fw_ie)) { + hdr = buf; + board_ie_id = le32_to_cpu(hdr->id); + board_ie_len = le32_to_cpu(hdr->len); + board_ie_data = hdr->data; + + buf_len -= sizeof(*hdr); + buf += sizeof(*hdr); + + if (buf_len < ALIGN(board_ie_len, 4)) { + ath10k_err(ar, "invalid ATH10K_BD_IE_BOARD length: %zu < %zu\n", + buf_len, ALIGN(board_ie_len, 4)); + ret = -EINVAL; + goto out; + } + + switch (board_ie_id) { + case ATH10K_BD_IE_BOARD_NAME: + ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "board name", "", + board_ie_data, board_ie_len); + + if (board_ie_len != strlen(boardname)) + break; + + ret = memcmp(board_ie_data, boardname, strlen(boardname)); + if (ret) + break; + + name_match_found = true; + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot found match for name '%s'", + boardname); + break; + case ATH10K_BD_IE_BOARD_DATA: + if (!name_match_found) + /* no match found */ + break; + + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot found board data for '%s'", + boardname); + + ar->normal_mode_fw.board_data = board_ie_data; + ar->normal_mode_fw.board_len = board_ie_len; + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot found eboard data for '%s'", + boardname); + + ar->normal_mode_fw.ext_board_data = board_ie_data; + ar->normal_mode_fw.ext_board_len = board_ie_len; + } + + ret = 0; + goto out; + default: + ath10k_warn(ar, "unknown ATH10K_BD_IE_BOARD found: %d\n", + board_ie_id); + break; + } + + /* jump over the padding */ + board_ie_len = ALIGN(board_ie_len, 4); + + buf_len -= board_ie_len; + buf += board_ie_len; + } + + /* no match found */ + ret = -ENOENT; + +out: + return ret; +} + +static int ath10k_core_search_bd(struct ath10k *ar, + const char *boardname, + const u8 *data, + size_t len) +{ + size_t ie_len; + struct ath10k_fw_ie *hdr; + int ret = -ENOENT, ie_id; + + while (len > sizeof(struct ath10k_fw_ie)) { + hdr = (struct ath10k_fw_ie *)data; + ie_id = le32_to_cpu(hdr->id); + ie_len = le32_to_cpu(hdr->len); + + len -= sizeof(*hdr); + data = hdr->data; + + if (len < ALIGN(ie_len, 4)) { + ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", + ie_id, ie_len, len); + return -EINVAL; + } + + switch (ie_id) { + case ATH10K_BD_IE_BOARD: + ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, + boardname, + ATH10K_BD_IE_BOARD); + if (ret == -ENOENT) + /* no match found, continue */ + break; + + /* either found or error, so stop searching */ + goto out; + case ATH10K_BD_IE_BOARD_EXT: + ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, + boardname, + ATH10K_BD_IE_BOARD_EXT); + if (ret == -ENOENT) + /* no match found, continue */ + break; + + /* either found or error, so stop searching */ + goto out; + } + + /* jump over the padding */ + ie_len = ALIGN(ie_len, 4); + + len -= ie_len; + data += ie_len; + } + +out: + /* return result of parse_bd_ie_board() or -ENOENT */ + return ret; +} + +static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, + const char *boardname, + const char *fallback_boardname, + const char *filename) +{ + size_t len, magic_len; + const u8 *data; + int ret; + + /* Skip if already fetched during board data download */ + if (!ar->normal_mode_fw.board) + ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, + ar->hw_params.fw.dir, + filename); + if (IS_ERR(ar->normal_mode_fw.board)) + return PTR_ERR(ar->normal_mode_fw.board); + + data = ar->normal_mode_fw.board->data; + len = ar->normal_mode_fw.board->size; + + /* magic has extra null byte padded */ + magic_len = strlen(ATH10K_BOARD_MAGIC) + 1; + if (len < magic_len) { + ath10k_err(ar, "failed to find magic value in %s/%s, file too short: %zu\n", + ar->hw_params.fw.dir, filename, len); + ret = -EINVAL; + goto err; + } + + if (memcmp(data, ATH10K_BOARD_MAGIC, magic_len)) { + ath10k_err(ar, "found invalid board magic\n"); + ret = -EINVAL; + goto err; + } + + /* magic is padded to 4 bytes */ + magic_len = ALIGN(magic_len, 4); + if (len < magic_len) { + ath10k_err(ar, "failed: %s/%s too small to contain board data, len: %zu\n", + ar->hw_params.fw.dir, filename, len); + ret = -EINVAL; + goto err; + } + + data += magic_len; + len -= magic_len; + + /* attempt to find boardname in the IE list */ + ret = ath10k_core_search_bd(ar, boardname, data, len); + + /* if we didn't find it and have a fallback name, try that */ + if (ret == -ENOENT && fallback_boardname) + ret = ath10k_core_search_bd(ar, fallback_boardname, data, len); + + if (ret == -ENOENT) { + ath10k_err(ar, + "failed to fetch board data for %s from %s/%s\n", + boardname, ar->hw_params.fw.dir, filename); + ret = -ENODATA; + } + + if (ret) + goto err; + + return 0; + +err: + ath10k_core_free_board_files(ar); + return ret; +} + +static int ath10k_core_create_board_name(struct ath10k *ar, char *name, + size_t name_len, bool with_variant) +{ + /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ + char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; + + if (with_variant && ar->id.bdf_ext[0] != '\0') + scnprintf(variant, sizeof(variant), ",variant=%s", + ar->id.bdf_ext); + + if (ar->id.bmi_ids_valid) { + scnprintf(name, name_len, + "bus=%s,bmi-chip-id=%d,bmi-board-id=%d%s", + ath10k_bus_str(ar->hif.bus), + ar->id.bmi_chip_id, + ar->id.bmi_board_id, variant); + goto out; + } + + if (ar->id.qmi_ids_valid) { + if (with_variant && ar->id.bdf_ext[0] != '\0') + scnprintf(name, name_len, + "bus=%s,qmi-board-id=%x,qmi-chip-id=%x%s", + ath10k_bus_str(ar->hif.bus), + ar->id.qmi_board_id, ar->id.qmi_chip_id, + variant); + else + scnprintf(name, name_len, + "bus=%s,qmi-board-id=%x", + ath10k_bus_str(ar->hif.bus), + ar->id.qmi_board_id); + goto out; + } + + scnprintf(name, name_len, + "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s", + ath10k_bus_str(ar->hif.bus), + ar->id.vendor, ar->id.device, + ar->id.subsystem_vendor, ar->id.subsystem_device, variant); +out: + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name); + + return 0; +} + +static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name, + size_t name_len) +{ + if (ar->id.bmi_ids_valid) { + scnprintf(name, name_len, + "bus=%s,bmi-chip-id=%d,bmi-eboard-id=%d", + ath10k_bus_str(ar->hif.bus), + ar->id.bmi_chip_id, + ar->id.bmi_eboard_id); + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using eboard name '%s'\n", name); + return 0; + } + /* Fallback if returned board id is zero */ + return -1; +} + +int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type) +{ + char boardname[100], fallback_boardname[100]; + int ret; + + if (bd_ie_type == ATH10K_BD_IE_BOARD) { + ret = ath10k_core_create_board_name(ar, boardname, + sizeof(boardname), true); + if (ret) { + ath10k_err(ar, "failed to create board name: %d", ret); + return ret; + } + + ret = ath10k_core_create_board_name(ar, fallback_boardname, + sizeof(boardname), false); + if (ret) { + ath10k_err(ar, "failed to create fallback board name: %d", ret); + return ret; + } + } else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) { + ret = ath10k_core_create_eboard_name(ar, boardname, + sizeof(boardname)); + if (ret) { + ath10k_err(ar, "fallback to eboard.bin since board id 0"); + goto fallback; + } + } + + ar->bd_api = 2; + ret = ath10k_core_fetch_board_data_api_n(ar, boardname, + fallback_boardname, + ATH10K_BOARD_API2_FILE); + if (!ret) + goto success; + +fallback: + ar->bd_api = 1; + ret = ath10k_core_fetch_board_data_api_1(ar, bd_ie_type); + if (ret) { + ath10k_err(ar, "failed to fetch board-2.bin or board.bin from %s\n", + ar->hw_params.fw.dir); + return ret; + } + +success: + ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api); + return 0; +} +EXPORT_SYMBOL(ath10k_core_fetch_board_file); + +static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar) +{ + u32 result, address; + u8 ext_board_id; + int ret; + + address = ar->hw_params.patch_load_addr; + + if (!ar->normal_mode_fw.fw_file.otp_data || + !ar->normal_mode_fw.fw_file.otp_len) { + ath10k_warn(ar, + "failed to retrieve extended board id due to otp binary missing\n"); + return -ENODATA; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot upload otp to 0x%x len %zd for ext board id\n", + address, ar->normal_mode_fw.fw_file.otp_len); + + ret = ath10k_bmi_fast_download(ar, address, + ar->normal_mode_fw.fw_file.otp_data, + ar->normal_mode_fw.fw_file.otp_len); + if (ret) { + ath10k_err(ar, "could not write otp for ext board id check: %d\n", + ret); + return ret; + } + + ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EXT_BOARD_ID, &result); + if (ret) { + ath10k_err(ar, "could not execute otp for ext board id check: %d\n", + ret); + return ret; + } + + if (!result) { + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "ext board id does not exist in otp, ignore it\n"); + return -EOPNOTSUPP; + } + + ext_board_id = result & ATH10K_BMI_EBOARD_ID_STATUS_MASK; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot get otp ext board id result 0x%08x ext_board_id %d\n", + result, ext_board_id); + + ar->id.bmi_eboard_id = ext_board_id; + + return 0; +} + static int ath10k_download_board_data(struct ath10k *ar, const void *data, size_t data_len) { u32 board_data_size = ar->hw_params.fw.board_size; - u32 address; + u32 eboard_data_size = ar->hw_params.fw.ext_board_size; + u32 board_address; + u32 ext_board_address; int ret; ret = ath10k_push_board_ext_data(ar, data, data_len); @@ -790,13 +1614,13 @@ goto exit; } - ret = ath10k_bmi_read32(ar, hi_board_data, &address); + ret = ath10k_bmi_read32(ar, hi_board_data, &board_address); if (ret) { ath10k_err(ar, "could not read board data addr (%d)\n", ret); goto exit; } - ret = ath10k_bmi_write_memory(ar, address, data, + ret = ath10k_bmi_write_memory(ar, board_address, data, min_t(u32, board_data_size, data_len)); if (ret) { @@ -810,8 +1634,96 @@ goto exit; } + if (!ar->id.ext_bid_supported) + goto exit; + + /* Extended board data download */ + ret = ath10k_core_get_ext_board_id_from_otp(ar); + if (ret == -EOPNOTSUPP) { + /* Not fetching ext_board_data if ext board id is 0 */ + ath10k_dbg(ar, ATH10K_DBG_BOOT, "otp returned ext board id 0\n"); + return 0; + } else if (ret) { + ath10k_err(ar, "failed to get extended board id: %d\n", ret); + goto exit; + } + + ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD_EXT); + if (ret) + goto exit; + + if (ar->normal_mode_fw.ext_board_data) { + ext_board_address = board_address + EXT_BOARD_ADDRESS_OFFSET; + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "boot writing ext board data to addr 0x%x", + ext_board_address); + ret = ath10k_bmi_write_memory(ar, ext_board_address, + ar->normal_mode_fw.ext_board_data, + min_t(u32, eboard_data_size, data_len)); + if (ret) + ath10k_err(ar, "failed to write ext board data: %d\n", ret); + } + exit: return ret; +} + +static int ath10k_download_and_run_otp(struct ath10k *ar) +{ + u32 result, address = ar->hw_params.patch_load_addr; + u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; + int ret; + + ret = ath10k_download_board_data(ar, + ar->running_fw->board_data, + ar->running_fw->board_len); + if (ret) { + ath10k_err(ar, "failed to download board data: %d\n", ret); + return ret; + } + + /* OTP is optional */ + + if (!ar->running_fw->fw_file.otp_data || + !ar->running_fw->fw_file.otp_len) { + ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n", + ar->running_fw->fw_file.otp_data, + ar->running_fw->fw_file.otp_len); + return 0; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", + address, ar->running_fw->fw_file.otp_len); + + ret = ath10k_bmi_fast_download(ar, address, + ar->running_fw->fw_file.otp_data, + ar->running_fw->fw_file.otp_len); + if (ret) { + ath10k_err(ar, "could not write otp (%d)\n", ret); + return ret; + } + + /* As of now pre-cal is valid for 10_4 variants */ + if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || + ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) + bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; + + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); + if (ret) { + ath10k_err(ar, "could not execute otp (%d)\n", ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); + + if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, + ar->running_fw->fw_file.fw_features)) && + result != 0) { + ath10k_err(ar, "otp calibration failed: %d", result); + return -EINVAL; + } + + return 0; } static int ath10k_download_cal_file(struct ath10k *ar, @@ -918,591 +1830,6 @@ kfree(data); return ret; -} - -static int ath10k_core_get_board_id_from_otp(struct ath10k *ar) -{ - u32 result, address; - u8 board_id, chip_id; - int ret, bmi_board_id_param; - - address = ar->hw_params.patch_load_addr; - - if (!ar->normal_mode_fw.fw_file.otp_data || - !ar->normal_mode_fw.fw_file.otp_len) { - ath10k_warn(ar, - "failed to retrieve board id because of invalid otp\n"); - return -ENODATA; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot upload otp to 0x%x len %zd for board id\n", - address, ar->normal_mode_fw.fw_file.otp_len); - - ret = ath10k_bmi_fast_download(ar, address, - ar->normal_mode_fw.fw_file.otp_data, - ar->normal_mode_fw.fw_file.otp_len); - if (ret) { - ath10k_err(ar, "could not write otp for board id check: %d\n", - ret); - return ret; - } - - if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || - ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) - bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID; - else - bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID; - - ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result); - if (ret) { - ath10k_err(ar, "could not execute otp for board id check: %d\n", - ret); - return ret; - } - - board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP); - chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP); - - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot get otp board id result 0x%08x board_id %d chip_id %d\n", - result, board_id, chip_id); - - if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 || - (board_id == 0)) { - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "board id does not exist in otp, ignore it\n"); - return -EOPNOTSUPP; - } - - ar->id.bmi_ids_valid = true; - ar->id.bmi_board_id = board_id; - ar->id.bmi_chip_id = chip_id; - - return 0; -} - -static void ath10k_core_check_bdfext(const struct dmi_header *hdr, void *data) -{ - struct ath10k *ar = data; - const char *bdf_ext; - const char *magic = ATH10K_SMBIOS_BDF_EXT_MAGIC; - u8 bdf_enabled; - int i; - - if (hdr->type != ATH10K_SMBIOS_BDF_EXT_TYPE) - return; - - if (hdr->length != ATH10K_SMBIOS_BDF_EXT_LENGTH) { - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "wrong smbios bdf ext type length (%d).\n", - hdr->length); - return; - } - - bdf_enabled = *((u8 *)hdr + ATH10K_SMBIOS_BDF_EXT_OFFSET); - if (!bdf_enabled) { - ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not found.\n"); - return; - } - - /* Only one string exists (per spec) */ - bdf_ext = (char *)hdr + hdr->length; - - if (memcmp(bdf_ext, magic, strlen(magic)) != 0) { - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "bdf variant magic does not match.\n"); - return; - } - - for (i = 0; i < strlen(bdf_ext); i++) { - if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) { - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "bdf variant name contains non ascii chars.\n"); - return; - } - } - - /* Copy extension name without magic suffix */ - if (strscpy(ar->id.bdf_ext, bdf_ext + strlen(magic), - sizeof(ar->id.bdf_ext)) < 0) { - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", - bdf_ext); - return; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "found and validated bdf variant smbios_type 0x%x bdf %s\n", - ATH10K_SMBIOS_BDF_EXT_TYPE, bdf_ext); -} - -static int ath10k_core_check_smbios(struct ath10k *ar) -{ - ar->id.bdf_ext[0] = '\0'; - dmi_walk(ath10k_core_check_bdfext, ar); - - if (ar->id.bdf_ext[0] == '\0') - return -ENODATA; - - return 0; -} - -static int ath10k_core_check_dt(struct ath10k *ar) -{ - struct device_node *node; - const char *variant = NULL; - - node = ar->dev->of_node; - if (!node) - return -ENOENT; - - of_property_read_string(node, "qcom,ath10k-calibration-variant", - &variant); - if (!variant) - return -ENODATA; - - if (strscpy(ar->id.bdf_ext, variant, sizeof(ar->id.bdf_ext)) < 0) - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "bdf variant string is longer than the buffer can accommodate (variant: %s)\n", - variant); - - return 0; -} - -static int ath10k_download_and_run_otp(struct ath10k *ar) -{ - u32 result, address = ar->hw_params.patch_load_addr; - u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; - int ret; - - ret = ath10k_download_board_data(ar, - ar->running_fw->board_data, - ar->running_fw->board_len); - if (ret) { - ath10k_err(ar, "failed to download board data: %d\n", ret); - return ret; - } - - /* OTP is optional */ - - if (!ar->running_fw->fw_file.otp_data || - !ar->running_fw->fw_file.otp_len) { - ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n", - ar->running_fw->fw_file.otp_data, - ar->running_fw->fw_file.otp_len); - return 0; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n", - address, ar->running_fw->fw_file.otp_len); - - ret = ath10k_bmi_fast_download(ar, address, - ar->running_fw->fw_file.otp_data, - ar->running_fw->fw_file.otp_len); - if (ret) { - ath10k_err(ar, "could not write otp (%d)\n", ret); - return ret; - } - - /* As of now pre-cal is valid for 10_4 variants */ - if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT || - ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE) - bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL; - - ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); - if (ret) { - ath10k_err(ar, "could not execute otp (%d)\n", ret); - return ret; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result); - - if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT, - ar->running_fw->fw_file.fw_features)) && - result != 0) { - ath10k_err(ar, "otp calibration failed: %d", result); - return -EINVAL; - } - - return 0; -} - -static int ath10k_download_fw(struct ath10k *ar) -{ - u32 address, data_len; - const void *data; - int ret; - - address = ar->hw_params.patch_load_addr; - - data = ar->running_fw->fw_file.firmware_data; - data_len = ar->running_fw->fw_file.firmware_len; - - ret = ath10k_swap_code_seg_configure(ar, &ar->running_fw->fw_file); - if (ret) { - ath10k_err(ar, "failed to configure fw code swap: %d\n", - ret); - return ret; - } - - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot uploading firmware image %pK len %d\n", - data, data_len); - - ret = ath10k_bmi_fast_download(ar, address, data, data_len); - if (ret) { - ath10k_err(ar, "failed to download firmware: %d\n", - ret); - return ret; - } - - return ret; -} - -static void ath10k_core_free_board_files(struct ath10k *ar) -{ - if (!IS_ERR(ar->normal_mode_fw.board)) - release_firmware(ar->normal_mode_fw.board); - - ar->normal_mode_fw.board = NULL; - ar->normal_mode_fw.board_data = NULL; - ar->normal_mode_fw.board_len = 0; -} - -static void ath10k_core_free_firmware_files(struct ath10k *ar) -{ - if (!IS_ERR(ar->normal_mode_fw.fw_file.firmware)) - release_firmware(ar->normal_mode_fw.fw_file.firmware); - - if (!IS_ERR(ar->cal_file)) - release_firmware(ar->cal_file); - - if (!IS_ERR(ar->pre_cal_file)) - release_firmware(ar->pre_cal_file); - - ath10k_swap_code_seg_release(ar, &ar->normal_mode_fw.fw_file); - - ar->normal_mode_fw.fw_file.otp_data = NULL; - ar->normal_mode_fw.fw_file.otp_len = 0; - - ar->normal_mode_fw.fw_file.firmware = NULL; - ar->normal_mode_fw.fw_file.firmware_data = NULL; - ar->normal_mode_fw.fw_file.firmware_len = 0; - - ar->cal_file = NULL; - ar->pre_cal_file = NULL; -} - -static int ath10k_fetch_cal_file(struct ath10k *ar) -{ - char filename[100]; - - /* pre-cal-<bus>-<id>.bin */ - scnprintf(filename, sizeof(filename), "pre-cal-%s-%s.bin", - ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); - - ar->pre_cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename); - if (!IS_ERR(ar->pre_cal_file)) - goto success; - - /* cal-<bus>-<id>.bin */ - scnprintf(filename, sizeof(filename), "cal-%s-%s.bin", - ath10k_bus_str(ar->hif.bus), dev_name(ar->dev)); - - ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename); - if (IS_ERR(ar->cal_file)) - /* calibration file is optional, don't print any warnings */ - return PTR_ERR(ar->cal_file); -success: - ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n", - ATH10K_FW_DIR, filename); - - return 0; -} - -static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar) -{ - if (!ar->hw_params.fw.board) { - ath10k_err(ar, "failed to find board file fw entry\n"); - return -EINVAL; - } - - ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, - ar->hw_params.fw.dir, - ar->hw_params.fw.board); - if (IS_ERR(ar->normal_mode_fw.board)) - return PTR_ERR(ar->normal_mode_fw.board); - - ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data; - ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size; - - return 0; -} - -static int ath10k_core_parse_bd_ie_board(struct ath10k *ar, - const void *buf, size_t buf_len, - const char *boardname) -{ - const struct ath10k_fw_ie *hdr; - bool name_match_found; - int ret, board_ie_id; - size_t board_ie_len; - const void *board_ie_data; - - name_match_found = false; - - /* go through ATH10K_BD_IE_BOARD_ elements */ - while (buf_len > sizeof(struct ath10k_fw_ie)) { - hdr = buf; - board_ie_id = le32_to_cpu(hdr->id); - board_ie_len = le32_to_cpu(hdr->len); - board_ie_data = hdr->data; - - buf_len -= sizeof(*hdr); - buf += sizeof(*hdr); - - if (buf_len < ALIGN(board_ie_len, 4)) { - ath10k_err(ar, "invalid ATH10K_BD_IE_BOARD length: %zu < %zu\n", - buf_len, ALIGN(board_ie_len, 4)); - ret = -EINVAL; - goto out; - } - - switch (board_ie_id) { - case ATH10K_BD_IE_BOARD_NAME: - ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "board name", "", - board_ie_data, board_ie_len); - - if (board_ie_len != strlen(boardname)) - break; - - ret = memcmp(board_ie_data, boardname, strlen(boardname)); - if (ret) - break; - - name_match_found = true; - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot found match for name '%s'", - boardname); - break; - case ATH10K_BD_IE_BOARD_DATA: - if (!name_match_found) - /* no match found */ - break; - - ath10k_dbg(ar, ATH10K_DBG_BOOT, - "boot found board data for '%s'", - boardname); - - ar->normal_mode_fw.board_data = board_ie_data; - ar->normal_mode_fw.board_len = board_ie_len; - - ret = 0; - goto out; - default: - ath10k_warn(ar, "unknown ATH10K_BD_IE_BOARD found: %d\n", - board_ie_id); - break; - } - - /* jump over the padding */ - board_ie_len = ALIGN(board_ie_len, 4); - - buf_len -= board_ie_len; - buf += board_ie_len; - } - - /* no match found */ - ret = -ENOENT; - -out: - return ret; -} - -static int ath10k_core_search_bd(struct ath10k *ar, - const char *boardname, - const u8 *data, - size_t len) -{ - size_t ie_len; - struct ath10k_fw_ie *hdr; - int ret = -ENOENT, ie_id; - - while (len > sizeof(struct ath10k_fw_ie)) { - hdr = (struct ath10k_fw_ie *)data; - ie_id = le32_to_cpu(hdr->id); - ie_len = le32_to_cpu(hdr->len); - - len -= sizeof(*hdr); - data = hdr->data; - - if (len < ALIGN(ie_len, 4)) { - ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n", - ie_id, ie_len, len); - return -EINVAL; - } - - switch (ie_id) { - case ATH10K_BD_IE_BOARD: - ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len, - boardname); - if (ret == -ENOENT) - /* no match found, continue */ - break; - - /* either found or error, so stop searching */ - goto out; - } - - /* jump over the padding */ - ie_len = ALIGN(ie_len, 4); - - len -= ie_len; - data += ie_len; - } - -out: - /* return result of parse_bd_ie_board() or -ENOENT */ - return ret; -} - -static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar, - const char *boardname, - const char *fallback_boardname, - const char *filename) -{ - size_t len, magic_len; - const u8 *data; - int ret; - - ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar, - ar->hw_params.fw.dir, - filename); - if (IS_ERR(ar->normal_mode_fw.board)) - return PTR_ERR(ar->normal_mode_fw.board); - - data = ar->normal_mode_fw.board->data; - len = ar->normal_mode_fw.board->size; - - /* magic has extra null byte padded */ - magic_len = strlen(ATH10K_BOARD_MAGIC) + 1; - if (len < magic_len) { - ath10k_err(ar, "failed to find magic value in %s/%s, file too short: %zu\n", - ar->hw_params.fw.dir, filename, len); - ret = -EINVAL; - goto err; - } - - if (memcmp(data, ATH10K_BOARD_MAGIC, magic_len)) { - ath10k_err(ar, "found invalid board magic\n"); - ret = -EINVAL; - goto err; - } - - /* magic is padded to 4 bytes */ - magic_len = ALIGN(magic_len, 4); - if (len < magic_len) { - ath10k_err(ar, "failed: %s/%s too small to contain board data, len: %zu\n", - ar->hw_params.fw.dir, filename, len); - ret = -EINVAL; - goto err; - } - - data += magic_len; - len -= magic_len; - - /* attempt to find boardname in the IE list */ - ret = ath10k_core_search_bd(ar, boardname, data, len); - - /* if we didn't find it and have a fallback name, try that */ - if (ret == -ENOENT && fallback_boardname) - ret = ath10k_core_search_bd(ar, fallback_boardname, data, len); - - if (ret == -ENOENT) { - ath10k_err(ar, - "failed to fetch board data for %s from %s/%s\n", - boardname, ar->hw_params.fw.dir, filename); - ret = -ENODATA; - } - - if (ret) - goto err; - - return 0; - -err: - ath10k_core_free_board_files(ar); - return ret; -} - -static int ath10k_core_create_board_name(struct ath10k *ar, char *name, - size_t name_len, bool with_variant) -{ - /* strlen(',variant=') + strlen(ar->id.bdf_ext) */ - char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 }; - - if (with_variant && ar->id.bdf_ext[0] != '\0') - scnprintf(variant, sizeof(variant), ",variant=%s", - ar->id.bdf_ext); - - if (ar->id.bmi_ids_valid) { - scnprintf(name, name_len, - "bus=%s,bmi-chip-id=%d,bmi-board-id=%d%s", - ath10k_bus_str(ar->hif.bus), - ar->id.bmi_chip_id, - ar->id.bmi_board_id, variant); - goto out; - } - - scnprintf(name, name_len, - "bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s", - ath10k_bus_str(ar->hif.bus), - ar->id.vendor, ar->id.device, - ar->id.subsystem_vendor, ar->id.subsystem_device, variant); -out: - ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name); - - return 0; -} - -static int ath10k_core_fetch_board_file(struct ath10k *ar) -{ - char boardname[100], fallback_boardname[100]; - int ret; - - ret = ath10k_core_create_board_name(ar, boardname, - sizeof(boardname), true); - if (ret) { - ath10k_err(ar, "failed to create board name: %d", ret); - return ret; - } - - ret = ath10k_core_create_board_name(ar, fallback_boardname, - sizeof(boardname), false); - if (ret) { - ath10k_err(ar, "failed to create fallback board name: %d", ret); - return ret; - } - - ar->bd_api = 2; - ret = ath10k_core_fetch_board_data_api_n(ar, boardname, - fallback_boardname, - ATH10K_BOARD_API2_FILE); - if (!ret) - goto success; - - ar->bd_api = 1; - ret = ath10k_core_fetch_board_data_api_1(ar); - if (ret) { - ath10k_err(ar, "failed to fetch board-2.bin or board.bin from %s\n", - ar->hw_params.fw.dir); - return ret; - } - -success: - ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api); - return 0; } int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name, @@ -1849,6 +2176,40 @@ return 0; } +static void ath10k_core_fetch_btcoex_dt(struct ath10k *ar) +{ + struct device_node *node; + u8 coex_support = 0; + int ret; + + node = ar->dev->of_node; + if (!node) + goto out; + + ret = of_property_read_u8(node, "qcom,coexist-support", &coex_support); + if (ret) { + ar->coex_support = true; + goto out; + } + + if (coex_support) { + ar->coex_support = true; + } else { + ar->coex_support = false; + ar->coex_gpio_pin = -1; + goto out; + } + + ret = of_property_read_u32(node, "qcom,coexist-gpio-pin", + &ar->coex_gpio_pin); + if (ret) + ar->coex_gpio_pin = -1; + +out: + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot coex_support %d coex_gpio_pin %d\n", + ar->coex_support, ar->coex_gpio_pin); +} + static int ath10k_init_uart(struct ath10k *ar) { int ret; @@ -1863,8 +2224,19 @@ return ret; } - if (!uart_print) + if (!uart_print) { + if (ar->hw_params.uart_pin_workaround) { + ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, + ar->hw_params.uart_pin); + if (ret) { + ath10k_warn(ar, "failed to set UART TX pin: %d", + ret); + return ret; + } + } + return 0; + } ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin); if (ret) { @@ -1891,13 +2263,14 @@ static int ath10k_init_hw_params(struct ath10k *ar) { - const struct ath10k_hw_params *uninitialized_var(hw_params); + const struct ath10k_hw_params *hw_params; int i; for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) { hw_params = &ath10k_hw_params_list[i]; - if (hw_params->id == ar->target_version && + if (hw_params->bus == ar->hif.bus && + hw_params->id == ar->target_version && hw_params->dev_id == ar->dev_id) break; } @@ -1936,6 +2309,7 @@ complete(&ar->offchan_tx_completed); complete(&ar->install_key_done); complete(&ar->vdev_setup_done); + complete(&ar->vdev_delete_done); complete(&ar->thermal.wmi_sync); complete(&ar->bss_survey_done); wake_up(&ar->htt.empty_tx_wq); @@ -1969,7 +2343,7 @@ break; case ATH10K_STATE_RESTARTED: ar->state = ATH10K_STATE_WEDGED; - /* fall through */ + fallthrough; case ATH10K_STATE_WEDGED: ath10k_warn(ar, "device is wedged, will not restart\n"); break; @@ -1984,6 +2358,8 @@ if (ret) ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d", ret); + + complete(&ar->driver_recovery); } static void ath10k_core_set_coverage_class_work(struct work_struct *work) @@ -1998,6 +2374,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) { struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file; + int max_num_peers; if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) && !test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) { @@ -2077,7 +2454,7 @@ switch (fw_file->wmi_op_version) { case ATH10K_FW_WMI_OP_VERSION_MAIN: - ar->max_num_peers = TARGET_NUM_PEERS; + max_num_peers = TARGET_NUM_PEERS; ar->max_num_stations = TARGET_NUM_STATIONS; ar->max_num_vdevs = TARGET_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; @@ -2089,10 +2466,10 @@ case ATH10K_FW_WMI_OP_VERSION_10_2: case ATH10K_FW_WMI_OP_VERSION_10_2_4: if (ath10k_peer_stats_enabled(ar)) { - ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS; + max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS; ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS; } else { - ar->max_num_peers = TARGET_10X_NUM_PEERS; + max_num_peers = TARGET_10X_NUM_PEERS; ar->max_num_stations = TARGET_10X_NUM_STATIONS; } ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; @@ -2101,19 +2478,23 @@ ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_TLV: - ar->max_num_peers = TARGET_TLV_NUM_PEERS; + max_num_peers = TARGET_TLV_NUM_PEERS; ar->max_num_stations = TARGET_TLV_NUM_STATIONS; ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS; ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS; - ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC; + if (ar->hif.bus == ATH10K_BUS_SDIO) + ar->htt.max_num_pending_tx = + TARGET_TLV_NUM_MSDU_DESC_HL; + else + ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC; ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS; - ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | - WMI_STAT_PEER; + ar->fw_stats_req_mask = WMI_TLV_STAT_PDEV | WMI_TLV_STAT_VDEV | + WMI_TLV_STAT_PEER | WMI_TLV_STAT_PEER_EXTD; ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; ar->wmi.mgmt_max_num_pending_tx = TARGET_TLV_MGMT_NUM_MSDU_DESC; break; case ATH10K_FW_WMI_OP_VERSION_10_4: - ar->max_num_peers = TARGET_10_4_NUM_PEERS; + max_num_peers = TARGET_10_4_NUM_PEERS; ar->max_num_stations = TARGET_10_4_NUM_STATIONS; ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; @@ -2132,9 +2513,15 @@ break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: + default: WARN_ON(1); return -EINVAL; } + + if (ar->hw_params.num_peers) + ar->max_num_peers = ar->hw_params.num_peers; + else + ar->max_num_peers = max_num_peers; /* Backwards compatibility for firmwares without * ATH10K_FW_IE_HTT_OP_VERSION. @@ -2212,6 +2599,28 @@ return 0; } +static int ath10k_core_compat_services(struct ath10k *ar) +{ + struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file; + + /* all 10.x firmware versions support thermal throttling but don't + * advertise the support via service flags so we have to hardcode + * it here + */ + switch (fw_file->wmi_op_version) { + case ATH10K_FW_WMI_OP_VERSION_10_1: + case ATH10K_FW_WMI_OP_VERSION_10_2: + case ATH10K_FW_WMI_OP_VERSION_10_2_4: + case ATH10K_FW_WMI_OP_VERSION_10_4: + set_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map); + break; + default: + break; + } + + return 0; +} + int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, const struct ath10k_fw_components *fw) { @@ -2227,6 +2636,13 @@ if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, ar->running_fw->fw_file.fw_features)) { ath10k_bmi_start(ar); + + /* Enable hardware clock to speed up firmware download */ + if (ar->hw_params.hw_ops->enable_pll_clk) { + status = ar->hw_params.hw_ops->enable_pll_clk(ar); + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot enable pll ret %d\n", + status); + } if (ath10k_init_configure_target(ar)) { status = -EINVAL; @@ -2262,8 +2678,13 @@ if (status) goto err; - if (ar->hif.bus == ATH10K_BUS_SDIO) - ath10k_init_sdio(ar); + if (ar->hif.bus == ATH10K_BUS_SDIO) { + status = ath10k_init_sdio(ar, mode); + if (status) { + ath10k_err(ar, "failed to init SDIO: %d\n", status); + goto err; + } + } } ar->htc.htc_ops.target_send_suspend_complete = @@ -2324,6 +2745,12 @@ goto err_hif_stop; } + status = ath10k_hif_start_post(ar); + if (status) { + ath10k_err(ar, "failed to swap mailbox: %d\n", status); + goto err_hif_stop; + } + if (mode == ATH10K_FIRMWARE_MODE_NORMAL) { status = ath10k_htt_connect(&ar->htt); if (status) { @@ -2367,14 +2794,22 @@ if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map)) val |= WMI_10_4_BSS_CHANNEL_INFO_64; + ath10k_core_fetch_btcoex_dt(ar); + /* 10.4 firmware supports BT-Coex without reloading firmware * via pdev param. To support Bluetooth coexistence pdev param, * WMI_COEX_GPIO_SUPPORT of extended resource config should be * enabled always. + * + * We can still enable BTCOEX if firmware has the support + * eventhough btceox_support value is + * ATH10K_DT_BTCOEX_NOT_FOUND */ + if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map) && test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM, - ar->running_fw->fw_file.fw_features)) + ar->running_fw->fw_file.fw_features) && + ar->coex_support) val |= WMI_10_4_COEX_GPIO_SUPPORT; if (test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY, @@ -2384,6 +2819,17 @@ if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map)) val |= WMI_10_4_TDLS_UAPSD_BUFFER_STA; + + if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, + ar->wmi.svc_map)) + val |= WMI_10_4_TX_DATA_ACK_RSSI; + + if (test_bit(WMI_SERVICE_REPORT_AIRTIME, ar->wmi.svc_map)) + val |= WMI_10_4_REPORT_AIRTIME; + + if (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT, + ar->wmi.svc_map)) + val |= WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT; status = ath10k_mac_ext_resource_config(ar, val); if (status) { @@ -2404,6 +2850,19 @@ status = ath10k_wmi_wait_for_unified_ready(ar); if (status) { ath10k_err(ar, "wmi unified ready event not received\n"); + goto err_hif_stop; + } + + status = ath10k_core_compat_services(ar); + if (status) { + ath10k_err(ar, "compat services failed: %d\n", status); + goto err_hif_stop; + } + + status = ath10k_wmi_pdev_set_base_macaddr(ar, ar->mac_addr); + if (status && status != -EOPNOTSUPP) { + ath10k_err(ar, + "failed to set base mac address: %d\n", status); goto err_hif_stop; } @@ -2455,6 +2914,12 @@ status = ath10k_debug_start(ar); if (status) goto err_hif_stop; + + status = ath10k_hif_set_target_log_mode(ar, fw_diag_log); + if (status && status != -EOPNOTSUPP) { + ath10k_warn(ar, "set target log mode failed: %d\n", status); + goto err_hif_stop; + } return 0; @@ -2508,6 +2973,8 @@ ath10k_htt_tx_stop(&ar->htt); ath10k_htt_rx_free(&ar->htt); ath10k_wmi_detach(ar); + + ar->id.bmi_ids_valid = false; } EXPORT_SYMBOL(ath10k_core_stop); @@ -2521,7 +2988,7 @@ struct bmi_target_info target_info; int ret = 0; - ret = ath10k_hif_power_up(ar); + ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_NORMAL); if (ret) { ath10k_err(ar, "could not power on hif bus (%d)\n", ret); return ret; @@ -2609,7 +3076,7 @@ if (ret) ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n"); - ret = ath10k_core_fetch_board_file(ar); + ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD); if (ret) { ath10k_err(ar, "failed to fetch board file: %d\n", ret); goto err_free_firmware_files; @@ -2617,6 +3084,8 @@ ath10k_debug_print_board_info(ar); } + + device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr)); ret = ath10k_core_init_firmware_features(ar); if (ret) { @@ -2730,9 +3199,11 @@ return; } -int ath10k_core_register(struct ath10k *ar, u32 chip_id) +int ath10k_core_register(struct ath10k *ar, + const struct ath10k_bus_params *bus_params) { - ar->chip_id = chip_id; + ar->bus_param = *bus_params; + queue_work(ar->workqueue, &ar->register_work); return 0; @@ -2832,12 +3303,16 @@ init_completion(&ar->scan.completed); init_completion(&ar->scan.on_channel); init_completion(&ar->target_suspend); + init_completion(&ar->driver_recovery); init_completion(&ar->wow.wakeup_completed); init_completion(&ar->install_key_done); init_completion(&ar->vdev_setup_done); + init_completion(&ar->vdev_delete_done); init_completion(&ar->thermal.wmi_sync); init_completion(&ar->bss_survey_done); + init_completion(&ar->peer_delete_done); + init_completion(&ar->peer_stats_info_complete); INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work); @@ -2849,15 +3324,21 @@ if (!ar->workqueue_aux) goto err_free_wq; - mutex_init(&ar->conf_mutex); - spin_lock_init(&ar->data_lock); - spin_lock_init(&ar->txqs_lock); + ar->workqueue_tx_complete = + create_singlethread_workqueue("ath10k_tx_complete_wq"); + if (!ar->workqueue_tx_complete) + goto err_free_aux_wq; - INIT_LIST_HEAD(&ar->txqs); + mutex_init(&ar->conf_mutex); + mutex_init(&ar->dump_mutex); + spin_lock_init(&ar->data_lock); + INIT_LIST_HEAD(&ar->peers); init_waitqueue_head(&ar->peer_mapping_wq); init_waitqueue_head(&ar->htt.empty_tx_wq); init_waitqueue_head(&ar->wmi.tx_credits_wq); + + skb_queue_head_init(&ar->htt.rx_indication_head); init_completion(&ar->offchan_tx_completed); INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work); @@ -2875,7 +3356,7 @@ ret = ath10k_coredump_create(ar); if (ret) - goto err_free_aux_wq; + goto err_free_tx_complete; ret = ath10k_debug_create(ar); if (ret) @@ -2885,12 +3366,12 @@ err_free_coredump: ath10k_coredump_destroy(ar); - +err_free_tx_complete: + destroy_workqueue(ar->workqueue_tx_complete); err_free_aux_wq: destroy_workqueue(ar->workqueue_aux); err_free_wq: destroy_workqueue(ar->workqueue); - err_free_mac: ath10k_mac_destroy(ar); @@ -2906,6 +3387,9 @@ flush_workqueue(ar->workqueue_aux); destroy_workqueue(ar->workqueue_aux); + flush_workqueue(ar->workqueue_tx_complete); + destroy_workqueue(ar->workqueue_tx_complete); + ath10k_debug_destroy(ar); ath10k_coredump_destroy(ar); ath10k_htt_tx_destroy(&ar->htt); -- Gitblit v1.6.2