Path: blob/main/sys/contrib/dev/athk/ath11k/core.c
105221 views
// SPDX-License-Identifier: BSD-3-Clause-Clear1/*2* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.3* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.4* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.5*/67#if defined(__FreeBSD__)8#define LINUXKPI_PARAM_PREFIX ath11k_core_9#endif1011#include <linux/export.h>12#include <linux/module.h>13#include <linux/slab.h>14#include <linux/remoteproc.h>15#include <linux/firmware.h>16#if defined(CONFIG_OF)17#include <linux/of.h>18#endif19#if defined(__FreeBSD__)20#include <linux/delay.h>21#endif2223#include "core.h"24#include "dp_tx.h"25#include "dp_rx.h"26#include "debug.h"27#include "hif.h"28#include "wow.h"29#include "fw.h"3031unsigned int ath11k_debug_mask;32EXPORT_SYMBOL(ath11k_debug_mask);33module_param_named(debug_mask, ath11k_debug_mask, uint, 0644);34MODULE_PARM_DESC(debug_mask, "Debugging mask");3536static unsigned int ath11k_crypto_mode;37module_param_named(crypto_mode, ath11k_crypto_mode, uint, 0644);38MODULE_PARM_DESC(crypto_mode, "crypto mode: 0-hardware, 1-software");3940/* frame mode values are mapped as per enum ath11k_hw_txrx_mode */41unsigned int ath11k_frame_mode = ATH11K_HW_TXRX_NATIVE_WIFI;42module_param_named(frame_mode, ath11k_frame_mode, uint, 0644);43MODULE_PARM_DESC(frame_mode,44"Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");4546bool ath11k_ftm_mode;47module_param_named(ftm_mode, ath11k_ftm_mode, bool, 0444);48MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");4950static const struct ath11k_hw_params ath11k_hw_params[] = {51{52.hw_rev = ATH11K_HW_IPQ8074,53.name = "ipq8074 hw2.0",54.fw = {55.dir = "IPQ8074/hw2.0",56.board_size = 256 * 1024,57.cal_offset = 128 * 1024,58},59.max_radios = 3,60.bdf_addr = 0x4B0C0000,61.hw_ops = &ipq8074_ops,62.ring_mask = &ath11k_hw_ring_mask_ipq8074,63.internal_sleep_clock = false,64.regs = &ipq8074_regs,65.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074,66.host_ce_config = ath11k_host_ce_config_ipq8074,67.ce_count = 12,68.target_ce_config = ath11k_target_ce_config_wlan_ipq8074,69.target_ce_count = 11,70.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq8074,71.svc_to_ce_map_len = 21,72.ce_ie_addr = &ath11k_ce_ie_addr_ipq8074,73.single_pdev_only = false,74.rxdma1_enable = true,75.num_rxdma_per_pdev = 1,76.rx_mac_buf_ring = false,77.vdev_start_delay = false,78.htt_peer_map_v2 = true,7980.spectral = {81.fft_sz = 2,82/* HW bug, expected BIN size is 2 bytes but HW report as 4 bytes.83* so added pad size as 2 bytes to compensate the BIN size84*/85.fft_pad_sz = 2,86.summary_pad_sz = 0,87.fft_hdr_len = 16,88.max_fft_bins = 512,89.fragment_160mhz = true,90},9192.interface_modes = BIT(NL80211_IFTYPE_STATION) |93BIT(NL80211_IFTYPE_AP) |94BIT(NL80211_IFTYPE_MESH_POINT),95.supports_monitor = true,96.full_monitor_mode = false,97.supports_shadow_regs = false,98.idle_ps = false,99.supports_sta_ps = false,100.coldboot_cal_mm = true,101.coldboot_cal_ftm = true,102.cbcal_restart_fw = true,103.fw_mem_mode = 0,104.num_vdevs = 16 + 1,105.num_peers = 512,106.supports_suspend = false,107.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),108.supports_regdb = false,109.fix_l1ss = true,110.credit_flow = false,111.max_tx_ring = DP_TCL_NUM_RING_MAX,112.hal_params = &ath11k_hw_hal_params_ipq8074,113.supports_dynamic_smps_6ghz = false,114.alloc_cacheable_memory = true,115.supports_rssi_stats = false,116.fw_wmi_diag_event = false,117.current_cc_support = false,118.dbr_debug_support = true,119.global_reset = false,120.bios_sar_capa = NULL,121.m3_fw_support = false,122.fixed_bdf_addr = true,123.fixed_mem_region = true,124.static_window_map = false,125.hybrid_bus_type = false,126.fixed_fw_mem = false,127.support_off_channel_tx = false,128.supports_multi_bssid = false,129130.sram_dump = {},131132.tcl_ring_retry = true,133.tx_ring_size = DP_TCL_DATA_RING_SIZE,134.smp2p_wow_exit = false,135.support_dual_stations = false,136.pdev_suspend = false,137},138{139.hw_rev = ATH11K_HW_IPQ6018_HW10,140.name = "ipq6018 hw1.0",141.fw = {142.dir = "IPQ6018/hw1.0",143.board_size = 256 * 1024,144.cal_offset = 128 * 1024,145},146.max_radios = 2,147.bdf_addr = 0x4ABC0000,148.hw_ops = &ipq6018_ops,149.ring_mask = &ath11k_hw_ring_mask_ipq8074,150.internal_sleep_clock = false,151.regs = &ipq8074_regs,152.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074,153.host_ce_config = ath11k_host_ce_config_ipq8074,154.ce_count = 12,155.target_ce_config = ath11k_target_ce_config_wlan_ipq8074,156.target_ce_count = 11,157.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq6018,158.svc_to_ce_map_len = 19,159.ce_ie_addr = &ath11k_ce_ie_addr_ipq8074,160.single_pdev_only = false,161.rxdma1_enable = true,162.num_rxdma_per_pdev = 1,163.rx_mac_buf_ring = false,164.vdev_start_delay = false,165.htt_peer_map_v2 = true,166167.spectral = {168.fft_sz = 4,169.fft_pad_sz = 0,170.summary_pad_sz = 0,171.fft_hdr_len = 16,172.max_fft_bins = 512,173.fragment_160mhz = true,174},175176.interface_modes = BIT(NL80211_IFTYPE_STATION) |177BIT(NL80211_IFTYPE_AP) |178BIT(NL80211_IFTYPE_MESH_POINT),179.supports_monitor = true,180.full_monitor_mode = false,181.supports_shadow_regs = false,182.idle_ps = false,183.supports_sta_ps = false,184.coldboot_cal_mm = true,185.coldboot_cal_ftm = true,186.cbcal_restart_fw = true,187.fw_mem_mode = 0,188.num_vdevs = 16 + 1,189.num_peers = 512,190.supports_suspend = false,191.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),192.supports_regdb = false,193.fix_l1ss = true,194.credit_flow = false,195.max_tx_ring = DP_TCL_NUM_RING_MAX,196.hal_params = &ath11k_hw_hal_params_ipq8074,197.supports_dynamic_smps_6ghz = false,198.alloc_cacheable_memory = true,199.supports_rssi_stats = false,200.fw_wmi_diag_event = false,201.current_cc_support = false,202.dbr_debug_support = true,203.global_reset = false,204.bios_sar_capa = NULL,205.m3_fw_support = false,206.fixed_bdf_addr = true,207.fixed_mem_region = true,208.static_window_map = false,209.hybrid_bus_type = false,210.fixed_fw_mem = false,211.support_off_channel_tx = false,212.supports_multi_bssid = false,213214.sram_dump = {},215216.tcl_ring_retry = true,217.tx_ring_size = DP_TCL_DATA_RING_SIZE,218.smp2p_wow_exit = false,219.support_fw_mac_sequence = false,220.support_dual_stations = false,221.pdev_suspend = false,222},223{224.name = "qca6390 hw2.0",225.hw_rev = ATH11K_HW_QCA6390_HW20,226.fw = {227.dir = "QCA6390/hw2.0",228.board_size = 256 * 1024,229.cal_offset = 128 * 1024,230},231.max_radios = 3,232.bdf_addr = 0x4B0C0000,233.hw_ops = &qca6390_ops,234.ring_mask = &ath11k_hw_ring_mask_qca6390,235.internal_sleep_clock = true,236.regs = &qca6390_regs,237.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390,238.host_ce_config = ath11k_host_ce_config_qca6390,239.ce_count = 9,240.target_ce_config = ath11k_target_ce_config_wlan_qca6390,241.target_ce_count = 9,242.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,243.svc_to_ce_map_len = 14,244.ce_ie_addr = &ath11k_ce_ie_addr_ipq8074,245.single_pdev_only = true,246.rxdma1_enable = false,247.num_rxdma_per_pdev = 2,248.rx_mac_buf_ring = true,249.vdev_start_delay = true,250.htt_peer_map_v2 = false,251252.spectral = {253.fft_sz = 0,254.fft_pad_sz = 0,255.summary_pad_sz = 0,256.fft_hdr_len = 0,257.max_fft_bins = 0,258.fragment_160mhz = false,259},260261.interface_modes = BIT(NL80211_IFTYPE_STATION) |262BIT(NL80211_IFTYPE_AP) |263BIT(NL80211_IFTYPE_P2P_DEVICE) |264BIT(NL80211_IFTYPE_P2P_CLIENT) |265BIT(NL80211_IFTYPE_P2P_GO),266.supports_monitor = false,267.full_monitor_mode = false,268.supports_shadow_regs = true,269.idle_ps = true,270.supports_sta_ps = true,271.coldboot_cal_mm = false,272.coldboot_cal_ftm = false,273.cbcal_restart_fw = false,274.fw_mem_mode = 0,275.num_vdevs = 2 + 1,276.num_peers = 512,277.supports_suspend = true,278.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),279.supports_regdb = false,280.fix_l1ss = true,281.credit_flow = true,282.max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390,283.hal_params = &ath11k_hw_hal_params_qca6390,284.supports_dynamic_smps_6ghz = false,285.alloc_cacheable_memory = false,286.supports_rssi_stats = true,287.fw_wmi_diag_event = true,288.current_cc_support = true,289.dbr_debug_support = false,290.global_reset = true,291.bios_sar_capa = NULL,292.m3_fw_support = true,293.fixed_bdf_addr = false,294.fixed_mem_region = false,295.static_window_map = false,296.hybrid_bus_type = false,297.fixed_fw_mem = false,298.support_off_channel_tx = true,299.supports_multi_bssid = true,300301.sram_dump = {302.start = 0x01400000,303.end = 0x0171ffff,304},305306.tcl_ring_retry = true,307.tx_ring_size = DP_TCL_DATA_RING_SIZE,308.smp2p_wow_exit = false,309.support_fw_mac_sequence = true,310.support_dual_stations = true,311.pdev_suspend = false,312},313{314.name = "qcn9074 hw1.0",315.hw_rev = ATH11K_HW_QCN9074_HW10,316.fw = {317.dir = "QCN9074/hw1.0",318.board_size = 256 * 1024,319.cal_offset = 128 * 1024,320},321.max_radios = 1,322.single_pdev_only = false,323.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9074,324.hw_ops = &qcn9074_ops,325.ring_mask = &ath11k_hw_ring_mask_qcn9074,326.internal_sleep_clock = false,327.regs = &qcn9074_regs,328.host_ce_config = ath11k_host_ce_config_qcn9074,329.ce_count = 6,330.target_ce_config = ath11k_target_ce_config_wlan_qcn9074,331.target_ce_count = 9,332.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qcn9074,333.svc_to_ce_map_len = 18,334.ce_ie_addr = &ath11k_ce_ie_addr_ipq8074,335.rxdma1_enable = true,336.num_rxdma_per_pdev = 1,337.rx_mac_buf_ring = false,338.vdev_start_delay = false,339.htt_peer_map_v2 = true,340341.spectral = {342.fft_sz = 2,343.fft_pad_sz = 0,344.summary_pad_sz = 16,345.fft_hdr_len = 24,346.max_fft_bins = 1024,347.fragment_160mhz = false,348},349350.interface_modes = BIT(NL80211_IFTYPE_STATION) |351BIT(NL80211_IFTYPE_AP) |352BIT(NL80211_IFTYPE_MESH_POINT),353.supports_monitor = true,354.full_monitor_mode = true,355.supports_shadow_regs = false,356.idle_ps = false,357.supports_sta_ps = false,358.coldboot_cal_mm = false,359.coldboot_cal_ftm = true,360.cbcal_restart_fw = true,361.fw_mem_mode = 2,362.num_vdevs = 8,363.num_peers = 128,364.supports_suspend = false,365.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),366.supports_regdb = false,367.fix_l1ss = true,368.credit_flow = false,369.max_tx_ring = DP_TCL_NUM_RING_MAX,370.hal_params = &ath11k_hw_hal_params_ipq8074,371.supports_dynamic_smps_6ghz = true,372.alloc_cacheable_memory = true,373.supports_rssi_stats = false,374.fw_wmi_diag_event = false,375.current_cc_support = false,376.dbr_debug_support = true,377.global_reset = false,378.bios_sar_capa = NULL,379.m3_fw_support = true,380.fixed_bdf_addr = false,381.fixed_mem_region = false,382.static_window_map = true,383.hybrid_bus_type = false,384.fixed_fw_mem = false,385.support_off_channel_tx = false,386.supports_multi_bssid = false,387388.sram_dump = {},389390.tcl_ring_retry = true,391.tx_ring_size = DP_TCL_DATA_RING_SIZE,392.smp2p_wow_exit = false,393.support_fw_mac_sequence = false,394.support_dual_stations = false,395.pdev_suspend = false,396},397{398.name = "wcn6855 hw2.0",399.hw_rev = ATH11K_HW_WCN6855_HW20,400.fw = {401.dir = "WCN6855/hw2.0",402.board_size = 256 * 1024,403.cal_offset = 128 * 1024,404},405.max_radios = 3,406.bdf_addr = 0x4B0C0000,407.hw_ops = &wcn6855_ops,408.ring_mask = &ath11k_hw_ring_mask_qca6390,409.internal_sleep_clock = true,410.regs = &wcn6855_regs,411.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390,412.host_ce_config = ath11k_host_ce_config_qca6390,413.ce_count = 9,414.target_ce_config = ath11k_target_ce_config_wlan_qca6390,415.target_ce_count = 9,416.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,417.svc_to_ce_map_len = 14,418.ce_ie_addr = &ath11k_ce_ie_addr_ipq8074,419.single_pdev_only = true,420.rxdma1_enable = false,421.num_rxdma_per_pdev = 2,422.rx_mac_buf_ring = true,423.vdev_start_delay = true,424.htt_peer_map_v2 = false,425426.spectral = {427.fft_sz = 0,428.fft_pad_sz = 0,429.summary_pad_sz = 0,430.fft_hdr_len = 0,431.max_fft_bins = 0,432.fragment_160mhz = false,433},434435.interface_modes = BIT(NL80211_IFTYPE_STATION) |436BIT(NL80211_IFTYPE_AP) |437BIT(NL80211_IFTYPE_P2P_DEVICE) |438BIT(NL80211_IFTYPE_P2P_CLIENT) |439BIT(NL80211_IFTYPE_P2P_GO),440.supports_monitor = false,441.full_monitor_mode = false,442.supports_shadow_regs = true,443.idle_ps = true,444.supports_sta_ps = true,445.coldboot_cal_mm = false,446.coldboot_cal_ftm = false,447.cbcal_restart_fw = false,448.fw_mem_mode = 0,449.num_vdevs = 2 + 1,450.num_peers = 512,451.supports_suspend = true,452.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),453.supports_regdb = true,454.fix_l1ss = false,455.credit_flow = true,456.max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390,457.hal_params = &ath11k_hw_hal_params_qca6390,458.supports_dynamic_smps_6ghz = false,459.alloc_cacheable_memory = false,460.supports_rssi_stats = true,461.fw_wmi_diag_event = true,462.current_cc_support = true,463.dbr_debug_support = false,464.global_reset = true,465.bios_sar_capa = &ath11k_hw_sar_capa_wcn6855,466.m3_fw_support = true,467.fixed_bdf_addr = false,468.fixed_mem_region = false,469.static_window_map = false,470.hybrid_bus_type = false,471.fixed_fw_mem = false,472.support_off_channel_tx = true,473.supports_multi_bssid = true,474475.sram_dump = {476.start = 0x01400000,477.end = 0x0177ffff,478},479480.tcl_ring_retry = true,481.tx_ring_size = DP_TCL_DATA_RING_SIZE,482.smp2p_wow_exit = false,483.support_fw_mac_sequence = true,484.support_dual_stations = true,485.pdev_suspend = false,486},487{488.name = "wcn6855 hw2.1",489.hw_rev = ATH11K_HW_WCN6855_HW21,490.fw = {491.dir = "WCN6855/hw2.1",492.board_size = 256 * 1024,493.cal_offset = 128 * 1024,494},495.max_radios = 3,496.bdf_addr = 0x4B0C0000,497.hw_ops = &wcn6855_ops,498.ring_mask = &ath11k_hw_ring_mask_qca6390,499.internal_sleep_clock = true,500.regs = &wcn6855_regs,501.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390,502.host_ce_config = ath11k_host_ce_config_qca6390,503.ce_count = 9,504.target_ce_config = ath11k_target_ce_config_wlan_qca6390,505.target_ce_count = 9,506.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,507.svc_to_ce_map_len = 14,508.single_pdev_only = true,509.rxdma1_enable = false,510.num_rxdma_per_pdev = 2,511.rx_mac_buf_ring = true,512.vdev_start_delay = true,513.htt_peer_map_v2 = false,514515.spectral = {516.fft_sz = 0,517.fft_pad_sz = 0,518.summary_pad_sz = 0,519.fft_hdr_len = 0,520.max_fft_bins = 0,521.fragment_160mhz = false,522},523524.interface_modes = BIT(NL80211_IFTYPE_STATION) |525BIT(NL80211_IFTYPE_AP) |526BIT(NL80211_IFTYPE_P2P_DEVICE) |527BIT(NL80211_IFTYPE_P2P_CLIENT) |528BIT(NL80211_IFTYPE_P2P_GO),529.supports_monitor = false,530.supports_shadow_regs = true,531.idle_ps = true,532.supports_sta_ps = true,533.coldboot_cal_mm = false,534.coldboot_cal_ftm = false,535.cbcal_restart_fw = false,536.fw_mem_mode = 0,537.num_vdevs = 2 + 1,538.num_peers = 512,539.supports_suspend = true,540.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),541.supports_regdb = true,542.fix_l1ss = false,543.credit_flow = true,544.max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390,545.hal_params = &ath11k_hw_hal_params_qca6390,546.supports_dynamic_smps_6ghz = false,547.alloc_cacheable_memory = false,548.supports_rssi_stats = true,549.fw_wmi_diag_event = true,550.current_cc_support = true,551.dbr_debug_support = false,552.global_reset = true,553.bios_sar_capa = &ath11k_hw_sar_capa_wcn6855,554.m3_fw_support = true,555.fixed_bdf_addr = false,556.fixed_mem_region = false,557.static_window_map = false,558.hybrid_bus_type = false,559.fixed_fw_mem = false,560.support_off_channel_tx = true,561.supports_multi_bssid = true,562563.sram_dump = {564.start = 0x01400000,565.end = 0x0177ffff,566},567568.tcl_ring_retry = true,569.tx_ring_size = DP_TCL_DATA_RING_SIZE,570.smp2p_wow_exit = false,571.support_fw_mac_sequence = true,572.support_dual_stations = true,573.pdev_suspend = false,574},575{576.name = "wcn6750 hw1.0",577.hw_rev = ATH11K_HW_WCN6750_HW10,578.fw = {579.dir = "WCN6750/hw1.0",580.board_size = 256 * 1024,581.cal_offset = 128 * 1024,582},583.max_radios = 1,584.bdf_addr = 0x4B0C0000,585.hw_ops = &wcn6750_ops,586.ring_mask = &ath11k_hw_ring_mask_wcn6750,587.internal_sleep_clock = false,588.regs = &wcn6750_regs,589.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_WCN6750,590.host_ce_config = ath11k_host_ce_config_qca6390,591.ce_count = 9,592.target_ce_config = ath11k_target_ce_config_wlan_qca6390,593.target_ce_count = 9,594.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,595.svc_to_ce_map_len = 14,596.ce_ie_addr = &ath11k_ce_ie_addr_ipq8074,597.single_pdev_only = true,598.rxdma1_enable = false,599.num_rxdma_per_pdev = 1,600.rx_mac_buf_ring = true,601.vdev_start_delay = true,602.htt_peer_map_v2 = false,603604.spectral = {605.fft_sz = 0,606.fft_pad_sz = 0,607.summary_pad_sz = 0,608.fft_hdr_len = 0,609.max_fft_bins = 0,610.fragment_160mhz = false,611},612613.interface_modes = BIT(NL80211_IFTYPE_STATION) |614BIT(NL80211_IFTYPE_AP),615.supports_monitor = false,616.supports_shadow_regs = true,617.idle_ps = true,618.supports_sta_ps = true,619.coldboot_cal_mm = true,620.coldboot_cal_ftm = true,621.cbcal_restart_fw = false,622.fw_mem_mode = 0,623.num_vdevs = 3,624.num_peers = 512,625.supports_suspend = false,626.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),627.supports_regdb = true,628.fix_l1ss = false,629.credit_flow = true,630.max_tx_ring = DP_TCL_NUM_RING_MAX,631.hal_params = &ath11k_hw_hal_params_wcn6750,632.supports_dynamic_smps_6ghz = false,633.alloc_cacheable_memory = false,634.supports_rssi_stats = true,635.fw_wmi_diag_event = true,636.current_cc_support = true,637.dbr_debug_support = false,638.global_reset = false,639.bios_sar_capa = &ath11k_hw_sar_capa_wcn6855,640.m3_fw_support = false,641.fixed_bdf_addr = false,642.fixed_mem_region = false,643.static_window_map = true,644.hybrid_bus_type = true,645.fixed_fw_mem = true,646.support_off_channel_tx = true,647.supports_multi_bssid = true,648649.sram_dump = {},650651.tcl_ring_retry = false,652.tx_ring_size = DP_TCL_DATA_RING_SIZE_WCN6750,653.smp2p_wow_exit = true,654.support_fw_mac_sequence = true,655.support_dual_stations = false,656.pdev_suspend = true,657},658{659.hw_rev = ATH11K_HW_IPQ5018_HW10,660.name = "ipq5018 hw1.0",661.fw = {662.dir = "IPQ5018/hw1.0",663.board_size = 256 * 1024,664.cal_offset = 128 * 1024,665},666.max_radios = MAX_RADIOS_5018,667.bdf_addr = 0x4BA00000,668/* hal_desc_sz and hw ops are similar to qcn9074 */669.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),670.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ8074,671.ring_mask = &ath11k_hw_ring_mask_ipq8074,672.credit_flow = false,673.max_tx_ring = 1,674.spectral = {675.fft_sz = 2,676.fft_pad_sz = 0,677.summary_pad_sz = 16,678.fft_hdr_len = 24,679.max_fft_bins = 1024,680},681.internal_sleep_clock = false,682.regs = &ipq5018_regs,683.hw_ops = &ipq5018_ops,684.host_ce_config = ath11k_host_ce_config_qcn9074,685.ce_count = CE_CNT_5018,686.target_ce_config = ath11k_target_ce_config_wlan_ipq5018,687.target_ce_count = TARGET_CE_CNT_5018,688.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_ipq5018,689.svc_to_ce_map_len = SVC_CE_MAP_LEN_5018,690.ce_ie_addr = &ath11k_ce_ie_addr_ipq5018,691.ce_remap = &ath11k_ce_remap_ipq5018,692.rxdma1_enable = true,693.num_rxdma_per_pdev = RXDMA_PER_PDEV_5018,694.rx_mac_buf_ring = false,695.vdev_start_delay = false,696.htt_peer_map_v2 = true,697.interface_modes = BIT(NL80211_IFTYPE_STATION) |698BIT(NL80211_IFTYPE_AP) |699BIT(NL80211_IFTYPE_MESH_POINT),700.supports_monitor = false,701.supports_sta_ps = false,702.supports_shadow_regs = false,703.fw_mem_mode = 0,704.num_vdevs = 16 + 1,705.num_peers = 512,706.supports_regdb = false,707.idle_ps = false,708.supports_suspend = false,709.hal_params = &ath11k_hw_hal_params_ipq8074,710.single_pdev_only = false,711.coldboot_cal_mm = true,712.coldboot_cal_ftm = true,713.cbcal_restart_fw = true,714.fix_l1ss = true,715.supports_dynamic_smps_6ghz = false,716.alloc_cacheable_memory = true,717.supports_rssi_stats = false,718.fw_wmi_diag_event = false,719.current_cc_support = false,720.dbr_debug_support = true,721.global_reset = false,722.bios_sar_capa = NULL,723.m3_fw_support = false,724.fixed_bdf_addr = true,725.fixed_mem_region = true,726.static_window_map = false,727.hybrid_bus_type = false,728.fixed_fw_mem = false,729.support_off_channel_tx = false,730.supports_multi_bssid = false,731732.sram_dump = {},733734.tcl_ring_retry = true,735.tx_ring_size = DP_TCL_DATA_RING_SIZE,736.smp2p_wow_exit = false,737.support_fw_mac_sequence = false,738.support_dual_stations = false,739.pdev_suspend = false,740},741{742.name = "qca2066 hw2.1",743.hw_rev = ATH11K_HW_QCA2066_HW21,744.fw = {745.dir = "QCA2066/hw2.1",746.board_size = 256 * 1024,747.cal_offset = 128 * 1024,748},749.max_radios = 3,750.bdf_addr = 0x4B0C0000,751.hw_ops = &wcn6855_ops,752.ring_mask = &ath11k_hw_ring_mask_qca6390,753.internal_sleep_clock = true,754.regs = &wcn6855_regs,755.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390,756.host_ce_config = ath11k_host_ce_config_qca6390,757.ce_count = 9,758.target_ce_config = ath11k_target_ce_config_wlan_qca6390,759.target_ce_count = 9,760.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,761.svc_to_ce_map_len = 14,762.ce_ie_addr = &ath11k_ce_ie_addr_ipq8074,763.single_pdev_only = true,764.rxdma1_enable = false,765.num_rxdma_per_pdev = 2,766.rx_mac_buf_ring = true,767.vdev_start_delay = true,768.htt_peer_map_v2 = false,769770.spectral = {771.fft_sz = 0,772.fft_pad_sz = 0,773.summary_pad_sz = 0,774.fft_hdr_len = 0,775.max_fft_bins = 0,776.fragment_160mhz = false,777},778779.interface_modes = BIT(NL80211_IFTYPE_STATION) |780BIT(NL80211_IFTYPE_AP) |781BIT(NL80211_IFTYPE_P2P_DEVICE) |782BIT(NL80211_IFTYPE_P2P_CLIENT) |783BIT(NL80211_IFTYPE_P2P_GO),784.supports_monitor = false,785.full_monitor_mode = false,786.supports_shadow_regs = true,787.idle_ps = true,788.supports_sta_ps = true,789.coldboot_cal_mm = false,790.coldboot_cal_ftm = false,791.cbcal_restart_fw = false,792.fw_mem_mode = 0,793.num_vdevs = 2 + 1,794.num_peers = 512,795.supports_suspend = true,796.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),797.supports_regdb = true,798.fix_l1ss = false,799.credit_flow = true,800.max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390,801.hal_params = &ath11k_hw_hal_params_qca6390,802.supports_dynamic_smps_6ghz = false,803.alloc_cacheable_memory = false,804.supports_rssi_stats = true,805.fw_wmi_diag_event = true,806.current_cc_support = true,807.dbr_debug_support = false,808.global_reset = true,809.bios_sar_capa = &ath11k_hw_sar_capa_wcn6855,810.m3_fw_support = true,811.fixed_bdf_addr = false,812.fixed_mem_region = false,813.static_window_map = false,814.hybrid_bus_type = false,815.fixed_fw_mem = false,816.support_off_channel_tx = true,817.supports_multi_bssid = true,818819.sram_dump = {820.start = 0x01400000,821.end = 0x0177ffff,822},823824.tcl_ring_retry = true,825.tx_ring_size = DP_TCL_DATA_RING_SIZE,826.smp2p_wow_exit = false,827.support_fw_mac_sequence = true,828.support_dual_stations = true,829},830{831.name = "qca6698aq hw2.1",832.hw_rev = ATH11K_HW_QCA6698AQ_HW21,833.fw = {834.dir = "QCA6698AQ/hw2.1",835.board_size = 256 * 1024,836.cal_offset = 128 * 1024,837},838.max_radios = 3,839.bdf_addr = 0x4B0C0000,840.hw_ops = &wcn6855_ops,841.ring_mask = &ath11k_hw_ring_mask_qca6390,842.internal_sleep_clock = true,843.regs = &wcn6855_regs,844.qmi_service_ins_id = ATH11K_QMI_WLFW_SERVICE_INS_ID_V01_QCA6390,845.host_ce_config = ath11k_host_ce_config_qca6390,846.ce_count = 9,847.target_ce_config = ath11k_target_ce_config_wlan_qca6390,848.target_ce_count = 9,849.svc_to_ce_map = ath11k_target_service_to_ce_map_wlan_qca6390,850.svc_to_ce_map_len = 14,851.single_pdev_only = true,852.rxdma1_enable = false,853.num_rxdma_per_pdev = 2,854.rx_mac_buf_ring = true,855.vdev_start_delay = true,856.htt_peer_map_v2 = false,857858.spectral = {859.fft_sz = 0,860.fft_pad_sz = 0,861.summary_pad_sz = 0,862.fft_hdr_len = 0,863.max_fft_bins = 0,864.fragment_160mhz = false,865},866867.interface_modes = BIT(NL80211_IFTYPE_STATION) |868BIT(NL80211_IFTYPE_AP) |869BIT(NL80211_IFTYPE_P2P_DEVICE) |870BIT(NL80211_IFTYPE_P2P_CLIENT) |871BIT(NL80211_IFTYPE_P2P_GO),872.supports_monitor = false,873.supports_shadow_regs = true,874.idle_ps = true,875.supports_sta_ps = true,876.coldboot_cal_mm = false,877.coldboot_cal_ftm = false,878.cbcal_restart_fw = false,879.fw_mem_mode = 0,880.num_vdevs = 2 + 1,881.num_peers = 512,882.supports_suspend = true,883.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),884.supports_regdb = true,885.fix_l1ss = false,886.credit_flow = true,887.max_tx_ring = DP_TCL_NUM_RING_MAX_QCA6390,888.hal_params = &ath11k_hw_hal_params_qca6390,889.supports_dynamic_smps_6ghz = false,890.alloc_cacheable_memory = false,891.supports_rssi_stats = true,892.fw_wmi_diag_event = true,893.current_cc_support = true,894.dbr_debug_support = false,895.global_reset = true,896.bios_sar_capa = &ath11k_hw_sar_capa_wcn6855,897.m3_fw_support = true,898.fixed_bdf_addr = false,899.fixed_mem_region = false,900.static_window_map = false,901.hybrid_bus_type = false,902.fixed_fw_mem = false,903.support_off_channel_tx = true,904.supports_multi_bssid = true,905906.sram_dump = {907.start = 0x01400000,908.end = 0x0177ffff,909},910911.tcl_ring_retry = true,912.tx_ring_size = DP_TCL_DATA_RING_SIZE,913.smp2p_wow_exit = false,914.support_fw_mac_sequence = true,915.support_dual_stations = true,916.pdev_suspend = false,917},918};919920static const struct dmi_system_id ath11k_pm_quirk_table[] = {921{922.driver_data = (void *)ATH11K_PM_WOW,923.matches = { /* X13 G4 AMD #1 */924DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),925DMI_MATCH(DMI_PRODUCT_NAME, "21J3"),926},927},928{929.driver_data = (void *)ATH11K_PM_WOW,930.matches = { /* X13 G4 AMD #2 */931DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),932DMI_MATCH(DMI_PRODUCT_NAME, "21J4"),933},934},935{936.driver_data = (void *)ATH11K_PM_WOW,937.matches = { /* T14 G4 AMD #1 */938DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),939DMI_MATCH(DMI_PRODUCT_NAME, "21K3"),940},941},942{943.driver_data = (void *)ATH11K_PM_WOW,944.matches = { /* T14 G4 AMD #2 */945DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),946DMI_MATCH(DMI_PRODUCT_NAME, "21K4"),947},948},949{950.driver_data = (void *)ATH11K_PM_WOW,951.matches = { /* P14s G4 AMD #1 */952DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),953DMI_MATCH(DMI_PRODUCT_NAME, "21K5"),954},955},956{957.driver_data = (void *)ATH11K_PM_WOW,958.matches = { /* P14s G4 AMD #2 */959DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),960DMI_MATCH(DMI_PRODUCT_NAME, "21K6"),961},962},963{964.driver_data = (void *)ATH11K_PM_WOW,965.matches = { /* T16 G2 AMD #1 */966DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),967DMI_MATCH(DMI_PRODUCT_NAME, "21K7"),968},969},970{971.driver_data = (void *)ATH11K_PM_WOW,972.matches = { /* T16 G2 AMD #2 */973DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),974DMI_MATCH(DMI_PRODUCT_NAME, "21K8"),975},976},977{978.driver_data = (void *)ATH11K_PM_WOW,979.matches = { /* P16s G2 AMD #1 */980DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),981DMI_MATCH(DMI_PRODUCT_NAME, "21K9"),982},983},984{985.driver_data = (void *)ATH11K_PM_WOW,986.matches = { /* P16s G2 AMD #2 */987DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),988DMI_MATCH(DMI_PRODUCT_NAME, "21KA"),989},990},991{992.driver_data = (void *)ATH11K_PM_WOW,993.matches = { /* T14s G4 AMD #1 */994DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),995DMI_MATCH(DMI_PRODUCT_NAME, "21F8"),996},997},998{999.driver_data = (void *)ATH11K_PM_WOW,1000.matches = { /* T14s G4 AMD #2 */1001DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),1002DMI_MATCH(DMI_PRODUCT_NAME, "21F9"),1003},1004},1005{}1006};10071008void ath11k_fw_stats_pdevs_free(struct list_head *head)1009{1010struct ath11k_fw_stats_pdev *i, *tmp;10111012list_for_each_entry_safe(i, tmp, head, list) {1013list_del(&i->list);1014kfree(i);1015}1016}10171018void ath11k_fw_stats_vdevs_free(struct list_head *head)1019{1020struct ath11k_fw_stats_vdev *i, *tmp;10211022list_for_each_entry_safe(i, tmp, head, list) {1023list_del(&i->list);1024kfree(i);1025}1026}10271028void ath11k_fw_stats_bcn_free(struct list_head *head)1029{1030struct ath11k_fw_stats_bcn *i, *tmp;10311032list_for_each_entry_safe(i, tmp, head, list) {1033list_del(&i->list);1034kfree(i);1035}1036}10371038void ath11k_fw_stats_init(struct ath11k *ar)1039{1040INIT_LIST_HEAD(&ar->fw_stats.pdevs);1041INIT_LIST_HEAD(&ar->fw_stats.vdevs);1042INIT_LIST_HEAD(&ar->fw_stats.bcn);10431044init_completion(&ar->fw_stats_complete);1045init_completion(&ar->fw_stats_done);1046}10471048void ath11k_fw_stats_free(struct ath11k_fw_stats *stats)1049{1050ath11k_fw_stats_pdevs_free(&stats->pdevs);1051ath11k_fw_stats_vdevs_free(&stats->vdevs);1052ath11k_fw_stats_bcn_free(&stats->bcn);1053}10541055bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab)1056{1057if (!ath11k_cold_boot_cal)1058return false;10591060if (ath11k_ftm_mode)1061return ab->hw_params.coldboot_cal_ftm;10621063else1064return ab->hw_params.coldboot_cal_mm;1065}10661067/* Check if we need to continue with suspend/resume operation.1068* Return:1069* a negative value: error happens and don't continue.1070* 0: no error but don't continue.1071* positive value: no error and do continue.1072*/1073static int ath11k_core_continue_suspend_resume(struct ath11k_base *ab)1074{1075struct ath11k *ar;10761077if (!ab->hw_params.supports_suspend)1078return -EOPNOTSUPP;10791080/* so far single_pdev_only chips have supports_suspend as true1081* so pass 0 as a dummy pdev_id here.1082*/1083ar = ab->pdevs[0].ar;1084if (!ar || ar->state != ATH11K_STATE_OFF)1085return 0;10861087return 1;1088}10891090static int ath11k_core_suspend_wow(struct ath11k_base *ab)1091{1092int ret;10931094ret = ath11k_dp_rx_pktlog_stop(ab, true);1095if (ret) {1096ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",1097ret);1098return ret;1099}11001101/* So far only single_pdev_only devices can reach here,1102* so it is valid to handle the first, and the only, pdev.1103*/1104ret = ath11k_mac_wait_tx_complete(ab->pdevs[0].ar);1105if (ret) {1106ath11k_warn(ab, "failed to wait tx complete: %d\n", ret);1107return ret;1108}11091110ret = ath11k_wow_enable(ab);1111if (ret) {1112ath11k_warn(ab, "failed to enable wow during suspend: %d\n", ret);1113return ret;1114}11151116ret = ath11k_dp_rx_pktlog_stop(ab, false);1117if (ret) {1118ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",1119ret);1120return ret;1121}11221123ath11k_ce_stop_shadow_timers(ab);1124ath11k_dp_stop_shadow_timers(ab);11251126ath11k_hif_irq_disable(ab);1127ath11k_hif_ce_irq_disable(ab);11281129ret = ath11k_hif_suspend(ab);1130if (ret) {1131ath11k_warn(ab, "failed to suspend hif: %d\n", ret);1132return ret;1133}11341135return 0;1136}11371138static int ath11k_core_suspend_default(struct ath11k_base *ab)1139{1140int ret;11411142ret = ath11k_dp_rx_pktlog_stop(ab, true);1143if (ret) {1144ath11k_warn(ab, "failed to stop dp rx (and timer) pktlog during suspend: %d\n",1145ret);1146return ret;1147}11481149/* So far only single_pdev_only devices can reach here,1150* so it is valid to handle the first, and the only, pdev.1151*/1152ret = ath11k_mac_wait_tx_complete(ab->pdevs[0].ar);1153if (ret) {1154ath11k_warn(ab, "failed to wait tx complete: %d\n", ret);1155return ret;1156}11571158ret = ath11k_dp_rx_pktlog_stop(ab, false);1159if (ret) {1160ath11k_warn(ab, "failed to stop dp rx pktlog during suspend: %d\n",1161ret);1162return ret;1163}11641165ath11k_ce_stop_shadow_timers(ab);1166ath11k_dp_stop_shadow_timers(ab);11671168/* PM framework skips suspend_late/resume_early callbacks1169* if other devices report errors in their suspend callbacks.1170* However ath11k_core_resume() would still be called because1171* here we return success thus kernel put us on dpm_suspended_list.1172* Since we won't go through a power down/up cycle, there is1173* no chance to call complete(&ab->restart_completed) in1174* ath11k_core_restart(), making ath11k_core_resume() timeout.1175* So call it here to avoid this issue. This also works in case1176* no error happens thus suspend_late/resume_early get called,1177* because it will be reinitialized in ath11k_core_resume_early().1178*/1179complete(&ab->restart_completed);11801181return 0;1182}11831184int ath11k_core_suspend(struct ath11k_base *ab)1185{1186int ret;11871188ret = ath11k_core_continue_suspend_resume(ab);1189if (ret <= 0)1190return ret;11911192if (ab->actual_pm_policy == ATH11K_PM_WOW)1193return ath11k_core_suspend_wow(ab);11941195return ath11k_core_suspend_default(ab);1196}1197EXPORT_SYMBOL(ath11k_core_suspend);11981199int ath11k_core_suspend_late(struct ath11k_base *ab)1200{1201int ret;12021203ret = ath11k_core_continue_suspend_resume(ab);1204if (ret <= 0)1205return ret;12061207if (ab->actual_pm_policy == ATH11K_PM_WOW)1208return 0;12091210ath11k_hif_irq_disable(ab);1211ath11k_hif_ce_irq_disable(ab);12121213ath11k_hif_power_down(ab, true);12141215return 0;1216}1217EXPORT_SYMBOL(ath11k_core_suspend_late);12181219int ath11k_core_resume_early(struct ath11k_base *ab)1220{1221int ret;12221223ret = ath11k_core_continue_suspend_resume(ab);1224if (ret <= 0)1225return ret;12261227if (ab->actual_pm_policy == ATH11K_PM_WOW)1228return 0;12291230reinit_completion(&ab->restart_completed);1231ret = ath11k_hif_power_up(ab);1232if (ret)1233ath11k_warn(ab, "failed to power up hif during resume: %d\n", ret);12341235return ret;1236}1237EXPORT_SYMBOL(ath11k_core_resume_early);12381239static int ath11k_core_resume_default(struct ath11k_base *ab)1240{1241struct ath11k *ar;1242long time_left;1243int ret;12441245time_left = wait_for_completion_timeout(&ab->restart_completed,1246ATH11K_RESET_TIMEOUT_HZ);1247if (time_left == 0) {1248ath11k_warn(ab, "timeout while waiting for restart complete");1249return -ETIMEDOUT;1250}12511252/* So far only single_pdev_only devices can reach here,1253* so it is valid to handle the first, and the only, pdev.1254*/1255ar = ab->pdevs[0].ar;1256if (ab->hw_params.current_cc_support &&1257ar->alpha2[0] != 0 && ar->alpha2[1] != 0) {1258ret = ath11k_reg_set_cc(ar);1259if (ret) {1260ath11k_warn(ab, "failed to set country code during resume: %d\n",1261ret);1262return ret;1263}1264}12651266ret = ath11k_dp_rx_pktlog_start(ab);1267if (ret)1268ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n",1269ret);12701271return ret;1272}12731274static int ath11k_core_resume_wow(struct ath11k_base *ab)1275{1276int ret;12771278ret = ath11k_hif_resume(ab);1279if (ret) {1280ath11k_warn(ab, "failed to resume hif during resume: %d\n", ret);1281return ret;1282}12831284ath11k_hif_ce_irq_enable(ab);1285ath11k_hif_irq_enable(ab);12861287ret = ath11k_dp_rx_pktlog_start(ab);1288if (ret) {1289ath11k_warn(ab, "failed to start rx pktlog during resume: %d\n",1290ret);1291return ret;1292}12931294ret = ath11k_wow_wakeup(ab);1295if (ret) {1296ath11k_warn(ab, "failed to wakeup wow during resume: %d\n", ret);1297return ret;1298}12991300return 0;1301}13021303int ath11k_core_resume(struct ath11k_base *ab)1304{1305int ret;13061307ret = ath11k_core_continue_suspend_resume(ab);1308if (ret <= 0)1309return ret;13101311if (ab->actual_pm_policy == ATH11K_PM_WOW)1312return ath11k_core_resume_wow(ab);13131314return ath11k_core_resume_default(ab);1315}1316EXPORT_SYMBOL(ath11k_core_resume);13171318static void ath11k_core_check_cc_code_bdfext(const struct dmi_header *hdr, void *data)1319{1320struct ath11k_base *ab = data;1321const char *magic = ATH11K_SMBIOS_BDF_EXT_MAGIC;1322#if defined(__linux__)1323struct ath11k_smbios_bdf *smbios = (struct ath11k_smbios_bdf *)hdr;1324#elif defined(__FreeBSD__)1325const struct ath11k_smbios_bdf *smbios = (const struct ath11k_smbios_bdf *)hdr;1326#endif1327ssize_t copied;1328size_t len;1329int i;13301331if (ab->qmi.target.bdf_ext[0] != '\0')1332return;13331334if (hdr->type != ATH11K_SMBIOS_BDF_EXT_TYPE)1335return;13361337if (hdr->length != ATH11K_SMBIOS_BDF_EXT_LENGTH) {1338ath11k_dbg(ab, ATH11K_DBG_BOOT,1339"wrong smbios bdf ext type length (%d).\n",1340hdr->length);1341return;1342}13431344spin_lock_bh(&ab->base_lock);13451346switch (smbios->country_code_flag) {1347case ATH11K_SMBIOS_CC_ISO:1348ab->new_alpha2[0] = (smbios->cc_code >> 8) & 0xff;1349ab->new_alpha2[1] = smbios->cc_code & 0xff;1350ath11k_dbg(ab, ATH11K_DBG_BOOT, "smbios cc_code %c%c\n",1351ab->new_alpha2[0], ab->new_alpha2[1]);1352break;1353case ATH11K_SMBIOS_CC_WW:1354ab->new_alpha2[0] = '0';1355ab->new_alpha2[1] = '0';1356ath11k_dbg(ab, ATH11K_DBG_BOOT, "smbios worldwide regdomain\n");1357break;1358default:1359ath11k_dbg(ab, ATH11K_DBG_BOOT, "ignore smbios country code setting %d\n",1360smbios->country_code_flag);1361break;1362}13631364spin_unlock_bh(&ab->base_lock);13651366if (!smbios->bdf_enabled) {1367ath11k_dbg(ab, ATH11K_DBG_BOOT, "bdf variant name not found.\n");1368return;1369}13701371/* Only one string exists (per spec) */1372if (memcmp(smbios->bdf_ext, magic, strlen(magic)) != 0) {1373ath11k_dbg(ab, ATH11K_DBG_BOOT,1374"bdf variant magic does not match.\n");1375return;1376}13771378len = min_t(size_t,1379strlen(smbios->bdf_ext), sizeof(ab->qmi.target.bdf_ext));1380for (i = 0; i < len; i++) {1381if (!isascii(smbios->bdf_ext[i]) || !isprint(smbios->bdf_ext[i])) {1382ath11k_dbg(ab, ATH11K_DBG_BOOT,1383"bdf variant name contains non ascii chars.\n");1384return;1385}1386}13871388/* Copy extension name without magic prefix */1389copied = strscpy(ab->qmi.target.bdf_ext, smbios->bdf_ext + strlen(magic),1390sizeof(ab->qmi.target.bdf_ext));1391if (copied < 0) {1392ath11k_dbg(ab, ATH11K_DBG_BOOT,1393"bdf variant string is longer than the buffer can accommodate\n");1394return;1395}13961397ath11k_dbg(ab, ATH11K_DBG_BOOT,1398"found and validated bdf variant smbios_type 0x%x bdf %s\n",1399ATH11K_SMBIOS_BDF_EXT_TYPE, ab->qmi.target.bdf_ext);1400}14011402int ath11k_core_check_smbios(struct ath11k_base *ab)1403{1404ab->qmi.target.bdf_ext[0] = '\0';1405dmi_walk(ath11k_core_check_cc_code_bdfext, ab);14061407if (ab->qmi.target.bdf_ext[0] == '\0')1408return -ENODATA;14091410return 0;1411}14121413int ath11k_core_check_dt(struct ath11k_base *ab)1414{1415#if defined(__linux__)1416size_t max_len = sizeof(ab->qmi.target.bdf_ext);1417const char *variant = NULL;1418struct device_node *node;14191420node = ab->dev->of_node;1421if (!node)1422return -ENOENT;14231424of_property_read_string(node, "qcom,calibration-variant",1425&variant);1426if (!variant)1427of_property_read_string(node, "qcom,ath11k-calibration-variant",1428&variant);1429if (!variant)1430return -ENODATA;14311432if (strscpy(ab->qmi.target.bdf_ext, variant, max_len) < 0)1433ath11k_dbg(ab, ATH11K_DBG_BOOT,1434"bdf variant string is longer than the buffer can accommodate (variant: %s)\n",1435variant);14361437return 0;1438#elif defined(__FreeBSD__)1439return -ENOENT;1440#endif1441}14421443enum ath11k_bdf_name_type {1444ATH11K_BDF_NAME_FULL,1445ATH11K_BDF_NAME_BUS_NAME,1446ATH11K_BDF_NAME_CHIP_ID,1447};14481449static int __ath11k_core_create_board_name(struct ath11k_base *ab, char *name,1450size_t name_len, bool with_variant,1451enum ath11k_bdf_name_type name_type)1452{1453/* strlen(',variant=') + strlen(ab->qmi.target.bdf_ext) */1454char variant[9 + ATH11K_QMI_BDF_EXT_STR_LENGTH] = {};14551456if (with_variant && ab->qmi.target.bdf_ext[0] != '\0')1457scnprintf(variant, sizeof(variant), ",variant=%s",1458ab->qmi.target.bdf_ext);14591460switch (ab->id.bdf_search) {1461case ATH11K_BDF_SEARCH_BUS_AND_BOARD:1462switch (name_type) {1463case ATH11K_BDF_NAME_FULL:1464scnprintf(name, name_len,1465"bus=%s,vendor=%04x,device=%04x,subsystem-vendor=%04x,subsystem-device=%04x,qmi-chip-id=%d,qmi-board-id=%d%s",1466ath11k_bus_str(ab->hif.bus),1467ab->id.vendor, ab->id.device,1468ab->id.subsystem_vendor,1469ab->id.subsystem_device,1470ab->qmi.target.chip_id,1471ab->qmi.target.board_id,1472variant);1473break;1474case ATH11K_BDF_NAME_BUS_NAME:1475scnprintf(name, name_len,1476"bus=%s",1477ath11k_bus_str(ab->hif.bus));1478break;1479case ATH11K_BDF_NAME_CHIP_ID:1480scnprintf(name, name_len,1481"bus=%s,qmi-chip-id=%d",1482ath11k_bus_str(ab->hif.bus),1483ab->qmi.target.chip_id);1484break;1485}1486break;1487default:1488scnprintf(name, name_len,1489"bus=%s,qmi-chip-id=%d,qmi-board-id=%d%s",1490ath11k_bus_str(ab->hif.bus),1491ab->qmi.target.chip_id,1492ab->qmi.target.board_id, variant);1493break;1494}14951496ath11k_dbg(ab, ATH11K_DBG_BOOT, "using board name '%s'\n", name);14971498return 0;1499}15001501static int ath11k_core_create_board_name(struct ath11k_base *ab, char *name,1502size_t name_len)1503{1504return __ath11k_core_create_board_name(ab, name, name_len, true,1505ATH11K_BDF_NAME_FULL);1506}15071508static int ath11k_core_create_fallback_board_name(struct ath11k_base *ab, char *name,1509size_t name_len)1510{1511return __ath11k_core_create_board_name(ab, name, name_len, false,1512ATH11K_BDF_NAME_FULL);1513}15141515static int ath11k_core_create_bus_type_board_name(struct ath11k_base *ab, char *name,1516size_t name_len)1517{1518return __ath11k_core_create_board_name(ab, name, name_len, false,1519ATH11K_BDF_NAME_BUS_NAME);1520}15211522static int ath11k_core_create_chip_id_board_name(struct ath11k_base *ab, char *name,1523size_t name_len)1524{1525return __ath11k_core_create_board_name(ab, name, name_len, false,1526ATH11K_BDF_NAME_CHIP_ID);1527}15281529const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,1530const char *file)1531{1532const struct firmware *fw;1533char path[100];1534int ret;15351536if (file == NULL)1537return ERR_PTR(-ENOENT);15381539ath11k_core_create_firmware_path(ab, file, path, sizeof(path));15401541ret = firmware_request_nowarn(&fw, path, ab->dev);1542if (ret)1543return ERR_PTR(ret);15441545ath11k_dbg(ab, ATH11K_DBG_BOOT, "firmware request %s size %zu\n",1546path, fw->size);15471548return fw;1549}15501551void ath11k_core_free_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd)1552{1553if (!IS_ERR(bd->fw))1554release_firmware(bd->fw);15551556memset(bd, 0, sizeof(*bd));1557}15581559static int ath11k_core_parse_bd_ie_board(struct ath11k_base *ab,1560struct ath11k_board_data *bd,1561#if defined(__linux__)1562const void *buf, size_t buf_len,1563#elif defined(__FreeBSD__)1564const u8 *buf, size_t buf_len,1565#endif1566const char *boardname,1567int ie_id,1568int name_id,1569int data_id)1570{1571const struct ath11k_fw_ie *hdr;1572bool name_match_found;1573int ret, board_ie_id;1574size_t board_ie_len;1575const void *board_ie_data;15761577name_match_found = false;15781579/* go through ATH11K_BD_IE_BOARD_/ATH11K_BD_IE_REGDB_ elements */1580while (buf_len > sizeof(struct ath11k_fw_ie)) {1581#if defined(__linux__)1582hdr = buf;1583#elif defined(__FreeBSD__)1584hdr = (const struct ath11k_fw_ie *)buf;1585#endif1586board_ie_id = le32_to_cpu(hdr->id);1587board_ie_len = le32_to_cpu(hdr->len);1588board_ie_data = hdr->data;15891590buf_len -= sizeof(*hdr);1591buf += sizeof(*hdr);15921593if (buf_len < ALIGN(board_ie_len, 4)) {1594ath11k_err(ab, "invalid %s length: %zu < %zu\n",1595ath11k_bd_ie_type_str(ie_id),1596buf_len, ALIGN(board_ie_len, 4));1597ret = -EINVAL;1598goto out;1599}16001601if (board_ie_id == name_id) {1602ath11k_dbg_dump(ab, ATH11K_DBG_BOOT, "board name", "",1603board_ie_data, board_ie_len);16041605if (board_ie_len != strlen(boardname))1606goto next;16071608ret = memcmp(board_ie_data, boardname, strlen(boardname));1609if (ret)1610goto next;16111612name_match_found = true;1613ath11k_dbg(ab, ATH11K_DBG_BOOT,1614"found match %s for name '%s'",1615ath11k_bd_ie_type_str(ie_id),1616boardname);1617} else if (board_ie_id == data_id) {1618if (!name_match_found)1619/* no match found */1620goto next;16211622ath11k_dbg(ab, ATH11K_DBG_BOOT,1623"found %s for '%s'",1624ath11k_bd_ie_type_str(ie_id),1625boardname);16261627bd->data = board_ie_data;1628bd->len = board_ie_len;16291630ret = 0;1631goto out;1632} else {1633ath11k_warn(ab, "unknown %s id found: %d\n",1634ath11k_bd_ie_type_str(ie_id),1635board_ie_id);1636}1637next:1638/* jump over the padding */1639board_ie_len = ALIGN(board_ie_len, 4);16401641buf_len -= board_ie_len;1642buf += board_ie_len;1643}16441645/* no match found */1646ret = -ENOENT;16471648out:1649return ret;1650}16511652static int ath11k_core_fetch_board_data_api_n(struct ath11k_base *ab,1653struct ath11k_board_data *bd,1654const char *boardname,1655int ie_id_match,1656int name_id,1657int data_id)1658{1659size_t len, magic_len;1660const u8 *data;1661char *filename, filepath[100];1662size_t ie_len;1663#if defined(__linux__)1664struct ath11k_fw_ie *hdr;1665#elif defined(__FreeBSD__)1666const struct ath11k_fw_ie *hdr;1667#endif1668int ret, ie_id;16691670filename = ATH11K_BOARD_API2_FILE;16711672if (!bd->fw)1673bd->fw = ath11k_core_firmware_request(ab, filename);16741675if (IS_ERR(bd->fw))1676return PTR_ERR(bd->fw);16771678data = bd->fw->data;1679len = bd->fw->size;16801681ath11k_core_create_firmware_path(ab, filename,1682filepath, sizeof(filepath));16831684/* magic has extra null byte padded */1685magic_len = strlen(ATH11K_BOARD_MAGIC) + 1;1686if (len < magic_len) {1687ath11k_err(ab, "failed to find magic value in %s, file too short: %zu\n",1688filepath, len);1689ret = -EINVAL;1690goto err;1691}16921693if (memcmp(data, ATH11K_BOARD_MAGIC, magic_len)) {1694ath11k_err(ab, "found invalid board magic\n");1695ret = -EINVAL;1696goto err;1697}16981699/* magic is padded to 4 bytes */1700magic_len = ALIGN(magic_len, 4);1701if (len < magic_len) {1702ath11k_err(ab, "failed: %s too small to contain board data, len: %zu\n",1703filepath, len);1704ret = -EINVAL;1705goto err;1706}17071708data += magic_len;1709len -= magic_len;17101711while (len > sizeof(struct ath11k_fw_ie)) {1712#if defined(__linux__)1713hdr = (struct ath11k_fw_ie *)data;1714#elif defined(__FreeBSD__)1715hdr = (const struct ath11k_fw_ie *)data;1716#endif1717ie_id = le32_to_cpu(hdr->id);1718ie_len = le32_to_cpu(hdr->len);17191720len -= sizeof(*hdr);1721data = hdr->data;17221723if (len < ALIGN(ie_len, 4)) {1724ath11k_err(ab, "invalid length for board ie_id %d ie_len %zu len %zu\n",1725ie_id, ie_len, len);1726ret = -EINVAL;1727goto err;1728}17291730if (ie_id == ie_id_match) {1731ret = ath11k_core_parse_bd_ie_board(ab, bd, data,1732ie_len,1733boardname,1734ie_id_match,1735name_id,1736data_id);1737if (ret == -ENOENT)1738/* no match found, continue */1739goto next;1740else if (ret)1741/* there was an error, bail out */1742goto err;1743/* either found or error, so stop searching */1744goto out;1745}1746next:1747/* jump over the padding */1748ie_len = ALIGN(ie_len, 4);17491750len -= ie_len;1751data += ie_len;1752}17531754out:1755if (!bd->data || !bd->len) {1756ath11k_dbg(ab, ATH11K_DBG_BOOT,1757"failed to fetch %s for %s from %s\n",1758ath11k_bd_ie_type_str(ie_id_match),1759boardname, filepath);1760ret = -ENODATA;1761goto err;1762}17631764return 0;17651766err:1767ath11k_core_free_bdf(ab, bd);1768return ret;1769}17701771int ath11k_core_fetch_board_data_api_1(struct ath11k_base *ab,1772struct ath11k_board_data *bd,1773const char *name)1774{1775bd->fw = ath11k_core_firmware_request(ab, name);17761777if (IS_ERR(bd->fw))1778return PTR_ERR(bd->fw);17791780bd->data = bd->fw->data;1781bd->len = bd->fw->size;17821783return 0;1784}17851786#define BOARD_NAME_SIZE 2001787int ath11k_core_fetch_bdf(struct ath11k_base *ab, struct ath11k_board_data *bd)1788{1789char *boardname = NULL, *fallback_boardname = NULL, *chip_id_boardname = NULL;1790char *filename, filepath[100];1791int bd_api;1792int ret = 0;17931794filename = ATH11K_BOARD_API2_FILE;1795boardname = kzalloc(BOARD_NAME_SIZE, GFP_KERNEL);1796if (!boardname) {1797ret = -ENOMEM;1798goto exit;1799}18001801ret = ath11k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);1802if (ret) {1803ath11k_err(ab, "failed to create board name: %d", ret);1804goto exit;1805}18061807bd_api = 2;1808ret = ath11k_core_fetch_board_data_api_n(ab, bd, boardname,1809ATH11K_BD_IE_BOARD,1810ATH11K_BD_IE_BOARD_NAME,1811ATH11K_BD_IE_BOARD_DATA);1812if (!ret)1813goto exit;18141815fallback_boardname = kzalloc(BOARD_NAME_SIZE, GFP_KERNEL);1816if (!fallback_boardname) {1817ret = -ENOMEM;1818goto exit;1819}18201821ret = ath11k_core_create_fallback_board_name(ab, fallback_boardname,1822BOARD_NAME_SIZE);1823if (ret) {1824ath11k_err(ab, "failed to create fallback board name: %d", ret);1825goto exit;1826}18271828ret = ath11k_core_fetch_board_data_api_n(ab, bd, fallback_boardname,1829ATH11K_BD_IE_BOARD,1830ATH11K_BD_IE_BOARD_NAME,1831ATH11K_BD_IE_BOARD_DATA);1832if (!ret)1833goto exit;18341835chip_id_boardname = kzalloc(BOARD_NAME_SIZE, GFP_KERNEL);1836if (!chip_id_boardname) {1837ret = -ENOMEM;1838goto exit;1839}18401841ret = ath11k_core_create_chip_id_board_name(ab, chip_id_boardname,1842BOARD_NAME_SIZE);1843if (ret) {1844ath11k_err(ab, "failed to create chip id board name: %d", ret);1845goto exit;1846}18471848ret = ath11k_core_fetch_board_data_api_n(ab, bd, chip_id_boardname,1849ATH11K_BD_IE_BOARD,1850ATH11K_BD_IE_BOARD_NAME,1851ATH11K_BD_IE_BOARD_DATA);18521853if (!ret)1854goto exit;18551856bd_api = 1;1857ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_DEFAULT_BOARD_FILE);1858if (ret) {1859ath11k_core_create_firmware_path(ab, filename,1860filepath, sizeof(filepath));1861ath11k_err(ab, "failed to fetch board data for %s from %s\n",1862boardname, filepath);1863if (memcmp(boardname, fallback_boardname, strlen(boardname)))1864ath11k_err(ab, "failed to fetch board data for %s from %s\n",1865fallback_boardname, filepath);18661867ath11k_err(ab, "failed to fetch board data for %s from %s\n",1868chip_id_boardname, filepath);18691870ath11k_err(ab, "failed to fetch board.bin from %s\n",1871ab->hw_params.fw.dir);1872}18731874exit:1875kfree(boardname);1876kfree(fallback_boardname);1877kfree(chip_id_boardname);18781879if (!ret)1880ath11k_dbg(ab, ATH11K_DBG_BOOT, "using board api %d\n", bd_api);18811882return ret;1883}18841885int ath11k_core_fetch_regdb(struct ath11k_base *ab, struct ath11k_board_data *bd)1886{1887char boardname[BOARD_NAME_SIZE], default_boardname[BOARD_NAME_SIZE];1888int ret;18891890ret = ath11k_core_create_board_name(ab, boardname, BOARD_NAME_SIZE);1891if (ret) {1892ath11k_dbg(ab, ATH11K_DBG_BOOT,1893"failed to create board name for regdb: %d", ret);1894goto exit;1895}18961897ret = ath11k_core_fetch_board_data_api_n(ab, bd, boardname,1898ATH11K_BD_IE_REGDB,1899ATH11K_BD_IE_REGDB_NAME,1900ATH11K_BD_IE_REGDB_DATA);1901if (!ret)1902goto exit;19031904ret = ath11k_core_create_bus_type_board_name(ab, default_boardname,1905BOARD_NAME_SIZE);1906if (ret) {1907ath11k_dbg(ab, ATH11K_DBG_BOOT,1908"failed to create default board name for regdb: %d", ret);1909goto exit;1910}19111912ret = ath11k_core_fetch_board_data_api_n(ab, bd, default_boardname,1913ATH11K_BD_IE_REGDB,1914ATH11K_BD_IE_REGDB_NAME,1915ATH11K_BD_IE_REGDB_DATA);1916if (!ret)1917goto exit;19181919ret = ath11k_core_fetch_board_data_api_1(ab, bd, ATH11K_REGDB_FILE_NAME);1920if (ret)1921ath11k_dbg(ab, ATH11K_DBG_BOOT, "failed to fetch %s from %s\n",1922ATH11K_REGDB_FILE_NAME, ab->hw_params.fw.dir);19231924exit:1925if (!ret)1926ath11k_dbg(ab, ATH11K_DBG_BOOT, "fetched regdb\n");19271928return ret;1929}19301931static void ath11k_core_stop(struct ath11k_base *ab)1932{1933if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))1934ath11k_qmi_firmware_stop(ab);19351936ath11k_hif_stop(ab);1937ath11k_wmi_detach(ab);1938ath11k_dp_pdev_reo_cleanup(ab);19391940/* De-Init of components as needed */1941}19421943static int ath11k_core_soc_create(struct ath11k_base *ab)1944{1945int ret;19461947if (ath11k_ftm_mode) {1948ab->fw_mode = ATH11K_FIRMWARE_MODE_FTM;1949ath11k_info(ab, "Booting in factory test mode\n");1950}19511952ret = ath11k_qmi_init_service(ab);1953if (ret) {1954ath11k_err(ab, "failed to initialize qmi :%d\n", ret);1955return ret;1956}19571958ret = ath11k_debugfs_soc_create(ab);1959if (ret) {1960ath11k_err(ab, "failed to create ath11k debugfs\n");1961goto err_qmi_deinit;1962}19631964ret = ath11k_hif_power_up(ab);1965if (ret) {1966ath11k_err(ab, "failed to power up :%d\n", ret);1967goto err_debugfs_reg;1968}19691970return 0;19711972err_debugfs_reg:1973ath11k_debugfs_soc_destroy(ab);1974err_qmi_deinit:1975ath11k_qmi_deinit_service(ab);1976return ret;1977}19781979static void ath11k_core_soc_destroy(struct ath11k_base *ab)1980{1981ath11k_debugfs_soc_destroy(ab);1982ath11k_dp_free(ab);1983ath11k_reg_free(ab);1984ath11k_qmi_deinit_service(ab);1985}19861987static int ath11k_core_pdev_create(struct ath11k_base *ab)1988{1989int ret;19901991ret = ath11k_debugfs_pdev_create(ab);1992if (ret) {1993ath11k_err(ab, "failed to create core pdev debugfs: %d\n", ret);1994return ret;1995}19961997ret = ath11k_dp_pdev_alloc(ab);1998if (ret) {1999ath11k_err(ab, "failed to attach DP pdev: %d\n", ret);2000goto err_pdev_debug;2001}20022003ret = ath11k_mac_register(ab);2004if (ret) {2005ath11k_err(ab, "failed register the radio with mac80211: %d\n", ret);2006goto err_dp_pdev_free;2007}20082009ret = ath11k_thermal_register(ab);2010if (ret) {2011ath11k_err(ab, "could not register thermal device: %d\n",2012ret);2013goto err_mac_unregister;2014}20152016ret = ath11k_spectral_init(ab);2017if (ret) {2018ath11k_err(ab, "failed to init spectral %d\n", ret);2019goto err_thermal_unregister;2020}20212022return 0;20232024err_thermal_unregister:2025ath11k_thermal_unregister(ab);2026err_mac_unregister:2027ath11k_mac_unregister(ab);2028err_dp_pdev_free:2029ath11k_dp_pdev_free(ab);2030err_pdev_debug:2031ath11k_debugfs_pdev_destroy(ab);20322033return ret;2034}20352036static void ath11k_core_pdev_suspend_target(struct ath11k_base *ab)2037{2038struct ath11k *ar;2039struct ath11k_pdev *pdev;2040unsigned long time_left;2041int ret;2042int i;20432044if (!ab->hw_params.pdev_suspend)2045return;20462047for (i = 0; i < ab->num_radios; i++) {2048pdev = &ab->pdevs[i];2049ar = pdev->ar;20502051reinit_completion(&ab->htc_suspend);20522053ret = ath11k_wmi_pdev_suspend(ar, WMI_PDEV_SUSPEND_AND_DISABLE_INTR,2054pdev->pdev_id);2055if (ret) {2056ath11k_warn(ab, "could not suspend target :%d\n", ret);2057/* pointless to try other pdevs */2058return;2059}20602061time_left = wait_for_completion_timeout(&ab->htc_suspend, 3 * HZ);20622063if (!time_left) {2064ath11k_warn(ab, "suspend timed out - target pause event never came\n");2065/* pointless to try other pdevs */2066return;2067}2068}2069}20702071static void ath11k_core_pdev_destroy(struct ath11k_base *ab)2072{2073ath11k_spectral_deinit(ab);2074ath11k_thermal_unregister(ab);2075ath11k_mac_unregister(ab);2076ath11k_core_pdev_suspend_target(ab);2077ath11k_hif_irq_disable(ab);2078ath11k_dp_pdev_free(ab);2079ath11k_debugfs_pdev_destroy(ab);2080}20812082static int ath11k_core_start(struct ath11k_base *ab)2083{2084int ret;20852086ret = ath11k_wmi_attach(ab);2087if (ret) {2088ath11k_err(ab, "failed to attach wmi: %d\n", ret);2089return ret;2090}20912092ret = ath11k_htc_init(ab);2093if (ret) {2094ath11k_err(ab, "failed to init htc: %d\n", ret);2095goto err_wmi_detach;2096}20972098ret = ath11k_hif_start(ab);2099if (ret) {2100ath11k_err(ab, "failed to start HIF: %d\n", ret);2101goto err_wmi_detach;2102}21032104ret = ath11k_htc_wait_target(&ab->htc);2105if (ret) {2106ath11k_err(ab, "failed to connect to HTC: %d\n", ret);2107goto err_hif_stop;2108}21092110ret = ath11k_dp_htt_connect(&ab->dp);2111if (ret) {2112ath11k_err(ab, "failed to connect to HTT: %d\n", ret);2113goto err_hif_stop;2114}21152116ret = ath11k_wmi_connect(ab);2117if (ret) {2118ath11k_err(ab, "failed to connect wmi: %d\n", ret);2119goto err_hif_stop;2120}21212122ret = ath11k_htc_start(&ab->htc);2123if (ret) {2124ath11k_err(ab, "failed to start HTC: %d\n", ret);2125goto err_hif_stop;2126}21272128ret = ath11k_wmi_wait_for_service_ready(ab);2129if (ret) {2130ath11k_err(ab, "failed to receive wmi service ready event: %d\n",2131ret);2132goto err_hif_stop;2133}21342135ret = ath11k_mac_allocate(ab);2136if (ret) {2137ath11k_err(ab, "failed to create new hw device with mac80211 :%d\n",2138ret);2139goto err_hif_stop;2140}21412142ath11k_dp_pdev_pre_alloc(ab);21432144ret = ath11k_dp_pdev_reo_setup(ab);2145if (ret) {2146ath11k_err(ab, "failed to initialize reo destination rings: %d\n", ret);2147goto err_mac_destroy;2148}21492150ret = ath11k_wmi_cmd_init(ab);2151if (ret) {2152ath11k_err(ab, "failed to send wmi init cmd: %d\n", ret);2153goto err_reo_cleanup;2154}21552156ret = ath11k_wmi_wait_for_unified_ready(ab);2157if (ret) {2158ath11k_err(ab, "failed to receive wmi unified ready event: %d\n",2159ret);2160goto err_reo_cleanup;2161}21622163/* put hardware to DBS mode */2164if (ab->hw_params.single_pdev_only && ab->hw_params.num_rxdma_per_pdev > 1) {2165ret = ath11k_wmi_set_hw_mode(ab, WMI_HOST_HW_MODE_DBS);2166if (ret) {2167ath11k_err(ab, "failed to send dbs mode: %d\n", ret);2168goto err_hif_stop;2169}2170}21712172ret = ath11k_dp_tx_htt_h2t_ver_req_msg(ab);2173if (ret) {2174ath11k_err(ab, "failed to send htt version request message: %d\n",2175ret);2176goto err_reo_cleanup;2177}21782179return 0;21802181err_reo_cleanup:2182ath11k_dp_pdev_reo_cleanup(ab);2183err_mac_destroy:2184ath11k_mac_destroy(ab);2185err_hif_stop:2186ath11k_hif_stop(ab);2187err_wmi_detach:2188ath11k_wmi_detach(ab);21892190return ret;2191}21922193static int ath11k_core_start_firmware(struct ath11k_base *ab,2194enum ath11k_firmware_mode mode)2195{2196int ret;21972198ath11k_ce_get_shadow_config(ab, &ab->qmi.ce_cfg.shadow_reg_v2,2199&ab->qmi.ce_cfg.shadow_reg_v2_len);22002201ret = ath11k_qmi_firmware_start(ab, mode);2202if (ret) {2203ath11k_err(ab, "failed to send firmware start: %d\n", ret);2204return ret;2205}22062207return ret;2208}22092210int ath11k_core_qmi_firmware_ready(struct ath11k_base *ab)2211{2212int ret;22132214switch (ath11k_crypto_mode) {2215case ATH11K_CRYPT_MODE_SW:2216set_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags);2217set_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags);2218break;2219case ATH11K_CRYPT_MODE_HW:2220clear_bit(ATH11K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags);2221clear_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags);2222break;2223default:2224ath11k_info(ab, "invalid crypto_mode: %d\n", ath11k_crypto_mode);2225return -EINVAL;2226}22272228ret = ath11k_core_start_firmware(ab, ab->fw_mode);2229if (ret) {2230ath11k_err(ab, "failed to start firmware: %d\n", ret);2231return ret;2232}22332234ret = ath11k_ce_init_pipes(ab);2235if (ret) {2236ath11k_err(ab, "failed to initialize CE: %d\n", ret);2237goto err_firmware_stop;2238}22392240ret = ath11k_dp_alloc(ab);2241if (ret) {2242ath11k_err(ab, "failed to init DP: %d\n", ret);2243goto err_firmware_stop;2244}22452246if (ath11k_frame_mode == ATH11K_HW_TXRX_RAW)2247set_bit(ATH11K_FLAG_RAW_MODE, &ab->dev_flags);22482249mutex_lock(&ab->core_lock);2250ret = ath11k_core_start(ab);2251if (ret) {2252ath11k_err(ab, "failed to start core: %d\n", ret);2253goto err_dp_free;2254}22552256ret = ath11k_core_pdev_create(ab);2257if (ret) {2258ath11k_err(ab, "failed to create pdev core: %d\n", ret);2259goto err_core_stop;2260}2261ath11k_hif_irq_enable(ab);2262mutex_unlock(&ab->core_lock);22632264return 0;22652266err_core_stop:2267ath11k_core_stop(ab);2268ath11k_mac_destroy(ab);2269err_dp_free:2270ath11k_dp_free(ab);2271mutex_unlock(&ab->core_lock);2272err_firmware_stop:2273ath11k_qmi_firmware_stop(ab);22742275return ret;2276}22772278static int ath11k_core_reconfigure_on_crash(struct ath11k_base *ab)2279{2280int ret;22812282mutex_lock(&ab->core_lock);2283ath11k_thermal_unregister(ab);2284ath11k_dp_pdev_free(ab);2285ath11k_spectral_deinit(ab);2286ath11k_ce_cleanup_pipes(ab);2287ath11k_wmi_detach(ab);2288ath11k_dp_pdev_reo_cleanup(ab);2289mutex_unlock(&ab->core_lock);22902291ath11k_dp_free(ab);2292ath11k_hal_srng_clear(ab);22932294ab->free_vdev_map = (1LL << (ab->num_radios * TARGET_NUM_VDEVS(ab))) - 1;22952296clear_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags);22972298ret = ath11k_core_qmi_firmware_ready(ab);2299if (ret)2300goto err_hal_srng_deinit;23012302clear_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags);23032304return 0;23052306err_hal_srng_deinit:2307ath11k_hal_srng_deinit(ab);2308return ret;2309}23102311void ath11k_core_halt(struct ath11k *ar)2312{2313struct ath11k_base *ab = ar->ab;2314struct list_head *pos, *n;23152316lockdep_assert_held(&ar->conf_mutex);23172318ar->num_created_vdevs = 0;2319ar->allocated_vdev_map = 0;23202321ath11k_mac_scan_finish(ar);2322ath11k_mac_peer_cleanup_all(ar);2323cancel_delayed_work_sync(&ar->scan.timeout);2324cancel_work_sync(&ar->channel_update_work);2325cancel_work_sync(&ar->regd_update_work);2326cancel_work_sync(&ab->update_11d_work);23272328rcu_assign_pointer(ab->pdevs_active[ar->pdev_idx], NULL);2329synchronize_rcu();23302331spin_lock_bh(&ar->data_lock);2332list_for_each_safe(pos, n, &ar->arvifs)2333list_del_init(pos);2334spin_unlock_bh(&ar->data_lock);23352336idr_init(&ar->txmgmt_idr);2337}23382339static void ath11k_update_11d(struct work_struct *work)2340{2341struct ath11k_base *ab = container_of(work, struct ath11k_base, update_11d_work);2342struct ath11k *ar;2343struct ath11k_pdev *pdev;2344int ret, i;23452346for (i = 0; i < ab->num_radios; i++) {2347pdev = &ab->pdevs[i];2348ar = pdev->ar;23492350spin_lock_bh(&ab->base_lock);2351memcpy(&ar->alpha2, &ab->new_alpha2, 2);2352spin_unlock_bh(&ab->base_lock);23532354ath11k_dbg(ab, ATH11K_DBG_WMI, "update 11d new cc %c%c for pdev %d\n",2355ar->alpha2[0], ar->alpha2[1], i);23562357ret = ath11k_reg_set_cc(ar);2358if (ret)2359ath11k_warn(ar->ab,2360"pdev id %d failed set current country code: %d\n",2361i, ret);2362}2363}23642365void ath11k_core_pre_reconfigure_recovery(struct ath11k_base *ab)2366{2367struct ath11k *ar;2368struct ath11k_pdev *pdev;2369int i;23702371spin_lock_bh(&ab->base_lock);2372ab->stats.fw_crash_counter++;2373spin_unlock_bh(&ab->base_lock);23742375for (i = 0; i < ab->num_radios; i++) {2376pdev = &ab->pdevs[i];2377ar = pdev->ar;2378if (!ar || ar->state == ATH11K_STATE_OFF ||2379ar->state == ATH11K_STATE_FTM)2380continue;23812382ieee80211_stop_queues(ar->hw);2383ath11k_mac_drain_tx(ar);2384ar->state_11d = ATH11K_11D_IDLE;2385complete(&ar->completed_11d_scan);2386complete(&ar->scan.started);2387complete_all(&ar->scan.completed);2388complete(&ar->scan.on_channel);2389complete(&ar->peer_assoc_done);2390complete(&ar->peer_delete_done);2391complete(&ar->install_key_done);2392complete(&ar->vdev_setup_done);2393complete(&ar->vdev_delete_done);2394complete(&ar->bss_survey_done);2395complete(&ar->thermal.wmi_sync);23962397wake_up(&ar->dp.tx_empty_waitq);2398idr_for_each(&ar->txmgmt_idr,2399ath11k_mac_tx_mgmt_pending_free, ar);2400idr_destroy(&ar->txmgmt_idr);2401wake_up(&ar->txmgmt_empty_waitq);24022403ar->monitor_vdev_id = -1;2404clear_bit(ATH11K_FLAG_MONITOR_STARTED, &ar->monitor_flags);2405clear_bit(ATH11K_FLAG_MONITOR_VDEV_CREATED, &ar->monitor_flags);2406}24072408wake_up(&ab->wmi_ab.tx_credits_wq);2409wake_up(&ab->peer_mapping_wq);24102411reinit_completion(&ab->driver_recovery);2412}24132414static void ath11k_core_post_reconfigure_recovery(struct ath11k_base *ab)2415{2416struct ath11k *ar;2417struct ath11k_pdev *pdev;2418int i;24192420for (i = 0; i < ab->num_radios; i++) {2421pdev = &ab->pdevs[i];2422ar = pdev->ar;2423if (!ar || ar->state == ATH11K_STATE_OFF)2424continue;24252426mutex_lock(&ar->conf_mutex);24272428switch (ar->state) {2429case ATH11K_STATE_ON:2430ar->state = ATH11K_STATE_RESTARTING;2431ath11k_core_halt(ar);2432ieee80211_restart_hw(ar->hw);2433break;2434case ATH11K_STATE_OFF:2435ath11k_warn(ab,2436"cannot restart radio %d that hasn't been started\n",2437i);2438break;2439case ATH11K_STATE_RESTARTING:2440break;2441case ATH11K_STATE_RESTARTED:2442ar->state = ATH11K_STATE_WEDGED;2443fallthrough;2444case ATH11K_STATE_WEDGED:2445ath11k_warn(ab,2446"device is wedged, will not restart radio %d\n", i);2447break;2448case ATH11K_STATE_FTM:2449ath11k_dbg(ab, ATH11K_DBG_TESTMODE,2450"fw mode reset done radio %d\n", i);2451break;2452}24532454mutex_unlock(&ar->conf_mutex);2455}2456complete(&ab->driver_recovery);2457}24582459static void ath11k_core_restart(struct work_struct *work)2460{2461struct ath11k_base *ab = container_of(work, struct ath11k_base, restart_work);2462int ret;24632464ret = ath11k_core_reconfigure_on_crash(ab);2465if (ret) {2466ath11k_err(ab, "failed to reconfigure driver on crash recovery\n");2467return;2468}24692470if (ab->is_reset)2471complete_all(&ab->reconfigure_complete);24722473if (!ab->is_reset)2474ath11k_core_post_reconfigure_recovery(ab);24752476complete(&ab->restart_completed);2477}24782479static void ath11k_core_reset(struct work_struct *work)2480{2481struct ath11k_base *ab = container_of(work, struct ath11k_base, reset_work);2482int reset_count, fail_cont_count;2483long time_left;24842485if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags))) {2486ath11k_warn(ab, "ignore reset dev flags 0x%lx\n", ab->dev_flags);2487return;2488}24892490/* Sometimes the recovery will fail and then the next all recovery fail,2491* this is to avoid infinite recovery since it can not recovery success.2492*/2493fail_cont_count = atomic_read(&ab->fail_cont_count);24942495if (fail_cont_count >= ATH11K_RESET_MAX_FAIL_COUNT_FINAL)2496return;24972498if (fail_cont_count >= ATH11K_RESET_MAX_FAIL_COUNT_FIRST &&2499time_before(jiffies, ab->reset_fail_timeout))2500return;25012502reset_count = atomic_inc_return(&ab->reset_count);25032504if (reset_count > 1) {2505/* Sometimes it happened another reset worker before the previous one2506* completed, then the second reset worker will destroy the previous one,2507* thus below is to avoid that.2508*/2509ath11k_warn(ab, "already resetting count %d\n", reset_count);25102511reinit_completion(&ab->reset_complete);2512time_left = wait_for_completion_timeout(&ab->reset_complete,2513ATH11K_RESET_TIMEOUT_HZ);25142515if (time_left) {2516ath11k_dbg(ab, ATH11K_DBG_BOOT, "to skip reset\n");2517atomic_dec(&ab->reset_count);2518return;2519}25202521ab->reset_fail_timeout = jiffies + ATH11K_RESET_FAIL_TIMEOUT_HZ;2522/* Record the continuous recovery fail count when recovery failed*/2523atomic_inc(&ab->fail_cont_count);2524}25252526ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset starting\n");25272528ab->is_reset = true;2529atomic_set(&ab->recovery_count, 0);2530reinit_completion(&ab->recovery_start);2531atomic_set(&ab->recovery_start_count, 0);25322533ath11k_coredump_collect(ab);2534ath11k_core_pre_reconfigure_recovery(ab);25352536reinit_completion(&ab->reconfigure_complete);2537ath11k_core_post_reconfigure_recovery(ab);25382539ath11k_dbg(ab, ATH11K_DBG_BOOT, "waiting recovery start...\n");25402541time_left = wait_for_completion_timeout(&ab->recovery_start,2542ATH11K_RECOVER_START_TIMEOUT_HZ);25432544ath11k_hif_irq_disable(ab);2545ath11k_hif_ce_irq_disable(ab);25462547ath11k_hif_power_down(ab, false);2548ath11k_hif_power_up(ab);25492550ath11k_dbg(ab, ATH11K_DBG_BOOT, "reset started\n");2551}25522553static int ath11k_init_hw_params(struct ath11k_base *ab)2554{2555const struct ath11k_hw_params *hw_params = NULL;2556int i;25572558for (i = 0; i < ARRAY_SIZE(ath11k_hw_params); i++) {2559hw_params = &ath11k_hw_params[i];25602561if (hw_params->hw_rev == ab->hw_rev)2562break;2563}25642565if (i == ARRAY_SIZE(ath11k_hw_params)) {2566ath11k_err(ab, "Unsupported hardware version: 0x%x\n", ab->hw_rev);2567return -EINVAL;2568}25692570ab->hw_params = *hw_params;25712572ath11k_info(ab, "%s\n", ab->hw_params.name);25732574return 0;2575}25762577int ath11k_core_pre_init(struct ath11k_base *ab)2578{2579int ret;25802581ret = ath11k_init_hw_params(ab);2582if (ret) {2583ath11k_err(ab, "failed to get hw params: %d\n", ret);2584return ret;2585}25862587ret = ath11k_fw_pre_init(ab);2588if (ret) {2589ath11k_err(ab, "failed to pre init firmware: %d", ret);2590return ret;2591}25922593return 0;2594}2595EXPORT_SYMBOL(ath11k_core_pre_init);25962597static int ath11k_core_pm_notify(struct notifier_block *nb,2598unsigned long action, void *nouse)2599{2600struct ath11k_base *ab = container_of(nb, struct ath11k_base,2601pm_nb);26022603switch (action) {2604case PM_SUSPEND_PREPARE:2605ab->actual_pm_policy = ab->pm_policy;2606break;2607case PM_HIBERNATION_PREPARE:2608ab->actual_pm_policy = ATH11K_PM_DEFAULT;2609break;2610default:2611break;2612}26132614return NOTIFY_OK;2615}26162617static int ath11k_core_pm_notifier_register(struct ath11k_base *ab)2618{2619ab->pm_nb.notifier_call = ath11k_core_pm_notify;2620return register_pm_notifier(&ab->pm_nb);2621}26222623void ath11k_core_pm_notifier_unregister(struct ath11k_base *ab)2624{2625int ret;26262627ret = unregister_pm_notifier(&ab->pm_nb);2628if (ret)2629/* just warn here, there is nothing can be done in fail case */2630ath11k_warn(ab, "failed to unregister PM notifier %d\n", ret);2631}2632EXPORT_SYMBOL(ath11k_core_pm_notifier_unregister);26332634int ath11k_core_init(struct ath11k_base *ab)2635{2636const struct dmi_system_id *dmi_id;2637int ret;26382639dmi_id = dmi_first_match(ath11k_pm_quirk_table);2640if (dmi_id)2641ab->pm_policy = (kernel_ulong_t)dmi_id->driver_data;2642else2643ab->pm_policy = ATH11K_PM_DEFAULT;26442645ath11k_dbg(ab, ATH11K_DBG_BOOT, "pm policy %u\n", ab->pm_policy);26462647ret = ath11k_core_pm_notifier_register(ab);2648if (ret) {2649ath11k_err(ab, "failed to register PM notifier: %d\n", ret);2650return ret;2651}26522653ret = ath11k_core_soc_create(ab);2654if (ret) {2655ath11k_err(ab, "failed to create soc core: %d\n", ret);2656goto err_unregister_pm_notifier;2657}26582659return 0;26602661err_unregister_pm_notifier:2662ath11k_core_pm_notifier_unregister(ab);26632664return ret;2665}2666EXPORT_SYMBOL(ath11k_core_init);26672668void ath11k_core_deinit(struct ath11k_base *ab)2669{2670mutex_lock(&ab->core_lock);26712672ath11k_core_pdev_destroy(ab);2673ath11k_core_stop(ab);26742675mutex_unlock(&ab->core_lock);26762677ath11k_hif_power_down(ab, false);2678ath11k_mac_destroy(ab);2679ath11k_core_soc_destroy(ab);2680ath11k_core_pm_notifier_unregister(ab);2681}2682EXPORT_SYMBOL(ath11k_core_deinit);26832684void ath11k_core_free(struct ath11k_base *ab)2685{2686destroy_workqueue(ab->workqueue_aux);2687destroy_workqueue(ab->workqueue);26882689kfree(ab);2690}2691EXPORT_SYMBOL(ath11k_core_free);26922693struct ath11k_base *ath11k_core_alloc(struct device *dev, size_t priv_size,2694enum ath11k_bus bus)2695{2696struct ath11k_base *ab;26972698ab = kzalloc(sizeof(*ab) + priv_size, GFP_KERNEL);2699if (!ab)2700return NULL;27012702init_completion(&ab->driver_recovery);27032704ab->workqueue = create_singlethread_workqueue("ath11k_wq");2705if (!ab->workqueue)2706goto err_sc_free;27072708ab->workqueue_aux = create_singlethread_workqueue("ath11k_aux_wq");2709if (!ab->workqueue_aux)2710goto err_free_wq;27112712mutex_init(&ab->core_lock);2713mutex_init(&ab->tbl_mtx_lock);2714spin_lock_init(&ab->base_lock);2715mutex_init(&ab->vdev_id_11d_lock);2716init_completion(&ab->reset_complete);2717init_completion(&ab->reconfigure_complete);2718init_completion(&ab->recovery_start);27192720INIT_LIST_HEAD(&ab->peers);2721init_waitqueue_head(&ab->peer_mapping_wq);2722init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);2723init_waitqueue_head(&ab->qmi.cold_boot_waitq);2724INIT_WORK(&ab->restart_work, ath11k_core_restart);2725INIT_WORK(&ab->update_11d_work, ath11k_update_11d);2726INIT_WORK(&ab->reset_work, ath11k_core_reset);2727INIT_WORK(&ab->dump_work, ath11k_coredump_upload);2728timer_setup(&ab->rx_replenish_retry, ath11k_ce_rx_replenish_retry, 0);2729init_completion(&ab->htc_suspend);2730init_completion(&ab->wow.wakeup_completed);2731init_completion(&ab->restart_completed);27322733ab->dev = dev;2734ab->hif.bus = bus;27352736return ab;27372738err_free_wq:2739destroy_workqueue(ab->workqueue);2740err_sc_free:2741kfree(ab);2742return NULL;2743}2744EXPORT_SYMBOL(ath11k_core_alloc);27452746MODULE_DESCRIPTION("Core module for Qualcomm Atheros 802.11ax wireless LAN cards.");2747MODULE_LICENSE("Dual BSD/GPL");274827492750