Path: blob/main/sys/contrib/dev/athk/ath10k/core.c
105221 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2005-2011 Atheros Communications Inc.3* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.4* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.5* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.6*/78#if defined(__FreeBSD__)9#define LINUXKPI_PARAM_PREFIX ath10k_core_10#endif1112#include <linux/export.h>13#include <linux/module.h>14#include <linux/firmware.h>15#include <linux/of.h>16#include <linux/property.h>17#include <linux/dmi.h>18#include <linux/ctype.h>19#include <linux/pm_qos.h>20#include <linux/nvmem-consumer.h>21#include <asm/byteorder.h>2223#include "core.h"24#include "mac.h"25#include "htc.h"26#include "hif.h"27#include "wmi.h"28#include "bmi.h"29#include "debug.h"30#include "htt.h"31#include "testmode.h"32#include "wmi-ops.h"33#include "coredump.h"34#if defined(CONFIG_FWLOG)35#include "fwlog.h"36#endif37#include "leds.h"3839unsigned int ath10k_debug_mask;40EXPORT_SYMBOL(ath10k_debug_mask);4142static unsigned int ath10k_cryptmode_param;43static bool uart_print;44static bool skip_otp;45static bool fw_diag_log;4647/* frame mode values are mapped as per enum ath10k_hw_txrx_mode */48unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI;4950unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) |51BIT(ATH10K_FW_CRASH_DUMP_CE_DATA);5253/* FIXME: most of these should be readonly */54module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);55module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);56module_param(uart_print, bool, 0644);57module_param(skip_otp, bool, 0644);58module_param(fw_diag_log, bool, 0644);59module_param_named(frame_mode, ath10k_frame_mode, uint, 0644);60module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444);6162MODULE_PARM_DESC(debug_mask, "Debugging mask");63MODULE_PARM_DESC(uart_print, "Uart target debugging");64MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");65MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");66MODULE_PARM_DESC(frame_mode,67"Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");68MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file");69MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging");7071static const struct ath10k_hw_params ath10k_hw_params_list[] = {72{73.id = QCA988X_HW_2_0_VERSION,74.dev_id = QCA988X_2_0_DEVICE_ID,75.bus = ATH10K_BUS_PCI,76.name = "qca988x hw2.0",77.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,78.uart_pin = 7,79.led_pin = 1,80.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,81.otp_exe_param = 0,82.channel_counters_freq_hz = 88000,83.max_probe_resp_desc_thres = 0,84.cal_data_len = 2116,85.fw = {86.dir = QCA988X_HW_2_0_FW_DIR,87.board_size = QCA988X_BOARD_DATA_SZ,88.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,89},90.rx_desc_ops = &qca988x_rx_desc_ops,91.hw_ops = &qca988x_ops,92.decap_align_bytes = 4,93.spectral_bin_discard = 0,94.spectral_bin_offset = 0,95.vht160_mcs_rx_highest = 0,96.vht160_mcs_tx_highest = 0,97.n_cipher_suites = 8,98.ast_skid_limit = 0x10,99.num_wds_entries = 0x20,100.target_64bit = false,101.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,102.shadow_reg_support = false,103.rri_on_ddr = false,104.hw_filter_reset_required = true,105.fw_diag_ce_download = false,106.credit_size_workaround = false,107.tx_stats_over_pktlog = true,108.dynamic_sar_support = false,109.hw_restart_disconnect = false,110.use_fw_tx_credits = true,111.delay_unmap_buffer = false,112.mcast_frame_registration = false,113},114{115.id = QCA988X_HW_2_0_VERSION,116.dev_id = QCA988X_2_0_DEVICE_ID_UBNT,117.name = "qca988x hw2.0 ubiquiti",118.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,119.uart_pin = 7,120.led_pin = 0,121.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,122.otp_exe_param = 0,123.channel_counters_freq_hz = 88000,124.max_probe_resp_desc_thres = 0,125.cal_data_len = 2116,126.fw = {127.dir = QCA988X_HW_2_0_FW_DIR,128.board_size = QCA988X_BOARD_DATA_SZ,129.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,130},131.rx_desc_ops = &qca988x_rx_desc_ops,132.hw_ops = &qca988x_ops,133.decap_align_bytes = 4,134.spectral_bin_discard = 0,135.spectral_bin_offset = 0,136.vht160_mcs_rx_highest = 0,137.vht160_mcs_tx_highest = 0,138.n_cipher_suites = 8,139.ast_skid_limit = 0x10,140.num_wds_entries = 0x20,141.target_64bit = false,142.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,143.shadow_reg_support = false,144.rri_on_ddr = false,145.hw_filter_reset_required = true,146.fw_diag_ce_download = false,147.credit_size_workaround = false,148.tx_stats_over_pktlog = true,149.dynamic_sar_support = false,150.hw_restart_disconnect = false,151.use_fw_tx_credits = true,152.delay_unmap_buffer = false,153.mcast_frame_registration = false,154},155{156.id = QCA9887_HW_1_0_VERSION,157.dev_id = QCA9887_1_0_DEVICE_ID,158.bus = ATH10K_BUS_PCI,159.name = "qca9887 hw1.0",160.patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,161.uart_pin = 7,162.led_pin = 1,163.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,164.otp_exe_param = 0,165.channel_counters_freq_hz = 88000,166.max_probe_resp_desc_thres = 0,167.cal_data_len = 2116,168.fw = {169.dir = QCA9887_HW_1_0_FW_DIR,170.board_size = QCA9887_BOARD_DATA_SZ,171.board_ext_size = QCA9887_BOARD_EXT_DATA_SZ,172},173.rx_desc_ops = &qca988x_rx_desc_ops,174.hw_ops = &qca988x_ops,175.decap_align_bytes = 4,176.spectral_bin_discard = 0,177.spectral_bin_offset = 0,178.vht160_mcs_rx_highest = 0,179.vht160_mcs_tx_highest = 0,180.n_cipher_suites = 8,181.ast_skid_limit = 0x10,182.num_wds_entries = 0x20,183.target_64bit = false,184.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,185.shadow_reg_support = false,186.rri_on_ddr = false,187.hw_filter_reset_required = true,188.fw_diag_ce_download = false,189.credit_size_workaround = false,190.tx_stats_over_pktlog = false,191.dynamic_sar_support = false,192.hw_restart_disconnect = false,193.use_fw_tx_credits = true,194.delay_unmap_buffer = false,195.mcast_frame_registration = false,196},197{198.id = QCA6174_HW_3_2_VERSION,199.dev_id = QCA6174_3_2_DEVICE_ID,200.bus = ATH10K_BUS_SDIO,201.name = "qca6174 hw3.2 sdio",202.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,203.uart_pin = 19,204.led_pin = 0,205.otp_exe_param = 0,206.channel_counters_freq_hz = 88000,207.max_probe_resp_desc_thres = 0,208.cal_data_len = 0,209.fw = {210.dir = QCA6174_HW_3_0_FW_DIR,211.board_size = QCA6174_BOARD_DATA_SZ,212.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,213},214.rx_desc_ops = &qca988x_rx_desc_ops,215.hw_ops = &qca6174_sdio_ops,216.hw_clk = qca6174_clk,217.target_cpu_freq = 176000000,218.decap_align_bytes = 4,219.n_cipher_suites = 8,220.num_peers = 10,221.ast_skid_limit = 0x10,222.num_wds_entries = 0x20,223.uart_pin_workaround = true,224.tx_stats_over_pktlog = false,225.credit_size_workaround = false,226.bmi_large_size_download = true,227.supports_peer_stats_info = true,228.dynamic_sar_support = true,229.hw_restart_disconnect = false,230.use_fw_tx_credits = true,231.delay_unmap_buffer = false,232.mcast_frame_registration = false,233},234{235.id = QCA6174_HW_2_1_VERSION,236.dev_id = QCA6164_2_1_DEVICE_ID,237.bus = ATH10K_BUS_PCI,238.name = "qca6164 hw2.1",239.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,240.uart_pin = 6,241.led_pin = 0,242.otp_exe_param = 0,243.channel_counters_freq_hz = 88000,244.max_probe_resp_desc_thres = 0,245.cal_data_len = 8124,246.fw = {247.dir = QCA6174_HW_2_1_FW_DIR,248.board_size = QCA6174_BOARD_DATA_SZ,249.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,250},251.rx_desc_ops = &qca988x_rx_desc_ops,252.hw_ops = &qca988x_ops,253.decap_align_bytes = 4,254.spectral_bin_discard = 0,255.spectral_bin_offset = 0,256.vht160_mcs_rx_highest = 0,257.vht160_mcs_tx_highest = 0,258.n_cipher_suites = 8,259.ast_skid_limit = 0x10,260.num_wds_entries = 0x20,261.target_64bit = false,262.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,263.shadow_reg_support = false,264.rri_on_ddr = false,265.hw_filter_reset_required = true,266.fw_diag_ce_download = false,267.credit_size_workaround = false,268.tx_stats_over_pktlog = false,269.dynamic_sar_support = false,270.hw_restart_disconnect = false,271.use_fw_tx_credits = true,272.delay_unmap_buffer = false,273.mcast_frame_registration = false,274},275{276.id = QCA6174_HW_2_1_VERSION,277.dev_id = QCA6174_2_1_DEVICE_ID,278.bus = ATH10K_BUS_PCI,279.name = "qca6174 hw2.1",280.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,281.uart_pin = 6,282.led_pin = 0,283.otp_exe_param = 0,284.channel_counters_freq_hz = 88000,285.max_probe_resp_desc_thres = 0,286.cal_data_len = 8124,287.fw = {288.dir = QCA6174_HW_2_1_FW_DIR,289.board_size = QCA6174_BOARD_DATA_SZ,290.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,291},292.rx_desc_ops = &qca988x_rx_desc_ops,293.hw_ops = &qca988x_ops,294.decap_align_bytes = 4,295.spectral_bin_discard = 0,296.spectral_bin_offset = 0,297.vht160_mcs_rx_highest = 0,298.vht160_mcs_tx_highest = 0,299.n_cipher_suites = 8,300.ast_skid_limit = 0x10,301.num_wds_entries = 0x20,302.target_64bit = false,303.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,304.shadow_reg_support = false,305.rri_on_ddr = false,306.hw_filter_reset_required = true,307.fw_diag_ce_download = false,308.credit_size_workaround = false,309.tx_stats_over_pktlog = false,310.dynamic_sar_support = false,311.hw_restart_disconnect = false,312.use_fw_tx_credits = true,313.delay_unmap_buffer = false,314.mcast_frame_registration = false,315},316{317.id = QCA6174_HW_3_0_VERSION,318.dev_id = QCA6174_2_1_DEVICE_ID,319.bus = ATH10K_BUS_PCI,320.name = "qca6174 hw3.0",321.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,322.uart_pin = 6,323.led_pin = 0,324.otp_exe_param = 0,325.channel_counters_freq_hz = 88000,326.max_probe_resp_desc_thres = 0,327.cal_data_len = 8124,328.fw = {329.dir = QCA6174_HW_3_0_FW_DIR,330.board_size = QCA6174_BOARD_DATA_SZ,331.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,332},333.rx_desc_ops = &qca988x_rx_desc_ops,334.hw_ops = &qca988x_ops,335.decap_align_bytes = 4,336.spectral_bin_discard = 0,337.spectral_bin_offset = 0,338.vht160_mcs_rx_highest = 0,339.vht160_mcs_tx_highest = 0,340.n_cipher_suites = 8,341.ast_skid_limit = 0x10,342.num_wds_entries = 0x20,343.target_64bit = false,344.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,345.shadow_reg_support = false,346.rri_on_ddr = false,347.hw_filter_reset_required = true,348.fw_diag_ce_download = false,349.credit_size_workaround = false,350.tx_stats_over_pktlog = false,351.dynamic_sar_support = false,352.hw_restart_disconnect = false,353.use_fw_tx_credits = true,354.delay_unmap_buffer = false,355.mcast_frame_registration = false,356},357{358.id = QCA6174_HW_3_2_VERSION,359.dev_id = QCA6174_2_1_DEVICE_ID,360.bus = ATH10K_BUS_PCI,361.name = "qca6174 hw3.2",362.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,363.uart_pin = 6,364.led_pin = 0,365.otp_exe_param = 0,366.channel_counters_freq_hz = 88000,367.max_probe_resp_desc_thres = 0,368.cal_data_len = 8124,369.fw = {370/* uses same binaries as hw3.0 */371.dir = QCA6174_HW_3_0_FW_DIR,372.board_size = QCA6174_BOARD_DATA_SZ,373.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,374},375.rx_desc_ops = &qca988x_rx_desc_ops,376.hw_ops = &qca6174_ops,377.hw_clk = qca6174_clk,378.target_cpu_freq = 176000000,379.decap_align_bytes = 4,380.spectral_bin_discard = 0,381.spectral_bin_offset = 0,382.vht160_mcs_rx_highest = 0,383.vht160_mcs_tx_highest = 0,384.n_cipher_suites = 8,385.ast_skid_limit = 0x10,386.num_wds_entries = 0x20,387.target_64bit = false,388.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,389.shadow_reg_support = false,390.rri_on_ddr = false,391.hw_filter_reset_required = true,392.fw_diag_ce_download = true,393.credit_size_workaround = false,394.tx_stats_over_pktlog = false,395.supports_peer_stats_info = true,396.dynamic_sar_support = true,397.hw_restart_disconnect = false,398.use_fw_tx_credits = true,399.delay_unmap_buffer = false,400.mcast_frame_registration = true,401},402{403.id = QCA99X0_HW_2_0_DEV_VERSION,404.dev_id = QCA99X0_2_0_DEVICE_ID,405.bus = ATH10K_BUS_PCI,406.name = "qca99x0 hw2.0",407.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,408.uart_pin = 7,409.led_pin = 17,410.otp_exe_param = 0x00000700,411.continuous_frag_desc = true,412.cck_rate_map_rev2 = true,413.channel_counters_freq_hz = 150000,414.max_probe_resp_desc_thres = 24,415.tx_chain_mask = 0xf,416.rx_chain_mask = 0xf,417.max_spatial_stream = 4,418.cal_data_len = 12064,419.fw = {420.dir = QCA99X0_HW_2_0_FW_DIR,421.board_size = QCA99X0_BOARD_DATA_SZ,422.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,423},424.sw_decrypt_mcast_mgmt = true,425.rx_desc_ops = &qca99x0_rx_desc_ops,426.hw_ops = &qca99x0_ops,427.decap_align_bytes = 1,428.spectral_bin_discard = 4,429.spectral_bin_offset = 0,430.vht160_mcs_rx_highest = 0,431.vht160_mcs_tx_highest = 0,432.n_cipher_suites = 11,433.ast_skid_limit = 0x10,434.num_wds_entries = 0x20,435.target_64bit = false,436.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,437.shadow_reg_support = false,438.rri_on_ddr = false,439.hw_filter_reset_required = true,440.fw_diag_ce_download = false,441.credit_size_workaround = false,442.tx_stats_over_pktlog = false,443.dynamic_sar_support = false,444.hw_restart_disconnect = false,445.use_fw_tx_credits = true,446.delay_unmap_buffer = false,447.mcast_frame_registration = false,448},449{450.id = QCA9984_HW_1_0_DEV_VERSION,451.dev_id = QCA9984_1_0_DEVICE_ID,452.bus = ATH10K_BUS_PCI,453.name = "qca9984/qca9994 hw1.0",454.patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,455.uart_pin = 7,456.led_pin = 17,457.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,458.otp_exe_param = 0x00000700,459.continuous_frag_desc = true,460.cck_rate_map_rev2 = true,461.channel_counters_freq_hz = 150000,462.max_probe_resp_desc_thres = 24,463.tx_chain_mask = 0xf,464.rx_chain_mask = 0xf,465.max_spatial_stream = 4,466.cal_data_len = 12064,467.fw = {468.dir = QCA9984_HW_1_0_FW_DIR,469.board_size = QCA99X0_BOARD_DATA_SZ,470.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,471.ext_board_size = QCA99X0_EXT_BOARD_DATA_SZ,472},473.sw_decrypt_mcast_mgmt = true,474.rx_desc_ops = &qca99x0_rx_desc_ops,475.hw_ops = &qca99x0_ops,476.decap_align_bytes = 1,477.spectral_bin_discard = 12,478.spectral_bin_offset = 8,479480/* Can do only 2x2 VHT160 or 80+80. 1560Mbps is 4x4 80Mhz481* or 2x2 160Mhz, long-guard-interval.482*/483.vht160_mcs_rx_highest = 1560,484.vht160_mcs_tx_highest = 1560,485.n_cipher_suites = 11,486.ast_skid_limit = 0x10,487.num_wds_entries = 0x20,488.target_64bit = false,489.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,490.shadow_reg_support = false,491.rri_on_ddr = false,492.hw_filter_reset_required = true,493.fw_diag_ce_download = false,494.credit_size_workaround = false,495.tx_stats_over_pktlog = false,496.dynamic_sar_support = false,497.hw_restart_disconnect = false,498.use_fw_tx_credits = true,499.delay_unmap_buffer = false,500.mcast_frame_registration = false,501},502{503.id = QCA9888_HW_2_0_DEV_VERSION,504.dev_id = QCA9888_2_0_DEVICE_ID,505.bus = ATH10K_BUS_PCI,506.name = "qca9888 hw2.0",507.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,508.uart_pin = 7,509.led_pin = 17,510.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,511.otp_exe_param = 0x00000700,512.continuous_frag_desc = true,513.channel_counters_freq_hz = 150000,514.max_probe_resp_desc_thres = 24,515.tx_chain_mask = 3,516.rx_chain_mask = 3,517.max_spatial_stream = 2,518.cal_data_len = 12064,519.fw = {520.dir = QCA9888_HW_2_0_FW_DIR,521.board_size = QCA99X0_BOARD_DATA_SZ,522.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,523},524.sw_decrypt_mcast_mgmt = true,525.rx_desc_ops = &qca99x0_rx_desc_ops,526.hw_ops = &qca99x0_ops,527.decap_align_bytes = 1,528.spectral_bin_discard = 12,529.spectral_bin_offset = 8,530531/* Can do only 1x1 VHT160 or 80+80. 780Mbps is 2x2 80Mhz or532* 1x1 160Mhz, long-guard-interval.533*/534.vht160_mcs_rx_highest = 780,535.vht160_mcs_tx_highest = 780,536.n_cipher_suites = 11,537.ast_skid_limit = 0x10,538.num_wds_entries = 0x20,539.target_64bit = false,540.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,541.shadow_reg_support = false,542.rri_on_ddr = false,543.hw_filter_reset_required = true,544.fw_diag_ce_download = false,545.credit_size_workaround = false,546.tx_stats_over_pktlog = false,547.dynamic_sar_support = false,548.hw_restart_disconnect = false,549.use_fw_tx_credits = true,550.delay_unmap_buffer = false,551.mcast_frame_registration = false,552},553{554.id = QCA9377_HW_1_0_DEV_VERSION,555.dev_id = QCA9377_1_0_DEVICE_ID,556.bus = ATH10K_BUS_PCI,557.name = "qca9377 hw1.0",558.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,559.uart_pin = 6,560.led_pin = 0,561.otp_exe_param = 0,562.channel_counters_freq_hz = 88000,563.max_probe_resp_desc_thres = 0,564.cal_data_len = 8124,565.fw = {566.dir = QCA9377_HW_1_0_FW_DIR,567.board_size = QCA9377_BOARD_DATA_SZ,568.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,569},570.rx_desc_ops = &qca988x_rx_desc_ops,571.hw_ops = &qca988x_ops,572.decap_align_bytes = 4,573.spectral_bin_discard = 0,574.spectral_bin_offset = 0,575.vht160_mcs_rx_highest = 0,576.vht160_mcs_tx_highest = 0,577.n_cipher_suites = 8,578.ast_skid_limit = 0x10,579.num_wds_entries = 0x20,580.target_64bit = false,581.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,582.shadow_reg_support = false,583.rri_on_ddr = false,584.hw_filter_reset_required = true,585.fw_diag_ce_download = false,586.credit_size_workaround = false,587.tx_stats_over_pktlog = false,588.dynamic_sar_support = false,589.hw_restart_disconnect = false,590.use_fw_tx_credits = true,591.delay_unmap_buffer = false,592.mcast_frame_registration = false,593},594{595.id = QCA9377_HW_1_1_DEV_VERSION,596.dev_id = QCA9377_1_0_DEVICE_ID,597.bus = ATH10K_BUS_PCI,598.name = "qca9377 hw1.1",599.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,600.uart_pin = 6,601.led_pin = 0,602.otp_exe_param = 0,603.channel_counters_freq_hz = 88000,604.max_probe_resp_desc_thres = 0,605.cal_data_len = 8124,606.fw = {607.dir = QCA9377_HW_1_0_FW_DIR,608.board_size = QCA9377_BOARD_DATA_SZ,609.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,610},611.rx_desc_ops = &qca988x_rx_desc_ops,612.hw_ops = &qca6174_ops,613.hw_clk = qca6174_clk,614.target_cpu_freq = 176000000,615.decap_align_bytes = 4,616.spectral_bin_discard = 0,617.spectral_bin_offset = 0,618.vht160_mcs_rx_highest = 0,619.vht160_mcs_tx_highest = 0,620.n_cipher_suites = 8,621.ast_skid_limit = 0x10,622.num_wds_entries = 0x20,623.target_64bit = false,624.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,625.shadow_reg_support = false,626.rri_on_ddr = false,627.hw_filter_reset_required = true,628.fw_diag_ce_download = true,629.credit_size_workaround = false,630.tx_stats_over_pktlog = false,631.dynamic_sar_support = false,632.hw_restart_disconnect = false,633.use_fw_tx_credits = true,634.delay_unmap_buffer = false,635.mcast_frame_registration = false,636},637{638.id = QCA9377_HW_1_1_DEV_VERSION,639.dev_id = QCA9377_1_0_DEVICE_ID,640.bus = ATH10K_BUS_SDIO,641.name = "qca9377 hw1.1 sdio",642.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,643.uart_pin = 19,644.led_pin = 0,645.otp_exe_param = 0,646.channel_counters_freq_hz = 88000,647.max_probe_resp_desc_thres = 0,648.cal_data_len = 8124,649.fw = {650.dir = QCA9377_HW_1_0_FW_DIR,651.board_size = QCA9377_BOARD_DATA_SZ,652.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,653},654.rx_desc_ops = &qca988x_rx_desc_ops,655.hw_ops = &qca6174_ops,656.hw_clk = qca6174_clk,657.target_cpu_freq = 176000000,658.decap_align_bytes = 4,659.n_cipher_suites = 8,660.num_peers = TARGET_QCA9377_HL_NUM_PEERS,661.ast_skid_limit = 0x10,662.num_wds_entries = 0x20,663.uart_pin_workaround = true,664.credit_size_workaround = true,665.dynamic_sar_support = false,666.hw_restart_disconnect = false,667.use_fw_tx_credits = true,668.delay_unmap_buffer = false,669.mcast_frame_registration = false,670},671{672.id = QCA4019_HW_1_0_DEV_VERSION,673.dev_id = 0,674.bus = ATH10K_BUS_AHB,675.name = "qca4019 hw1.0",676.patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR,677.uart_pin = 7,678.led_pin = 0,679.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,680.otp_exe_param = 0x0010000,681.continuous_frag_desc = true,682.cck_rate_map_rev2 = true,683.channel_counters_freq_hz = 125000,684.max_probe_resp_desc_thres = 24,685.tx_chain_mask = 0x3,686.rx_chain_mask = 0x3,687.max_spatial_stream = 2,688.cal_data_len = 12064,689.fw = {690.dir = QCA4019_HW_1_0_FW_DIR,691.board_size = QCA4019_BOARD_DATA_SZ,692.board_ext_size = QCA4019_BOARD_EXT_DATA_SZ,693},694.sw_decrypt_mcast_mgmt = true,695.rx_desc_ops = &qca99x0_rx_desc_ops,696.hw_ops = &qca99x0_ops,697.decap_align_bytes = 1,698.spectral_bin_discard = 4,699.spectral_bin_offset = 0,700.vht160_mcs_rx_highest = 0,701.vht160_mcs_tx_highest = 0,702.n_cipher_suites = 11,703.ast_skid_limit = 0x10,704.num_wds_entries = 0x20,705.target_64bit = false,706.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,707.shadow_reg_support = false,708.rri_on_ddr = false,709.hw_filter_reset_required = true,710.fw_diag_ce_download = false,711.credit_size_workaround = false,712.tx_stats_over_pktlog = false,713.dynamic_sar_support = false,714.hw_restart_disconnect = false,715.use_fw_tx_credits = true,716.delay_unmap_buffer = false,717.mcast_frame_registration = false,718},719{720.id = WCN3990_HW_1_0_DEV_VERSION,721.dev_id = 0,722.bus = ATH10K_BUS_SNOC,723.name = "wcn3990 hw1.0",724.led_pin = 0,725.continuous_frag_desc = true,726.tx_chain_mask = 0x7,727.rx_chain_mask = 0x7,728.max_spatial_stream = 4,729.fw = {730.dir = WCN3990_HW_1_0_FW_DIR,731.board_size = WCN3990_BOARD_DATA_SZ,732.board_ext_size = WCN3990_BOARD_EXT_DATA_SZ,733},734.sw_decrypt_mcast_mgmt = true,735.rx_desc_ops = &wcn3990_rx_desc_ops,736.hw_ops = &wcn3990_ops,737.decap_align_bytes = 1,738.num_peers = TARGET_HL_TLV_NUM_PEERS,739.n_cipher_suites = 11,740.ast_skid_limit = TARGET_HL_TLV_AST_SKID_LIMIT,741.num_wds_entries = TARGET_HL_TLV_NUM_WDS_ENTRIES,742.target_64bit = true,743.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC,744.shadow_reg_support = true,745.rri_on_ddr = true,746.hw_filter_reset_required = false,747.fw_diag_ce_download = false,748.credit_size_workaround = false,749.tx_stats_over_pktlog = false,750.dynamic_sar_support = true,751.hw_restart_disconnect = true,752.use_fw_tx_credits = false,753.delay_unmap_buffer = true,754.mcast_frame_registration = false,755},756};757758static const char *const ath10k_core_fw_feature_str[] = {759[ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX] = "wmi-mgmt-rx",760[ATH10K_FW_FEATURE_WMI_10X] = "wmi-10.x",761[ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX] = "has-wmi-mgmt-tx",762[ATH10K_FW_FEATURE_NO_P2P] = "no-p2p",763[ATH10K_FW_FEATURE_WMI_10_2] = "wmi-10.2",764[ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT] = "multi-vif-ps",765[ATH10K_FW_FEATURE_WOWLAN_SUPPORT] = "wowlan",766[ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp",767[ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad",768[ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init",769[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",770[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",771[ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",772[ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl",773[ATH10K_FW_FEATURE_BTCOEX_PARAM] = "btcoex-param",774[ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR] = "skip-null-func-war",775[ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast",776[ATH10K_FW_FEATURE_NO_PS] = "no-ps",777[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",778[ATH10K_FW_FEATURE_NON_BMI] = "non-bmi",779[ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL] = "single-chan-info-per-channel",780[ATH10K_FW_FEATURE_PEER_FIXED_RATE] = "peer-fixed-rate",781[ATH10K_FW_FEATURE_IRAM_RECOVERY] = "iram-recovery",782};783784static unsigned int ath10k_core_get_fw_feature_str(char *buf,785size_t buf_len,786enum ath10k_fw_features feat)787{788/* make sure that ath10k_core_fw_feature_str[] gets updated */789BUILD_BUG_ON(ARRAY_SIZE(ath10k_core_fw_feature_str) !=790ATH10K_FW_FEATURE_COUNT);791792if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) ||793WARN_ON(!ath10k_core_fw_feature_str[feat])) {794return scnprintf(buf, buf_len, "bit%d", feat);795}796797return scnprintf(buf, buf_len, "%s", ath10k_core_fw_feature_str[feat]);798}799800void ath10k_core_get_fw_features_str(struct ath10k *ar,801char *buf,802size_t buf_len)803{804size_t len = 0;805int i;806807for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) {808if (test_bit(i, ar->normal_mode_fw.fw_file.fw_features)) {809if (len > 0)810len += scnprintf(buf + len, buf_len - len, ",");811812len += ath10k_core_get_fw_feature_str(buf + len,813buf_len - len,814i);815}816}817}818819static void ath10k_send_suspend_complete(struct ath10k *ar)820{821ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n");822823complete(&ar->target_suspend);824}825826static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)827{828bool mtu_workaround = ar->hw_params.credit_size_workaround;829int ret;830u32 param = 0;831832ret = ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256);833if (ret)834return ret;835836ret = ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99);837if (ret)838return ret;839840ret = ath10k_bmi_read32(ar, hi_acs_flags, ¶m);841if (ret)842return ret;843844param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;845846if (mode == ATH10K_FIRMWARE_MODE_NORMAL && !mtu_workaround)847param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;848else849param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;850851if (mode == ATH10K_FIRMWARE_MODE_UTF)852param &= ~HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;853else854param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;855856ret = ath10k_bmi_write32(ar, hi_acs_flags, param);857if (ret)858return ret;859860ret = ath10k_bmi_read32(ar, hi_option_flag2, ¶m);861if (ret)862return ret;863864param |= HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_HOST;865866ret = ath10k_bmi_write32(ar, hi_option_flag2, param);867if (ret)868return ret;869870return 0;871}872873static int ath10k_init_configure_target(struct ath10k *ar)874{875u32 param_host;876int ret;877878/* tell target which HTC version it is used*/879ret = ath10k_bmi_write32(ar, hi_app_host_interest,880HTC_PROTOCOL_VERSION);881if (ret) {882ath10k_err(ar, "settings HTC version failed\n");883return ret;884}885886/* set the firmware mode to STA/IBSS/AP */887ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m_host);888if (ret) {889ath10k_err(ar, "setting firmware mode (1/2) failed\n");890return ret;891}892893/* TODO following parameters need to be re-visited. */894/* num_device */895param_host |= (1 << HI_OPTION_NUM_DEV_SHIFT);896/* Firmware mode */897/* FIXME: Why FW_MODE_AP ??.*/898param_host |= (HI_OPTION_FW_MODE_AP << HI_OPTION_FW_MODE_SHIFT);899/* mac_addr_method */900param_host |= (1 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);901/* firmware_bridge */902param_host |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);903/* fwsubmode */904param_host |= (0 << HI_OPTION_FW_SUBMODE_SHIFT);905906ret = ath10k_bmi_write32(ar, hi_option_flag, param_host);907if (ret) {908ath10k_err(ar, "setting firmware mode (2/2) failed\n");909return ret;910}911912/* We do all byte-swapping on the host */913ret = ath10k_bmi_write32(ar, hi_be, 0);914if (ret) {915ath10k_err(ar, "setting host CPU BE mode failed\n");916return ret;917}918919/* FW descriptor/Data swap flags */920ret = ath10k_bmi_write32(ar, hi_fw_swap, 0);921922if (ret) {923ath10k_err(ar, "setting FW data/desc swap flags failed\n");924return ret;925}926927/* Some devices have a special sanity check that verifies the PCI928* Device ID is written to this host interest var. It is known to be929* required to boot QCA6164.930*/931ret = ath10k_bmi_write32(ar, hi_hci_uart_pwr_mgmt_params_ext,932ar->dev_id);933if (ret) {934ath10k_err(ar, "failed to set pwr_mgmt_params: %d\n", ret);935return ret;936}937938return 0;939}940941static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,942const char *dir,943const char *file)944{945char filename[100];946const struct firmware *fw;947int ret;948949if (file == NULL)950return ERR_PTR(-ENOENT);951952if (dir == NULL)953dir = ".";954955if (ar->board_name) {956snprintf(filename, sizeof(filename), "%s/%s/%s",957dir, ar->board_name, file);958ret = firmware_request_nowarn(&fw, filename, ar->dev);959ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n",960filename, ret);961if (!ret)962return fw;963}964965snprintf(filename, sizeof(filename), "%s/%s", dir, file);966ret = firmware_request_nowarn(&fw, filename, ar->dev);967ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n",968filename, ret);969if (ret)970return ERR_PTR(ret);971972return fw;973}974975#if defined(__linux__)976static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,977#elif defined(__FreeBSD__)978static int ath10k_push_board_ext_data(struct ath10k *ar, const u8 *data,979#endif980size_t data_len)981{982u32 board_data_size = ar->hw_params.fw.board_size;983u32 board_ext_data_size = ar->hw_params.fw.board_ext_size;984u32 board_ext_data_addr;985int ret;986987ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr);988if (ret) {989ath10k_err(ar, "could not read board ext data addr (%d)\n",990ret);991return ret;992}993994ath10k_dbg(ar, ATH10K_DBG_BOOT,995"boot push board extended data addr 0x%x\n",996board_ext_data_addr);997998if (board_ext_data_addr == 0)999return 0;10001001if (data_len != (board_data_size + board_ext_data_size)) {1002ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",1003data_len, board_data_size, board_ext_data_size);1004return -EINVAL;1005}10061007ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,1008data + board_data_size,1009board_ext_data_size);1010if (ret) {1011ath10k_err(ar, "could not write board ext data (%d)\n", ret);1012return ret;1013}10141015ret = ath10k_bmi_write32(ar, hi_board_ext_data_config,1016(board_ext_data_size << 16) | 1);1017if (ret) {1018ath10k_err(ar, "could not write board ext data bit (%d)\n",1019ret);1020return ret;1021}10221023return 0;1024}10251026static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)1027{1028u32 result, address;1029u8 board_id, chip_id;1030bool ext_bid_support;1031int ret, bmi_board_id_param;10321033address = ar->hw_params.patch_load_addr;10341035if (!ar->normal_mode_fw.fw_file.otp_data ||1036!ar->normal_mode_fw.fw_file.otp_len) {1037ath10k_warn(ar,1038"failed to retrieve board id because of invalid otp\n");1039return -ENODATA;1040}10411042if (ar->id.bmi_ids_valid) {1043ath10k_dbg(ar, ATH10K_DBG_BOOT,1044"boot already acquired valid otp board id,skip download, board_id %d chip_id %d\n",1045ar->id.bmi_board_id, ar->id.bmi_chip_id);1046goto skip_otp_download;1047}10481049ath10k_dbg(ar, ATH10K_DBG_BOOT,1050"boot upload otp to 0x%x len %zd for board id\n",1051address, ar->normal_mode_fw.fw_file.otp_len);10521053ret = ath10k_bmi_fast_download(ar, address,1054ar->normal_mode_fw.fw_file.otp_data,1055ar->normal_mode_fw.fw_file.otp_len);1056if (ret) {1057ath10k_err(ar, "could not write otp for board id check: %d\n",1058ret);1059return ret;1060}10611062if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||1063ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE ||1064ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM)1065bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID;1066else1067bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID;10681069ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result);1070if (ret) {1071ath10k_err(ar, "could not execute otp for board id check: %d\n",1072ret);1073return ret;1074}10751076board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP);1077chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP);1078ext_bid_support = (result & ATH10K_BMI_EXT_BOARD_ID_SUPPORT);10791080ath10k_dbg(ar, ATH10K_DBG_BOOT,1081"boot get otp board id result 0x%08x board_id %d chip_id %d ext_bid_support %d\n",1082result, board_id, chip_id, ext_bid_support);10831084ar->id.ext_bid_supported = ext_bid_support;10851086if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 ||1087(board_id == 0)) {1088ath10k_dbg(ar, ATH10K_DBG_BOOT,1089"board id does not exist in otp, ignore it\n");1090return -EOPNOTSUPP;1091}10921093ar->id.bmi_ids_valid = true;1094ar->id.bmi_board_id = board_id;1095ar->id.bmi_chip_id = chip_id;10961097skip_otp_download:10981099return 0;1100}11011102static void ath10k_core_check_bdfext(const struct dmi_header *hdr, void *data)1103{1104struct ath10k *ar = data;1105const char *bdf_ext;1106const char *magic = ATH10K_SMBIOS_BDF_EXT_MAGIC;1107u8 bdf_enabled;1108int i;11091110if (hdr->type != ATH10K_SMBIOS_BDF_EXT_TYPE)1111return;11121113if (hdr->length != ATH10K_SMBIOS_BDF_EXT_LENGTH) {1114ath10k_dbg(ar, ATH10K_DBG_BOOT,1115"wrong smbios bdf ext type length (%d).\n",1116hdr->length);1117return;1118}11191120#if defined(__linux__)1121bdf_enabled = *((u8 *)hdr + ATH10K_SMBIOS_BDF_EXT_OFFSET);1122#elif defined(__FreeBSD__)1123bdf_enabled = *((const u8 *)hdr + ATH10K_SMBIOS_BDF_EXT_OFFSET);1124#endif1125if (!bdf_enabled) {1126ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not found.\n");1127return;1128}11291130/* Only one string exists (per spec) */1131#if defined(__linux__)1132bdf_ext = (char *)hdr + hdr->length;1133#elif defined(__FreeBSD__)1134bdf_ext = (const char *)hdr + hdr->length;1135#endif11361137if (memcmp(bdf_ext, magic, strlen(magic)) != 0) {1138ath10k_dbg(ar, ATH10K_DBG_BOOT,1139"bdf variant magic does not match.\n");1140return;1141}11421143for (i = 0; i < strlen(bdf_ext); i++) {1144if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) {1145ath10k_dbg(ar, ATH10K_DBG_BOOT,1146"bdf variant name contains non ascii chars.\n");1147return;1148}1149}11501151/* Copy extension name without magic suffix */1152if (strscpy(ar->id.bdf_ext, bdf_ext + strlen(magic),1153sizeof(ar->id.bdf_ext)) < 0) {1154ath10k_dbg(ar, ATH10K_DBG_BOOT,1155"bdf variant string is longer than the buffer can accommodate (variant: %s)\n",1156bdf_ext);1157return;1158}11591160ath10k_dbg(ar, ATH10K_DBG_BOOT,1161"found and validated bdf variant smbios_type 0x%x bdf %s\n",1162ATH10K_SMBIOS_BDF_EXT_TYPE, bdf_ext);1163}11641165static int ath10k_core_check_smbios(struct ath10k *ar)1166{1167ar->id.bdf_ext[0] = '\0';1168dmi_walk(ath10k_core_check_bdfext, ar);11691170if (ar->id.bdf_ext[0] == '\0')1171return -ENODATA;11721173return 0;1174}11751176int ath10k_core_check_dt(struct ath10k *ar)1177{1178#if defined(__linux__) || (defined(__FreeBSD__) && defined(CONFIG_OF))1179struct device_node *node;1180const char *variant = NULL;11811182node = ar->dev->of_node;1183if (!node)1184return -ENOENT;11851186of_property_read_string(node, "qcom,calibration-variant",1187&variant);1188if (!variant)1189of_property_read_string(node, "qcom,ath10k-calibration-variant",1190&variant);1191if (!variant)1192return -ENODATA;11931194if (strscpy(ar->id.bdf_ext, variant, sizeof(ar->id.bdf_ext)) < 0)1195ath10k_dbg(ar, ATH10K_DBG_BOOT,1196"bdf variant string is longer than the buffer can accommodate (variant: %s)\n",1197variant);11981199return 0;1200#else1201return -ENOENT;1202#endif1203}1204EXPORT_SYMBOL(ath10k_core_check_dt);12051206static int ath10k_download_fw(struct ath10k *ar)1207{1208u32 address, data_len;1209const void *data;1210int ret;1211struct pm_qos_request latency_qos = {};12121213address = ar->hw_params.patch_load_addr;12141215data = ar->running_fw->fw_file.firmware_data;1216data_len = ar->running_fw->fw_file.firmware_len;12171218ret = ath10k_swap_code_seg_configure(ar, &ar->running_fw->fw_file);1219if (ret) {1220ath10k_err(ar, "failed to configure fw code swap: %d\n",1221ret);1222return ret;1223}12241225ath10k_dbg(ar, ATH10K_DBG_BOOT,1226"boot uploading firmware image %p len %d\n",1227data, data_len);12281229/* Check if device supports to download firmware via1230* diag copy engine. Downloading firmware via diag CE1231* greatly reduces the time to download firmware.1232*/1233if (ar->hw_params.fw_diag_ce_download) {1234ret = ath10k_hw_diag_fast_download(ar, address,1235data, data_len);1236if (ret == 0)1237/* firmware upload via diag ce was successful */1238return 0;12391240ath10k_warn(ar,1241"failed to upload firmware via diag ce, trying BMI: %d",1242ret);1243}12441245cpu_latency_qos_add_request(&latency_qos, 0);12461247ret = ath10k_bmi_fast_download(ar, address, data, data_len);12481249cpu_latency_qos_remove_request(&latency_qos);12501251return ret;1252}12531254void ath10k_core_free_board_files(struct ath10k *ar)1255{1256if (!IS_ERR(ar->normal_mode_fw.board))1257release_firmware(ar->normal_mode_fw.board);12581259if (!IS_ERR(ar->normal_mode_fw.ext_board))1260release_firmware(ar->normal_mode_fw.ext_board);12611262ar->normal_mode_fw.board = NULL;1263ar->normal_mode_fw.board_data = NULL;1264ar->normal_mode_fw.board_len = 0;1265ar->normal_mode_fw.ext_board = NULL;1266ar->normal_mode_fw.ext_board_data = NULL;1267ar->normal_mode_fw.ext_board_len = 0;1268}1269EXPORT_SYMBOL(ath10k_core_free_board_files);12701271static void ath10k_core_free_firmware_files(struct ath10k *ar)1272{1273if (!IS_ERR(ar->normal_mode_fw.fw_file.firmware))1274release_firmware(ar->normal_mode_fw.fw_file.firmware);12751276if (!IS_ERR(ar->cal_file))1277release_firmware(ar->cal_file);12781279if (!IS_ERR(ar->pre_cal_file))1280release_firmware(ar->pre_cal_file);12811282ath10k_swap_code_seg_release(ar, &ar->normal_mode_fw.fw_file);12831284ar->normal_mode_fw.fw_file.otp_data = NULL;1285ar->normal_mode_fw.fw_file.otp_len = 0;12861287ar->normal_mode_fw.fw_file.firmware = NULL;1288ar->normal_mode_fw.fw_file.firmware_data = NULL;1289ar->normal_mode_fw.fw_file.firmware_len = 0;12901291ar->cal_file = NULL;1292ar->pre_cal_file = NULL;1293}12941295static int ath10k_fetch_cal_file(struct ath10k *ar)1296{1297char filename[100];12981299/* pre-cal-<bus>-<id>.bin */1300scnprintf(filename, sizeof(filename), "pre-cal-%s-%s.bin",1301ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));13021303ar->pre_cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);1304if (!IS_ERR(ar->pre_cal_file))1305goto success;13061307/* cal-<bus>-<id>.bin */1308scnprintf(filename, sizeof(filename), "cal-%s-%s.bin",1309ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));13101311ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);1312if (IS_ERR(ar->cal_file))1313/* calibration file is optional, don't print any warnings */1314return PTR_ERR(ar->cal_file);1315success:1316ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n",1317ATH10K_FW_DIR, filename);13181319return 0;1320}13211322static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)1323{1324const struct firmware *fw;1325char boardname[100];13261327if (bd_ie_type == ATH10K_BD_IE_BOARD) {1328scnprintf(boardname, sizeof(boardname), "board-%s-%s.bin",1329ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));13301331ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,1332ar->hw_params.fw.dir,1333boardname);1334if (IS_ERR(ar->normal_mode_fw.board)) {1335fw = ath10k_fetch_fw_file(ar,1336ar->hw_params.fw.dir,1337ATH10K_BOARD_DATA_FILE);1338ar->normal_mode_fw.board = fw;1339}13401341if (IS_ERR(ar->normal_mode_fw.board))1342return PTR_ERR(ar->normal_mode_fw.board);13431344ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data;1345ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size;1346} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {1347fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,1348ATH10K_EBOARD_DATA_FILE);1349ar->normal_mode_fw.ext_board = fw;1350if (IS_ERR(ar->normal_mode_fw.ext_board))1351return PTR_ERR(ar->normal_mode_fw.ext_board);13521353ar->normal_mode_fw.ext_board_data = ar->normal_mode_fw.ext_board->data;1354ar->normal_mode_fw.ext_board_len = ar->normal_mode_fw.ext_board->size;1355}13561357return 0;1358}13591360static int ath10k_core_parse_bd_ie_board(struct ath10k *ar,1361#if defined(__linux__)1362const void *buf, size_t buf_len,1363#elif defined(__FreeBSD__)1364const u8 *buf, size_t buf_len,1365#endif1366const char *boardname,1367int bd_ie_type)1368{1369const struct ath10k_fw_ie *hdr;1370bool name_match_found;1371int ret, board_ie_id;1372size_t board_ie_len;1373const void *board_ie_data;13741375name_match_found = false;13761377/* go through ATH10K_BD_IE_BOARD_ elements */1378while (buf_len > sizeof(struct ath10k_fw_ie)) {1379#if defined(__linux__)1380hdr = buf;1381#elif defined(__FreeBSD__)1382hdr = (const void *)buf;1383#endif1384board_ie_id = le32_to_cpu(hdr->id);1385board_ie_len = le32_to_cpu(hdr->len);1386board_ie_data = hdr->data;13871388buf_len -= sizeof(*hdr);1389buf += sizeof(*hdr);13901391if (buf_len < ALIGN(board_ie_len, 4)) {1392ath10k_err(ar, "invalid ATH10K_BD_IE_BOARD length: %zu < %zu\n",1393buf_len, ALIGN(board_ie_len, 4));1394ret = -EINVAL;1395goto out;1396}13971398switch (board_ie_id) {1399case ATH10K_BD_IE_BOARD_NAME:1400ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "board name", "",1401board_ie_data, board_ie_len);14021403if (board_ie_len != strlen(boardname))1404break;14051406ret = memcmp(board_ie_data, boardname, strlen(boardname));1407if (ret)1408break;14091410name_match_found = true;1411ath10k_dbg(ar, ATH10K_DBG_BOOT,1412"boot found match for name '%s'",1413boardname);1414break;1415case ATH10K_BD_IE_BOARD_DATA:1416if (!name_match_found)1417/* no match found */1418break;14191420if (bd_ie_type == ATH10K_BD_IE_BOARD) {1421ath10k_dbg(ar, ATH10K_DBG_BOOT,1422"boot found board data for '%s'",1423boardname);14241425ar->normal_mode_fw.board_data = board_ie_data;1426ar->normal_mode_fw.board_len = board_ie_len;1427} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {1428ath10k_dbg(ar, ATH10K_DBG_BOOT,1429"boot found eboard data for '%s'",1430boardname);14311432ar->normal_mode_fw.ext_board_data = board_ie_data;1433ar->normal_mode_fw.ext_board_len = board_ie_len;1434}14351436ret = 0;1437goto out;1438default:1439ath10k_warn(ar, "unknown ATH10K_BD_IE_BOARD found: %d\n",1440board_ie_id);1441break;1442}14431444/* jump over the padding */1445board_ie_len = ALIGN(board_ie_len, 4);14461447buf_len -= board_ie_len;1448buf += board_ie_len;1449}14501451/* no match found */1452ret = -ENOENT;14531454out:1455return ret;1456}14571458static int ath10k_core_search_bd(struct ath10k *ar,1459const char *boardname,1460const u8 *data,1461size_t len)1462{1463size_t ie_len;1464#if defined(__linux__)1465struct ath10k_fw_ie *hdr;1466#elif defined(__FreeBSD__)1467const struct ath10k_fw_ie *hdr;1468#endif1469int ret = -ENOENT, ie_id;14701471while (len > sizeof(struct ath10k_fw_ie)) {1472#if defined(__linux__)1473hdr = (struct ath10k_fw_ie *)data;1474#elif defined(__FreeBSD__)1475hdr = (const struct ath10k_fw_ie *)data;1476#endif1477ie_id = le32_to_cpu(hdr->id);1478ie_len = le32_to_cpu(hdr->len);14791480len -= sizeof(*hdr);1481data = hdr->data;14821483if (len < ALIGN(ie_len, 4)) {1484ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n",1485ie_id, ie_len, len);1486return -EINVAL;1487}14881489switch (ie_id) {1490case ATH10K_BD_IE_BOARD:1491ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,1492boardname,1493ATH10K_BD_IE_BOARD);1494if (ret == -ENOENT)1495/* no match found, continue */1496break;14971498/* either found or error, so stop searching */1499goto out;1500case ATH10K_BD_IE_BOARD_EXT:1501ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,1502boardname,1503ATH10K_BD_IE_BOARD_EXT);1504if (ret == -ENOENT)1505/* no match found, continue */1506break;15071508/* either found or error, so stop searching */1509goto out;1510}15111512/* jump over the padding */1513ie_len = ALIGN(ie_len, 4);15141515len -= ie_len;1516data += ie_len;1517}15181519out:1520/* return result of parse_bd_ie_board() or -ENOENT */1521return ret;1522}15231524static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,1525const char *boardname,1526const char *fallback_boardname1,1527const char *fallback_boardname2,1528const char *filename)1529{1530size_t len, magic_len;1531const u8 *data;1532int ret;15331534/* Skip if already fetched during board data download */1535if (!ar->normal_mode_fw.board)1536ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,1537ar->hw_params.fw.dir,1538filename);1539if (IS_ERR(ar->normal_mode_fw.board))1540return PTR_ERR(ar->normal_mode_fw.board);15411542data = ar->normal_mode_fw.board->data;1543len = ar->normal_mode_fw.board->size;15441545/* magic has extra null byte padded */1546magic_len = strlen(ATH10K_BOARD_MAGIC) + 1;1547if (len < magic_len) {1548ath10k_err(ar, "failed to find magic value in %s/%s, file too short: %zu\n",1549ar->hw_params.fw.dir, filename, len);1550ret = -EINVAL;1551goto err;1552}15531554if (memcmp(data, ATH10K_BOARD_MAGIC, magic_len)) {1555ath10k_err(ar, "found invalid board magic\n");1556ret = -EINVAL;1557goto err;1558}15591560/* magic is padded to 4 bytes */1561magic_len = ALIGN(magic_len, 4);1562if (len < magic_len) {1563ath10k_err(ar, "failed: %s/%s too small to contain board data, len: %zu\n",1564ar->hw_params.fw.dir, filename, len);1565ret = -EINVAL;1566goto err;1567}15681569data += magic_len;1570len -= magic_len;15711572/* attempt to find boardname in the IE list */1573ret = ath10k_core_search_bd(ar, boardname, data, len);15741575/* if we didn't find it and have a fallback name, try that */1576if (ret == -ENOENT && fallback_boardname1)1577ret = ath10k_core_search_bd(ar, fallback_boardname1, data, len);15781579if (ret == -ENOENT && fallback_boardname2)1580ret = ath10k_core_search_bd(ar, fallback_boardname2, data, len);15811582if (ret == -ENOENT) {1583ath10k_err(ar,1584"failed to fetch board data for %s from %s/%s\n",1585boardname, ar->hw_params.fw.dir, filename);1586ret = -ENODATA;1587}15881589if (ret)1590goto err;15911592return 0;15931594err:1595ath10k_core_free_board_files(ar);1596return ret;1597}15981599static int ath10k_core_create_board_name(struct ath10k *ar, char *name,1600size_t name_len, bool with_variant,1601bool with_chip_id)1602{1603/* strlen(',variant=') + strlen(ar->id.bdf_ext) */1604char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = {};16051606if (with_variant && ar->id.bdf_ext[0] != '\0')1607scnprintf(variant, sizeof(variant), ",variant=%s",1608ar->id.bdf_ext);16091610if (ar->id.bmi_ids_valid) {1611scnprintf(name, name_len,1612"bus=%s,bmi-chip-id=%d,bmi-board-id=%d%s",1613ath10k_bus_str(ar->hif.bus),1614ar->id.bmi_chip_id,1615ar->id.bmi_board_id, variant);1616goto out;1617}16181619if (ar->id.qmi_ids_valid) {1620if (with_chip_id)1621scnprintf(name, name_len,1622"bus=%s,qmi-board-id=%x,qmi-chip-id=%x%s",1623ath10k_bus_str(ar->hif.bus),1624ar->id.qmi_board_id, ar->id.qmi_chip_id,1625variant);1626else1627scnprintf(name, name_len,1628"bus=%s,qmi-board-id=%x",1629ath10k_bus_str(ar->hif.bus),1630ar->id.qmi_board_id);1631goto out;1632}16331634scnprintf(name, name_len,1635"bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s",1636ath10k_bus_str(ar->hif.bus),1637ar->id.vendor, ar->id.device,1638ar->id.subsystem_vendor, ar->id.subsystem_device, variant);1639out:1640ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name);16411642return 0;1643}16441645static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name,1646size_t name_len)1647{1648if (ar->id.bmi_ids_valid) {1649scnprintf(name, name_len,1650"bus=%s,bmi-chip-id=%d,bmi-eboard-id=%d",1651ath10k_bus_str(ar->hif.bus),1652ar->id.bmi_chip_id,1653ar->id.bmi_eboard_id);16541655ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using eboard name '%s'\n", name);1656return 0;1657}1658/* Fallback if returned board id is zero */1659return -1;1660}16611662int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)1663{1664char boardname[100], fallback_boardname1[100], fallback_boardname2[100];1665int ret;16661667if (bd_ie_type == ATH10K_BD_IE_BOARD) {1668/* With variant and chip id */1669ret = ath10k_core_create_board_name(ar, boardname,1670sizeof(boardname), true,1671true);1672if (ret) {1673ath10k_err(ar, "failed to create board name: %d", ret);1674return ret;1675}16761677/* Without variant and only chip-id */1678ret = ath10k_core_create_board_name(ar, fallback_boardname1,1679sizeof(boardname), false,1680true);1681if (ret) {1682ath10k_err(ar, "failed to create 1st fallback board name: %d",1683ret);1684return ret;1685}16861687/* Without variant and without chip-id */1688ret = ath10k_core_create_board_name(ar, fallback_boardname2,1689sizeof(boardname), false,1690false);1691if (ret) {1692ath10k_err(ar, "failed to create 2nd fallback board name: %d",1693ret);1694return ret;1695}1696} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {1697ret = ath10k_core_create_eboard_name(ar, boardname,1698sizeof(boardname));1699if (ret) {1700ath10k_err(ar, "fallback to eboard.bin since board id 0");1701goto fallback;1702}1703}17041705ar->bd_api = 2;1706ret = ath10k_core_fetch_board_data_api_n(ar, boardname,1707fallback_boardname1,1708fallback_boardname2,1709ATH10K_BOARD_API2_FILE);1710if (!ret)1711goto success;17121713fallback:1714ar->bd_api = 1;1715ret = ath10k_core_fetch_board_data_api_1(ar, bd_ie_type);1716if (ret) {1717ath10k_err(ar, "failed to fetch board-2.bin or board.bin from %s\n",1718ar->hw_params.fw.dir);1719return ret;1720}17211722success:1723ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api);1724return 0;1725}1726EXPORT_SYMBOL(ath10k_core_fetch_board_file);17271728static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar)1729{1730u32 result, address;1731u8 ext_board_id;1732int ret;17331734address = ar->hw_params.patch_load_addr;17351736if (!ar->normal_mode_fw.fw_file.otp_data ||1737!ar->normal_mode_fw.fw_file.otp_len) {1738ath10k_warn(ar,1739"failed to retrieve extended board id due to otp binary missing\n");1740return -ENODATA;1741}17421743ath10k_dbg(ar, ATH10K_DBG_BOOT,1744"boot upload otp to 0x%x len %zd for ext board id\n",1745address, ar->normal_mode_fw.fw_file.otp_len);17461747ret = ath10k_bmi_fast_download(ar, address,1748ar->normal_mode_fw.fw_file.otp_data,1749ar->normal_mode_fw.fw_file.otp_len);1750if (ret) {1751ath10k_err(ar, "could not write otp for ext board id check: %d\n",1752ret);1753return ret;1754}17551756ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EXT_BOARD_ID, &result);1757if (ret) {1758ath10k_err(ar, "could not execute otp for ext board id check: %d\n",1759ret);1760return ret;1761}17621763if (!result) {1764ath10k_dbg(ar, ATH10K_DBG_BOOT,1765"ext board id does not exist in otp, ignore it\n");1766return -EOPNOTSUPP;1767}17681769ext_board_id = result & ATH10K_BMI_EBOARD_ID_STATUS_MASK;17701771ath10k_dbg(ar, ATH10K_DBG_BOOT,1772"boot get otp ext board id result 0x%08x ext_board_id %d\n",1773result, ext_board_id);17741775ar->id.bmi_eboard_id = ext_board_id;17761777return 0;1778}17791780static int ath10k_download_board_data(struct ath10k *ar, const void *data,1781size_t data_len)1782{1783u32 board_data_size = ar->hw_params.fw.board_size;1784u32 eboard_data_size = ar->hw_params.fw.ext_board_size;1785u32 board_address;1786u32 ext_board_address;1787int ret;17881789ret = ath10k_push_board_ext_data(ar, data, data_len);1790if (ret) {1791ath10k_err(ar, "could not push board ext data (%d)\n", ret);1792goto exit;1793}17941795ret = ath10k_bmi_read32(ar, hi_board_data, &board_address);1796if (ret) {1797ath10k_err(ar, "could not read board data addr (%d)\n", ret);1798goto exit;1799}18001801ret = ath10k_bmi_write_memory(ar, board_address, data,1802min_t(u32, board_data_size,1803data_len));1804if (ret) {1805ath10k_err(ar, "could not write board data (%d)\n", ret);1806goto exit;1807}18081809ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);1810if (ret) {1811ath10k_err(ar, "could not write board data bit (%d)\n", ret);1812goto exit;1813}18141815if (!ar->id.ext_bid_supported)1816goto exit;18171818/* Extended board data download */1819ret = ath10k_core_get_ext_board_id_from_otp(ar);1820if (ret == -EOPNOTSUPP) {1821/* Not fetching ext_board_data if ext board id is 0 */1822ath10k_dbg(ar, ATH10K_DBG_BOOT, "otp returned ext board id 0\n");1823return 0;1824} else if (ret) {1825ath10k_err(ar, "failed to get extended board id: %d\n", ret);1826goto exit;1827}18281829ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD_EXT);1830if (ret)1831goto exit;18321833if (ar->normal_mode_fw.ext_board_data) {1834ext_board_address = board_address + EXT_BOARD_ADDRESS_OFFSET;1835ath10k_dbg(ar, ATH10K_DBG_BOOT,1836"boot writing ext board data to addr 0x%x",1837ext_board_address);1838ret = ath10k_bmi_write_memory(ar, ext_board_address,1839ar->normal_mode_fw.ext_board_data,1840min_t(u32, eboard_data_size, data_len));1841if (ret)1842ath10k_err(ar, "failed to write ext board data: %d\n", ret);1843}18441845exit:1846return ret;1847}18481849static int ath10k_download_and_run_otp(struct ath10k *ar)1850{1851u32 result, address = ar->hw_params.patch_load_addr;1852u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param;1853int ret;18541855ret = ath10k_download_board_data(ar,1856ar->running_fw->board_data,1857ar->running_fw->board_len);1858if (ret) {1859ath10k_err(ar, "failed to download board data: %d\n", ret);1860return ret;1861}18621863/* OTP is optional */18641865if (!ar->running_fw->fw_file.otp_data ||1866!ar->running_fw->fw_file.otp_len) {1867ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",1868ar->running_fw->fw_file.otp_data,1869ar->running_fw->fw_file.otp_len);1870return 0;1871}18721873ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",1874address, ar->running_fw->fw_file.otp_len);18751876ret = ath10k_bmi_fast_download(ar, address,1877ar->running_fw->fw_file.otp_data,1878ar->running_fw->fw_file.otp_len);1879if (ret) {1880ath10k_err(ar, "could not write otp (%d)\n", ret);1881return ret;1882}18831884/* As of now pre-cal is valid for 10_4 variants */1885if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||1886ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE ||1887ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM)1888bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;18891890ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);1891if (ret) {1892ath10k_err(ar, "could not execute otp (%d)\n", ret);1893return ret;1894}18951896ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);18971898if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,1899ar->running_fw->fw_file.fw_features)) &&1900result != 0) {1901ath10k_err(ar, "otp calibration failed: %d", result);1902return -EINVAL;1903}19041905return 0;1906}19071908static int ath10k_download_cal_file(struct ath10k *ar,1909const struct firmware *file)1910{1911int ret;19121913if (!file)1914return -ENOENT;19151916if (IS_ERR(file))1917return PTR_ERR(file);19181919ret = ath10k_download_board_data(ar, file->data, file->size);1920if (ret) {1921ath10k_err(ar, "failed to download cal_file data: %d\n", ret);1922return ret;1923}19241925ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");19261927return 0;1928}19291930static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name)1931{1932#if defined(__linux__) || (defined(__FreeBSD__) && defined(CONFIG_OF))1933struct device_node *node;1934int data_len;1935void *data;1936int ret;19371938node = ar->dev->of_node;1939if (!node)1940/* Device Tree is optional, don't print any warnings if1941* there's no node for ath10k.1942*/1943return -ENOENT;19441945if (!of_get_property(node, dt_name, &data_len)) {1946/* The calibration data node is optional */1947return -ENOENT;1948}19491950if (data_len != ar->hw_params.cal_data_len) {1951ath10k_warn(ar, "invalid calibration data length in DT: %d\n",1952data_len);1953ret = -EMSGSIZE;1954goto out;1955}19561957data = kmalloc(data_len, GFP_KERNEL);1958if (!data) {1959ret = -ENOMEM;1960goto out;1961}19621963ret = of_property_read_u8_array(node, dt_name, data, data_len);1964if (ret) {1965ath10k_warn(ar, "failed to read calibration data from DT: %d\n",1966ret);1967goto out_free;1968}19691970ret = ath10k_download_board_data(ar, data, data_len);1971if (ret) {1972ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",1973ret);1974goto out_free;1975}19761977ret = 0;19781979out_free:1980kfree(data);19811982out:1983return ret;1984#else1985return -ENOENT;1986#endif1987}19881989static int ath10k_download_cal_eeprom(struct ath10k *ar)1990{1991size_t data_len;1992void *data = NULL;1993int ret;19941995ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len);1996if (ret) {1997if (ret != -EOPNOTSUPP)1998ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n",1999ret);2000goto out_free;2001}20022003ret = ath10k_download_board_data(ar, data, data_len);2004if (ret) {2005ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n",2006ret);2007goto out_free;2008}20092010ret = 0;20112012out_free:2013kfree(data);20142015return ret;2016}20172018static int ath10k_download_cal_nvmem(struct ath10k *ar, const char *cell_name)2019{2020#if defined(__linux__)2021struct nvmem_cell *cell;2022void *buf;2023size_t len;2024#endif2025int ret;20262027#if defined(__linux__)2028cell = devm_nvmem_cell_get(ar->dev, cell_name);2029if (IS_ERR(cell)) {2030ret = PTR_ERR(cell);2031return ret;2032}20332034buf = nvmem_cell_read(cell, &len);2035if (IS_ERR(buf))2036return PTR_ERR(buf);20372038if (ar->hw_params.cal_data_len != len) {2039kfree(buf);2040ath10k_warn(ar, "invalid calibration data length in nvmem-cell '%s': %zu != %u\n",2041cell_name, len, ar->hw_params.cal_data_len);2042return -EMSGSIZE;2043}20442045ret = ath10k_download_board_data(ar, buf, len);2046kfree(buf);2047#elif defined(__FreeBSD__)2048ret = -EOPNOTSUPP;2049#endif2050if (ret)2051ath10k_warn(ar, "failed to download calibration data from nvmem-cell '%s': %d\n",2052cell_name, ret);20532054return ret;2055}20562057int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,2058struct ath10k_fw_file *fw_file)2059{2060size_t magic_len, len, ie_len;2061int ie_id, i, index, bit, ret;2062#if defined(__linux__)2063struct ath10k_fw_ie *hdr;2064#elif defined(__FreeBSD__)2065const struct ath10k_fw_ie *hdr;2066#endif2067const u8 *data;2068#if defined(__linux__)2069__le32 *timestamp, *version;2070#elif defined(__FreeBSD__)2071const __le32 *timestamp, *version;2072#endif20732074/* first fetch the firmware file (firmware-*.bin) */2075fw_file->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,2076name);2077if (IS_ERR(fw_file->firmware))2078return PTR_ERR(fw_file->firmware);20792080data = fw_file->firmware->data;2081len = fw_file->firmware->size;20822083/* magic also includes the null byte, check that as well */2084magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;20852086if (len < magic_len) {2087ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n",2088ar->hw_params.fw.dir, name, len);2089ret = -EINVAL;2090goto err;2091}20922093if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {2094ath10k_err(ar, "invalid firmware magic\n");2095ret = -EINVAL;2096goto err;2097}20982099/* jump over the padding */2100magic_len = ALIGN(magic_len, 4);21012102len -= magic_len;2103data += magic_len;21042105/* loop elements */2106while (len > sizeof(struct ath10k_fw_ie)) {2107#if defined(__linux__)2108hdr = (struct ath10k_fw_ie *)data;2109#elif defined(__FreeBSD__)2110hdr = (const struct ath10k_fw_ie *)data;2111#endif21122113ie_id = le32_to_cpu(hdr->id);2114ie_len = le32_to_cpu(hdr->len);21152116len -= sizeof(*hdr);2117data += sizeof(*hdr);21182119if (len < ie_len) {2120ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",2121ie_id, len, ie_len);2122ret = -EINVAL;2123goto err;2124}21252126switch (ie_id) {2127case ATH10K_FW_IE_FW_VERSION:2128if (ie_len > sizeof(fw_file->fw_version) - 1)2129break;21302131memcpy(fw_file->fw_version, data, ie_len);2132fw_file->fw_version[ie_len] = '\0';21332134ath10k_dbg(ar, ATH10K_DBG_BOOT,2135"found fw version %s\n",2136fw_file->fw_version);2137break;2138case ATH10K_FW_IE_TIMESTAMP:2139if (ie_len != sizeof(u32))2140break;21412142#if defined(__linux__)2143timestamp = (__le32 *)data;2144#elif defined(__FreeBSD__)2145timestamp = (const __le32 *)data;2146#endif21472148ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n",2149le32_to_cpup(timestamp));2150break;2151case ATH10K_FW_IE_FEATURES:2152ath10k_dbg(ar, ATH10K_DBG_BOOT,2153"found firmware features ie (%zd B)\n",2154ie_len);21552156for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) {2157index = i / 8;2158bit = i % 8;21592160if (index == ie_len)2161break;21622163if (data[index] & (1 << bit)) {2164ath10k_dbg(ar, ATH10K_DBG_BOOT,2165"Enabling feature bit: %i\n",2166i);2167__set_bit(i, fw_file->fw_features);2168}2169}21702171ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",2172fw_file->fw_features,2173sizeof(fw_file->fw_features));2174break;2175case ATH10K_FW_IE_FW_IMAGE:2176ath10k_dbg(ar, ATH10K_DBG_BOOT,2177"found fw image ie (%zd B)\n",2178ie_len);21792180fw_file->firmware_data = data;2181fw_file->firmware_len = ie_len;21822183break;2184case ATH10K_FW_IE_OTP_IMAGE:2185ath10k_dbg(ar, ATH10K_DBG_BOOT,2186"found otp image ie (%zd B)\n",2187ie_len);21882189fw_file->otp_data = data;2190fw_file->otp_len = ie_len;21912192break;2193case ATH10K_FW_IE_WMI_OP_VERSION:2194if (ie_len != sizeof(u32))2195break;21962197#if defined(__linux__)2198version = (__le32 *)data;2199#elif defined(__FreeBSD__)2200version = (const __le32 *)data;2201#endif22022203fw_file->wmi_op_version = le32_to_cpup(version);22042205ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n",2206fw_file->wmi_op_version);2207break;2208case ATH10K_FW_IE_HTT_OP_VERSION:2209if (ie_len != sizeof(u32))2210break;22112212#if defined(__linux__)2213version = (__le32 *)data;2214#elif defined(__FreeBSD__)2215version = (const __le32 *)data;2216#endif22172218fw_file->htt_op_version = le32_to_cpup(version);22192220ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n",2221fw_file->htt_op_version);2222break;2223case ATH10K_FW_IE_FW_CODE_SWAP_IMAGE:2224ath10k_dbg(ar, ATH10K_DBG_BOOT,2225"found fw code swap image ie (%zd B)\n",2226ie_len);2227fw_file->codeswap_data = data;2228fw_file->codeswap_len = ie_len;2229break;2230default:2231ath10k_warn(ar, "Unknown FW IE: %u\n",2232le32_to_cpu(hdr->id));2233break;2234}22352236/* jump over the padding */2237ie_len = ALIGN(ie_len, 4);22382239len -= ie_len;2240data += ie_len;2241}22422243if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, fw_file->fw_features) &&2244(!fw_file->firmware_data || !fw_file->firmware_len)) {2245ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",2246ar->hw_params.fw.dir, name);2247ret = -ENOMEDIUM;2248goto err;2249}22502251return 0;22522253err:2254ath10k_core_free_firmware_files(ar);2255return ret;2256}22572258static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name,2259size_t fw_name_len, int fw_api)2260{2261switch (ar->hif.bus) {2262case ATH10K_BUS_SDIO:2263case ATH10K_BUS_USB:2264scnprintf(fw_name, fw_name_len, "%s-%s-%d.bin",2265ATH10K_FW_FILE_BASE, ath10k_bus_str(ar->hif.bus),2266fw_api);2267break;2268case ATH10K_BUS_PCI:2269case ATH10K_BUS_AHB:2270case ATH10K_BUS_SNOC:2271scnprintf(fw_name, fw_name_len, "%s-%d.bin",2272ATH10K_FW_FILE_BASE, fw_api);2273break;2274}2275}22762277static int ath10k_core_fetch_firmware_files(struct ath10k *ar)2278{2279int ret, i;2280char fw_name[100];22812282/* calibration file is optional, don't check for any errors */2283ath10k_fetch_cal_file(ar);22842285for (i = ATH10K_FW_API_MAX; i >= ATH10K_FW_API_MIN; i--) {2286ar->fw_api = i;2287ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n",2288ar->fw_api);22892290ath10k_core_get_fw_name(ar, fw_name, sizeof(fw_name), ar->fw_api);2291ret = ath10k_core_fetch_firmware_api_n(ar, fw_name,2292&ar->normal_mode_fw.fw_file);2293if (!ret)2294goto success;2295}22962297/* we end up here if we couldn't fetch any firmware */22982299ath10k_err(ar, "Failed to find firmware-N.bin (N between %d and %d) from %s: %d",2300ATH10K_FW_API_MIN, ATH10K_FW_API_MAX, ar->hw_params.fw.dir,2301ret);23022303return ret;23042305success:2306ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);23072308return 0;2309}23102311static int ath10k_core_pre_cal_download(struct ath10k *ar)2312{2313int ret;23142315ret = ath10k_download_cal_nvmem(ar, "pre-calibration");2316if (ret == 0) {2317ar->cal_mode = ATH10K_PRE_CAL_MODE_NVMEM;2318goto success;2319} else if (ret == -EPROBE_DEFER) {2320return ret;2321}23222323ath10k_dbg(ar, ATH10K_DBG_BOOT,2324"boot did not find a pre-calibration nvmem-cell, try file next: %d\n",2325ret);23262327ret = ath10k_download_cal_file(ar, ar->pre_cal_file);2328if (ret == 0) {2329ar->cal_mode = ATH10K_PRE_CAL_MODE_FILE;2330goto success;2331}23322333ath10k_dbg(ar, ATH10K_DBG_BOOT,2334"boot did not find a pre calibration file, try DT next: %d\n",2335ret);23362337ret = ath10k_download_cal_dt(ar, "qcom,pre-calibration-data");2338if (ret == -ENOENT)2339ret = ath10k_download_cal_dt(ar, "qcom,ath10k-pre-calibration-data");2340if (ret) {2341ath10k_dbg(ar, ATH10K_DBG_BOOT,2342"unable to load pre cal data from DT: %d\n", ret);2343return ret;2344}2345ar->cal_mode = ATH10K_PRE_CAL_MODE_DT;23462347success:2348ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",2349ath10k_cal_mode_str(ar->cal_mode));23502351return 0;2352}23532354static int ath10k_core_pre_cal_config(struct ath10k *ar)2355{2356int ret;23572358ret = ath10k_core_pre_cal_download(ar);2359if (ret) {2360ath10k_dbg(ar, ATH10K_DBG_BOOT,2361"failed to load pre cal data: %d\n", ret);2362return ret;2363}23642365ret = ath10k_core_get_board_id_from_otp(ar);2366if (ret) {2367ath10k_err(ar, "failed to get board id: %d\n", ret);2368return ret;2369}23702371ret = ath10k_download_and_run_otp(ar);2372if (ret) {2373ath10k_err(ar, "failed to run otp: %d\n", ret);2374return ret;2375}23762377ath10k_dbg(ar, ATH10K_DBG_BOOT,2378"pre cal configuration done successfully\n");23792380return 0;2381}23822383static int ath10k_download_cal_data(struct ath10k *ar)2384{2385int ret;23862387ret = ath10k_core_pre_cal_config(ar);2388if (ret == 0)2389return 0;23902391ath10k_dbg(ar, ATH10K_DBG_BOOT,2392"pre cal download procedure failed, try cal file: %d\n",2393ret);23942395ret = ath10k_download_cal_nvmem(ar, "calibration");2396if (ret == 0) {2397ar->cal_mode = ATH10K_CAL_MODE_NVMEM;2398goto done;2399} else if (ret == -EPROBE_DEFER) {2400return ret;2401}24022403ath10k_dbg(ar, ATH10K_DBG_BOOT,2404"boot did not find a calibration nvmem-cell, try file next: %d\n",2405ret);24062407ret = ath10k_download_cal_file(ar, ar->cal_file);2408if (ret == 0) {2409ar->cal_mode = ATH10K_CAL_MODE_FILE;2410goto done;2411}24122413ath10k_dbg(ar, ATH10K_DBG_BOOT,2414"boot did not find a calibration file, try DT next: %d\n",2415ret);24162417ret = ath10k_download_cal_dt(ar, "qcom,calibration-data");2418if (ret == -ENOENT)2419ret = ath10k_download_cal_dt(ar, "qcom,ath10k-calibration-data");2420if (ret == 0) {2421ar->cal_mode = ATH10K_CAL_MODE_DT;2422goto done;2423}24242425ath10k_dbg(ar, ATH10K_DBG_BOOT,2426"boot did not find DT entry, try target EEPROM next: %d\n",2427ret);24282429ret = ath10k_download_cal_eeprom(ar);2430if (ret == 0) {2431ar->cal_mode = ATH10K_CAL_MODE_EEPROM;2432goto done;2433}24342435ath10k_dbg(ar, ATH10K_DBG_BOOT,2436"boot did not find target EEPROM entry, try OTP next: %d\n",2437ret);24382439ret = ath10k_download_and_run_otp(ar);2440if (ret) {2441ath10k_err(ar, "failed to run otp: %d\n", ret);2442return ret;2443}24442445ar->cal_mode = ATH10K_CAL_MODE_OTP;24462447done:2448ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",2449ath10k_cal_mode_str(ar->cal_mode));2450return 0;2451}24522453static void ath10k_core_fetch_btcoex_dt(struct ath10k *ar)2454{2455#if defined(__linux__) || (defined(__FreeBSD__) && defined(CONFIG_OF))2456struct device_node *node;2457u8 coex_support = 0;2458int ret;24592460node = ar->dev->of_node;2461if (!node)2462goto out;24632464ret = of_property_read_u8(node, "qcom,coexist-support", &coex_support);2465if (ret) {2466ar->coex_support = true;2467goto out;2468}24692470if (coex_support) {2471ar->coex_support = true;2472} else {2473ar->coex_support = false;2474ar->coex_gpio_pin = -1;2475goto out;2476}24772478ret = of_property_read_u32(node, "qcom,coexist-gpio-pin",2479&ar->coex_gpio_pin);2480if (ret)2481ar->coex_gpio_pin = -1;24822483out:2484#endif2485ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot coex_support %d coex_gpio_pin %d\n",2486ar->coex_support, ar->coex_gpio_pin);2487}24882489static int ath10k_init_uart(struct ath10k *ar)2490{2491int ret;24922493/*2494* Explicitly setting UART prints to zero as target turns it on2495* based on scratch registers.2496*/2497ret = ath10k_bmi_write32(ar, hi_serial_enable, 0);2498if (ret) {2499ath10k_warn(ar, "could not disable UART prints (%d)\n", ret);2500return ret;2501}25022503if (!uart_print) {2504if (ar->hw_params.uart_pin_workaround) {2505ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin,2506ar->hw_params.uart_pin);2507if (ret) {2508ath10k_warn(ar, "failed to set UART TX pin: %d",2509ret);2510return ret;2511}2512}25132514return 0;2515}25162517ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);2518if (ret) {2519ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);2520return ret;2521}25222523ret = ath10k_bmi_write32(ar, hi_serial_enable, 1);2524if (ret) {2525ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);2526return ret;2527}25282529/* Set the UART baud rate to 19200. */2530ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200);2531if (ret) {2532ath10k_warn(ar, "could not set the baud rate (%d)\n", ret);2533return ret;2534}25352536ath10k_info(ar, "UART prints enabled\n");2537return 0;2538}25392540static int ath10k_init_hw_params(struct ath10k *ar)2541{2542const struct ath10k_hw_params *hw_params;2543int i;25442545for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {2546hw_params = &ath10k_hw_params_list[i];25472548if (hw_params->bus == ar->hif.bus &&2549hw_params->id == ar->target_version &&2550hw_params->dev_id == ar->dev_id)2551break;2552}25532554if (i == ARRAY_SIZE(ath10k_hw_params_list)) {2555ath10k_err(ar, "Unsupported hardware version: 0x%x\n",2556ar->target_version);2557return -EINVAL;2558}25592560ar->hw_params = *hw_params;25612562ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",2563ar->hw_params.name, ar->target_version);25642565return 0;2566}25672568static void ath10k_core_recovery_check_work(struct work_struct *work)2569{2570struct ath10k *ar = container_of(work, struct ath10k, recovery_check_work);2571long time_left;25722573/* Sometimes the recovery will fail and then the next all recovery fail,2574* so avoid infinite recovery.2575*/2576if (atomic_read(&ar->fail_cont_count) >= ATH10K_RECOVERY_MAX_FAIL_COUNT) {2577ath10k_err(ar, "consecutive fail %d times, will shutdown driver!",2578atomic_read(&ar->fail_cont_count));2579ar->state = ATH10K_STATE_WEDGED;2580return;2581}25822583ath10k_dbg(ar, ATH10K_DBG_BOOT, "total recovery count: %d", ++ar->recovery_count);25842585if (atomic_read(&ar->pending_recovery)) {2586/* Sometimes it happened another recovery work before the previous one2587* completed, then the second recovery work will destroy the previous2588* one, thus below is to avoid that.2589*/2590time_left = wait_for_completion_timeout(&ar->driver_recovery,2591ATH10K_RECOVERY_TIMEOUT_HZ);2592if (time_left) {2593ath10k_warn(ar, "previous recovery succeeded, skip this!\n");2594return;2595}25962597/* Record the continuous recovery fail count when recovery failed. */2598atomic_inc(&ar->fail_cont_count);25992600/* Avoid having multiple recoveries at the same time. */2601return;2602}26032604atomic_inc(&ar->pending_recovery);2605queue_work(ar->workqueue, &ar->restart_work);2606}26072608void ath10k_core_start_recovery(struct ath10k *ar)2609{2610/* Use workqueue_aux to avoid blocking recovery tracking */2611queue_work(ar->workqueue_aux, &ar->recovery_check_work);2612}2613EXPORT_SYMBOL(ath10k_core_start_recovery);26142615void ath10k_core_napi_enable(struct ath10k *ar)2616{2617lockdep_assert_held(&ar->conf_mutex);26182619if (test_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags))2620return;26212622napi_enable(&ar->napi);2623set_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags);2624}2625EXPORT_SYMBOL(ath10k_core_napi_enable);26262627void ath10k_core_napi_sync_disable(struct ath10k *ar)2628{2629lockdep_assert_held(&ar->conf_mutex);26302631if (!test_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags))2632return;26332634napi_synchronize(&ar->napi);2635napi_disable(&ar->napi);2636clear_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags);2637}2638EXPORT_SYMBOL(ath10k_core_napi_sync_disable);26392640static void ath10k_core_restart(struct work_struct *work)2641{2642struct ath10k *ar = container_of(work, struct ath10k, restart_work);2643int ret;26442645reinit_completion(&ar->driver_recovery);26462647set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);26482649/* Place a barrier to make sure the compiler doesn't reorder2650* CRASH_FLUSH and calling other functions.2651*/2652barrier();26532654ieee80211_stop_queues(ar->hw);2655ath10k_drain_tx(ar);2656complete(&ar->scan.started);2657complete(&ar->scan.completed);2658complete(&ar->scan.on_channel);2659complete(&ar->offchan_tx_completed);2660complete(&ar->install_key_done);2661complete(&ar->vdev_setup_done);2662complete(&ar->vdev_delete_done);2663complete(&ar->thermal.wmi_sync);2664complete(&ar->bss_survey_done);2665wake_up(&ar->htt.empty_tx_wq);2666wake_up(&ar->wmi.tx_credits_wq);2667wake_up(&ar->peer_mapping_wq);26682669/* TODO: We can have one instance of cancelling coverage_class_work by2670* moving it to ath10k_halt(), so that both stop() and restart() would2671* call that but it takes conf_mutex() and if we call cancel_work_sync()2672* with conf_mutex it will deadlock.2673*/2674cancel_work_sync(&ar->set_coverage_class_work);26752676mutex_lock(&ar->conf_mutex);26772678switch (ar->state) {2679case ATH10K_STATE_ON:2680ar->state = ATH10K_STATE_RESTARTING;2681ath10k_halt(ar);2682ath10k_scan_finish(ar);2683ieee80211_restart_hw(ar->hw);2684break;2685case ATH10K_STATE_OFF:2686/* this can happen if driver is being unloaded2687* or if the crash happens during FW probing2688*/2689ath10k_warn(ar, "cannot restart a device that hasn't been started\n");2690break;2691case ATH10K_STATE_RESTARTING:2692/* hw restart might be requested from multiple places */2693break;2694case ATH10K_STATE_RESTARTED:2695ar->state = ATH10K_STATE_WEDGED;2696fallthrough;2697case ATH10K_STATE_WEDGED:2698ath10k_warn(ar, "device is wedged, will not restart\n");2699break;2700case ATH10K_STATE_UTF:2701ath10k_warn(ar, "firmware restart in UTF mode not supported\n");2702break;2703}27042705mutex_unlock(&ar->conf_mutex);27062707ret = ath10k_coredump_submit(ar);2708if (ret)2709ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d",2710ret);2711}27122713static void ath10k_core_set_coverage_class_work(struct work_struct *work)2714{2715struct ath10k *ar = container_of(work, struct ath10k,2716set_coverage_class_work);27172718if (ar->hw_params.hw_ops->set_coverage_class)2719ar->hw_params.hw_ops->set_coverage_class(ar, -1, -1);2720}27212722static int ath10k_core_init_firmware_features(struct ath10k *ar)2723{2724struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;2725int max_num_peers;27262727if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) &&2728!test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) {2729ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");2730return -EINVAL;2731}27322733if (fw_file->wmi_op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) {2734ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n",2735ATH10K_FW_WMI_OP_VERSION_MAX, fw_file->wmi_op_version);2736return -EINVAL;2737}27382739ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_NATIVE_WIFI;2740switch (ath10k_cryptmode_param) {2741case ATH10K_CRYPT_MODE_HW:2742clear_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags);2743clear_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags);2744break;2745case ATH10K_CRYPT_MODE_SW:2746if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,2747fw_file->fw_features)) {2748ath10k_err(ar, "cryptmode > 0 requires raw mode support from firmware");2749return -EINVAL;2750}27512752set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags);2753set_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags);2754break;2755default:2756ath10k_info(ar, "invalid cryptmode: %d\n",2757ath10k_cryptmode_param);2758return -EINVAL;2759}27602761ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT;2762ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT;27632764if (ath10k_frame_mode == ATH10K_HW_TXRX_RAW) {2765if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,2766fw_file->fw_features)) {2767ath10k_err(ar, "rawmode = 1 requires support from firmware");2768return -EINVAL;2769}2770set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags);2771}27722773if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {2774ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_RAW;27752776/* Workaround:2777*2778* Firmware A-MSDU aggregation breaks with RAW Tx encap mode2779* and causes enormous performance issues (malformed frames,2780* etc).2781*2782* Disabling A-MSDU makes RAW mode stable with heavy traffic2783* albeit a bit slower compared to regular operation.2784*/2785ar->htt.max_num_amsdu = 1;2786}27872788/* Backwards compatibility for firmwares without2789* ATH10K_FW_IE_WMI_OP_VERSION.2790*/2791if (fw_file->wmi_op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) {2792if (test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) {2793if (test_bit(ATH10K_FW_FEATURE_WMI_10_2,2794fw_file->fw_features))2795fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_2;2796else2797fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;2798} else {2799fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_MAIN;2800}2801}28022803switch (fw_file->wmi_op_version) {2804case ATH10K_FW_WMI_OP_VERSION_MAIN:2805max_num_peers = TARGET_NUM_PEERS;2806ar->max_num_stations = TARGET_NUM_STATIONS;2807ar->max_num_vdevs = TARGET_NUM_VDEVS;2808ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;2809ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |2810WMI_STAT_PEER;2811ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;2812break;2813case ATH10K_FW_WMI_OP_VERSION_10_1:2814case ATH10K_FW_WMI_OP_VERSION_10_2:2815case ATH10K_FW_WMI_OP_VERSION_10_2_4:2816if (ath10k_peer_stats_enabled(ar)) {2817max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;2818ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS;2819} else {2820max_num_peers = TARGET_10X_NUM_PEERS;2821ar->max_num_stations = TARGET_10X_NUM_STATIONS;2822}2823ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;2824ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;2825ar->fw_stats_req_mask = WMI_STAT_PEER;2826ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;2827#if defined(CONFIG_FWLOG)2828ar->fwlog_max_moduleid = ATH10K_FWLOG_MODULE_ID_MAX_10_2_4;2829#endif2830break;2831case ATH10K_FW_WMI_OP_VERSION_TLV:2832max_num_peers = TARGET_TLV_NUM_PEERS;2833ar->max_num_stations = TARGET_TLV_NUM_STATIONS;2834ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;2835ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS;2836if (ar->hif.bus == ATH10K_BUS_SDIO)2837ar->htt.max_num_pending_tx =2838TARGET_TLV_NUM_MSDU_DESC_HL;2839else2840ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;2841ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS;2842ar->fw_stats_req_mask = WMI_TLV_STAT_PDEV | WMI_TLV_STAT_VDEV |2843WMI_TLV_STAT_PEER | WMI_TLV_STAT_PEER_EXTD;2844ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;2845ar->wmi.mgmt_max_num_pending_tx = TARGET_TLV_MGMT_NUM_MSDU_DESC;2846break;2847case ATH10K_FW_WMI_OP_VERSION_10_4:2848max_num_peers = TARGET_10_4_NUM_PEERS;2849ar->max_num_stations = TARGET_10_4_NUM_STATIONS;2850ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS;2851ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;2852ar->num_tids = TARGET_10_4_TGT_NUM_TIDS;2853ar->fw_stats_req_mask = WMI_10_4_STAT_PEER |2854WMI_10_4_STAT_PEER_EXTD |2855WMI_10_4_STAT_VDEV_EXTD;2856ar->max_spatial_stream = ar->hw_params.max_spatial_stream;2857ar->max_num_tdls_vdevs = TARGET_10_4_NUM_TDLS_VDEVS;28582859if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,2860fw_file->fw_features))2861ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC_PFC;2862else2863ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC;2864break;2865case ATH10K_FW_WMI_OP_VERSION_UNSET:2866case ATH10K_FW_WMI_OP_VERSION_MAX:2867default:2868WARN_ON(1);2869return -EINVAL;2870}28712872if (ar->hw_params.num_peers)2873ar->max_num_peers = ar->hw_params.num_peers;2874else2875ar->max_num_peers = max_num_peers;28762877/* Backwards compatibility for firmwares without2878* ATH10K_FW_IE_HTT_OP_VERSION.2879*/2880if (fw_file->htt_op_version == ATH10K_FW_HTT_OP_VERSION_UNSET) {2881switch (fw_file->wmi_op_version) {2882case ATH10K_FW_WMI_OP_VERSION_MAIN:2883fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_MAIN;2884break;2885case ATH10K_FW_WMI_OP_VERSION_10_1:2886case ATH10K_FW_WMI_OP_VERSION_10_2:2887case ATH10K_FW_WMI_OP_VERSION_10_2_4:2888fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;2889break;2890case ATH10K_FW_WMI_OP_VERSION_TLV:2891fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;2892break;2893case ATH10K_FW_WMI_OP_VERSION_10_4:2894case ATH10K_FW_WMI_OP_VERSION_UNSET:2895case ATH10K_FW_WMI_OP_VERSION_MAX:2896ath10k_err(ar, "htt op version not found from fw meta data");2897return -EINVAL;2898}2899}29002901return 0;2902}29032904static int ath10k_core_reset_rx_filter(struct ath10k *ar)2905{2906int ret;2907int vdev_id;2908int vdev_type;2909int vdev_subtype;2910const u8 *vdev_addr;29112912vdev_id = 0;2913vdev_type = WMI_VDEV_TYPE_STA;2914vdev_subtype = ath10k_wmi_get_vdev_subtype(ar, WMI_VDEV_SUBTYPE_NONE);2915vdev_addr = ar->mac_addr;29162917ret = ath10k_wmi_vdev_create(ar, vdev_id, vdev_type, vdev_subtype,2918vdev_addr);2919if (ret) {2920ath10k_err(ar, "failed to create dummy vdev: %d\n", ret);2921return ret;2922}29232924ret = ath10k_wmi_vdev_delete(ar, vdev_id);2925if (ret) {2926ath10k_err(ar, "failed to delete dummy vdev: %d\n", ret);2927return ret;2928}29292930/* WMI and HTT may use separate HIF pipes and are not guaranteed to be2931* serialized properly implicitly.2932*2933* Moreover (most) WMI commands have no explicit acknowledges. It is2934* possible to infer it implicitly by poking firmware with echo2935* command - getting a reply means all preceding comments have been2936* (mostly) processed.2937*2938* In case of vdev create/delete this is sufficient.2939*2940* Without this it's possible to end up with a race when HTT Rx ring is2941* started before vdev create/delete hack is complete allowing a short2942* window of opportunity to receive (and Tx ACK) a bunch of frames.2943*/2944ret = ath10k_wmi_barrier(ar);2945if (ret) {2946ath10k_err(ar, "failed to ping firmware: %d\n", ret);2947return ret;2948}29492950return 0;2951}29522953static int ath10k_core_compat_services(struct ath10k *ar)2954{2955struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;29562957/* all 10.x firmware versions support thermal throttling but don't2958* advertise the support via service flags so we have to hardcode2959* it here2960*/2961switch (fw_file->wmi_op_version) {2962case ATH10K_FW_WMI_OP_VERSION_10_1:2963case ATH10K_FW_WMI_OP_VERSION_10_2:2964case ATH10K_FW_WMI_OP_VERSION_10_2_4:2965case ATH10K_FW_WMI_OP_VERSION_10_4:2966set_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map);2967break;2968default:2969break;2970}29712972return 0;2973}29742975#define TGT_IRAM_READ_PER_ITR (8 * 1024)29762977static int ath10k_core_copy_target_iram(struct ath10k *ar)2978{2979const struct ath10k_hw_mem_layout *hw_mem;2980const struct ath10k_mem_region *tmp, *mem_region = NULL;2981dma_addr_t paddr;2982void *vaddr = NULL;2983u8 num_read_itr;2984int i, ret;2985u32 len, remaining_len;29862987/* copy target iram feature must work also when2988* ATH10K_FW_CRASH_DUMP_RAM_DATA is disabled, so2989* _ath10k_coredump_get_mem_layout() to accomplist that2990*/2991hw_mem = _ath10k_coredump_get_mem_layout(ar);2992if (!hw_mem)2993/* if CONFIG_DEV_COREDUMP is disabled we get NULL, then2994* just silently disable the feature by doing nothing2995*/2996return 0;29972998for (i = 0; i < hw_mem->region_table.size; i++) {2999tmp = &hw_mem->region_table.regions[i];3000if (tmp->type == ATH10K_MEM_REGION_TYPE_REG) {3001mem_region = tmp;3002break;3003}3004}30053006if (!mem_region)3007return -ENOMEM;30083009for (i = 0; i < ar->wmi.num_mem_chunks; i++) {3010if (ar->wmi.mem_chunks[i].req_id ==3011WMI_IRAM_RECOVERY_HOST_MEM_REQ_ID) {3012vaddr = ar->wmi.mem_chunks[i].vaddr;3013len = ar->wmi.mem_chunks[i].len;3014break;3015}3016}30173018if (!vaddr || !len) {3019ath10k_warn(ar, "No allocated memory for IRAM back up");3020return -ENOMEM;3021}30223023len = (len < mem_region->len) ? len : mem_region->len;3024paddr = mem_region->start;3025num_read_itr = len / TGT_IRAM_READ_PER_ITR;3026remaining_len = len % TGT_IRAM_READ_PER_ITR;3027for (i = 0; i < num_read_itr; i++) {3028ret = ath10k_hif_diag_read(ar, paddr, vaddr,3029TGT_IRAM_READ_PER_ITR);3030if (ret) {3031ath10k_warn(ar, "failed to copy firmware IRAM contents: %d",3032ret);3033return ret;3034}30353036paddr += TGT_IRAM_READ_PER_ITR;3037#if defined(__linux__)3038vaddr += TGT_IRAM_READ_PER_ITR;3039#elif defined(__FreeBSD__)3040vaddr = (void *)((uintptr_t)vaddr + TGT_IRAM_READ_PER_ITR);3041#endif3042}30433044if (remaining_len) {3045ret = ath10k_hif_diag_read(ar, paddr, vaddr, remaining_len);3046if (ret) {3047ath10k_warn(ar, "failed to copy firmware IRAM contents: %d",3048ret);3049return ret;3050}3051}30523053ath10k_dbg(ar, ATH10K_DBG_BOOT, "target IRAM back up completed\n");30543055return 0;3056}30573058int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,3059const struct ath10k_fw_components *fw)3060{3061int status;3062u32 val;30633064lockdep_assert_held(&ar->conf_mutex);30653066clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);30673068ar->running_fw = fw;30693070if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,3071ar->running_fw->fw_file.fw_features)) {3072ath10k_bmi_start(ar);30733074/* Enable hardware clock to speed up firmware download */3075if (ar->hw_params.hw_ops->enable_pll_clk) {3076status = ar->hw_params.hw_ops->enable_pll_clk(ar);3077ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot enable pll ret %d\n",3078status);3079}30803081if (ath10k_init_configure_target(ar)) {3082status = -EINVAL;3083goto err;3084}30853086status = ath10k_download_cal_data(ar);3087if (status)3088goto err;30893090/* Some of qca988x solutions are having global reset issue3091* during target initialization. Bypassing PLL setting before3092* downloading firmware and letting the SoC run on REF_CLK is3093* fixing the problem. Corresponding firmware change is also3094* needed to set the clock source once the target is3095* initialized.3096*/3097if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,3098ar->running_fw->fw_file.fw_features)) {3099status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1);3100if (status) {3101ath10k_err(ar, "could not write to skip_clock_init: %d\n",3102status);3103goto err;3104}3105}31063107status = ath10k_download_fw(ar);3108if (status)3109goto err;31103111status = ath10k_init_uart(ar);3112if (status)3113goto err;31143115if (ar->hif.bus == ATH10K_BUS_SDIO) {3116status = ath10k_init_sdio(ar, mode);3117if (status) {3118ath10k_err(ar, "failed to init SDIO: %d\n", status);3119goto err;3120}3121}3122}31233124ar->htc.htc_ops.target_send_suspend_complete =3125ath10k_send_suspend_complete;31263127status = ath10k_htc_init(ar);3128if (status) {3129ath10k_err(ar, "could not init HTC (%d)\n", status);3130goto err;3131}31323133if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,3134ar->running_fw->fw_file.fw_features)) {3135status = ath10k_bmi_done(ar);3136if (status)3137goto err;3138}31393140status = ath10k_wmi_attach(ar);3141if (status) {3142ath10k_err(ar, "WMI attach failed: %d\n", status);3143goto err;3144}31453146status = ath10k_htt_init(ar);3147if (status) {3148ath10k_err(ar, "failed to init htt: %d\n", status);3149goto err_wmi_detach;3150}31513152status = ath10k_htt_tx_start(&ar->htt);3153if (status) {3154ath10k_err(ar, "failed to alloc htt tx: %d\n", status);3155goto err_wmi_detach;3156}31573158/* If firmware indicates Full Rx Reorder support it must be used in a3159* slightly different manner. Let HTT code know.3160*/3161ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,3162ar->wmi.svc_map));31633164status = ath10k_htt_rx_alloc(&ar->htt);3165if (status) {3166ath10k_err(ar, "failed to alloc htt rx: %d\n", status);3167goto err_htt_tx_detach;3168}31693170status = ath10k_hif_start(ar);3171if (status) {3172ath10k_err(ar, "could not start HIF: %d\n", status);3173goto err_htt_rx_detach;3174}31753176status = ath10k_htc_wait_target(&ar->htc);3177if (status) {3178ath10k_err(ar, "failed to connect to HTC: %d\n", status);3179goto err_hif_stop;3180}31813182status = ath10k_hif_start_post(ar);3183if (status) {3184ath10k_err(ar, "failed to swap mailbox: %d\n", status);3185goto err_hif_stop;3186}31873188if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {3189status = ath10k_htt_connect(&ar->htt);3190if (status) {3191ath10k_err(ar, "failed to connect htt (%d)\n", status);3192goto err_hif_stop;3193}3194}31953196status = ath10k_wmi_connect(ar);3197if (status) {3198ath10k_err(ar, "could not connect wmi: %d\n", status);3199goto err_hif_stop;3200}32013202status = ath10k_htc_start(&ar->htc);3203if (status) {3204ath10k_err(ar, "failed to start htc: %d\n", status);3205goto err_hif_stop;3206}32073208if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {3209status = ath10k_wmi_wait_for_service_ready(ar);3210if (status) {3211ath10k_warn(ar, "wmi service ready event not received");3212goto err_hif_stop;3213}3214}32153216ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",3217ar->hw->wiphy->fw_version);32183219if (test_bit(ATH10K_FW_FEATURE_IRAM_RECOVERY,3220ar->running_fw->fw_file.fw_features)) {3221status = ath10k_core_copy_target_iram(ar);3222if (status) {3223ath10k_warn(ar, "failed to copy target iram contents: %d",3224status);3225goto err_hif_stop;3226}3227}32283229if (test_bit(WMI_SERVICE_EXT_RES_CFG_SUPPORT, ar->wmi.svc_map) &&3230mode == ATH10K_FIRMWARE_MODE_NORMAL) {3231val = 0;3232if (ath10k_peer_stats_enabled(ar))3233val = WMI_10_4_PEER_STATS;32343235/* Enable vdev stats by default */3236val |= WMI_10_4_VDEV_STATS;32373238if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))3239val |= WMI_10_4_BSS_CHANNEL_INFO_64;32403241ath10k_core_fetch_btcoex_dt(ar);32423243/* 10.4 firmware supports BT-Coex without reloading firmware3244* via pdev param. To support Bluetooth coexistence pdev param,3245* WMI_COEX_GPIO_SUPPORT of extended resource config should be3246* enabled always.3247*3248* We can still enable BTCOEX if firmware has the support3249* even though btceox_support value is3250* ATH10K_DT_BTCOEX_NOT_FOUND3251*/32523253if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map) &&3254test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM,3255ar->running_fw->fw_file.fw_features) &&3256ar->coex_support)3257val |= WMI_10_4_COEX_GPIO_SUPPORT;32583259if (test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,3260ar->wmi.svc_map))3261val |= WMI_10_4_TDLS_EXPLICIT_MODE_ONLY;32623263if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA,3264ar->wmi.svc_map))3265val |= WMI_10_4_TDLS_UAPSD_BUFFER_STA;32663267if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI,3268ar->wmi.svc_map))3269val |= WMI_10_4_TX_DATA_ACK_RSSI;32703271if (test_bit(WMI_SERVICE_REPORT_AIRTIME, ar->wmi.svc_map))3272val |= WMI_10_4_REPORT_AIRTIME;32733274if (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT,3275ar->wmi.svc_map))3276val |= WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT;32773278status = ath10k_mac_ext_resource_config(ar, val);3279if (status) {3280ath10k_err(ar,3281"failed to send ext resource cfg command : %d\n",3282status);3283goto err_hif_stop;3284}3285}32863287status = ath10k_wmi_cmd_init(ar);3288if (status) {3289ath10k_err(ar, "could not send WMI init command (%d)\n",3290status);3291goto err_hif_stop;3292}32933294status = ath10k_wmi_wait_for_unified_ready(ar);3295if (status) {3296ath10k_err(ar, "wmi unified ready event not received\n");3297goto err_hif_stop;3298}32993300status = ath10k_core_compat_services(ar);3301if (status) {3302ath10k_err(ar, "compat services failed: %d\n", status);3303goto err_hif_stop;3304}33053306status = ath10k_wmi_pdev_set_base_macaddr(ar, ar->mac_addr);3307if (status && status != -EOPNOTSUPP) {3308ath10k_err(ar,3309"failed to set base mac address: %d\n", status);3310goto err_hif_stop;3311}33123313/* Some firmware revisions do not properly set up hardware rx filter3314* registers.3315*3316* A known example from QCA9880 and 10.2.4 is that MAC_PCU_ADDR1_MASK3317* is filled with 0s instead of 1s allowing HW to respond with ACKs to3318* any frames that matches MAC_PCU_RX_FILTER which is also3319* misconfigured to accept anything.3320*3321* The ADDR1 is programmed using internal firmware structure field and3322* can't be (easily/sanely) reached from the driver explicitly. It is3323* possible to implicitly make it correct by creating a dummy vdev and3324* then deleting it.3325*/3326if (ar->hw_params.hw_filter_reset_required &&3327mode == ATH10K_FIRMWARE_MODE_NORMAL) {3328status = ath10k_core_reset_rx_filter(ar);3329if (status) {3330ath10k_err(ar,3331"failed to reset rx filter: %d\n", status);3332goto err_hif_stop;3333}3334}33353336status = ath10k_htt_rx_ring_refill(ar);3337if (status) {3338ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);3339goto err_hif_stop;3340}33413342if (ar->max_num_vdevs >= 64)3343ar->free_vdev_map = 0xFFFFFFFFFFFFFFFFLL;3344else3345ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;33463347INIT_LIST_HEAD(&ar->arvifs);33483349/* we don't care about HTT in UTF mode */3350if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {3351status = ath10k_htt_setup(&ar->htt);3352if (status) {3353ath10k_err(ar, "failed to setup htt: %d\n", status);3354goto err_hif_stop;3355}3356}33573358status = ath10k_debug_start(ar);3359if (status)3360goto err_hif_stop;33613362status = ath10k_hif_set_target_log_mode(ar, fw_diag_log);3363if (status && status != -EOPNOTSUPP) {3364ath10k_warn(ar, "set target log mode failed: %d\n", status);3365goto err_hif_stop;3366}33673368status = ath10k_leds_start(ar);3369if (status)3370goto err_hif_stop;33713372return 0;33733374err_hif_stop:3375ath10k_hif_stop(ar);3376err_htt_rx_detach:3377ath10k_htt_rx_free(&ar->htt);3378err_htt_tx_detach:3379ath10k_htt_tx_free(&ar->htt);3380err_wmi_detach:3381ath10k_wmi_detach(ar);3382err:3383return status;3384}3385EXPORT_SYMBOL(ath10k_core_start);33863387int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)3388{3389int ret;3390unsigned long time_left;33913392reinit_completion(&ar->target_suspend);33933394ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);3395if (ret) {3396ath10k_warn(ar, "could not suspend target (%d)\n", ret);3397return ret;3398}33993400time_left = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);34013402if (!time_left) {3403ath10k_warn(ar, "suspend timed out - target pause event never came\n");3404return -ETIMEDOUT;3405}34063407return 0;3408}34093410void ath10k_core_stop(struct ath10k *ar)3411{3412lockdep_assert_held(&ar->conf_mutex);3413ath10k_debug_stop(ar);34143415/* try to suspend target */3416if (ar->state != ATH10K_STATE_RESTARTING &&3417ar->state != ATH10K_STATE_UTF)3418ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);34193420ath10k_hif_stop(ar);3421ath10k_htt_tx_stop(&ar->htt);3422ath10k_htt_rx_free(&ar->htt);3423ath10k_wmi_detach(ar);34243425ar->id.bmi_ids_valid = false;3426}3427EXPORT_SYMBOL(ath10k_core_stop);34283429/* mac80211 manages fw/hw initialization through start/stop hooks. However in3430* order to know what hw capabilities should be advertised to mac80211 it is3431* necessary to load the firmware (and tear it down immediately since start3432* hook will try to init it again) before registering3433*/3434static int ath10k_core_probe_fw(struct ath10k *ar)3435{3436struct bmi_target_info target_info = {};3437int ret = 0;34383439ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_NORMAL);3440if (ret) {3441ath10k_err(ar, "could not power on hif bus (%d)\n", ret);3442return ret;3443}34443445switch (ar->hif.bus) {3446case ATH10K_BUS_SDIO:3447ret = ath10k_bmi_get_target_info_sdio(ar, &target_info);3448if (ret) {3449ath10k_err(ar, "could not get target info (%d)\n", ret);3450goto err_power_down;3451}3452ar->target_version = target_info.version;3453ar->hw->wiphy->hw_version = target_info.version;3454break;3455case ATH10K_BUS_PCI:3456case ATH10K_BUS_AHB:3457case ATH10K_BUS_USB:3458ret = ath10k_bmi_get_target_info(ar, &target_info);3459if (ret) {3460ath10k_err(ar, "could not get target info (%d)\n", ret);3461goto err_power_down;3462}3463ar->target_version = target_info.version;3464ar->hw->wiphy->hw_version = target_info.version;3465break;3466case ATH10K_BUS_SNOC:3467ret = ath10k_hif_get_target_info(ar, &target_info);3468if (ret) {3469ath10k_err(ar, "could not get target info (%d)\n", ret);3470goto err_power_down;3471}3472ar->target_version = target_info.version;3473ar->hw->wiphy->hw_version = target_info.version;3474break;3475default:3476ath10k_err(ar, "incorrect hif bus type: %d\n", ar->hif.bus);3477}34783479ret = ath10k_init_hw_params(ar);3480if (ret) {3481ath10k_err(ar, "could not get hw params (%d)\n", ret);3482goto err_power_down;3483}34843485ret = ath10k_core_fetch_firmware_files(ar);3486if (ret) {3487ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);3488goto err_power_down;3489}34903491BUILD_BUG_ON(sizeof(ar->hw->wiphy->fw_version) !=3492sizeof(ar->normal_mode_fw.fw_file.fw_version));3493memcpy(ar->hw->wiphy->fw_version, ar->normal_mode_fw.fw_file.fw_version,3494sizeof(ar->hw->wiphy->fw_version));34953496ath10k_debug_print_hwfw_info(ar);34973498if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,3499ar->normal_mode_fw.fw_file.fw_features)) {3500ret = ath10k_core_pre_cal_download(ar);3501if (ret) {3502/* pre calibration data download is not necessary3503* for all the chipsets. Ignore failures and continue.3504*/3505ath10k_dbg(ar, ATH10K_DBG_BOOT,3506"could not load pre cal data: %d\n", ret);3507}35083509ret = ath10k_core_get_board_id_from_otp(ar);3510if (ret && ret != -EOPNOTSUPP) {3511ath10k_err(ar, "failed to get board id from otp: %d\n",3512ret);3513goto err_free_firmware_files;3514}35153516ret = ath10k_core_check_smbios(ar);3517if (ret)3518ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n");35193520ret = ath10k_core_check_dt(ar);3521if (ret)3522ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n");35233524ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD);3525if (ret) {3526ath10k_err(ar, "failed to fetch board file: %d\n", ret);3527goto err_free_firmware_files;3528}35293530ath10k_debug_print_board_info(ar);3531}35323533device_get_mac_address(ar->dev, ar->mac_addr);35343535ret = ath10k_core_init_firmware_features(ar);3536if (ret) {3537ath10k_err(ar, "fatal problem with firmware features: %d\n",3538ret);3539goto err_free_firmware_files;3540}35413542if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,3543ar->normal_mode_fw.fw_file.fw_features)) {3544ret = ath10k_swap_code_seg_init(ar,3545&ar->normal_mode_fw.fw_file);3546if (ret) {3547ath10k_err(ar, "failed to initialize code swap segment: %d\n",3548ret);3549goto err_free_firmware_files;3550}3551}35523553mutex_lock(&ar->conf_mutex);35543555ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL,3556&ar->normal_mode_fw);3557if (ret) {3558ath10k_err(ar, "could not init core (%d)\n", ret);3559goto err_unlock;3560}35613562ath10k_debug_print_boot_info(ar);3563ath10k_core_stop(ar);35643565mutex_unlock(&ar->conf_mutex);35663567ath10k_hif_power_down(ar);3568return 0;35693570err_unlock:3571mutex_unlock(&ar->conf_mutex);35723573err_free_firmware_files:3574ath10k_core_free_firmware_files(ar);35753576err_power_down:3577ath10k_hif_power_down(ar);35783579return ret;3580}35813582static void ath10k_core_register_work(struct work_struct *work)3583{3584struct ath10k *ar = container_of(work, struct ath10k, register_work);3585int status;35863587/* peer stats are enabled by default */3588set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);35893590status = ath10k_core_probe_fw(ar);3591if (status) {3592ath10k_err(ar, "could not probe fw (%d)\n", status);3593goto err;3594}35953596status = ath10k_mac_register(ar);3597if (status) {3598ath10k_err(ar, "could not register to mac80211 (%d)\n", status);3599goto err_release_fw;3600}36013602status = ath10k_coredump_register(ar);3603if (status) {3604ath10k_err(ar, "unable to register coredump\n");3605goto err_unregister_mac;3606}36073608status = ath10k_debug_register(ar);3609if (status) {3610ath10k_err(ar, "unable to initialize debugfs\n");3611goto err_unregister_coredump;3612}36133614status = ath10k_spectral_create(ar);3615if (status) {3616ath10k_err(ar, "failed to initialize spectral\n");3617goto err_debug_destroy;3618}36193620status = ath10k_thermal_register(ar);3621if (status) {3622ath10k_err(ar, "could not register thermal device: %d\n",3623status);3624goto err_spectral_destroy;3625}3626#if defined(CONFIG_FWLOG)3627ath10k_fwlog_register(ar);3628#endif36293630status = ath10k_leds_register(ar);3631if (status) {3632ath10k_err(ar, "could not register leds: %d\n",3633status);3634goto err_thermal_unregister;3635}36363637set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);3638return;36393640err_thermal_unregister:3641ath10k_thermal_unregister(ar);3642err_spectral_destroy:3643ath10k_spectral_destroy(ar);3644err_debug_destroy:3645ath10k_debug_destroy(ar);3646err_unregister_coredump:3647ath10k_coredump_unregister(ar);3648err_unregister_mac:3649ath10k_mac_unregister(ar);3650err_release_fw:3651ath10k_core_free_firmware_files(ar);3652err:3653/* TODO: It's probably a good idea to release device from the driver3654* but calling device_release_driver() here will cause a deadlock.3655*/3656return;3657}36583659int ath10k_core_register(struct ath10k *ar,3660const struct ath10k_bus_params *bus_params)3661{3662ar->bus_param = *bus_params;36633664queue_work(ar->workqueue, &ar->register_work);36653666return 0;3667}3668EXPORT_SYMBOL(ath10k_core_register);36693670void ath10k_core_unregister(struct ath10k *ar)3671{3672cancel_work_sync(&ar->register_work);36733674if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))3675return;36763677ath10k_leds_unregister(ar);36783679ath10k_thermal_unregister(ar);3680/* Stop spectral before unregistering from mac80211 to remove the3681* relayfs debugfs file cleanly. Otherwise the parent debugfs tree3682* would be already be free'd recursively, leading to a double free.3683*/3684ath10k_spectral_destroy(ar);36853686/* We must unregister from mac80211 before we stop HTC and HIF.3687* Otherwise we will fail to submit commands to FW and mac80211 will be3688* unhappy about callback failures.3689*/3690ath10k_mac_unregister(ar);36913692ath10k_testmode_destroy(ar);36933694ath10k_core_free_firmware_files(ar);3695ath10k_core_free_board_files(ar);36963697ath10k_debug_unregister(ar);3698#if defined(CONFIG_FWLOG)3699ath10k_fwlog_unregister(ar);3700#endif3701}3702EXPORT_SYMBOL(ath10k_core_unregister);37033704struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,3705enum ath10k_bus bus,3706enum ath10k_hw_rev hw_rev,3707const struct ath10k_hif_ops *hif_ops)3708{3709struct ath10k *ar;3710int ret;37113712ar = ath10k_mac_create(priv_size);3713if (!ar)3714return NULL;37153716ar->ath_common.priv = ar;3717ar->ath_common.hw = ar->hw;3718ar->dev = dev;3719ar->hw_rev = hw_rev;3720ar->hif.ops = hif_ops;3721ar->hif.bus = bus;37223723switch (hw_rev) {3724case ATH10K_HW_QCA988X:3725case ATH10K_HW_QCA9887:3726ar->regs = &qca988x_regs;3727ar->hw_ce_regs = &qcax_ce_regs;3728ar->hw_values = &qca988x_values;3729break;3730case ATH10K_HW_QCA6174:3731case ATH10K_HW_QCA9377:3732ar->regs = &qca6174_regs;3733ar->hw_ce_regs = &qcax_ce_regs;3734ar->hw_values = &qca6174_values;3735break;3736case ATH10K_HW_QCA99X0:3737case ATH10K_HW_QCA9984:3738ar->regs = &qca99x0_regs;3739ar->hw_ce_regs = &qcax_ce_regs;3740ar->hw_values = &qca99x0_values;3741break;3742case ATH10K_HW_QCA9888:3743ar->regs = &qca99x0_regs;3744ar->hw_ce_regs = &qcax_ce_regs;3745ar->hw_values = &qca9888_values;3746break;3747case ATH10K_HW_QCA4019:3748ar->regs = &qca4019_regs;3749ar->hw_ce_regs = &qcax_ce_regs;3750ar->hw_values = &qca4019_values;3751break;3752case ATH10K_HW_WCN3990:3753ar->regs = &wcn3990_regs;3754ar->hw_ce_regs = &wcn3990_ce_regs;3755ar->hw_values = &wcn3990_values;3756break;3757default:3758ath10k_err(ar, "unsupported core hardware revision %d\n",3759hw_rev);3760ret = -EOPNOTSUPP;3761goto err_free_mac;3762}37633764init_completion(&ar->scan.started);3765init_completion(&ar->scan.completed);3766init_completion(&ar->scan.on_channel);3767init_completion(&ar->target_suspend);3768init_completion(&ar->driver_recovery);3769init_completion(&ar->wow.wakeup_completed);37703771init_completion(&ar->install_key_done);3772init_completion(&ar->vdev_setup_done);3773init_completion(&ar->vdev_delete_done);3774init_completion(&ar->thermal.wmi_sync);3775init_completion(&ar->bss_survey_done);3776init_completion(&ar->peer_delete_done);3777init_completion(&ar->peer_stats_info_complete);37783779INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);37803781ar->workqueue = create_singlethread_workqueue("ath10k_wq");3782if (!ar->workqueue)3783goto err_free_mac;37843785ar->workqueue_aux = create_singlethread_workqueue("ath10k_aux_wq");3786if (!ar->workqueue_aux)3787goto err_free_wq;37883789ar->workqueue_tx_complete =3790create_singlethread_workqueue("ath10k_tx_complete_wq");3791if (!ar->workqueue_tx_complete)3792goto err_free_aux_wq;37933794mutex_init(&ar->conf_mutex);3795mutex_init(&ar->dump_mutex);3796spin_lock_init(&ar->data_lock);37973798for (int ac = 0; ac < IEEE80211_NUM_ACS; ac++)3799spin_lock_init(&ar->queue_lock[ac]);38003801INIT_LIST_HEAD(&ar->peers);3802init_waitqueue_head(&ar->peer_mapping_wq);3803init_waitqueue_head(&ar->htt.empty_tx_wq);3804init_waitqueue_head(&ar->wmi.tx_credits_wq);38053806skb_queue_head_init(&ar->htt.rx_indication_head);38073808init_completion(&ar->offchan_tx_completed);3809INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);3810skb_queue_head_init(&ar->offchan_tx_queue);38113812INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);3813skb_queue_head_init(&ar->wmi_mgmt_tx_queue);38143815INIT_WORK(&ar->register_work, ath10k_core_register_work);3816INIT_WORK(&ar->restart_work, ath10k_core_restart);3817INIT_WORK(&ar->recovery_check_work, ath10k_core_recovery_check_work);3818INIT_WORK(&ar->set_coverage_class_work,3819ath10k_core_set_coverage_class_work);38203821ar->napi_dev = alloc_netdev_dummy(0);3822if (!ar->napi_dev)3823goto err_free_tx_complete;38243825ret = ath10k_coredump_create(ar);3826if (ret)3827goto err_free_netdev;38283829ret = ath10k_debug_create(ar);3830if (ret)3831goto err_free_coredump;38323833return ar;38343835err_free_coredump:3836ath10k_coredump_destroy(ar);3837err_free_netdev:3838free_netdev(ar->napi_dev);3839err_free_tx_complete:3840destroy_workqueue(ar->workqueue_tx_complete);3841err_free_aux_wq:3842destroy_workqueue(ar->workqueue_aux);3843err_free_wq:3844destroy_workqueue(ar->workqueue);3845err_free_mac:3846ath10k_mac_destroy(ar);38473848return NULL;3849}3850EXPORT_SYMBOL(ath10k_core_create);38513852void ath10k_core_destroy(struct ath10k *ar)3853{3854destroy_workqueue(ar->workqueue);38553856destroy_workqueue(ar->workqueue_aux);38573858destroy_workqueue(ar->workqueue_tx_complete);38593860free_netdev(ar->napi_dev);3861ath10k_debug_destroy(ar);3862ath10k_coredump_destroy(ar);3863ath10k_htt_tx_destroy(&ar->htt);3864ath10k_wmi_free_host_mem(ar);3865ath10k_mac_destroy(ar);3866}3867EXPORT_SYMBOL(ath10k_core_destroy);38683869MODULE_AUTHOR("Qualcomm Atheros");3870MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ac wireless LAN cards.");3871MODULE_LICENSE("Dual BSD/GPL");3872#if defined(__FreeBSD__)3873MODULE_VERSION(ath10k, 1);3874MODULE_DEPEND(ath10k, linuxkpi, 1, 1, 1);3875MODULE_DEPEND(ath10k, linuxkpi_wlan, 1, 1, 1);3876MODULE_DEPEND(ath10k, athk_common, 1, 1, 1);3877#endif387838793880