Path: blob/main/sys/contrib/dev/athk/ath10k/core.c
48375 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*/67#if defined(__FreeBSD__)8#define LINUXKPI_PARAM_PREFIX ath10k_core_9#endif1011#include <linux/module.h>12#include <linux/firmware.h>13#if defined(__linux__) || (defined(__FreeBSD__) && defined(CONFIG_OF))14#include <linux/of.h>15#endif16#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#endif3738unsigned int ath10k_debug_mask;39EXPORT_SYMBOL(ath10k_debug_mask);4041static unsigned int ath10k_cryptmode_param;42static bool uart_print;43static bool skip_otp;44static bool fw_diag_log;4546/* frame mode values are mapped as per enum ath10k_hw_txrx_mode */47unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI;4849unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) |50BIT(ATH10K_FW_CRASH_DUMP_CE_DATA);5152/* FIXME: most of these should be readonly */53module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);54module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);55module_param(uart_print, bool, 0644);56module_param(skip_otp, bool, 0644);57module_param(fw_diag_log, bool, 0644);58module_param_named(frame_mode, ath10k_frame_mode, uint, 0644);59module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444);6061MODULE_PARM_DESC(debug_mask, "Debugging mask");62MODULE_PARM_DESC(uart_print, "Uart target debugging");63MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");64MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");65MODULE_PARM_DESC(frame_mode,66"Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");67MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file");68MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging");6970static const struct ath10k_hw_params ath10k_hw_params_list[] = {71{72.id = QCA988X_HW_2_0_VERSION,73.dev_id = QCA988X_2_0_DEVICE_ID,74.bus = ATH10K_BUS_PCI,75.name = "qca988x hw2.0",76.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,77.uart_pin = 7,78.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,79.otp_exe_param = 0,80.channel_counters_freq_hz = 88000,81.max_probe_resp_desc_thres = 0,82.cal_data_len = 2116,83.fw = {84.dir = QCA988X_HW_2_0_FW_DIR,85.board = QCA988X_HW_2_0_BOARD_DATA_FILE,86.board_size = QCA988X_BOARD_DATA_SZ,87.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,88},89.rx_desc_ops = &qca988x_rx_desc_ops,90.hw_ops = &qca988x_ops,91.decap_align_bytes = 4,92.spectral_bin_discard = 0,93.spectral_bin_offset = 0,94.vht160_mcs_rx_highest = 0,95.vht160_mcs_tx_highest = 0,96.n_cipher_suites = 8,97.ast_skid_limit = 0x10,98.num_wds_entries = 0x20,99.target_64bit = false,100.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,101.shadow_reg_support = false,102.rri_on_ddr = false,103.hw_filter_reset_required = true,104.fw_diag_ce_download = false,105.credit_size_workaround = false,106.tx_stats_over_pktlog = true,107.dynamic_sar_support = false,108.hw_restart_disconnect = false,109.use_fw_tx_credits = true,110.delay_unmap_buffer = false,111},112{113.id = QCA988X_HW_2_0_VERSION,114.dev_id = QCA988X_2_0_DEVICE_ID_UBNT,115.name = "qca988x hw2.0 ubiquiti",116.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,117.uart_pin = 7,118.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,119.otp_exe_param = 0,120.channel_counters_freq_hz = 88000,121.max_probe_resp_desc_thres = 0,122.cal_data_len = 2116,123.fw = {124.dir = QCA988X_HW_2_0_FW_DIR,125.board = QCA988X_HW_2_0_BOARD_DATA_FILE,126.board_size = QCA988X_BOARD_DATA_SZ,127.board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,128},129.rx_desc_ops = &qca988x_rx_desc_ops,130.hw_ops = &qca988x_ops,131.decap_align_bytes = 4,132.spectral_bin_discard = 0,133.spectral_bin_offset = 0,134.vht160_mcs_rx_highest = 0,135.vht160_mcs_tx_highest = 0,136.n_cipher_suites = 8,137.ast_skid_limit = 0x10,138.num_wds_entries = 0x20,139.target_64bit = false,140.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,141.shadow_reg_support = false,142.rri_on_ddr = false,143.hw_filter_reset_required = true,144.fw_diag_ce_download = false,145.credit_size_workaround = false,146.tx_stats_over_pktlog = true,147.dynamic_sar_support = false,148.hw_restart_disconnect = false,149.use_fw_tx_credits = true,150.delay_unmap_buffer = false,151},152{153.id = QCA9887_HW_1_0_VERSION,154.dev_id = QCA9887_1_0_DEVICE_ID,155.bus = ATH10K_BUS_PCI,156.name = "qca9887 hw1.0",157.patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR,158.uart_pin = 7,159.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,160.otp_exe_param = 0,161.channel_counters_freq_hz = 88000,162.max_probe_resp_desc_thres = 0,163.cal_data_len = 2116,164.fw = {165.dir = QCA9887_HW_1_0_FW_DIR,166.board = QCA9887_HW_1_0_BOARD_DATA_FILE,167.board_size = QCA9887_BOARD_DATA_SZ,168.board_ext_size = QCA9887_BOARD_EXT_DATA_SZ,169},170.rx_desc_ops = &qca988x_rx_desc_ops,171.hw_ops = &qca988x_ops,172.decap_align_bytes = 4,173.spectral_bin_discard = 0,174.spectral_bin_offset = 0,175.vht160_mcs_rx_highest = 0,176.vht160_mcs_tx_highest = 0,177.n_cipher_suites = 8,178.ast_skid_limit = 0x10,179.num_wds_entries = 0x20,180.target_64bit = false,181.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,182.shadow_reg_support = false,183.rri_on_ddr = false,184.hw_filter_reset_required = true,185.fw_diag_ce_download = false,186.credit_size_workaround = false,187.tx_stats_over_pktlog = false,188.dynamic_sar_support = false,189.hw_restart_disconnect = false,190.use_fw_tx_credits = true,191.delay_unmap_buffer = false,192},193{194.id = QCA6174_HW_3_2_VERSION,195.dev_id = QCA6174_3_2_DEVICE_ID,196.bus = ATH10K_BUS_SDIO,197.name = "qca6174 hw3.2 sdio",198.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,199.uart_pin = 19,200.otp_exe_param = 0,201.channel_counters_freq_hz = 88000,202.max_probe_resp_desc_thres = 0,203.cal_data_len = 0,204.fw = {205.dir = QCA6174_HW_3_0_FW_DIR,206.board = QCA6174_HW_3_0_BOARD_DATA_FILE,207.board_size = QCA6174_BOARD_DATA_SZ,208.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,209},210.rx_desc_ops = &qca988x_rx_desc_ops,211.hw_ops = &qca6174_sdio_ops,212.hw_clk = qca6174_clk,213.target_cpu_freq = 176000000,214.decap_align_bytes = 4,215.n_cipher_suites = 8,216.num_peers = 10,217.ast_skid_limit = 0x10,218.num_wds_entries = 0x20,219.uart_pin_workaround = true,220.tx_stats_over_pktlog = false,221.credit_size_workaround = false,222.bmi_large_size_download = true,223.supports_peer_stats_info = true,224.dynamic_sar_support = true,225.hw_restart_disconnect = false,226.use_fw_tx_credits = true,227.delay_unmap_buffer = false,228},229{230.id = QCA6174_HW_2_1_VERSION,231.dev_id = QCA6164_2_1_DEVICE_ID,232.bus = ATH10K_BUS_PCI,233.name = "qca6164 hw2.1",234.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,235.uart_pin = 6,236.otp_exe_param = 0,237.channel_counters_freq_hz = 88000,238.max_probe_resp_desc_thres = 0,239.cal_data_len = 8124,240.fw = {241.dir = QCA6174_HW_2_1_FW_DIR,242.board = QCA6174_HW_2_1_BOARD_DATA_FILE,243.board_size = QCA6174_BOARD_DATA_SZ,244.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,245},246.rx_desc_ops = &qca988x_rx_desc_ops,247.hw_ops = &qca988x_ops,248.decap_align_bytes = 4,249.spectral_bin_discard = 0,250.spectral_bin_offset = 0,251.vht160_mcs_rx_highest = 0,252.vht160_mcs_tx_highest = 0,253.n_cipher_suites = 8,254.ast_skid_limit = 0x10,255.num_wds_entries = 0x20,256.target_64bit = false,257.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,258.shadow_reg_support = false,259.rri_on_ddr = false,260.hw_filter_reset_required = true,261.fw_diag_ce_download = false,262.credit_size_workaround = false,263.tx_stats_over_pktlog = false,264.dynamic_sar_support = false,265.hw_restart_disconnect = false,266.use_fw_tx_credits = true,267.delay_unmap_buffer = false,268},269{270.id = QCA6174_HW_2_1_VERSION,271.dev_id = QCA6174_2_1_DEVICE_ID,272.bus = ATH10K_BUS_PCI,273.name = "qca6174 hw2.1",274.patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,275.uart_pin = 6,276.otp_exe_param = 0,277.channel_counters_freq_hz = 88000,278.max_probe_resp_desc_thres = 0,279.cal_data_len = 8124,280.fw = {281.dir = QCA6174_HW_2_1_FW_DIR,282.board = QCA6174_HW_2_1_BOARD_DATA_FILE,283.board_size = QCA6174_BOARD_DATA_SZ,284.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,285},286.rx_desc_ops = &qca988x_rx_desc_ops,287.hw_ops = &qca988x_ops,288.decap_align_bytes = 4,289.spectral_bin_discard = 0,290.spectral_bin_offset = 0,291.vht160_mcs_rx_highest = 0,292.vht160_mcs_tx_highest = 0,293.n_cipher_suites = 8,294.ast_skid_limit = 0x10,295.num_wds_entries = 0x20,296.target_64bit = false,297.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,298.shadow_reg_support = false,299.rri_on_ddr = false,300.hw_filter_reset_required = true,301.fw_diag_ce_download = false,302.credit_size_workaround = false,303.tx_stats_over_pktlog = false,304.dynamic_sar_support = false,305.hw_restart_disconnect = false,306.use_fw_tx_credits = true,307.delay_unmap_buffer = false,308},309{310.id = QCA6174_HW_3_0_VERSION,311.dev_id = QCA6174_2_1_DEVICE_ID,312.bus = ATH10K_BUS_PCI,313.name = "qca6174 hw3.0",314.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,315.uart_pin = 6,316.otp_exe_param = 0,317.channel_counters_freq_hz = 88000,318.max_probe_resp_desc_thres = 0,319.cal_data_len = 8124,320.fw = {321.dir = QCA6174_HW_3_0_FW_DIR,322.board = QCA6174_HW_3_0_BOARD_DATA_FILE,323.board_size = QCA6174_BOARD_DATA_SZ,324.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,325},326.rx_desc_ops = &qca988x_rx_desc_ops,327.hw_ops = &qca988x_ops,328.decap_align_bytes = 4,329.spectral_bin_discard = 0,330.spectral_bin_offset = 0,331.vht160_mcs_rx_highest = 0,332.vht160_mcs_tx_highest = 0,333.n_cipher_suites = 8,334.ast_skid_limit = 0x10,335.num_wds_entries = 0x20,336.target_64bit = false,337.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,338.shadow_reg_support = false,339.rri_on_ddr = false,340.hw_filter_reset_required = true,341.fw_diag_ce_download = false,342.credit_size_workaround = false,343.tx_stats_over_pktlog = false,344.dynamic_sar_support = false,345.hw_restart_disconnect = false,346.use_fw_tx_credits = true,347.delay_unmap_buffer = false,348},349{350.id = QCA6174_HW_3_2_VERSION,351.dev_id = QCA6174_2_1_DEVICE_ID,352.bus = ATH10K_BUS_PCI,353.name = "qca6174 hw3.2",354.patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,355.uart_pin = 6,356.otp_exe_param = 0,357.channel_counters_freq_hz = 88000,358.max_probe_resp_desc_thres = 0,359.cal_data_len = 8124,360.fw = {361/* uses same binaries as hw3.0 */362.dir = QCA6174_HW_3_0_FW_DIR,363.board = QCA6174_HW_3_0_BOARD_DATA_FILE,364.board_size = QCA6174_BOARD_DATA_SZ,365.board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,366},367.rx_desc_ops = &qca988x_rx_desc_ops,368.hw_ops = &qca6174_ops,369.hw_clk = qca6174_clk,370.target_cpu_freq = 176000000,371.decap_align_bytes = 4,372.spectral_bin_discard = 0,373.spectral_bin_offset = 0,374.vht160_mcs_rx_highest = 0,375.vht160_mcs_tx_highest = 0,376.n_cipher_suites = 8,377.ast_skid_limit = 0x10,378.num_wds_entries = 0x20,379.target_64bit = false,380.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,381.shadow_reg_support = false,382.rri_on_ddr = false,383.hw_filter_reset_required = true,384.fw_diag_ce_download = true,385.credit_size_workaround = false,386.tx_stats_over_pktlog = false,387.supports_peer_stats_info = true,388.dynamic_sar_support = true,389.hw_restart_disconnect = false,390.use_fw_tx_credits = true,391.delay_unmap_buffer = false,392},393{394.id = QCA99X0_HW_2_0_DEV_VERSION,395.dev_id = QCA99X0_2_0_DEVICE_ID,396.bus = ATH10K_BUS_PCI,397.name = "qca99x0 hw2.0",398.patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR,399.uart_pin = 7,400.otp_exe_param = 0x00000700,401.continuous_frag_desc = true,402.cck_rate_map_rev2 = true,403.channel_counters_freq_hz = 150000,404.max_probe_resp_desc_thres = 24,405.tx_chain_mask = 0xf,406.rx_chain_mask = 0xf,407.max_spatial_stream = 4,408.cal_data_len = 12064,409.fw = {410.dir = QCA99X0_HW_2_0_FW_DIR,411.board = QCA99X0_HW_2_0_BOARD_DATA_FILE,412.board_size = QCA99X0_BOARD_DATA_SZ,413.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,414},415.sw_decrypt_mcast_mgmt = true,416.rx_desc_ops = &qca99x0_rx_desc_ops,417.hw_ops = &qca99x0_ops,418.decap_align_bytes = 1,419.spectral_bin_discard = 4,420.spectral_bin_offset = 0,421.vht160_mcs_rx_highest = 0,422.vht160_mcs_tx_highest = 0,423.n_cipher_suites = 11,424.ast_skid_limit = 0x10,425.num_wds_entries = 0x20,426.target_64bit = false,427.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,428.shadow_reg_support = false,429.rri_on_ddr = false,430.hw_filter_reset_required = true,431.fw_diag_ce_download = false,432.credit_size_workaround = false,433.tx_stats_over_pktlog = false,434.dynamic_sar_support = false,435.hw_restart_disconnect = false,436.use_fw_tx_credits = true,437.delay_unmap_buffer = false,438},439{440.id = QCA9984_HW_1_0_DEV_VERSION,441.dev_id = QCA9984_1_0_DEVICE_ID,442.bus = ATH10K_BUS_PCI,443.name = "qca9984/qca9994 hw1.0",444.patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR,445.uart_pin = 7,446.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,447.otp_exe_param = 0x00000700,448.continuous_frag_desc = true,449.cck_rate_map_rev2 = true,450.channel_counters_freq_hz = 150000,451.max_probe_resp_desc_thres = 24,452.tx_chain_mask = 0xf,453.rx_chain_mask = 0xf,454.max_spatial_stream = 4,455.cal_data_len = 12064,456.fw = {457.dir = QCA9984_HW_1_0_FW_DIR,458.board = QCA9984_HW_1_0_BOARD_DATA_FILE,459.eboard = QCA9984_HW_1_0_EBOARD_DATA_FILE,460.board_size = QCA99X0_BOARD_DATA_SZ,461.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,462.ext_board_size = QCA99X0_EXT_BOARD_DATA_SZ,463},464.sw_decrypt_mcast_mgmt = true,465.rx_desc_ops = &qca99x0_rx_desc_ops,466.hw_ops = &qca99x0_ops,467.decap_align_bytes = 1,468.spectral_bin_discard = 12,469.spectral_bin_offset = 8,470471/* Can do only 2x2 VHT160 or 80+80. 1560Mbps is 4x4 80Mhz472* or 2x2 160Mhz, long-guard-interval.473*/474.vht160_mcs_rx_highest = 1560,475.vht160_mcs_tx_highest = 1560,476.n_cipher_suites = 11,477.ast_skid_limit = 0x10,478.num_wds_entries = 0x20,479.target_64bit = false,480.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,481.shadow_reg_support = false,482.rri_on_ddr = false,483.hw_filter_reset_required = true,484.fw_diag_ce_download = false,485.credit_size_workaround = false,486.tx_stats_over_pktlog = false,487.dynamic_sar_support = false,488.hw_restart_disconnect = false,489.use_fw_tx_credits = true,490.delay_unmap_buffer = false,491},492{493.id = QCA9888_HW_2_0_DEV_VERSION,494.dev_id = QCA9888_2_0_DEVICE_ID,495.bus = ATH10K_BUS_PCI,496.name = "qca9888 hw2.0",497.patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR,498.uart_pin = 7,499.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,500.otp_exe_param = 0x00000700,501.continuous_frag_desc = true,502.channel_counters_freq_hz = 150000,503.max_probe_resp_desc_thres = 24,504.tx_chain_mask = 3,505.rx_chain_mask = 3,506.max_spatial_stream = 2,507.cal_data_len = 12064,508.fw = {509.dir = QCA9888_HW_2_0_FW_DIR,510.board = QCA9888_HW_2_0_BOARD_DATA_FILE,511.board_size = QCA99X0_BOARD_DATA_SZ,512.board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,513},514.sw_decrypt_mcast_mgmt = true,515.rx_desc_ops = &qca99x0_rx_desc_ops,516.hw_ops = &qca99x0_ops,517.decap_align_bytes = 1,518.spectral_bin_discard = 12,519.spectral_bin_offset = 8,520521/* Can do only 1x1 VHT160 or 80+80. 780Mbps is 2x2 80Mhz or522* 1x1 160Mhz, long-guard-interval.523*/524.vht160_mcs_rx_highest = 780,525.vht160_mcs_tx_highest = 780,526.n_cipher_suites = 11,527.ast_skid_limit = 0x10,528.num_wds_entries = 0x20,529.target_64bit = false,530.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,531.shadow_reg_support = false,532.rri_on_ddr = false,533.hw_filter_reset_required = true,534.fw_diag_ce_download = false,535.credit_size_workaround = false,536.tx_stats_over_pktlog = false,537.dynamic_sar_support = false,538.hw_restart_disconnect = false,539.use_fw_tx_credits = true,540.delay_unmap_buffer = false,541},542{543.id = QCA9377_HW_1_0_DEV_VERSION,544.dev_id = QCA9377_1_0_DEVICE_ID,545.bus = ATH10K_BUS_PCI,546.name = "qca9377 hw1.0",547.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,548.uart_pin = 6,549.otp_exe_param = 0,550.channel_counters_freq_hz = 88000,551.max_probe_resp_desc_thres = 0,552.cal_data_len = 8124,553.fw = {554.dir = QCA9377_HW_1_0_FW_DIR,555.board = QCA9377_HW_1_0_BOARD_DATA_FILE,556.board_size = QCA9377_BOARD_DATA_SZ,557.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,558},559.rx_desc_ops = &qca988x_rx_desc_ops,560.hw_ops = &qca988x_ops,561.decap_align_bytes = 4,562.spectral_bin_discard = 0,563.spectral_bin_offset = 0,564.vht160_mcs_rx_highest = 0,565.vht160_mcs_tx_highest = 0,566.n_cipher_suites = 8,567.ast_skid_limit = 0x10,568.num_wds_entries = 0x20,569.target_64bit = false,570.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,571.shadow_reg_support = false,572.rri_on_ddr = false,573.hw_filter_reset_required = true,574.fw_diag_ce_download = false,575.credit_size_workaround = false,576.tx_stats_over_pktlog = false,577.dynamic_sar_support = false,578.hw_restart_disconnect = false,579.use_fw_tx_credits = true,580.delay_unmap_buffer = false,581},582{583.id = QCA9377_HW_1_1_DEV_VERSION,584.dev_id = QCA9377_1_0_DEVICE_ID,585.bus = ATH10K_BUS_PCI,586.name = "qca9377 hw1.1",587.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,588.uart_pin = 6,589.otp_exe_param = 0,590.channel_counters_freq_hz = 88000,591.max_probe_resp_desc_thres = 0,592.cal_data_len = 8124,593.fw = {594.dir = QCA9377_HW_1_0_FW_DIR,595.board = QCA9377_HW_1_0_BOARD_DATA_FILE,596.board_size = QCA9377_BOARD_DATA_SZ,597.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,598},599.rx_desc_ops = &qca988x_rx_desc_ops,600.hw_ops = &qca6174_ops,601.hw_clk = qca6174_clk,602.target_cpu_freq = 176000000,603.decap_align_bytes = 4,604.spectral_bin_discard = 0,605.spectral_bin_offset = 0,606.vht160_mcs_rx_highest = 0,607.vht160_mcs_tx_highest = 0,608.n_cipher_suites = 8,609.ast_skid_limit = 0x10,610.num_wds_entries = 0x20,611.target_64bit = false,612.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,613.shadow_reg_support = false,614.rri_on_ddr = false,615.hw_filter_reset_required = true,616.fw_diag_ce_download = true,617.credit_size_workaround = false,618.tx_stats_over_pktlog = false,619.dynamic_sar_support = false,620.hw_restart_disconnect = false,621.use_fw_tx_credits = true,622.delay_unmap_buffer = false,623},624{625.id = QCA9377_HW_1_1_DEV_VERSION,626.dev_id = QCA9377_1_0_DEVICE_ID,627.bus = ATH10K_BUS_SDIO,628.name = "qca9377 hw1.1 sdio",629.patch_load_addr = QCA9377_HW_1_0_PATCH_LOAD_ADDR,630.uart_pin = 19,631.otp_exe_param = 0,632.channel_counters_freq_hz = 88000,633.max_probe_resp_desc_thres = 0,634.cal_data_len = 8124,635.fw = {636.dir = QCA9377_HW_1_0_FW_DIR,637.board = QCA9377_HW_1_0_BOARD_DATA_FILE,638.board_size = QCA9377_BOARD_DATA_SZ,639.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,640},641.rx_desc_ops = &qca988x_rx_desc_ops,642.hw_ops = &qca6174_ops,643.hw_clk = qca6174_clk,644.target_cpu_freq = 176000000,645.decap_align_bytes = 4,646.n_cipher_suites = 8,647.num_peers = TARGET_QCA9377_HL_NUM_PEERS,648.ast_skid_limit = 0x10,649.num_wds_entries = 0x20,650.uart_pin_workaround = true,651.credit_size_workaround = true,652.dynamic_sar_support = false,653.hw_restart_disconnect = false,654.use_fw_tx_credits = true,655.delay_unmap_buffer = false,656},657{658.id = QCA4019_HW_1_0_DEV_VERSION,659.dev_id = 0,660.bus = ATH10K_BUS_AHB,661.name = "qca4019 hw1.0",662.patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR,663.uart_pin = 7,664.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,665.otp_exe_param = 0x0010000,666.continuous_frag_desc = true,667.cck_rate_map_rev2 = true,668.channel_counters_freq_hz = 125000,669.max_probe_resp_desc_thres = 24,670.tx_chain_mask = 0x3,671.rx_chain_mask = 0x3,672.max_spatial_stream = 2,673.cal_data_len = 12064,674.fw = {675.dir = QCA4019_HW_1_0_FW_DIR,676.board = QCA4019_HW_1_0_BOARD_DATA_FILE,677.board_size = QCA4019_BOARD_DATA_SZ,678.board_ext_size = QCA4019_BOARD_EXT_DATA_SZ,679},680.sw_decrypt_mcast_mgmt = true,681.rx_desc_ops = &qca99x0_rx_desc_ops,682.hw_ops = &qca99x0_ops,683.decap_align_bytes = 1,684.spectral_bin_discard = 4,685.spectral_bin_offset = 0,686.vht160_mcs_rx_highest = 0,687.vht160_mcs_tx_highest = 0,688.n_cipher_suites = 11,689.ast_skid_limit = 0x10,690.num_wds_entries = 0x20,691.target_64bit = false,692.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL,693.shadow_reg_support = false,694.rri_on_ddr = false,695.hw_filter_reset_required = true,696.fw_diag_ce_download = false,697.credit_size_workaround = false,698.tx_stats_over_pktlog = false,699.dynamic_sar_support = false,700.hw_restart_disconnect = false,701.use_fw_tx_credits = true,702.delay_unmap_buffer = false,703},704{705.id = WCN3990_HW_1_0_DEV_VERSION,706.dev_id = 0,707.bus = ATH10K_BUS_SNOC,708.name = "wcn3990 hw1.0",709.continuous_frag_desc = true,710.tx_chain_mask = 0x7,711.rx_chain_mask = 0x7,712.max_spatial_stream = 4,713.fw = {714.dir = WCN3990_HW_1_0_FW_DIR,715},716.sw_decrypt_mcast_mgmt = true,717.rx_desc_ops = &wcn3990_rx_desc_ops,718.hw_ops = &wcn3990_ops,719.decap_align_bytes = 1,720.num_peers = TARGET_HL_TLV_NUM_PEERS,721.n_cipher_suites = 11,722.ast_skid_limit = TARGET_HL_TLV_AST_SKID_LIMIT,723.num_wds_entries = TARGET_HL_TLV_NUM_WDS_ENTRIES,724.target_64bit = true,725.rx_ring_fill_level = HTT_RX_RING_FILL_LEVEL_DUAL_MAC,726.shadow_reg_support = true,727.rri_on_ddr = true,728.hw_filter_reset_required = false,729.fw_diag_ce_download = false,730.credit_size_workaround = false,731.tx_stats_over_pktlog = false,732.dynamic_sar_support = true,733.hw_restart_disconnect = true,734.use_fw_tx_credits = false,735.delay_unmap_buffer = true,736},737};738739static const char *const ath10k_core_fw_feature_str[] = {740[ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX] = "wmi-mgmt-rx",741[ATH10K_FW_FEATURE_WMI_10X] = "wmi-10.x",742[ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX] = "has-wmi-mgmt-tx",743[ATH10K_FW_FEATURE_NO_P2P] = "no-p2p",744[ATH10K_FW_FEATURE_WMI_10_2] = "wmi-10.2",745[ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT] = "multi-vif-ps",746[ATH10K_FW_FEATURE_WOWLAN_SUPPORT] = "wowlan",747[ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp",748[ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad",749[ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init",750[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",751[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",752[ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",753[ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl",754[ATH10K_FW_FEATURE_BTCOEX_PARAM] = "btcoex-param",755[ATH10K_FW_FEATURE_SKIP_NULL_FUNC_WAR] = "skip-null-func-war",756[ATH10K_FW_FEATURE_ALLOWS_MESH_BCAST] = "allows-mesh-bcast",757[ATH10K_FW_FEATURE_NO_PS] = "no-ps",758[ATH10K_FW_FEATURE_MGMT_TX_BY_REF] = "mgmt-tx-by-reference",759[ATH10K_FW_FEATURE_NON_BMI] = "non-bmi",760[ATH10K_FW_FEATURE_SINGLE_CHAN_INFO_PER_CHANNEL] = "single-chan-info-per-channel",761[ATH10K_FW_FEATURE_PEER_FIXED_RATE] = "peer-fixed-rate",762[ATH10K_FW_FEATURE_IRAM_RECOVERY] = "iram-recovery",763};764765static unsigned int ath10k_core_get_fw_feature_str(char *buf,766size_t buf_len,767enum ath10k_fw_features feat)768{769/* make sure that ath10k_core_fw_feature_str[] gets updated */770BUILD_BUG_ON(ARRAY_SIZE(ath10k_core_fw_feature_str) !=771ATH10K_FW_FEATURE_COUNT);772773if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) ||774WARN_ON(!ath10k_core_fw_feature_str[feat])) {775return scnprintf(buf, buf_len, "bit%d", feat);776}777778return scnprintf(buf, buf_len, "%s", ath10k_core_fw_feature_str[feat]);779}780781void ath10k_core_get_fw_features_str(struct ath10k *ar,782char *buf,783size_t buf_len)784{785size_t len = 0;786int i;787788for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) {789if (test_bit(i, ar->normal_mode_fw.fw_file.fw_features)) {790if (len > 0)791len += scnprintf(buf + len, buf_len - len, ",");792793len += ath10k_core_get_fw_feature_str(buf + len,794buf_len - len,795i);796}797}798}799800static void ath10k_send_suspend_complete(struct ath10k *ar)801{802ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n");803804complete(&ar->target_suspend);805}806807static int ath10k_init_sdio(struct ath10k *ar, enum ath10k_firmware_mode mode)808{809bool mtu_workaround = ar->hw_params.credit_size_workaround;810int ret;811u32 param = 0;812813ret = ath10k_bmi_write32(ar, hi_mbox_io_block_sz, 256);814if (ret)815return ret;816817ret = ath10k_bmi_write32(ar, hi_mbox_isr_yield_limit, 99);818if (ret)819return ret;820821ret = ath10k_bmi_read32(ar, hi_acs_flags, ¶m);822if (ret)823return ret;824825param |= HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET;826827if (mode == ATH10K_FIRMWARE_MODE_NORMAL && !mtu_workaround)828param |= HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;829else830param &= ~HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE;831832if (mode == ATH10K_FIRMWARE_MODE_UTF)833param &= ~HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;834else835param |= HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET;836837ret = ath10k_bmi_write32(ar, hi_acs_flags, param);838if (ret)839return ret;840841ret = ath10k_bmi_read32(ar, hi_option_flag2, ¶m);842if (ret)843return ret;844845param |= HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_HOST;846847ret = ath10k_bmi_write32(ar, hi_option_flag2, param);848if (ret)849return ret;850851return 0;852}853854static int ath10k_init_configure_target(struct ath10k *ar)855{856u32 param_host;857int ret;858859/* tell target which HTC version it is used*/860ret = ath10k_bmi_write32(ar, hi_app_host_interest,861HTC_PROTOCOL_VERSION);862if (ret) {863ath10k_err(ar, "settings HTC version failed\n");864return ret;865}866867/* set the firmware mode to STA/IBSS/AP */868ret = ath10k_bmi_read32(ar, hi_option_flag, ¶m_host);869if (ret) {870ath10k_err(ar, "setting firmware mode (1/2) failed\n");871return ret;872}873874/* TODO following parameters need to be re-visited. */875/* num_device */876param_host |= (1 << HI_OPTION_NUM_DEV_SHIFT);877/* Firmware mode */878/* FIXME: Why FW_MODE_AP ??.*/879param_host |= (HI_OPTION_FW_MODE_AP << HI_OPTION_FW_MODE_SHIFT);880/* mac_addr_method */881param_host |= (1 << HI_OPTION_MAC_ADDR_METHOD_SHIFT);882/* firmware_bridge */883param_host |= (0 << HI_OPTION_FW_BRIDGE_SHIFT);884/* fwsubmode */885param_host |= (0 << HI_OPTION_FW_SUBMODE_SHIFT);886887ret = ath10k_bmi_write32(ar, hi_option_flag, param_host);888if (ret) {889ath10k_err(ar, "setting firmware mode (2/2) failed\n");890return ret;891}892893/* We do all byte-swapping on the host */894ret = ath10k_bmi_write32(ar, hi_be, 0);895if (ret) {896ath10k_err(ar, "setting host CPU BE mode failed\n");897return ret;898}899900/* FW descriptor/Data swap flags */901ret = ath10k_bmi_write32(ar, hi_fw_swap, 0);902903if (ret) {904ath10k_err(ar, "setting FW data/desc swap flags failed\n");905return ret;906}907908/* Some devices have a special sanity check that verifies the PCI909* Device ID is written to this host interest var. It is known to be910* required to boot QCA6164.911*/912ret = ath10k_bmi_write32(ar, hi_hci_uart_pwr_mgmt_params_ext,913ar->dev_id);914if (ret) {915ath10k_err(ar, "failed to set pwr_mgmt_params: %d\n", ret);916return ret;917}918919return 0;920}921922static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,923const char *dir,924const char *file)925{926char filename[100];927const struct firmware *fw;928int ret;929930if (file == NULL)931return ERR_PTR(-ENOENT);932933if (dir == NULL)934dir = ".";935936snprintf(filename, sizeof(filename), "%s/%s", dir, file);937ret = firmware_request_nowarn(&fw, filename, ar->dev);938ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot fw request '%s': %d\n",939filename, ret);940941if (ret)942return ERR_PTR(ret);943944return fw;945}946947#if defined(__linux__)948static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,949#elif defined(__FreeBSD__)950static int ath10k_push_board_ext_data(struct ath10k *ar, const u8 *data,951#endif952size_t data_len)953{954u32 board_data_size = ar->hw_params.fw.board_size;955u32 board_ext_data_size = ar->hw_params.fw.board_ext_size;956u32 board_ext_data_addr;957int ret;958959ret = ath10k_bmi_read32(ar, hi_board_ext_data, &board_ext_data_addr);960if (ret) {961ath10k_err(ar, "could not read board ext data addr (%d)\n",962ret);963return ret;964}965966ath10k_dbg(ar, ATH10K_DBG_BOOT,967"boot push board extended data addr 0x%x\n",968board_ext_data_addr);969970if (board_ext_data_addr == 0)971return 0;972973if (data_len != (board_data_size + board_ext_data_size)) {974ath10k_err(ar, "invalid board (ext) data sizes %zu != %d+%d\n",975data_len, board_data_size, board_ext_data_size);976return -EINVAL;977}978979ret = ath10k_bmi_write_memory(ar, board_ext_data_addr,980data + board_data_size,981board_ext_data_size);982if (ret) {983ath10k_err(ar, "could not write board ext data (%d)\n", ret);984return ret;985}986987ret = ath10k_bmi_write32(ar, hi_board_ext_data_config,988(board_ext_data_size << 16) | 1);989if (ret) {990ath10k_err(ar, "could not write board ext data bit (%d)\n",991ret);992return ret;993}994995return 0;996}997998static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)999{1000u32 result, address;1001u8 board_id, chip_id;1002bool ext_bid_support;1003int ret, bmi_board_id_param;10041005address = ar->hw_params.patch_load_addr;10061007if (!ar->normal_mode_fw.fw_file.otp_data ||1008!ar->normal_mode_fw.fw_file.otp_len) {1009ath10k_warn(ar,1010"failed to retrieve board id because of invalid otp\n");1011return -ENODATA;1012}10131014if (ar->id.bmi_ids_valid) {1015ath10k_dbg(ar, ATH10K_DBG_BOOT,1016"boot already acquired valid otp board id,skip download, board_id %d chip_id %d\n",1017ar->id.bmi_board_id, ar->id.bmi_chip_id);1018goto skip_otp_download;1019}10201021ath10k_dbg(ar, ATH10K_DBG_BOOT,1022"boot upload otp to 0x%x len %zd for board id\n",1023address, ar->normal_mode_fw.fw_file.otp_len);10241025ret = ath10k_bmi_fast_download(ar, address,1026ar->normal_mode_fw.fw_file.otp_data,1027ar->normal_mode_fw.fw_file.otp_len);1028if (ret) {1029ath10k_err(ar, "could not write otp for board id check: %d\n",1030ret);1031return ret;1032}10331034if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||1035ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE ||1036ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM)1037bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID;1038else1039bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID;10401041ret = ath10k_bmi_execute(ar, address, bmi_board_id_param, &result);1042if (ret) {1043ath10k_err(ar, "could not execute otp for board id check: %d\n",1044ret);1045return ret;1046}10471048board_id = MS(result, ATH10K_BMI_BOARD_ID_FROM_OTP);1049chip_id = MS(result, ATH10K_BMI_CHIP_ID_FROM_OTP);1050ext_bid_support = (result & ATH10K_BMI_EXT_BOARD_ID_SUPPORT);10511052ath10k_dbg(ar, ATH10K_DBG_BOOT,1053"boot get otp board id result 0x%08x board_id %d chip_id %d ext_bid_support %d\n",1054result, board_id, chip_id, ext_bid_support);10551056ar->id.ext_bid_supported = ext_bid_support;10571058if ((result & ATH10K_BMI_BOARD_ID_STATUS_MASK) != 0 ||1059(board_id == 0)) {1060ath10k_dbg(ar, ATH10K_DBG_BOOT,1061"board id does not exist in otp, ignore it\n");1062return -EOPNOTSUPP;1063}10641065ar->id.bmi_ids_valid = true;1066ar->id.bmi_board_id = board_id;1067ar->id.bmi_chip_id = chip_id;10681069skip_otp_download:10701071return 0;1072}10731074static void ath10k_core_check_bdfext(const struct dmi_header *hdr, void *data)1075{1076struct ath10k *ar = data;1077const char *bdf_ext;1078const char *magic = ATH10K_SMBIOS_BDF_EXT_MAGIC;1079u8 bdf_enabled;1080int i;10811082if (hdr->type != ATH10K_SMBIOS_BDF_EXT_TYPE)1083return;10841085if (hdr->length != ATH10K_SMBIOS_BDF_EXT_LENGTH) {1086ath10k_dbg(ar, ATH10K_DBG_BOOT,1087"wrong smbios bdf ext type length (%d).\n",1088hdr->length);1089return;1090}10911092#if defined(__linux__)1093bdf_enabled = *((u8 *)hdr + ATH10K_SMBIOS_BDF_EXT_OFFSET);1094#elif defined(__FreeBSD__)1095bdf_enabled = *((const u8 *)hdr + ATH10K_SMBIOS_BDF_EXT_OFFSET);1096#endif1097if (!bdf_enabled) {1098ath10k_dbg(ar, ATH10K_DBG_BOOT, "bdf variant name not found.\n");1099return;1100}11011102/* Only one string exists (per spec) */1103#if defined(__linux__)1104bdf_ext = (char *)hdr + hdr->length;1105#elif defined(__FreeBSD__)1106bdf_ext = (const char *)hdr + hdr->length;1107#endif11081109if (memcmp(bdf_ext, magic, strlen(magic)) != 0) {1110ath10k_dbg(ar, ATH10K_DBG_BOOT,1111"bdf variant magic does not match.\n");1112return;1113}11141115for (i = 0; i < strlen(bdf_ext); i++) {1116if (!isascii(bdf_ext[i]) || !isprint(bdf_ext[i])) {1117ath10k_dbg(ar, ATH10K_DBG_BOOT,1118"bdf variant name contains non ascii chars.\n");1119return;1120}1121}11221123/* Copy extension name without magic suffix */1124if (strscpy(ar->id.bdf_ext, bdf_ext + strlen(magic),1125sizeof(ar->id.bdf_ext)) < 0) {1126ath10k_dbg(ar, ATH10K_DBG_BOOT,1127"bdf variant string is longer than the buffer can accommodate (variant: %s)\n",1128bdf_ext);1129return;1130}11311132ath10k_dbg(ar, ATH10K_DBG_BOOT,1133"found and validated bdf variant smbios_type 0x%x bdf %s\n",1134ATH10K_SMBIOS_BDF_EXT_TYPE, bdf_ext);1135}11361137static int ath10k_core_check_smbios(struct ath10k *ar)1138{1139ar->id.bdf_ext[0] = '\0';1140dmi_walk(ath10k_core_check_bdfext, ar);11411142if (ar->id.bdf_ext[0] == '\0')1143return -ENODATA;11441145return 0;1146}11471148int ath10k_core_check_dt(struct ath10k *ar)1149{1150#if defined(__linux__) || (defined(__FreeBSD__) && defined(CONFIG_OF))1151struct device_node *node;1152const char *variant = NULL;11531154node = ar->dev->of_node;1155if (!node)1156return -ENOENT;11571158of_property_read_string(node, "qcom,ath10k-calibration-variant",1159&variant);1160if (!variant)1161return -ENODATA;11621163if (strscpy(ar->id.bdf_ext, variant, sizeof(ar->id.bdf_ext)) < 0)1164ath10k_dbg(ar, ATH10K_DBG_BOOT,1165"bdf variant string is longer than the buffer can accommodate (variant: %s)\n",1166variant);11671168return 0;1169#else1170return -ENOENT;1171#endif1172}1173EXPORT_SYMBOL(ath10k_core_check_dt);11741175static int ath10k_download_fw(struct ath10k *ar)1176{1177u32 address, data_len;1178const void *data;1179int ret;1180struct pm_qos_request latency_qos;11811182address = ar->hw_params.patch_load_addr;11831184data = ar->running_fw->fw_file.firmware_data;1185data_len = ar->running_fw->fw_file.firmware_len;11861187ret = ath10k_swap_code_seg_configure(ar, &ar->running_fw->fw_file);1188if (ret) {1189ath10k_err(ar, "failed to configure fw code swap: %d\n",1190ret);1191return ret;1192}11931194ath10k_dbg(ar, ATH10K_DBG_BOOT,1195"boot uploading firmware image %pK len %d\n",1196data, data_len);11971198/* Check if device supports to download firmware via1199* diag copy engine. Downloading firmware via diag CE1200* greatly reduces the time to download firmware.1201*/1202if (ar->hw_params.fw_diag_ce_download) {1203ret = ath10k_hw_diag_fast_download(ar, address,1204data, data_len);1205if (ret == 0)1206/* firmware upload via diag ce was successful */1207return 0;12081209ath10k_warn(ar,1210"failed to upload firmware via diag ce, trying BMI: %d",1211ret);1212}12131214memset(&latency_qos, 0, sizeof(latency_qos));1215cpu_latency_qos_add_request(&latency_qos, 0);12161217ret = ath10k_bmi_fast_download(ar, address, data, data_len);12181219cpu_latency_qos_remove_request(&latency_qos);12201221return ret;1222}12231224void ath10k_core_free_board_files(struct ath10k *ar)1225{1226if (!IS_ERR(ar->normal_mode_fw.board))1227release_firmware(ar->normal_mode_fw.board);12281229if (!IS_ERR(ar->normal_mode_fw.ext_board))1230release_firmware(ar->normal_mode_fw.ext_board);12311232ar->normal_mode_fw.board = NULL;1233ar->normal_mode_fw.board_data = NULL;1234ar->normal_mode_fw.board_len = 0;1235ar->normal_mode_fw.ext_board = NULL;1236ar->normal_mode_fw.ext_board_data = NULL;1237ar->normal_mode_fw.ext_board_len = 0;1238}1239EXPORT_SYMBOL(ath10k_core_free_board_files);12401241static void ath10k_core_free_firmware_files(struct ath10k *ar)1242{1243if (!IS_ERR(ar->normal_mode_fw.fw_file.firmware))1244release_firmware(ar->normal_mode_fw.fw_file.firmware);12451246if (!IS_ERR(ar->cal_file))1247release_firmware(ar->cal_file);12481249if (!IS_ERR(ar->pre_cal_file))1250release_firmware(ar->pre_cal_file);12511252ath10k_swap_code_seg_release(ar, &ar->normal_mode_fw.fw_file);12531254ar->normal_mode_fw.fw_file.otp_data = NULL;1255ar->normal_mode_fw.fw_file.otp_len = 0;12561257ar->normal_mode_fw.fw_file.firmware = NULL;1258ar->normal_mode_fw.fw_file.firmware_data = NULL;1259ar->normal_mode_fw.fw_file.firmware_len = 0;12601261ar->cal_file = NULL;1262ar->pre_cal_file = NULL;1263}12641265static int ath10k_fetch_cal_file(struct ath10k *ar)1266{1267char filename[100];12681269/* pre-cal-<bus>-<id>.bin */1270scnprintf(filename, sizeof(filename), "pre-cal-%s-%s.bin",1271ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));12721273ar->pre_cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);1274if (!IS_ERR(ar->pre_cal_file))1275goto success;12761277/* cal-<bus>-<id>.bin */1278scnprintf(filename, sizeof(filename), "cal-%s-%s.bin",1279ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));12801281ar->cal_file = ath10k_fetch_fw_file(ar, ATH10K_FW_DIR, filename);1282if (IS_ERR(ar->cal_file))1283/* calibration file is optional, don't print any warnings */1284return PTR_ERR(ar->cal_file);1285success:1286ath10k_dbg(ar, ATH10K_DBG_BOOT, "found calibration file %s/%s\n",1287ATH10K_FW_DIR, filename);12881289return 0;1290}12911292static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)1293{1294const struct firmware *fw;1295char boardname[100];12961297if (bd_ie_type == ATH10K_BD_IE_BOARD) {1298if (!ar->hw_params.fw.board) {1299ath10k_err(ar, "failed to find board file fw entry\n");1300return -EINVAL;1301}13021303scnprintf(boardname, sizeof(boardname), "board-%s-%s.bin",1304ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));13051306ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,1307ar->hw_params.fw.dir,1308boardname);1309if (IS_ERR(ar->normal_mode_fw.board)) {1310fw = ath10k_fetch_fw_file(ar,1311ar->hw_params.fw.dir,1312ar->hw_params.fw.board);1313ar->normal_mode_fw.board = fw;1314}13151316if (IS_ERR(ar->normal_mode_fw.board))1317return PTR_ERR(ar->normal_mode_fw.board);13181319ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data;1320ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size;1321} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {1322if (!ar->hw_params.fw.eboard) {1323ath10k_err(ar, "failed to find eboard file fw entry\n");1324return -EINVAL;1325}13261327fw = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,1328ar->hw_params.fw.eboard);1329ar->normal_mode_fw.ext_board = fw;1330if (IS_ERR(ar->normal_mode_fw.ext_board))1331return PTR_ERR(ar->normal_mode_fw.ext_board);13321333ar->normal_mode_fw.ext_board_data = ar->normal_mode_fw.ext_board->data;1334ar->normal_mode_fw.ext_board_len = ar->normal_mode_fw.ext_board->size;1335}13361337return 0;1338}13391340static int ath10k_core_parse_bd_ie_board(struct ath10k *ar,1341#if defined(__linux__)1342const void *buf, size_t buf_len,1343#elif defined(__FreeBSD__)1344const u8 *buf, size_t buf_len,1345#endif1346const char *boardname,1347int bd_ie_type)1348{1349const struct ath10k_fw_ie *hdr;1350bool name_match_found;1351int ret, board_ie_id;1352size_t board_ie_len;1353const void *board_ie_data;13541355name_match_found = false;13561357/* go through ATH10K_BD_IE_BOARD_ elements */1358while (buf_len > sizeof(struct ath10k_fw_ie)) {1359#if defined(__linux__)1360hdr = buf;1361#elif defined(__FreeBSD__)1362hdr = (const void *)buf;1363#endif1364board_ie_id = le32_to_cpu(hdr->id);1365board_ie_len = le32_to_cpu(hdr->len);1366board_ie_data = hdr->data;13671368buf_len -= sizeof(*hdr);1369buf += sizeof(*hdr);13701371if (buf_len < ALIGN(board_ie_len, 4)) {1372ath10k_err(ar, "invalid ATH10K_BD_IE_BOARD length: %zu < %zu\n",1373buf_len, ALIGN(board_ie_len, 4));1374ret = -EINVAL;1375goto out;1376}13771378switch (board_ie_id) {1379case ATH10K_BD_IE_BOARD_NAME:1380ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "board name", "",1381board_ie_data, board_ie_len);13821383if (board_ie_len != strlen(boardname))1384break;13851386ret = memcmp(board_ie_data, boardname, strlen(boardname));1387if (ret)1388break;13891390name_match_found = true;1391ath10k_dbg(ar, ATH10K_DBG_BOOT,1392"boot found match for name '%s'",1393boardname);1394break;1395case ATH10K_BD_IE_BOARD_DATA:1396if (!name_match_found)1397/* no match found */1398break;13991400if (bd_ie_type == ATH10K_BD_IE_BOARD) {1401ath10k_dbg(ar, ATH10K_DBG_BOOT,1402"boot found board data for '%s'",1403boardname);14041405ar->normal_mode_fw.board_data = board_ie_data;1406ar->normal_mode_fw.board_len = board_ie_len;1407} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {1408ath10k_dbg(ar, ATH10K_DBG_BOOT,1409"boot found eboard data for '%s'",1410boardname);14111412ar->normal_mode_fw.ext_board_data = board_ie_data;1413ar->normal_mode_fw.ext_board_len = board_ie_len;1414}14151416ret = 0;1417goto out;1418default:1419ath10k_warn(ar, "unknown ATH10K_BD_IE_BOARD found: %d\n",1420board_ie_id);1421break;1422}14231424/* jump over the padding */1425board_ie_len = ALIGN(board_ie_len, 4);14261427buf_len -= board_ie_len;1428buf += board_ie_len;1429}14301431/* no match found */1432ret = -ENOENT;14331434out:1435return ret;1436}14371438static int ath10k_core_search_bd(struct ath10k *ar,1439const char *boardname,1440const u8 *data,1441size_t len)1442{1443size_t ie_len;1444#if defined(__linux__)1445struct ath10k_fw_ie *hdr;1446#elif defined(__FreeBSD__)1447const struct ath10k_fw_ie *hdr;1448#endif1449int ret = -ENOENT, ie_id;14501451while (len > sizeof(struct ath10k_fw_ie)) {1452#if defined(__linux__)1453hdr = (struct ath10k_fw_ie *)data;1454#elif defined(__FreeBSD__)1455hdr = (const struct ath10k_fw_ie *)data;1456#endif1457ie_id = le32_to_cpu(hdr->id);1458ie_len = le32_to_cpu(hdr->len);14591460len -= sizeof(*hdr);1461data = hdr->data;14621463if (len < ALIGN(ie_len, 4)) {1464ath10k_err(ar, "invalid length for board ie_id %d ie_len %zu len %zu\n",1465ie_id, ie_len, len);1466return -EINVAL;1467}14681469switch (ie_id) {1470case ATH10K_BD_IE_BOARD:1471ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,1472boardname,1473ATH10K_BD_IE_BOARD);1474if (ret == -ENOENT)1475/* no match found, continue */1476break;14771478/* either found or error, so stop searching */1479goto out;1480case ATH10K_BD_IE_BOARD_EXT:1481ret = ath10k_core_parse_bd_ie_board(ar, data, ie_len,1482boardname,1483ATH10K_BD_IE_BOARD_EXT);1484if (ret == -ENOENT)1485/* no match found, continue */1486break;14871488/* either found or error, so stop searching */1489goto out;1490}14911492/* jump over the padding */1493ie_len = ALIGN(ie_len, 4);14941495len -= ie_len;1496data += ie_len;1497}14981499out:1500/* return result of parse_bd_ie_board() or -ENOENT */1501return ret;1502}15031504static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,1505const char *boardname,1506const char *fallback_boardname1,1507const char *fallback_boardname2,1508const char *filename)1509{1510size_t len, magic_len;1511const u8 *data;1512int ret;15131514/* Skip if already fetched during board data download */1515if (!ar->normal_mode_fw.board)1516ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,1517ar->hw_params.fw.dir,1518filename);1519if (IS_ERR(ar->normal_mode_fw.board))1520return PTR_ERR(ar->normal_mode_fw.board);15211522data = ar->normal_mode_fw.board->data;1523len = ar->normal_mode_fw.board->size;15241525/* magic has extra null byte padded */1526magic_len = strlen(ATH10K_BOARD_MAGIC) + 1;1527if (len < magic_len) {1528ath10k_err(ar, "failed to find magic value in %s/%s, file too short: %zu\n",1529ar->hw_params.fw.dir, filename, len);1530ret = -EINVAL;1531goto err;1532}15331534if (memcmp(data, ATH10K_BOARD_MAGIC, magic_len)) {1535ath10k_err(ar, "found invalid board magic\n");1536ret = -EINVAL;1537goto err;1538}15391540/* magic is padded to 4 bytes */1541magic_len = ALIGN(magic_len, 4);1542if (len < magic_len) {1543ath10k_err(ar, "failed: %s/%s too small to contain board data, len: %zu\n",1544ar->hw_params.fw.dir, filename, len);1545ret = -EINVAL;1546goto err;1547}15481549data += magic_len;1550len -= magic_len;15511552/* attempt to find boardname in the IE list */1553ret = ath10k_core_search_bd(ar, boardname, data, len);15541555/* if we didn't find it and have a fallback name, try that */1556if (ret == -ENOENT && fallback_boardname1)1557ret = ath10k_core_search_bd(ar, fallback_boardname1, data, len);15581559if (ret == -ENOENT && fallback_boardname2)1560ret = ath10k_core_search_bd(ar, fallback_boardname2, data, len);15611562if (ret == -ENOENT) {1563ath10k_err(ar,1564"failed to fetch board data for %s from %s/%s\n",1565boardname, ar->hw_params.fw.dir, filename);1566ret = -ENODATA;1567}15681569if (ret)1570goto err;15711572return 0;15731574err:1575ath10k_core_free_board_files(ar);1576return ret;1577}15781579static int ath10k_core_create_board_name(struct ath10k *ar, char *name,1580size_t name_len, bool with_variant,1581bool with_chip_id)1582{1583/* strlen(',variant=') + strlen(ar->id.bdf_ext) */1584char variant[9 + ATH10K_SMBIOS_BDF_EXT_STR_LENGTH] = { 0 };15851586if (with_variant && ar->id.bdf_ext[0] != '\0')1587scnprintf(variant, sizeof(variant), ",variant=%s",1588ar->id.bdf_ext);15891590if (ar->id.bmi_ids_valid) {1591scnprintf(name, name_len,1592"bus=%s,bmi-chip-id=%d,bmi-board-id=%d%s",1593ath10k_bus_str(ar->hif.bus),1594ar->id.bmi_chip_id,1595ar->id.bmi_board_id, variant);1596goto out;1597}15981599if (ar->id.qmi_ids_valid) {1600if (with_chip_id)1601scnprintf(name, name_len,1602"bus=%s,qmi-board-id=%x,qmi-chip-id=%x%s",1603ath10k_bus_str(ar->hif.bus),1604ar->id.qmi_board_id, ar->id.qmi_chip_id,1605variant);1606else1607scnprintf(name, name_len,1608"bus=%s,qmi-board-id=%x",1609ath10k_bus_str(ar->hif.bus),1610ar->id.qmi_board_id);1611goto out;1612}16131614scnprintf(name, name_len,1615"bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x%s",1616ath10k_bus_str(ar->hif.bus),1617ar->id.vendor, ar->id.device,1618ar->id.subsystem_vendor, ar->id.subsystem_device, variant);1619out:1620ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using board name '%s'\n", name);16211622return 0;1623}16241625static int ath10k_core_create_eboard_name(struct ath10k *ar, char *name,1626size_t name_len)1627{1628if (ar->id.bmi_ids_valid) {1629scnprintf(name, name_len,1630"bus=%s,bmi-chip-id=%d,bmi-eboard-id=%d",1631ath10k_bus_str(ar->hif.bus),1632ar->id.bmi_chip_id,1633ar->id.bmi_eboard_id);16341635ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using eboard name '%s'\n", name);1636return 0;1637}1638/* Fallback if returned board id is zero */1639return -1;1640}16411642int ath10k_core_fetch_board_file(struct ath10k *ar, int bd_ie_type)1643{1644char boardname[100], fallback_boardname1[100], fallback_boardname2[100];1645int ret;16461647if (bd_ie_type == ATH10K_BD_IE_BOARD) {1648/* With variant and chip id */1649ret = ath10k_core_create_board_name(ar, boardname,1650sizeof(boardname), true,1651true);1652if (ret) {1653ath10k_err(ar, "failed to create board name: %d", ret);1654return ret;1655}16561657/* Without variant and only chip-id */1658ret = ath10k_core_create_board_name(ar, fallback_boardname1,1659sizeof(boardname), false,1660true);1661if (ret) {1662ath10k_err(ar, "failed to create 1st fallback board name: %d",1663ret);1664return ret;1665}16661667/* Without variant and without chip-id */1668ret = ath10k_core_create_board_name(ar, fallback_boardname2,1669sizeof(boardname), false,1670false);1671if (ret) {1672ath10k_err(ar, "failed to create 2nd fallback board name: %d",1673ret);1674return ret;1675}1676} else if (bd_ie_type == ATH10K_BD_IE_BOARD_EXT) {1677ret = ath10k_core_create_eboard_name(ar, boardname,1678sizeof(boardname));1679if (ret) {1680ath10k_err(ar, "fallback to eboard.bin since board id 0");1681goto fallback;1682}1683}16841685ar->bd_api = 2;1686ret = ath10k_core_fetch_board_data_api_n(ar, boardname,1687fallback_boardname1,1688fallback_boardname2,1689ATH10K_BOARD_API2_FILE);1690if (!ret)1691goto success;16921693fallback:1694ar->bd_api = 1;1695ret = ath10k_core_fetch_board_data_api_1(ar, bd_ie_type);1696if (ret) {1697ath10k_err(ar, "failed to fetch board-2.bin or board.bin from %s\n",1698ar->hw_params.fw.dir);1699return ret;1700}17011702success:1703ath10k_dbg(ar, ATH10K_DBG_BOOT, "using board api %d\n", ar->bd_api);1704return 0;1705}1706EXPORT_SYMBOL(ath10k_core_fetch_board_file);17071708static int ath10k_core_get_ext_board_id_from_otp(struct ath10k *ar)1709{1710u32 result, address;1711u8 ext_board_id;1712int ret;17131714address = ar->hw_params.patch_load_addr;17151716if (!ar->normal_mode_fw.fw_file.otp_data ||1717!ar->normal_mode_fw.fw_file.otp_len) {1718ath10k_warn(ar,1719"failed to retrieve extended board id due to otp binary missing\n");1720return -ENODATA;1721}17221723ath10k_dbg(ar, ATH10K_DBG_BOOT,1724"boot upload otp to 0x%x len %zd for ext board id\n",1725address, ar->normal_mode_fw.fw_file.otp_len);17261727ret = ath10k_bmi_fast_download(ar, address,1728ar->normal_mode_fw.fw_file.otp_data,1729ar->normal_mode_fw.fw_file.otp_len);1730if (ret) {1731ath10k_err(ar, "could not write otp for ext board id check: %d\n",1732ret);1733return ret;1734}17351736ret = ath10k_bmi_execute(ar, address, BMI_PARAM_GET_EXT_BOARD_ID, &result);1737if (ret) {1738ath10k_err(ar, "could not execute otp for ext board id check: %d\n",1739ret);1740return ret;1741}17421743if (!result) {1744ath10k_dbg(ar, ATH10K_DBG_BOOT,1745"ext board id does not exist in otp, ignore it\n");1746return -EOPNOTSUPP;1747}17481749ext_board_id = result & ATH10K_BMI_EBOARD_ID_STATUS_MASK;17501751ath10k_dbg(ar, ATH10K_DBG_BOOT,1752"boot get otp ext board id result 0x%08x ext_board_id %d\n",1753result, ext_board_id);17541755ar->id.bmi_eboard_id = ext_board_id;17561757return 0;1758}17591760static int ath10k_download_board_data(struct ath10k *ar, const void *data,1761size_t data_len)1762{1763u32 board_data_size = ar->hw_params.fw.board_size;1764u32 eboard_data_size = ar->hw_params.fw.ext_board_size;1765u32 board_address;1766u32 ext_board_address;1767int ret;17681769ret = ath10k_push_board_ext_data(ar, data, data_len);1770if (ret) {1771ath10k_err(ar, "could not push board ext data (%d)\n", ret);1772goto exit;1773}17741775ret = ath10k_bmi_read32(ar, hi_board_data, &board_address);1776if (ret) {1777ath10k_err(ar, "could not read board data addr (%d)\n", ret);1778goto exit;1779}17801781ret = ath10k_bmi_write_memory(ar, board_address, data,1782min_t(u32, board_data_size,1783data_len));1784if (ret) {1785ath10k_err(ar, "could not write board data (%d)\n", ret);1786goto exit;1787}17881789ret = ath10k_bmi_write32(ar, hi_board_data_initialized, 1);1790if (ret) {1791ath10k_err(ar, "could not write board data bit (%d)\n", ret);1792goto exit;1793}17941795if (!ar->id.ext_bid_supported)1796goto exit;17971798/* Extended board data download */1799ret = ath10k_core_get_ext_board_id_from_otp(ar);1800if (ret == -EOPNOTSUPP) {1801/* Not fetching ext_board_data if ext board id is 0 */1802ath10k_dbg(ar, ATH10K_DBG_BOOT, "otp returned ext board id 0\n");1803return 0;1804} else if (ret) {1805ath10k_err(ar, "failed to get extended board id: %d\n", ret);1806goto exit;1807}18081809ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD_EXT);1810if (ret)1811goto exit;18121813if (ar->normal_mode_fw.ext_board_data) {1814ext_board_address = board_address + EXT_BOARD_ADDRESS_OFFSET;1815ath10k_dbg(ar, ATH10K_DBG_BOOT,1816"boot writing ext board data to addr 0x%x",1817ext_board_address);1818ret = ath10k_bmi_write_memory(ar, ext_board_address,1819ar->normal_mode_fw.ext_board_data,1820min_t(u32, eboard_data_size, data_len));1821if (ret)1822ath10k_err(ar, "failed to write ext board data: %d\n", ret);1823}18241825exit:1826return ret;1827}18281829static int ath10k_download_and_run_otp(struct ath10k *ar)1830{1831u32 result, address = ar->hw_params.patch_load_addr;1832u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param;1833int ret;18341835ret = ath10k_download_board_data(ar,1836ar->running_fw->board_data,1837ar->running_fw->board_len);1838if (ret) {1839ath10k_err(ar, "failed to download board data: %d\n", ret);1840return ret;1841}18421843/* OTP is optional */18441845if (!ar->running_fw->fw_file.otp_data ||1846!ar->running_fw->fw_file.otp_len) {1847ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %pK otp_len %zd)!\n",1848ar->running_fw->fw_file.otp_data,1849ar->running_fw->fw_file.otp_len);1850return 0;1851}18521853ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",1854address, ar->running_fw->fw_file.otp_len);18551856ret = ath10k_bmi_fast_download(ar, address,1857ar->running_fw->fw_file.otp_data,1858ar->running_fw->fw_file.otp_len);1859if (ret) {1860ath10k_err(ar, "could not write otp (%d)\n", ret);1861return ret;1862}18631864/* As of now pre-cal is valid for 10_4 variants */1865if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||1866ar->cal_mode == ATH10K_PRE_CAL_MODE_FILE ||1867ar->cal_mode == ATH10K_PRE_CAL_MODE_NVMEM)1868bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;18691870ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);1871if (ret) {1872ath10k_err(ar, "could not execute otp (%d)\n", ret);1873return ret;1874}18751876ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);18771878if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,1879ar->running_fw->fw_file.fw_features)) &&1880result != 0) {1881ath10k_err(ar, "otp calibration failed: %d", result);1882return -EINVAL;1883}18841885return 0;1886}18871888static int ath10k_download_cal_file(struct ath10k *ar,1889const struct firmware *file)1890{1891int ret;18921893if (!file)1894return -ENOENT;18951896if (IS_ERR(file))1897return PTR_ERR(file);18981899ret = ath10k_download_board_data(ar, file->data, file->size);1900if (ret) {1901ath10k_err(ar, "failed to download cal_file data: %d\n", ret);1902return ret;1903}19041905ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cal file downloaded\n");19061907return 0;1908}19091910static int ath10k_download_cal_dt(struct ath10k *ar, const char *dt_name)1911{1912#if defined(__linux__) || (defined(__FreeBSD__) && defined(CONFIG_OF))1913struct device_node *node;1914int data_len;1915void *data;1916int ret;19171918node = ar->dev->of_node;1919if (!node)1920/* Device Tree is optional, don't print any warnings if1921* there's no node for ath10k.1922*/1923return -ENOENT;19241925if (!of_get_property(node, dt_name, &data_len)) {1926/* The calibration data node is optional */1927return -ENOENT;1928}19291930if (data_len != ar->hw_params.cal_data_len) {1931ath10k_warn(ar, "invalid calibration data length in DT: %d\n",1932data_len);1933ret = -EMSGSIZE;1934goto out;1935}19361937data = kmalloc(data_len, GFP_KERNEL);1938if (!data) {1939ret = -ENOMEM;1940goto out;1941}19421943ret = of_property_read_u8_array(node, dt_name, data, data_len);1944if (ret) {1945ath10k_warn(ar, "failed to read calibration data from DT: %d\n",1946ret);1947goto out_free;1948}19491950ret = ath10k_download_board_data(ar, data, data_len);1951if (ret) {1952ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",1953ret);1954goto out_free;1955}19561957ret = 0;19581959out_free:1960kfree(data);19611962out:1963return ret;1964#else1965return -ENOENT;1966#endif1967}19681969static int ath10k_download_cal_eeprom(struct ath10k *ar)1970{1971size_t data_len;1972void *data = NULL;1973int ret;19741975ret = ath10k_hif_fetch_cal_eeprom(ar, &data, &data_len);1976if (ret) {1977if (ret != -EOPNOTSUPP)1978ath10k_warn(ar, "failed to read calibration data from EEPROM: %d\n",1979ret);1980goto out_free;1981}19821983ret = ath10k_download_board_data(ar, data, data_len);1984if (ret) {1985ath10k_warn(ar, "failed to download calibration data from EEPROM: %d\n",1986ret);1987goto out_free;1988}19891990ret = 0;19911992out_free:1993kfree(data);19941995return ret;1996}19971998static int ath10k_download_cal_nvmem(struct ath10k *ar, const char *cell_name)1999{2000#if defined(__linux__)2001struct nvmem_cell *cell;2002void *buf;2003size_t len;2004#endif2005int ret;20062007#if defined(__linux__)2008cell = devm_nvmem_cell_get(ar->dev, cell_name);2009if (IS_ERR(cell)) {2010ret = PTR_ERR(cell);2011return ret;2012}20132014buf = nvmem_cell_read(cell, &len);2015if (IS_ERR(buf))2016return PTR_ERR(buf);20172018if (ar->hw_params.cal_data_len != len) {2019kfree(buf);2020ath10k_warn(ar, "invalid calibration data length in nvmem-cell '%s': %zu != %u\n",2021cell_name, len, ar->hw_params.cal_data_len);2022return -EMSGSIZE;2023}20242025ret = ath10k_download_board_data(ar, buf, len);2026kfree(buf);2027#elif defined(__FreeBSD__)2028ret = -ENXIO;2029#endif2030if (ret)2031ath10k_warn(ar, "failed to download calibration data from nvmem-cell '%s': %d\n",2032cell_name, ret);20332034return ret;2035}20362037int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,2038struct ath10k_fw_file *fw_file)2039{2040size_t magic_len, len, ie_len;2041int ie_id, i, index, bit, ret;2042#if defined(__linux__)2043struct ath10k_fw_ie *hdr;2044#elif defined(__FreeBSD__)2045const struct ath10k_fw_ie *hdr;2046#endif2047const u8 *data;2048#if defined(__linux__)2049__le32 *timestamp, *version;2050#elif defined(__FreeBSD__)2051const __le32 *timestamp, *version;2052#endif20532054/* first fetch the firmware file (firmware-*.bin) */2055fw_file->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,2056name);2057if (IS_ERR(fw_file->firmware))2058return PTR_ERR(fw_file->firmware);20592060data = fw_file->firmware->data;2061len = fw_file->firmware->size;20622063/* magic also includes the null byte, check that as well */2064magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;20652066if (len < magic_len) {2067ath10k_err(ar, "firmware file '%s/%s' too small to contain magic: %zu\n",2068ar->hw_params.fw.dir, name, len);2069ret = -EINVAL;2070goto err;2071}20722073if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {2074ath10k_err(ar, "invalid firmware magic\n");2075ret = -EINVAL;2076goto err;2077}20782079/* jump over the padding */2080magic_len = ALIGN(magic_len, 4);20812082len -= magic_len;2083data += magic_len;20842085/* loop elements */2086while (len > sizeof(struct ath10k_fw_ie)) {2087#if defined(__linux__)2088hdr = (struct ath10k_fw_ie *)data;2089#elif defined(__FreeBSD__)2090hdr = (const struct ath10k_fw_ie *)data;2091#endif20922093ie_id = le32_to_cpu(hdr->id);2094ie_len = le32_to_cpu(hdr->len);20952096len -= sizeof(*hdr);2097data += sizeof(*hdr);20982099if (len < ie_len) {2100ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",2101ie_id, len, ie_len);2102ret = -EINVAL;2103goto err;2104}21052106switch (ie_id) {2107case ATH10K_FW_IE_FW_VERSION:2108if (ie_len > sizeof(fw_file->fw_version) - 1)2109break;21102111memcpy(fw_file->fw_version, data, ie_len);2112fw_file->fw_version[ie_len] = '\0';21132114ath10k_dbg(ar, ATH10K_DBG_BOOT,2115"found fw version %s\n",2116fw_file->fw_version);2117break;2118case ATH10K_FW_IE_TIMESTAMP:2119if (ie_len != sizeof(u32))2120break;21212122#if defined(__linux__)2123timestamp = (__le32 *)data;2124#elif defined(__FreeBSD__)2125timestamp = (const __le32 *)data;2126#endif21272128ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw timestamp %d\n",2129le32_to_cpup(timestamp));2130break;2131case ATH10K_FW_IE_FEATURES:2132ath10k_dbg(ar, ATH10K_DBG_BOOT,2133"found firmware features ie (%zd B)\n",2134ie_len);21352136for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) {2137index = i / 8;2138bit = i % 8;21392140if (index == ie_len)2141break;21422143if (data[index] & (1 << bit)) {2144ath10k_dbg(ar, ATH10K_DBG_BOOT,2145"Enabling feature bit: %i\n",2146i);2147__set_bit(i, fw_file->fw_features);2148}2149}21502151ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",2152fw_file->fw_features,2153sizeof(fw_file->fw_features));2154break;2155case ATH10K_FW_IE_FW_IMAGE:2156ath10k_dbg(ar, ATH10K_DBG_BOOT,2157"found fw image ie (%zd B)\n",2158ie_len);21592160fw_file->firmware_data = data;2161fw_file->firmware_len = ie_len;21622163break;2164case ATH10K_FW_IE_OTP_IMAGE:2165ath10k_dbg(ar, ATH10K_DBG_BOOT,2166"found otp image ie (%zd B)\n",2167ie_len);21682169fw_file->otp_data = data;2170fw_file->otp_len = ie_len;21712172break;2173case ATH10K_FW_IE_WMI_OP_VERSION:2174if (ie_len != sizeof(u32))2175break;21762177#if defined(__linux__)2178version = (__le32 *)data;2179#elif defined(__FreeBSD__)2180version = (const __le32 *)data;2181#endif21822183fw_file->wmi_op_version = le32_to_cpup(version);21842185ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n",2186fw_file->wmi_op_version);2187break;2188case ATH10K_FW_IE_HTT_OP_VERSION:2189if (ie_len != sizeof(u32))2190break;21912192#if defined(__linux__)2193version = (__le32 *)data;2194#elif defined(__FreeBSD__)2195version = (const __le32 *)data;2196#endif21972198fw_file->htt_op_version = le32_to_cpup(version);21992200ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n",2201fw_file->htt_op_version);2202break;2203case ATH10K_FW_IE_FW_CODE_SWAP_IMAGE:2204ath10k_dbg(ar, ATH10K_DBG_BOOT,2205"found fw code swap image ie (%zd B)\n",2206ie_len);2207fw_file->codeswap_data = data;2208fw_file->codeswap_len = ie_len;2209break;2210default:2211ath10k_warn(ar, "Unknown FW IE: %u\n",2212le32_to_cpu(hdr->id));2213break;2214}22152216/* jump over the padding */2217ie_len = ALIGN(ie_len, 4);22182219len -= ie_len;2220data += ie_len;2221}22222223if (!test_bit(ATH10K_FW_FEATURE_NON_BMI, fw_file->fw_features) &&2224(!fw_file->firmware_data || !fw_file->firmware_len)) {2225ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",2226ar->hw_params.fw.dir, name);2227ret = -ENOMEDIUM;2228goto err;2229}22302231return 0;22322233err:2234ath10k_core_free_firmware_files(ar);2235return ret;2236}22372238static void ath10k_core_get_fw_name(struct ath10k *ar, char *fw_name,2239size_t fw_name_len, int fw_api)2240{2241switch (ar->hif.bus) {2242case ATH10K_BUS_SDIO:2243case ATH10K_BUS_USB:2244scnprintf(fw_name, fw_name_len, "%s-%s-%d.bin",2245ATH10K_FW_FILE_BASE, ath10k_bus_str(ar->hif.bus),2246fw_api);2247break;2248case ATH10K_BUS_PCI:2249case ATH10K_BUS_AHB:2250case ATH10K_BUS_SNOC:2251scnprintf(fw_name, fw_name_len, "%s-%d.bin",2252ATH10K_FW_FILE_BASE, fw_api);2253break;2254}2255}22562257static int ath10k_core_fetch_firmware_files(struct ath10k *ar)2258{2259int ret, i;2260char fw_name[100];22612262/* calibration file is optional, don't check for any errors */2263ath10k_fetch_cal_file(ar);22642265for (i = ATH10K_FW_API_MAX; i >= ATH10K_FW_API_MIN; i--) {2266ar->fw_api = i;2267ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n",2268ar->fw_api);22692270ath10k_core_get_fw_name(ar, fw_name, sizeof(fw_name), ar->fw_api);2271ret = ath10k_core_fetch_firmware_api_n(ar, fw_name,2272&ar->normal_mode_fw.fw_file);2273if (!ret)2274goto success;2275}22762277/* we end up here if we couldn't fetch any firmware */22782279ath10k_err(ar, "Failed to find firmware-N.bin (N between %d and %d) from %s: %d",2280ATH10K_FW_API_MIN, ATH10K_FW_API_MAX, ar->hw_params.fw.dir,2281ret);22822283return ret;22842285success:2286ath10k_dbg(ar, ATH10K_DBG_BOOT, "using fw api %d\n", ar->fw_api);22872288return 0;2289}22902291static int ath10k_core_pre_cal_download(struct ath10k *ar)2292{2293int ret;22942295ret = ath10k_download_cal_nvmem(ar, "pre-calibration");2296if (ret == 0) {2297ar->cal_mode = ATH10K_PRE_CAL_MODE_NVMEM;2298goto success;2299} else if (ret == -EPROBE_DEFER) {2300return ret;2301}23022303ath10k_dbg(ar, ATH10K_DBG_BOOT,2304"boot did not find a pre-calibration nvmem-cell, try file next: %d\n",2305ret);23062307ret = ath10k_download_cal_file(ar, ar->pre_cal_file);2308if (ret == 0) {2309ar->cal_mode = ATH10K_PRE_CAL_MODE_FILE;2310goto success;2311}23122313ath10k_dbg(ar, ATH10K_DBG_BOOT,2314"boot did not find a pre calibration file, try DT next: %d\n",2315ret);23162317ret = ath10k_download_cal_dt(ar, "qcom,ath10k-pre-calibration-data");2318if (ret) {2319ath10k_dbg(ar, ATH10K_DBG_BOOT,2320"unable to load pre cal data from DT: %d\n", ret);2321return ret;2322}2323ar->cal_mode = ATH10K_PRE_CAL_MODE_DT;23242325success:2326ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",2327ath10k_cal_mode_str(ar->cal_mode));23282329return 0;2330}23312332static int ath10k_core_pre_cal_config(struct ath10k *ar)2333{2334int ret;23352336ret = ath10k_core_pre_cal_download(ar);2337if (ret) {2338ath10k_dbg(ar, ATH10K_DBG_BOOT,2339"failed to load pre cal data: %d\n", ret);2340return ret;2341}23422343ret = ath10k_core_get_board_id_from_otp(ar);2344if (ret) {2345ath10k_err(ar, "failed to get board id: %d\n", ret);2346return ret;2347}23482349ret = ath10k_download_and_run_otp(ar);2350if (ret) {2351ath10k_err(ar, "failed to run otp: %d\n", ret);2352return ret;2353}23542355ath10k_dbg(ar, ATH10K_DBG_BOOT,2356"pre cal configuration done successfully\n");23572358return 0;2359}23602361static int ath10k_download_cal_data(struct ath10k *ar)2362{2363int ret;23642365ret = ath10k_core_pre_cal_config(ar);2366if (ret == 0)2367return 0;23682369ath10k_dbg(ar, ATH10K_DBG_BOOT,2370"pre cal download procedure failed, try cal file: %d\n",2371ret);23722373ret = ath10k_download_cal_nvmem(ar, "calibration");2374if (ret == 0) {2375ar->cal_mode = ATH10K_CAL_MODE_NVMEM;2376goto done;2377} else if (ret == -EPROBE_DEFER) {2378return ret;2379}23802381ath10k_dbg(ar, ATH10K_DBG_BOOT,2382"boot did not find a calibration nvmem-cell, try file next: %d\n",2383ret);23842385ret = ath10k_download_cal_file(ar, ar->cal_file);2386if (ret == 0) {2387ar->cal_mode = ATH10K_CAL_MODE_FILE;2388goto done;2389}23902391ath10k_dbg(ar, ATH10K_DBG_BOOT,2392"boot did not find a calibration file, try DT next: %d\n",2393ret);23942395ret = ath10k_download_cal_dt(ar, "qcom,ath10k-calibration-data");2396if (ret == 0) {2397ar->cal_mode = ATH10K_CAL_MODE_DT;2398goto done;2399}24002401ath10k_dbg(ar, ATH10K_DBG_BOOT,2402"boot did not find DT entry, try target EEPROM next: %d\n",2403ret);24042405ret = ath10k_download_cal_eeprom(ar);2406if (ret == 0) {2407ar->cal_mode = ATH10K_CAL_MODE_EEPROM;2408goto done;2409}24102411ath10k_dbg(ar, ATH10K_DBG_BOOT,2412"boot did not find target EEPROM entry, try OTP next: %d\n",2413ret);24142415ret = ath10k_download_and_run_otp(ar);2416if (ret) {2417ath10k_err(ar, "failed to run otp: %d\n", ret);2418return ret;2419}24202421ar->cal_mode = ATH10K_CAL_MODE_OTP;24222423done:2424ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot using calibration mode %s\n",2425ath10k_cal_mode_str(ar->cal_mode));2426return 0;2427}24282429static void ath10k_core_fetch_btcoex_dt(struct ath10k *ar)2430{2431#if defined(__linux__) || (defined(__FreeBSD__) && defined(CONFIG_OF))2432struct device_node *node;2433u8 coex_support = 0;2434int ret;24352436node = ar->dev->of_node;2437if (!node)2438goto out;24392440ret = of_property_read_u8(node, "qcom,coexist-support", &coex_support);2441if (ret) {2442ar->coex_support = true;2443goto out;2444}24452446if (coex_support) {2447ar->coex_support = true;2448} else {2449ar->coex_support = false;2450ar->coex_gpio_pin = -1;2451goto out;2452}24532454ret = of_property_read_u32(node, "qcom,coexist-gpio-pin",2455&ar->coex_gpio_pin);2456if (ret)2457ar->coex_gpio_pin = -1;24582459out:2460#endif2461ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot coex_support %d coex_gpio_pin %d\n",2462ar->coex_support, ar->coex_gpio_pin);2463}24642465static int ath10k_init_uart(struct ath10k *ar)2466{2467int ret;24682469/*2470* Explicitly setting UART prints to zero as target turns it on2471* based on scratch registers.2472*/2473ret = ath10k_bmi_write32(ar, hi_serial_enable, 0);2474if (ret) {2475ath10k_warn(ar, "could not disable UART prints (%d)\n", ret);2476return ret;2477}24782479if (!uart_print) {2480if (ar->hw_params.uart_pin_workaround) {2481ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin,2482ar->hw_params.uart_pin);2483if (ret) {2484ath10k_warn(ar, "failed to set UART TX pin: %d",2485ret);2486return ret;2487}2488}24892490return 0;2491}24922493ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);2494if (ret) {2495ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);2496return ret;2497}24982499ret = ath10k_bmi_write32(ar, hi_serial_enable, 1);2500if (ret) {2501ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);2502return ret;2503}25042505/* Set the UART baud rate to 19200. */2506ret = ath10k_bmi_write32(ar, hi_desired_baud_rate, 19200);2507if (ret) {2508ath10k_warn(ar, "could not set the baud rate (%d)\n", ret);2509return ret;2510}25112512ath10k_info(ar, "UART prints enabled\n");2513return 0;2514}25152516static int ath10k_init_hw_params(struct ath10k *ar)2517{2518const struct ath10k_hw_params *hw_params;2519int i;25202521for (i = 0; i < ARRAY_SIZE(ath10k_hw_params_list); i++) {2522hw_params = &ath10k_hw_params_list[i];25232524if (hw_params->bus == ar->hif.bus &&2525hw_params->id == ar->target_version &&2526hw_params->dev_id == ar->dev_id)2527break;2528}25292530if (i == ARRAY_SIZE(ath10k_hw_params_list)) {2531ath10k_err(ar, "Unsupported hardware version: 0x%x\n",2532ar->target_version);2533return -EINVAL;2534}25352536ar->hw_params = *hw_params;25372538ath10k_dbg(ar, ATH10K_DBG_BOOT, "Hardware name %s version 0x%x\n",2539ar->hw_params.name, ar->target_version);25402541return 0;2542}25432544void ath10k_core_start_recovery(struct ath10k *ar)2545{2546if (test_and_set_bit(ATH10K_FLAG_RESTARTING, &ar->dev_flags)) {2547ath10k_warn(ar, "already restarting\n");2548return;2549}25502551queue_work(ar->workqueue, &ar->restart_work);2552}2553EXPORT_SYMBOL(ath10k_core_start_recovery);25542555void ath10k_core_napi_enable(struct ath10k *ar)2556{2557lockdep_assert_held(&ar->conf_mutex);25582559if (test_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags))2560return;25612562napi_enable(&ar->napi);2563set_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags);2564}2565EXPORT_SYMBOL(ath10k_core_napi_enable);25662567void ath10k_core_napi_sync_disable(struct ath10k *ar)2568{2569lockdep_assert_held(&ar->conf_mutex);25702571if (!test_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags))2572return;25732574napi_synchronize(&ar->napi);2575napi_disable(&ar->napi);2576clear_bit(ATH10K_FLAG_NAPI_ENABLED, &ar->dev_flags);2577}2578EXPORT_SYMBOL(ath10k_core_napi_sync_disable);25792580static void ath10k_core_restart(struct work_struct *work)2581{2582struct ath10k *ar = container_of(work, struct ath10k, restart_work);2583int ret;25842585set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);25862587/* Place a barrier to make sure the compiler doesn't reorder2588* CRASH_FLUSH and calling other functions.2589*/2590barrier();25912592ieee80211_stop_queues(ar->hw);2593ath10k_drain_tx(ar);2594complete(&ar->scan.started);2595complete(&ar->scan.completed);2596complete(&ar->scan.on_channel);2597complete(&ar->offchan_tx_completed);2598complete(&ar->install_key_done);2599complete(&ar->vdev_setup_done);2600complete(&ar->vdev_delete_done);2601complete(&ar->thermal.wmi_sync);2602complete(&ar->bss_survey_done);2603wake_up(&ar->htt.empty_tx_wq);2604wake_up(&ar->wmi.tx_credits_wq);2605wake_up(&ar->peer_mapping_wq);26062607/* TODO: We can have one instance of cancelling coverage_class_work by2608* moving it to ath10k_halt(), so that both stop() and restart() would2609* call that but it takes conf_mutex() and if we call cancel_work_sync()2610* with conf_mutex it will deadlock.2611*/2612cancel_work_sync(&ar->set_coverage_class_work);26132614mutex_lock(&ar->conf_mutex);26152616switch (ar->state) {2617case ATH10K_STATE_ON:2618ar->state = ATH10K_STATE_RESTARTING;2619ath10k_halt(ar);2620ath10k_scan_finish(ar);2621ieee80211_restart_hw(ar->hw);2622break;2623case ATH10K_STATE_OFF:2624/* this can happen if driver is being unloaded2625* or if the crash happens during FW probing2626*/2627ath10k_warn(ar, "cannot restart a device that hasn't been started\n");2628break;2629case ATH10K_STATE_RESTARTING:2630/* hw restart might be requested from multiple places */2631break;2632case ATH10K_STATE_RESTARTED:2633ar->state = ATH10K_STATE_WEDGED;2634fallthrough;2635case ATH10K_STATE_WEDGED:2636ath10k_warn(ar, "device is wedged, will not restart\n");2637break;2638case ATH10K_STATE_UTF:2639ath10k_warn(ar, "firmware restart in UTF mode not supported\n");2640break;2641}26422643mutex_unlock(&ar->conf_mutex);26442645ret = ath10k_coredump_submit(ar);2646if (ret)2647ath10k_warn(ar, "failed to send firmware crash dump via devcoredump: %d",2648ret);26492650complete(&ar->driver_recovery);2651}26522653static void ath10k_core_set_coverage_class_work(struct work_struct *work)2654{2655struct ath10k *ar = container_of(work, struct ath10k,2656set_coverage_class_work);26572658if (ar->hw_params.hw_ops->set_coverage_class)2659ar->hw_params.hw_ops->set_coverage_class(ar, -1);2660}26612662static int ath10k_core_init_firmware_features(struct ath10k *ar)2663{2664struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;2665int max_num_peers;26662667if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) &&2668!test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) {2669ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");2670return -EINVAL;2671}26722673if (fw_file->wmi_op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) {2674ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n",2675ATH10K_FW_WMI_OP_VERSION_MAX, fw_file->wmi_op_version);2676return -EINVAL;2677}26782679ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_NATIVE_WIFI;2680switch (ath10k_cryptmode_param) {2681case ATH10K_CRYPT_MODE_HW:2682clear_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags);2683clear_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags);2684break;2685case ATH10K_CRYPT_MODE_SW:2686if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,2687fw_file->fw_features)) {2688ath10k_err(ar, "cryptmode > 0 requires raw mode support from firmware");2689return -EINVAL;2690}26912692set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags);2693set_bit(ATH10K_FLAG_HW_CRYPTO_DISABLED, &ar->dev_flags);2694break;2695default:2696ath10k_info(ar, "invalid cryptmode: %d\n",2697ath10k_cryptmode_param);2698return -EINVAL;2699}27002701ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT;2702ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT;27032704if (ath10k_frame_mode == ATH10K_HW_TXRX_RAW) {2705if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,2706fw_file->fw_features)) {2707ath10k_err(ar, "rawmode = 1 requires support from firmware");2708return -EINVAL;2709}2710set_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags);2711}27122713if (test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {2714ar->wmi.rx_decap_mode = ATH10K_HW_TXRX_RAW;27152716/* Workaround:2717*2718* Firmware A-MSDU aggregation breaks with RAW Tx encap mode2719* and causes enormous performance issues (malformed frames,2720* etc).2721*2722* Disabling A-MSDU makes RAW mode stable with heavy traffic2723* albeit a bit slower compared to regular operation.2724*/2725ar->htt.max_num_amsdu = 1;2726}27272728/* Backwards compatibility for firmwares without2729* ATH10K_FW_IE_WMI_OP_VERSION.2730*/2731if (fw_file->wmi_op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) {2732if (test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) {2733if (test_bit(ATH10K_FW_FEATURE_WMI_10_2,2734fw_file->fw_features))2735fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_2;2736else2737fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;2738} else {2739fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_MAIN;2740}2741}27422743switch (fw_file->wmi_op_version) {2744case ATH10K_FW_WMI_OP_VERSION_MAIN:2745max_num_peers = TARGET_NUM_PEERS;2746ar->max_num_stations = TARGET_NUM_STATIONS;2747ar->max_num_vdevs = TARGET_NUM_VDEVS;2748ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;2749ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV |2750WMI_STAT_PEER;2751ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;2752break;2753case ATH10K_FW_WMI_OP_VERSION_10_1:2754case ATH10K_FW_WMI_OP_VERSION_10_2:2755case ATH10K_FW_WMI_OP_VERSION_10_2_4:2756if (ath10k_peer_stats_enabled(ar)) {2757max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;2758ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS;2759} else {2760max_num_peers = TARGET_10X_NUM_PEERS;2761ar->max_num_stations = TARGET_10X_NUM_STATIONS;2762}2763ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;2764ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;2765ar->fw_stats_req_mask = WMI_STAT_PEER;2766ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;2767#if defined(CONFIG_FWLOG)2768ar->fwlog_max_moduleid = ATH10K_FWLOG_MODULE_ID_MAX_10_2_4;2769#endif2770break;2771case ATH10K_FW_WMI_OP_VERSION_TLV:2772max_num_peers = TARGET_TLV_NUM_PEERS;2773ar->max_num_stations = TARGET_TLV_NUM_STATIONS;2774ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;2775ar->max_num_tdls_vdevs = TARGET_TLV_NUM_TDLS_VDEVS;2776if (ar->hif.bus == ATH10K_BUS_SDIO)2777ar->htt.max_num_pending_tx =2778TARGET_TLV_NUM_MSDU_DESC_HL;2779else2780ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;2781ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS;2782ar->fw_stats_req_mask = WMI_TLV_STAT_PDEV | WMI_TLV_STAT_VDEV |2783WMI_TLV_STAT_PEER | WMI_TLV_STAT_PEER_EXTD;2784ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM;2785ar->wmi.mgmt_max_num_pending_tx = TARGET_TLV_MGMT_NUM_MSDU_DESC;2786break;2787case ATH10K_FW_WMI_OP_VERSION_10_4:2788max_num_peers = TARGET_10_4_NUM_PEERS;2789ar->max_num_stations = TARGET_10_4_NUM_STATIONS;2790ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS;2791ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;2792ar->num_tids = TARGET_10_4_TGT_NUM_TIDS;2793ar->fw_stats_req_mask = WMI_10_4_STAT_PEER |2794WMI_10_4_STAT_PEER_EXTD |2795WMI_10_4_STAT_VDEV_EXTD;2796ar->max_spatial_stream = ar->hw_params.max_spatial_stream;2797ar->max_num_tdls_vdevs = TARGET_10_4_NUM_TDLS_VDEVS;27982799if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,2800fw_file->fw_features))2801ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC_PFC;2802else2803ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC;2804break;2805case ATH10K_FW_WMI_OP_VERSION_UNSET:2806case ATH10K_FW_WMI_OP_VERSION_MAX:2807default:2808WARN_ON(1);2809return -EINVAL;2810}28112812if (ar->hw_params.num_peers)2813ar->max_num_peers = ar->hw_params.num_peers;2814else2815ar->max_num_peers = max_num_peers;28162817/* Backwards compatibility for firmwares without2818* ATH10K_FW_IE_HTT_OP_VERSION.2819*/2820if (fw_file->htt_op_version == ATH10K_FW_HTT_OP_VERSION_UNSET) {2821switch (fw_file->wmi_op_version) {2822case ATH10K_FW_WMI_OP_VERSION_MAIN:2823fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_MAIN;2824break;2825case ATH10K_FW_WMI_OP_VERSION_10_1:2826case ATH10K_FW_WMI_OP_VERSION_10_2:2827case ATH10K_FW_WMI_OP_VERSION_10_2_4:2828fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;2829break;2830case ATH10K_FW_WMI_OP_VERSION_TLV:2831fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;2832break;2833case ATH10K_FW_WMI_OP_VERSION_10_4:2834case ATH10K_FW_WMI_OP_VERSION_UNSET:2835case ATH10K_FW_WMI_OP_VERSION_MAX:2836ath10k_err(ar, "htt op version not found from fw meta data");2837return -EINVAL;2838}2839}28402841return 0;2842}28432844static int ath10k_core_reset_rx_filter(struct ath10k *ar)2845{2846int ret;2847int vdev_id;2848int vdev_type;2849int vdev_subtype;2850const u8 *vdev_addr;28512852vdev_id = 0;2853vdev_type = WMI_VDEV_TYPE_STA;2854vdev_subtype = ath10k_wmi_get_vdev_subtype(ar, WMI_VDEV_SUBTYPE_NONE);2855vdev_addr = ar->mac_addr;28562857ret = ath10k_wmi_vdev_create(ar, vdev_id, vdev_type, vdev_subtype,2858vdev_addr);2859if (ret) {2860ath10k_err(ar, "failed to create dummy vdev: %d\n", ret);2861return ret;2862}28632864ret = ath10k_wmi_vdev_delete(ar, vdev_id);2865if (ret) {2866ath10k_err(ar, "failed to delete dummy vdev: %d\n", ret);2867return ret;2868}28692870/* WMI and HTT may use separate HIF pipes and are not guaranteed to be2871* serialized properly implicitly.2872*2873* Moreover (most) WMI commands have no explicit acknowledges. It is2874* possible to infer it implicitly by poking firmware with echo2875* command - getting a reply means all preceding comments have been2876* (mostly) processed.2877*2878* In case of vdev create/delete this is sufficient.2879*2880* Without this it's possible to end up with a race when HTT Rx ring is2881* started before vdev create/delete hack is complete allowing a short2882* window of opportunity to receive (and Tx ACK) a bunch of frames.2883*/2884ret = ath10k_wmi_barrier(ar);2885if (ret) {2886ath10k_err(ar, "failed to ping firmware: %d\n", ret);2887return ret;2888}28892890return 0;2891}28922893static int ath10k_core_compat_services(struct ath10k *ar)2894{2895struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;28962897/* all 10.x firmware versions support thermal throttling but don't2898* advertise the support via service flags so we have to hardcode2899* it here2900*/2901switch (fw_file->wmi_op_version) {2902case ATH10K_FW_WMI_OP_VERSION_10_1:2903case ATH10K_FW_WMI_OP_VERSION_10_2:2904case ATH10K_FW_WMI_OP_VERSION_10_2_4:2905case ATH10K_FW_WMI_OP_VERSION_10_4:2906set_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map);2907break;2908default:2909break;2910}29112912return 0;2913}29142915#define TGT_IRAM_READ_PER_ITR (8 * 1024)29162917static int ath10k_core_copy_target_iram(struct ath10k *ar)2918{2919const struct ath10k_hw_mem_layout *hw_mem;2920const struct ath10k_mem_region *tmp, *mem_region = NULL;2921dma_addr_t paddr;2922void *vaddr = NULL;2923u8 num_read_itr;2924int i, ret;2925u32 len, remaining_len;29262927/* copy target iram feature must work also when2928* ATH10K_FW_CRASH_DUMP_RAM_DATA is disabled, so2929* _ath10k_coredump_get_mem_layout() to accomplist that2930*/2931hw_mem = _ath10k_coredump_get_mem_layout(ar);2932if (!hw_mem)2933/* if CONFIG_DEV_COREDUMP is disabled we get NULL, then2934* just silently disable the feature by doing nothing2935*/2936return 0;29372938for (i = 0; i < hw_mem->region_table.size; i++) {2939tmp = &hw_mem->region_table.regions[i];2940if (tmp->type == ATH10K_MEM_REGION_TYPE_REG) {2941mem_region = tmp;2942break;2943}2944}29452946if (!mem_region)2947return -ENOMEM;29482949for (i = 0; i < ar->wmi.num_mem_chunks; i++) {2950if (ar->wmi.mem_chunks[i].req_id ==2951WMI_IRAM_RECOVERY_HOST_MEM_REQ_ID) {2952vaddr = ar->wmi.mem_chunks[i].vaddr;2953len = ar->wmi.mem_chunks[i].len;2954break;2955}2956}29572958if (!vaddr || !len) {2959ath10k_warn(ar, "No allocated memory for IRAM back up");2960return -ENOMEM;2961}29622963len = (len < mem_region->len) ? len : mem_region->len;2964paddr = mem_region->start;2965num_read_itr = len / TGT_IRAM_READ_PER_ITR;2966remaining_len = len % TGT_IRAM_READ_PER_ITR;2967for (i = 0; i < num_read_itr; i++) {2968ret = ath10k_hif_diag_read(ar, paddr, vaddr,2969TGT_IRAM_READ_PER_ITR);2970if (ret) {2971ath10k_warn(ar, "failed to copy firmware IRAM contents: %d",2972ret);2973return ret;2974}29752976paddr += TGT_IRAM_READ_PER_ITR;2977#if defined(__linux__)2978vaddr += TGT_IRAM_READ_PER_ITR;2979#elif defined(__FreeBSD__)2980vaddr = (void *)((uintptr_t)vaddr + TGT_IRAM_READ_PER_ITR);2981#endif2982}29832984if (remaining_len) {2985ret = ath10k_hif_diag_read(ar, paddr, vaddr, remaining_len);2986if (ret) {2987ath10k_warn(ar, "failed to copy firmware IRAM contents: %d",2988ret);2989return ret;2990}2991}29922993ath10k_dbg(ar, ATH10K_DBG_BOOT, "target IRAM back up completed\n");29942995return 0;2996}29972998int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,2999const struct ath10k_fw_components *fw)3000{3001int status;3002u32 val;30033004lockdep_assert_held(&ar->conf_mutex);30053006clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);30073008ar->running_fw = fw;30093010if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,3011ar->running_fw->fw_file.fw_features)) {3012ath10k_bmi_start(ar);30133014/* Enable hardware clock to speed up firmware download */3015if (ar->hw_params.hw_ops->enable_pll_clk) {3016status = ar->hw_params.hw_ops->enable_pll_clk(ar);3017ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot enable pll ret %d\n",3018status);3019}30203021if (ath10k_init_configure_target(ar)) {3022status = -EINVAL;3023goto err;3024}30253026status = ath10k_download_cal_data(ar);3027if (status)3028goto err;30293030/* Some of qca988x solutions are having global reset issue3031* during target initialization. Bypassing PLL setting before3032* downloading firmware and letting the SoC run on REF_CLK is3033* fixing the problem. Corresponding firmware change is also3034* needed to set the clock source once the target is3035* initialized.3036*/3037if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,3038ar->running_fw->fw_file.fw_features)) {3039status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1);3040if (status) {3041ath10k_err(ar, "could not write to skip_clock_init: %d\n",3042status);3043goto err;3044}3045}30463047status = ath10k_download_fw(ar);3048if (status)3049goto err;30503051status = ath10k_init_uart(ar);3052if (status)3053goto err;30543055if (ar->hif.bus == ATH10K_BUS_SDIO) {3056status = ath10k_init_sdio(ar, mode);3057if (status) {3058ath10k_err(ar, "failed to init SDIO: %d\n", status);3059goto err;3060}3061}3062}30633064ar->htc.htc_ops.target_send_suspend_complete =3065ath10k_send_suspend_complete;30663067status = ath10k_htc_init(ar);3068if (status) {3069ath10k_err(ar, "could not init HTC (%d)\n", status);3070goto err;3071}30723073if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,3074ar->running_fw->fw_file.fw_features)) {3075status = ath10k_bmi_done(ar);3076if (status)3077goto err;3078}30793080status = ath10k_wmi_attach(ar);3081if (status) {3082ath10k_err(ar, "WMI attach failed: %d\n", status);3083goto err;3084}30853086status = ath10k_htt_init(ar);3087if (status) {3088ath10k_err(ar, "failed to init htt: %d\n", status);3089goto err_wmi_detach;3090}30913092status = ath10k_htt_tx_start(&ar->htt);3093if (status) {3094ath10k_err(ar, "failed to alloc htt tx: %d\n", status);3095goto err_wmi_detach;3096}30973098/* If firmware indicates Full Rx Reorder support it must be used in a3099* slightly different manner. Let HTT code know.3100*/3101ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,3102ar->wmi.svc_map));31033104status = ath10k_htt_rx_alloc(&ar->htt);3105if (status) {3106ath10k_err(ar, "failed to alloc htt rx: %d\n", status);3107goto err_htt_tx_detach;3108}31093110status = ath10k_hif_start(ar);3111if (status) {3112ath10k_err(ar, "could not start HIF: %d\n", status);3113goto err_htt_rx_detach;3114}31153116status = ath10k_htc_wait_target(&ar->htc);3117if (status) {3118ath10k_err(ar, "failed to connect to HTC: %d\n", status);3119goto err_hif_stop;3120}31213122status = ath10k_hif_start_post(ar);3123if (status) {3124ath10k_err(ar, "failed to swap mailbox: %d\n", status);3125goto err_hif_stop;3126}31273128if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {3129status = ath10k_htt_connect(&ar->htt);3130if (status) {3131ath10k_err(ar, "failed to connect htt (%d)\n", status);3132goto err_hif_stop;3133}3134}31353136status = ath10k_wmi_connect(ar);3137if (status) {3138ath10k_err(ar, "could not connect wmi: %d\n", status);3139goto err_hif_stop;3140}31413142status = ath10k_htc_start(&ar->htc);3143if (status) {3144ath10k_err(ar, "failed to start htc: %d\n", status);3145goto err_hif_stop;3146}31473148if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {3149status = ath10k_wmi_wait_for_service_ready(ar);3150if (status) {3151ath10k_warn(ar, "wmi service ready event not received");3152goto err_hif_stop;3153}3154}31553156ath10k_dbg(ar, ATH10K_DBG_BOOT, "firmware %s booted\n",3157ar->hw->wiphy->fw_version);31583159if (test_bit(ATH10K_FW_FEATURE_IRAM_RECOVERY,3160ar->running_fw->fw_file.fw_features)) {3161status = ath10k_core_copy_target_iram(ar);3162if (status) {3163ath10k_warn(ar, "failed to copy target iram contents: %d",3164status);3165goto err_hif_stop;3166}3167}31683169if (test_bit(WMI_SERVICE_EXT_RES_CFG_SUPPORT, ar->wmi.svc_map) &&3170mode == ATH10K_FIRMWARE_MODE_NORMAL) {3171val = 0;3172if (ath10k_peer_stats_enabled(ar))3173val = WMI_10_4_PEER_STATS;31743175/* Enable vdev stats by default */3176val |= WMI_10_4_VDEV_STATS;31773178if (test_bit(WMI_SERVICE_BSS_CHANNEL_INFO_64, ar->wmi.svc_map))3179val |= WMI_10_4_BSS_CHANNEL_INFO_64;31803181ath10k_core_fetch_btcoex_dt(ar);31823183/* 10.4 firmware supports BT-Coex without reloading firmware3184* via pdev param. To support Bluetooth coexistence pdev param,3185* WMI_COEX_GPIO_SUPPORT of extended resource config should be3186* enabled always.3187*3188* We can still enable BTCOEX if firmware has the support3189* even though btceox_support value is3190* ATH10K_DT_BTCOEX_NOT_FOUND3191*/31923193if (test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map) &&3194test_bit(ATH10K_FW_FEATURE_BTCOEX_PARAM,3195ar->running_fw->fw_file.fw_features) &&3196ar->coex_support)3197val |= WMI_10_4_COEX_GPIO_SUPPORT;31983199if (test_bit(WMI_SERVICE_TDLS_EXPLICIT_MODE_ONLY,3200ar->wmi.svc_map))3201val |= WMI_10_4_TDLS_EXPLICIT_MODE_ONLY;32023203if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA,3204ar->wmi.svc_map))3205val |= WMI_10_4_TDLS_UAPSD_BUFFER_STA;32063207if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI,3208ar->wmi.svc_map))3209val |= WMI_10_4_TX_DATA_ACK_RSSI;32103211if (test_bit(WMI_SERVICE_REPORT_AIRTIME, ar->wmi.svc_map))3212val |= WMI_10_4_REPORT_AIRTIME;32133214if (test_bit(WMI_SERVICE_EXT_PEER_TID_CONFIGS_SUPPORT,3215ar->wmi.svc_map))3216val |= WMI_10_4_EXT_PEER_TID_CONFIGS_SUPPORT;32173218status = ath10k_mac_ext_resource_config(ar, val);3219if (status) {3220ath10k_err(ar,3221"failed to send ext resource cfg command : %d\n",3222status);3223goto err_hif_stop;3224}3225}32263227status = ath10k_wmi_cmd_init(ar);3228if (status) {3229ath10k_err(ar, "could not send WMI init command (%d)\n",3230status);3231goto err_hif_stop;3232}32333234status = ath10k_wmi_wait_for_unified_ready(ar);3235if (status) {3236ath10k_err(ar, "wmi unified ready event not received\n");3237goto err_hif_stop;3238}32393240status = ath10k_core_compat_services(ar);3241if (status) {3242ath10k_err(ar, "compat services failed: %d\n", status);3243goto err_hif_stop;3244}32453246status = ath10k_wmi_pdev_set_base_macaddr(ar, ar->mac_addr);3247if (status && status != -EOPNOTSUPP) {3248ath10k_err(ar,3249"failed to set base mac address: %d\n", status);3250goto err_hif_stop;3251}32523253/* Some firmware revisions do not properly set up hardware rx filter3254* registers.3255*3256* A known example from QCA9880 and 10.2.4 is that MAC_PCU_ADDR1_MASK3257* is filled with 0s instead of 1s allowing HW to respond with ACKs to3258* any frames that matches MAC_PCU_RX_FILTER which is also3259* misconfigured to accept anything.3260*3261* The ADDR1 is programmed using internal firmware structure field and3262* can't be (easily/sanely) reached from the driver explicitly. It is3263* possible to implicitly make it correct by creating a dummy vdev and3264* then deleting it.3265*/3266if (ar->hw_params.hw_filter_reset_required &&3267mode == ATH10K_FIRMWARE_MODE_NORMAL) {3268status = ath10k_core_reset_rx_filter(ar);3269if (status) {3270ath10k_err(ar,3271"failed to reset rx filter: %d\n", status);3272goto err_hif_stop;3273}3274}32753276status = ath10k_htt_rx_ring_refill(ar);3277if (status) {3278ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);3279goto err_hif_stop;3280}32813282if (ar->max_num_vdevs >= 64)3283ar->free_vdev_map = 0xFFFFFFFFFFFFFFFFLL;3284else3285ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;32863287INIT_LIST_HEAD(&ar->arvifs);32883289/* we don't care about HTT in UTF mode */3290if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {3291status = ath10k_htt_setup(&ar->htt);3292if (status) {3293ath10k_err(ar, "failed to setup htt: %d\n", status);3294goto err_hif_stop;3295}3296}32973298status = ath10k_debug_start(ar);3299if (status)3300goto err_hif_stop;33013302status = ath10k_hif_set_target_log_mode(ar, fw_diag_log);3303if (status && status != -EOPNOTSUPP) {3304ath10k_warn(ar, "set target log mode failed: %d\n", status);3305goto err_hif_stop;3306}33073308return 0;33093310err_hif_stop:3311ath10k_hif_stop(ar);3312err_htt_rx_detach:3313ath10k_htt_rx_free(&ar->htt);3314err_htt_tx_detach:3315ath10k_htt_tx_free(&ar->htt);3316err_wmi_detach:3317ath10k_wmi_detach(ar);3318err:3319return status;3320}3321EXPORT_SYMBOL(ath10k_core_start);33223323int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt)3324{3325int ret;3326unsigned long time_left;33273328reinit_completion(&ar->target_suspend);33293330ret = ath10k_wmi_pdev_suspend_target(ar, suspend_opt);3331if (ret) {3332ath10k_warn(ar, "could not suspend target (%d)\n", ret);3333return ret;3334}33353336time_left = wait_for_completion_timeout(&ar->target_suspend, 1 * HZ);33373338if (!time_left) {3339ath10k_warn(ar, "suspend timed out - target pause event never came\n");3340return -ETIMEDOUT;3341}33423343return 0;3344}33453346void ath10k_core_stop(struct ath10k *ar)3347{3348lockdep_assert_held(&ar->conf_mutex);3349ath10k_debug_stop(ar);33503351/* try to suspend target */3352if (ar->state != ATH10K_STATE_RESTARTING &&3353ar->state != ATH10K_STATE_UTF)3354ath10k_wait_for_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR);33553356ath10k_hif_stop(ar);3357ath10k_htt_tx_stop(&ar->htt);3358ath10k_htt_rx_free(&ar->htt);3359ath10k_wmi_detach(ar);33603361ar->id.bmi_ids_valid = false;3362}3363EXPORT_SYMBOL(ath10k_core_stop);33643365/* mac80211 manages fw/hw initialization through start/stop hooks. However in3366* order to know what hw capabilities should be advertised to mac80211 it is3367* necessary to load the firmware (and tear it down immediately since start3368* hook will try to init it again) before registering3369*/3370static int ath10k_core_probe_fw(struct ath10k *ar)3371{3372struct bmi_target_info target_info;3373int ret = 0;33743375ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_NORMAL);3376if (ret) {3377ath10k_err(ar, "could not power on hif bus (%d)\n", ret);3378return ret;3379}33803381switch (ar->hif.bus) {3382case ATH10K_BUS_SDIO:3383memset(&target_info, 0, sizeof(target_info));3384ret = ath10k_bmi_get_target_info_sdio(ar, &target_info);3385if (ret) {3386ath10k_err(ar, "could not get target info (%d)\n", ret);3387goto err_power_down;3388}3389ar->target_version = target_info.version;3390ar->hw->wiphy->hw_version = target_info.version;3391break;3392case ATH10K_BUS_PCI:3393case ATH10K_BUS_AHB:3394case ATH10K_BUS_USB:3395memset(&target_info, 0, sizeof(target_info));3396ret = ath10k_bmi_get_target_info(ar, &target_info);3397if (ret) {3398ath10k_err(ar, "could not get target info (%d)\n", ret);3399goto err_power_down;3400}3401ar->target_version = target_info.version;3402ar->hw->wiphy->hw_version = target_info.version;3403break;3404case ATH10K_BUS_SNOC:3405memset(&target_info, 0, sizeof(target_info));3406ret = ath10k_hif_get_target_info(ar, &target_info);3407if (ret) {3408ath10k_err(ar, "could not get target info (%d)\n", ret);3409goto err_power_down;3410}3411ar->target_version = target_info.version;3412ar->hw->wiphy->hw_version = target_info.version;3413break;3414default:3415ath10k_err(ar, "incorrect hif bus type: %d\n", ar->hif.bus);3416}34173418ret = ath10k_init_hw_params(ar);3419if (ret) {3420ath10k_err(ar, "could not get hw params (%d)\n", ret);3421goto err_power_down;3422}34233424ret = ath10k_core_fetch_firmware_files(ar);3425if (ret) {3426ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);3427goto err_power_down;3428}34293430BUILD_BUG_ON(sizeof(ar->hw->wiphy->fw_version) !=3431sizeof(ar->normal_mode_fw.fw_file.fw_version));3432memcpy(ar->hw->wiphy->fw_version, ar->normal_mode_fw.fw_file.fw_version,3433sizeof(ar->hw->wiphy->fw_version));34343435ath10k_debug_print_hwfw_info(ar);34363437if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,3438ar->normal_mode_fw.fw_file.fw_features)) {3439ret = ath10k_core_pre_cal_download(ar);3440if (ret) {3441/* pre calibration data download is not necessary3442* for all the chipsets. Ignore failures and continue.3443*/3444ath10k_dbg(ar, ATH10K_DBG_BOOT,3445"could not load pre cal data: %d\n", ret);3446}34473448ret = ath10k_core_get_board_id_from_otp(ar);3449if (ret && ret != -EOPNOTSUPP) {3450ath10k_err(ar, "failed to get board id from otp: %d\n",3451ret);3452goto err_free_firmware_files;3453}34543455ret = ath10k_core_check_smbios(ar);3456if (ret)3457ath10k_dbg(ar, ATH10K_DBG_BOOT, "SMBIOS bdf variant name not set.\n");34583459ret = ath10k_core_check_dt(ar);3460if (ret)3461ath10k_dbg(ar, ATH10K_DBG_BOOT, "DT bdf variant name not set.\n");34623463ret = ath10k_core_fetch_board_file(ar, ATH10K_BD_IE_BOARD);3464if (ret) {3465ath10k_err(ar, "failed to fetch board file: %d\n", ret);3466goto err_free_firmware_files;3467}34683469ath10k_debug_print_board_info(ar);3470}34713472device_get_mac_address(ar->dev, ar->mac_addr);34733474ret = ath10k_core_init_firmware_features(ar);3475if (ret) {3476ath10k_err(ar, "fatal problem with firmware features: %d\n",3477ret);3478goto err_free_firmware_files;3479}34803481if (!test_bit(ATH10K_FW_FEATURE_NON_BMI,3482ar->normal_mode_fw.fw_file.fw_features)) {3483ret = ath10k_swap_code_seg_init(ar,3484&ar->normal_mode_fw.fw_file);3485if (ret) {3486ath10k_err(ar, "failed to initialize code swap segment: %d\n",3487ret);3488goto err_free_firmware_files;3489}3490}34913492mutex_lock(&ar->conf_mutex);34933494ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL,3495&ar->normal_mode_fw);3496if (ret) {3497ath10k_err(ar, "could not init core (%d)\n", ret);3498goto err_unlock;3499}35003501ath10k_debug_print_boot_info(ar);3502ath10k_core_stop(ar);35033504mutex_unlock(&ar->conf_mutex);35053506ath10k_hif_power_down(ar);3507return 0;35083509err_unlock:3510mutex_unlock(&ar->conf_mutex);35113512err_free_firmware_files:3513ath10k_core_free_firmware_files(ar);35143515err_power_down:3516ath10k_hif_power_down(ar);35173518return ret;3519}35203521static void ath10k_core_register_work(struct work_struct *work)3522{3523struct ath10k *ar = container_of(work, struct ath10k, register_work);3524int status;35253526/* peer stats are enabled by default */3527set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);35283529status = ath10k_core_probe_fw(ar);3530if (status) {3531ath10k_err(ar, "could not probe fw (%d)\n", status);3532goto err;3533}35343535status = ath10k_mac_register(ar);3536if (status) {3537ath10k_err(ar, "could not register to mac80211 (%d)\n", status);3538goto err_release_fw;3539}35403541status = ath10k_coredump_register(ar);3542if (status) {3543ath10k_err(ar, "unable to register coredump\n");3544goto err_unregister_mac;3545}35463547status = ath10k_debug_register(ar);3548if (status) {3549ath10k_err(ar, "unable to initialize debugfs\n");3550goto err_unregister_coredump;3551}35523553status = ath10k_spectral_create(ar);3554if (status) {3555ath10k_err(ar, "failed to initialize spectral\n");3556goto err_debug_destroy;3557}35583559status = ath10k_thermal_register(ar);3560if (status) {3561ath10k_err(ar, "could not register thermal device: %d\n",3562status);3563goto err_spectral_destroy;3564}3565#if defined(CONFIG_FWLOG)3566ath10k_fwlog_register(ar);3567#endif35683569set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);3570return;35713572err_spectral_destroy:3573ath10k_spectral_destroy(ar);3574err_debug_destroy:3575ath10k_debug_destroy(ar);3576err_unregister_coredump:3577ath10k_coredump_unregister(ar);3578err_unregister_mac:3579ath10k_mac_unregister(ar);3580err_release_fw:3581ath10k_core_free_firmware_files(ar);3582err:3583/* TODO: It's probably a good idea to release device from the driver3584* but calling device_release_driver() here will cause a deadlock.3585*/3586return;3587}35883589int ath10k_core_register(struct ath10k *ar,3590const struct ath10k_bus_params *bus_params)3591{3592ar->bus_param = *bus_params;35933594queue_work(ar->workqueue, &ar->register_work);35953596return 0;3597}3598EXPORT_SYMBOL(ath10k_core_register);35993600void ath10k_core_unregister(struct ath10k *ar)3601{3602cancel_work_sync(&ar->register_work);36033604if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))3605return;36063607ath10k_thermal_unregister(ar);3608/* Stop spectral before unregistering from mac80211 to remove the3609* relayfs debugfs file cleanly. Otherwise the parent debugfs tree3610* would be already be free'd recursively, leading to a double free.3611*/3612ath10k_spectral_destroy(ar);36133614/* We must unregister from mac80211 before we stop HTC and HIF.3615* Otherwise we will fail to submit commands to FW and mac80211 will be3616* unhappy about callback failures.3617*/3618ath10k_mac_unregister(ar);36193620ath10k_testmode_destroy(ar);36213622ath10k_core_free_firmware_files(ar);3623ath10k_core_free_board_files(ar);36243625ath10k_debug_unregister(ar);3626#if defined(CONFIG_FWLOG)3627ath10k_fwlog_unregister(ar);3628#endif3629}3630EXPORT_SYMBOL(ath10k_core_unregister);36313632struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,3633enum ath10k_bus bus,3634enum ath10k_hw_rev hw_rev,3635const struct ath10k_hif_ops *hif_ops)3636{3637struct ath10k *ar;3638int ret;36393640ar = ath10k_mac_create(priv_size);3641if (!ar)3642return NULL;36433644ar->ath_common.priv = ar;3645ar->ath_common.hw = ar->hw;3646ar->dev = dev;3647ar->hw_rev = hw_rev;3648ar->hif.ops = hif_ops;3649ar->hif.bus = bus;36503651switch (hw_rev) {3652case ATH10K_HW_QCA988X:3653case ATH10K_HW_QCA9887:3654ar->regs = &qca988x_regs;3655ar->hw_ce_regs = &qcax_ce_regs;3656ar->hw_values = &qca988x_values;3657break;3658case ATH10K_HW_QCA6174:3659case ATH10K_HW_QCA9377:3660ar->regs = &qca6174_regs;3661ar->hw_ce_regs = &qcax_ce_regs;3662ar->hw_values = &qca6174_values;3663break;3664case ATH10K_HW_QCA99X0:3665case ATH10K_HW_QCA9984:3666ar->regs = &qca99x0_regs;3667ar->hw_ce_regs = &qcax_ce_regs;3668ar->hw_values = &qca99x0_values;3669break;3670case ATH10K_HW_QCA9888:3671ar->regs = &qca99x0_regs;3672ar->hw_ce_regs = &qcax_ce_regs;3673ar->hw_values = &qca9888_values;3674break;3675case ATH10K_HW_QCA4019:3676ar->regs = &qca4019_regs;3677ar->hw_ce_regs = &qcax_ce_regs;3678ar->hw_values = &qca4019_values;3679break;3680case ATH10K_HW_WCN3990:3681ar->regs = &wcn3990_regs;3682ar->hw_ce_regs = &wcn3990_ce_regs;3683ar->hw_values = &wcn3990_values;3684break;3685default:3686ath10k_err(ar, "unsupported core hardware revision %d\n",3687hw_rev);3688ret = -ENOTSUPP;3689goto err_free_mac;3690}36913692init_completion(&ar->scan.started);3693init_completion(&ar->scan.completed);3694init_completion(&ar->scan.on_channel);3695init_completion(&ar->target_suspend);3696init_completion(&ar->driver_recovery);3697init_completion(&ar->wow.wakeup_completed);36983699init_completion(&ar->install_key_done);3700init_completion(&ar->vdev_setup_done);3701init_completion(&ar->vdev_delete_done);3702init_completion(&ar->thermal.wmi_sync);3703init_completion(&ar->bss_survey_done);3704init_completion(&ar->peer_delete_done);3705init_completion(&ar->peer_stats_info_complete);37063707INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);37083709ar->workqueue = create_singlethread_workqueue("ath10k_wq");3710if (!ar->workqueue)3711goto err_free_mac;37123713ar->workqueue_aux = create_singlethread_workqueue("ath10k_aux_wq");3714if (!ar->workqueue_aux)3715goto err_free_wq;37163717ar->workqueue_tx_complete =3718create_singlethread_workqueue("ath10k_tx_complete_wq");3719if (!ar->workqueue_tx_complete)3720goto err_free_aux_wq;37213722mutex_init(&ar->conf_mutex);3723mutex_init(&ar->dump_mutex);3724spin_lock_init(&ar->data_lock);37253726for (int ac = 0; ac < IEEE80211_NUM_ACS; ac++)3727spin_lock_init(&ar->queue_lock[ac]);37283729INIT_LIST_HEAD(&ar->peers);3730init_waitqueue_head(&ar->peer_mapping_wq);3731init_waitqueue_head(&ar->htt.empty_tx_wq);3732init_waitqueue_head(&ar->wmi.tx_credits_wq);37333734skb_queue_head_init(&ar->htt.rx_indication_head);37353736init_completion(&ar->offchan_tx_completed);3737INIT_WORK(&ar->offchan_tx_work, ath10k_offchan_tx_work);3738skb_queue_head_init(&ar->offchan_tx_queue);37393740INIT_WORK(&ar->wmi_mgmt_tx_work, ath10k_mgmt_over_wmi_tx_work);3741skb_queue_head_init(&ar->wmi_mgmt_tx_queue);37423743INIT_WORK(&ar->register_work, ath10k_core_register_work);3744INIT_WORK(&ar->restart_work, ath10k_core_restart);3745INIT_WORK(&ar->set_coverage_class_work,3746ath10k_core_set_coverage_class_work);37473748init_dummy_netdev(&ar->napi_dev);37493750ret = ath10k_coredump_create(ar);3751if (ret)3752goto err_free_tx_complete;37533754ret = ath10k_debug_create(ar);3755if (ret)3756goto err_free_coredump;37573758return ar;37593760err_free_coredump:3761ath10k_coredump_destroy(ar);3762err_free_tx_complete:3763destroy_workqueue(ar->workqueue_tx_complete);3764err_free_aux_wq:3765destroy_workqueue(ar->workqueue_aux);3766err_free_wq:3767destroy_workqueue(ar->workqueue);3768err_free_mac:3769ath10k_mac_destroy(ar);37703771return NULL;3772}3773EXPORT_SYMBOL(ath10k_core_create);37743775void ath10k_core_destroy(struct ath10k *ar)3776{3777destroy_workqueue(ar->workqueue);37783779destroy_workqueue(ar->workqueue_aux);37803781destroy_workqueue(ar->workqueue_tx_complete);37823783ath10k_debug_destroy(ar);3784ath10k_coredump_destroy(ar);3785ath10k_htt_tx_destroy(&ar->htt);3786ath10k_wmi_free_host_mem(ar);3787ath10k_mac_destroy(ar);3788}3789EXPORT_SYMBOL(ath10k_core_destroy);37903791MODULE_AUTHOR("Qualcomm Atheros");3792MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ac wireless LAN cards.");3793MODULE_LICENSE("Dual BSD/GPL");379437953796