18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: ISC 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2005-2011 Atheros Communications Inc. 48c2ecf20Sopenharmony_ci * Copyright (c) 2011-2017 Qualcomm Atheros, Inc. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/pci.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 108c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "core.h" 148c2ecf20Sopenharmony_ci#include "debug.h" 158c2ecf20Sopenharmony_ci#include "coredump.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "targaddrs.h" 188c2ecf20Sopenharmony_ci#include "bmi.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "hif.h" 218c2ecf20Sopenharmony_ci#include "htc.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "ce.h" 248c2ecf20Sopenharmony_ci#include "pci.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cienum ath10k_pci_reset_mode { 278c2ecf20Sopenharmony_ci ATH10K_PCI_RESET_AUTO = 0, 288c2ecf20Sopenharmony_ci ATH10K_PCI_RESET_WARM_ONLY = 1, 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic unsigned int ath10k_pci_irq_mode = ATH10K_PCI_IRQ_AUTO; 328c2ecf20Sopenharmony_cistatic unsigned int ath10k_pci_reset_mode = ATH10K_PCI_RESET_AUTO; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cimodule_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); 358c2ecf20Sopenharmony_ciMODULE_PARM_DESC(irq_mode, "0: auto, 1: legacy, 2: msi (default: 0)"); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cimodule_param_named(reset_mode, ath10k_pci_reset_mode, uint, 0644); 388c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* how long wait to wait for target to initialise, in ms */ 418c2ecf20Sopenharmony_ci#define ATH10K_PCI_TARGET_WAIT 3000 428c2ecf20Sopenharmony_ci#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci/* Maximum number of bytes that can be handled atomically by 458c2ecf20Sopenharmony_ci * diag read and write. 468c2ecf20Sopenharmony_ci */ 478c2ecf20Sopenharmony_ci#define ATH10K_DIAG_TRANSFER_LIMIT 0x5000 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define QCA99X0_PCIE_BAR0_START_REG 0x81030 508c2ecf20Sopenharmony_ci#define QCA99X0_CPU_MEM_ADDR_REG 0x4d00c 518c2ecf20Sopenharmony_ci#define QCA99X0_CPU_MEM_DATA_REG 0x4d010 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic const struct pci_device_id ath10k_pci_id_table[] = { 548c2ecf20Sopenharmony_ci /* PCI-E QCA988X V2 (Ubiquiti branded) */ 558c2ecf20Sopenharmony_ci { PCI_VDEVICE(UBIQUITI, QCA988X_2_0_DEVICE_ID_UBNT) }, 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ 588c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */ 598c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ 608c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */ 618c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATHEROS, QCA9888_2_0_DEVICE_ID) }, /* PCI-E QCA9888 V2 */ 628c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATHEROS, QCA9984_1_0_DEVICE_ID) }, /* PCI-E QCA9984 V1 */ 638c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATHEROS, QCA9377_1_0_DEVICE_ID) }, /* PCI-E QCA9377 V1 */ 648c2ecf20Sopenharmony_ci { PCI_VDEVICE(ATHEROS, QCA9887_1_0_DEVICE_ID) }, /* PCI-E QCA9887 */ 658c2ecf20Sopenharmony_ci {0} 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { 698c2ecf20Sopenharmony_ci /* QCA988X pre 2.0 chips are not supported because they need some nasty 708c2ecf20Sopenharmony_ci * hacks. ath10k doesn't have them and these devices crash horribly 718c2ecf20Sopenharmony_ci * because of that. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci { QCA988X_2_0_DEVICE_ID_UBNT, QCA988X_HW_2_0_CHIP_ID_REV }, 748c2ecf20Sopenharmony_ci { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci { QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, 778c2ecf20Sopenharmony_ci { QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, 788c2ecf20Sopenharmony_ci { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, 798c2ecf20Sopenharmony_ci { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, 808c2ecf20Sopenharmony_ci { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, 838c2ecf20Sopenharmony_ci { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, 848c2ecf20Sopenharmony_ci { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, 858c2ecf20Sopenharmony_ci { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, 868c2ecf20Sopenharmony_ci { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV }, 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci { QCA9984_1_0_DEVICE_ID, QCA9984_HW_1_0_CHIP_ID_REV }, 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci { QCA9888_2_0_DEVICE_ID, QCA9888_HW_2_0_CHIP_ID_REV }, 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_0_CHIP_ID_REV }, 958c2ecf20Sopenharmony_ci { QCA9377_1_0_DEVICE_ID, QCA9377_HW_1_1_CHIP_ID_REV }, 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci { QCA9887_1_0_DEVICE_ID, QCA9887_HW_1_0_CHIP_ID_REV }, 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic void ath10k_pci_buffer_cleanup(struct ath10k *ar); 1018c2ecf20Sopenharmony_cistatic int ath10k_pci_cold_reset(struct ath10k *ar); 1028c2ecf20Sopenharmony_cistatic int ath10k_pci_safe_chip_reset(struct ath10k *ar); 1038c2ecf20Sopenharmony_cistatic int ath10k_pci_init_irq(struct ath10k *ar); 1048c2ecf20Sopenharmony_cistatic int ath10k_pci_deinit_irq(struct ath10k *ar); 1058c2ecf20Sopenharmony_cistatic int ath10k_pci_request_irq(struct ath10k *ar); 1068c2ecf20Sopenharmony_cistatic void ath10k_pci_free_irq(struct ath10k *ar); 1078c2ecf20Sopenharmony_cistatic int ath10k_pci_bmi_wait(struct ath10k *ar, 1088c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *tx_pipe, 1098c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *rx_pipe, 1108c2ecf20Sopenharmony_ci struct bmi_xfer *xfer); 1118c2ecf20Sopenharmony_cistatic int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar); 1128c2ecf20Sopenharmony_cistatic void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state); 1138c2ecf20Sopenharmony_cistatic void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state); 1148c2ecf20Sopenharmony_cistatic void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state); 1158c2ecf20Sopenharmony_cistatic void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state); 1168c2ecf20Sopenharmony_cistatic void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state); 1178c2ecf20Sopenharmony_cistatic void ath10k_pci_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic const struct ce_attr pci_host_ce_config_wlan[] = { 1208c2ecf20Sopenharmony_ci /* CE0: host->target HTC control and raw streams */ 1218c2ecf20Sopenharmony_ci { 1228c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1238c2ecf20Sopenharmony_ci .src_nentries = 16, 1248c2ecf20Sopenharmony_ci .src_sz_max = 256, 1258c2ecf20Sopenharmony_ci .dest_nentries = 0, 1268c2ecf20Sopenharmony_ci .send_cb = ath10k_pci_htc_tx_cb, 1278c2ecf20Sopenharmony_ci }, 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* CE1: target->host HTT + HTC control */ 1308c2ecf20Sopenharmony_ci { 1318c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1328c2ecf20Sopenharmony_ci .src_nentries = 0, 1338c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1348c2ecf20Sopenharmony_ci .dest_nentries = 512, 1358c2ecf20Sopenharmony_ci .recv_cb = ath10k_pci_htt_htc_rx_cb, 1368c2ecf20Sopenharmony_ci }, 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* CE2: target->host WMI */ 1398c2ecf20Sopenharmony_ci { 1408c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1418c2ecf20Sopenharmony_ci .src_nentries = 0, 1428c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1438c2ecf20Sopenharmony_ci .dest_nentries = 128, 1448c2ecf20Sopenharmony_ci .recv_cb = ath10k_pci_htc_rx_cb, 1458c2ecf20Sopenharmony_ci }, 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* CE3: host->target WMI */ 1488c2ecf20Sopenharmony_ci { 1498c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1508c2ecf20Sopenharmony_ci .src_nentries = 32, 1518c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1528c2ecf20Sopenharmony_ci .dest_nentries = 0, 1538c2ecf20Sopenharmony_ci .send_cb = ath10k_pci_htc_tx_cb, 1548c2ecf20Sopenharmony_ci }, 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* CE4: host->target HTT */ 1578c2ecf20Sopenharmony_ci { 1588c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR, 1598c2ecf20Sopenharmony_ci .src_nentries = CE_HTT_H2T_MSG_SRC_NENTRIES, 1608c2ecf20Sopenharmony_ci .src_sz_max = 256, 1618c2ecf20Sopenharmony_ci .dest_nentries = 0, 1628c2ecf20Sopenharmony_ci .send_cb = ath10k_pci_htt_tx_cb, 1638c2ecf20Sopenharmony_ci }, 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* CE5: target->host HTT (HIF->HTT) */ 1668c2ecf20Sopenharmony_ci { 1678c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1688c2ecf20Sopenharmony_ci .src_nentries = 0, 1698c2ecf20Sopenharmony_ci .src_sz_max = 512, 1708c2ecf20Sopenharmony_ci .dest_nentries = 512, 1718c2ecf20Sopenharmony_ci .recv_cb = ath10k_pci_htt_rx_cb, 1728c2ecf20Sopenharmony_ci }, 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* CE6: target autonomous hif_memcpy */ 1758c2ecf20Sopenharmony_ci { 1768c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1778c2ecf20Sopenharmony_ci .src_nentries = 0, 1788c2ecf20Sopenharmony_ci .src_sz_max = 0, 1798c2ecf20Sopenharmony_ci .dest_nentries = 0, 1808c2ecf20Sopenharmony_ci }, 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* CE7: ce_diag, the Diagnostic Window */ 1838c2ecf20Sopenharmony_ci { 1848c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS | CE_ATTR_POLL, 1858c2ecf20Sopenharmony_ci .src_nentries = 2, 1868c2ecf20Sopenharmony_ci .src_sz_max = DIAG_TRANSFER_LIMIT, 1878c2ecf20Sopenharmony_ci .dest_nentries = 2, 1888c2ecf20Sopenharmony_ci }, 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* CE8: target->host pktlog */ 1918c2ecf20Sopenharmony_ci { 1928c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 1938c2ecf20Sopenharmony_ci .src_nentries = 0, 1948c2ecf20Sopenharmony_ci .src_sz_max = 2048, 1958c2ecf20Sopenharmony_ci .dest_nentries = 128, 1968c2ecf20Sopenharmony_ci .recv_cb = ath10k_pci_pktlog_rx_cb, 1978c2ecf20Sopenharmony_ci }, 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* CE9 target autonomous qcache memcpy */ 2008c2ecf20Sopenharmony_ci { 2018c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 2028c2ecf20Sopenharmony_ci .src_nentries = 0, 2038c2ecf20Sopenharmony_ci .src_sz_max = 0, 2048c2ecf20Sopenharmony_ci .dest_nentries = 0, 2058c2ecf20Sopenharmony_ci }, 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* CE10: target autonomous hif memcpy */ 2088c2ecf20Sopenharmony_ci { 2098c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 2108c2ecf20Sopenharmony_ci .src_nentries = 0, 2118c2ecf20Sopenharmony_ci .src_sz_max = 0, 2128c2ecf20Sopenharmony_ci .dest_nentries = 0, 2138c2ecf20Sopenharmony_ci }, 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci /* CE11: target autonomous hif memcpy */ 2168c2ecf20Sopenharmony_ci { 2178c2ecf20Sopenharmony_ci .flags = CE_ATTR_FLAGS, 2188c2ecf20Sopenharmony_ci .src_nentries = 0, 2198c2ecf20Sopenharmony_ci .src_sz_max = 0, 2208c2ecf20Sopenharmony_ci .dest_nentries = 0, 2218c2ecf20Sopenharmony_ci }, 2228c2ecf20Sopenharmony_ci}; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci/* Target firmware's Copy Engine configuration. */ 2258c2ecf20Sopenharmony_cistatic const struct ce_pipe_config pci_target_ce_config_wlan[] = { 2268c2ecf20Sopenharmony_ci /* CE0: host->target HTC control and raw streams */ 2278c2ecf20Sopenharmony_ci { 2288c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(0), 2298c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_OUT), 2308c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(32), 2318c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(256), 2328c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS), 2338c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 2348c2ecf20Sopenharmony_ci }, 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* CE1: target->host HTT + HTC control */ 2378c2ecf20Sopenharmony_ci { 2388c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(1), 2398c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_IN), 2408c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(32), 2418c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(2048), 2428c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS), 2438c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 2448c2ecf20Sopenharmony_ci }, 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* CE2: target->host WMI */ 2478c2ecf20Sopenharmony_ci { 2488c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(2), 2498c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_IN), 2508c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(64), 2518c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(2048), 2528c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS), 2538c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 2548c2ecf20Sopenharmony_ci }, 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* CE3: host->target WMI */ 2578c2ecf20Sopenharmony_ci { 2588c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(3), 2598c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_OUT), 2608c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(32), 2618c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(2048), 2628c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS), 2638c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 2648c2ecf20Sopenharmony_ci }, 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci /* CE4: host->target HTT */ 2678c2ecf20Sopenharmony_ci { 2688c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(4), 2698c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_OUT), 2708c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(256), 2718c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(256), 2728c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS), 2738c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 2748c2ecf20Sopenharmony_ci }, 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci /* NB: 50% of src nentries, since tx has 2 frags */ 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* CE5: target->host HTT (HIF->HTT) */ 2798c2ecf20Sopenharmony_ci { 2808c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(5), 2818c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_IN), 2828c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(32), 2838c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(512), 2848c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS), 2858c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 2868c2ecf20Sopenharmony_ci }, 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* CE6: Reserved for target autonomous hif_memcpy */ 2898c2ecf20Sopenharmony_ci { 2908c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(6), 2918c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_INOUT), 2928c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(32), 2938c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(4096), 2948c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS), 2958c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 2968c2ecf20Sopenharmony_ci }, 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* CE7 used only by Host */ 2998c2ecf20Sopenharmony_ci { 3008c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(7), 3018c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_INOUT), 3028c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(0), 3038c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(0), 3048c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(0), 3058c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 3068c2ecf20Sopenharmony_ci }, 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* CE8 target->host packtlog */ 3098c2ecf20Sopenharmony_ci { 3108c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(8), 3118c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_IN), 3128c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(64), 3138c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(2048), 3148c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), 3158c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 3168c2ecf20Sopenharmony_ci }, 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* CE9 target autonomous qcache memcpy */ 3198c2ecf20Sopenharmony_ci { 3208c2ecf20Sopenharmony_ci .pipenum = __cpu_to_le32(9), 3218c2ecf20Sopenharmony_ci .pipedir = __cpu_to_le32(PIPEDIR_INOUT), 3228c2ecf20Sopenharmony_ci .nentries = __cpu_to_le32(32), 3238c2ecf20Sopenharmony_ci .nbytes_max = __cpu_to_le32(2048), 3248c2ecf20Sopenharmony_ci .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), 3258c2ecf20Sopenharmony_ci .reserved = __cpu_to_le32(0), 3268c2ecf20Sopenharmony_ci }, 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci /* It not necessary to send target wlan configuration for CE10 & CE11 3298c2ecf20Sopenharmony_ci * as these CEs are not actively used in target. 3308c2ecf20Sopenharmony_ci */ 3318c2ecf20Sopenharmony_ci}; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* 3348c2ecf20Sopenharmony_ci * Map from service/endpoint to Copy Engine. 3358c2ecf20Sopenharmony_ci * This table is derived from the CE_PCI TABLE, above. 3368c2ecf20Sopenharmony_ci * It is passed to the Target at startup for use by firmware. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_cistatic const struct ce_service_to_pipe pci_target_service_to_ce_map_wlan[] = { 3398c2ecf20Sopenharmony_ci { 3408c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), 3418c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 3428c2ecf20Sopenharmony_ci __cpu_to_le32(3), 3438c2ecf20Sopenharmony_ci }, 3448c2ecf20Sopenharmony_ci { 3458c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO), 3468c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 3478c2ecf20Sopenharmony_ci __cpu_to_le32(2), 3488c2ecf20Sopenharmony_ci }, 3498c2ecf20Sopenharmony_ci { 3508c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), 3518c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 3528c2ecf20Sopenharmony_ci __cpu_to_le32(3), 3538c2ecf20Sopenharmony_ci }, 3548c2ecf20Sopenharmony_ci { 3558c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK), 3568c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 3578c2ecf20Sopenharmony_ci __cpu_to_le32(2), 3588c2ecf20Sopenharmony_ci }, 3598c2ecf20Sopenharmony_ci { 3608c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), 3618c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 3628c2ecf20Sopenharmony_ci __cpu_to_le32(3), 3638c2ecf20Sopenharmony_ci }, 3648c2ecf20Sopenharmony_ci { 3658c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE), 3668c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 3678c2ecf20Sopenharmony_ci __cpu_to_le32(2), 3688c2ecf20Sopenharmony_ci }, 3698c2ecf20Sopenharmony_ci { 3708c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), 3718c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 3728c2ecf20Sopenharmony_ci __cpu_to_le32(3), 3738c2ecf20Sopenharmony_ci }, 3748c2ecf20Sopenharmony_ci { 3758c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI), 3768c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 3778c2ecf20Sopenharmony_ci __cpu_to_le32(2), 3788c2ecf20Sopenharmony_ci }, 3798c2ecf20Sopenharmony_ci { 3808c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), 3818c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 3828c2ecf20Sopenharmony_ci __cpu_to_le32(3), 3838c2ecf20Sopenharmony_ci }, 3848c2ecf20Sopenharmony_ci { 3858c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL), 3868c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 3878c2ecf20Sopenharmony_ci __cpu_to_le32(2), 3888c2ecf20Sopenharmony_ci }, 3898c2ecf20Sopenharmony_ci { 3908c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), 3918c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 3928c2ecf20Sopenharmony_ci __cpu_to_le32(0), 3938c2ecf20Sopenharmony_ci }, 3948c2ecf20Sopenharmony_ci { 3958c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL), 3968c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 3978c2ecf20Sopenharmony_ci __cpu_to_le32(1), 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci { /* not used */ 4008c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), 4018c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 4028c2ecf20Sopenharmony_ci __cpu_to_le32(0), 4038c2ecf20Sopenharmony_ci }, 4048c2ecf20Sopenharmony_ci { /* not used */ 4058c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS), 4068c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 4078c2ecf20Sopenharmony_ci __cpu_to_le32(1), 4088c2ecf20Sopenharmony_ci }, 4098c2ecf20Sopenharmony_ci { 4108c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), 4118c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */ 4128c2ecf20Sopenharmony_ci __cpu_to_le32(4), 4138c2ecf20Sopenharmony_ci }, 4148c2ecf20Sopenharmony_ci { 4158c2ecf20Sopenharmony_ci __cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG), 4168c2ecf20Sopenharmony_ci __cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */ 4178c2ecf20Sopenharmony_ci __cpu_to_le32(5), 4188c2ecf20Sopenharmony_ci }, 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* (Additions here) */ 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci { /* must be last */ 4238c2ecf20Sopenharmony_ci __cpu_to_le32(0), 4248c2ecf20Sopenharmony_ci __cpu_to_le32(0), 4258c2ecf20Sopenharmony_ci __cpu_to_le32(0), 4268c2ecf20Sopenharmony_ci }, 4278c2ecf20Sopenharmony_ci}; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_cistatic bool ath10k_pci_is_awake(struct ath10k *ar) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 4328c2ecf20Sopenharmony_ci u32 val = ioread32(ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + 4338c2ecf20Sopenharmony_ci RTC_STATE_ADDRESS); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci return RTC_STATE_V_GET(val) == RTC_STATE_V_ON; 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic void __ath10k_pci_wake(struct ath10k *ar) 4398c2ecf20Sopenharmony_ci{ 4408c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci lockdep_assert_held(&ar_pci->ps_lock); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake reg refcount %lu awake %d\n", 4458c2ecf20Sopenharmony_ci ar_pci->ps_wake_refcount, ar_pci->ps_awake); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci iowrite32(PCIE_SOC_WAKE_V_MASK, 4488c2ecf20Sopenharmony_ci ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + 4498c2ecf20Sopenharmony_ci PCIE_SOC_WAKE_ADDRESS); 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic void __ath10k_pci_sleep(struct ath10k *ar) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci lockdep_assert_held(&ar_pci->ps_lock); 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep reg refcount %lu awake %d\n", 4598c2ecf20Sopenharmony_ci ar_pci->ps_wake_refcount, ar_pci->ps_awake); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci iowrite32(PCIE_SOC_WAKE_RESET, 4628c2ecf20Sopenharmony_ci ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + 4638c2ecf20Sopenharmony_ci PCIE_SOC_WAKE_ADDRESS); 4648c2ecf20Sopenharmony_ci ar_pci->ps_awake = false; 4658c2ecf20Sopenharmony_ci} 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_cistatic int ath10k_pci_wake_wait(struct ath10k *ar) 4688c2ecf20Sopenharmony_ci{ 4698c2ecf20Sopenharmony_ci int tot_delay = 0; 4708c2ecf20Sopenharmony_ci int curr_delay = 5; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci while (tot_delay < PCIE_WAKE_TIMEOUT) { 4738c2ecf20Sopenharmony_ci if (ath10k_pci_is_awake(ar)) { 4748c2ecf20Sopenharmony_ci if (tot_delay > PCIE_WAKE_LATE_US) 4758c2ecf20Sopenharmony_ci ath10k_warn(ar, "device wakeup took %d ms which is unusually long, otherwise it works normally.\n", 4768c2ecf20Sopenharmony_ci tot_delay / 1000); 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci udelay(curr_delay); 4818c2ecf20Sopenharmony_ci tot_delay += curr_delay; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (curr_delay < 50) 4848c2ecf20Sopenharmony_ci curr_delay += 5; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci return -ETIMEDOUT; 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic int ath10k_pci_force_wake(struct ath10k *ar) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 4938c2ecf20Sopenharmony_ci unsigned long flags; 4948c2ecf20Sopenharmony_ci int ret = 0; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (ar_pci->pci_ps) 4978c2ecf20Sopenharmony_ci return ret; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci spin_lock_irqsave(&ar_pci->ps_lock, flags); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci if (!ar_pci->ps_awake) { 5028c2ecf20Sopenharmony_ci iowrite32(PCIE_SOC_WAKE_V_MASK, 5038c2ecf20Sopenharmony_ci ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + 5048c2ecf20Sopenharmony_ci PCIE_SOC_WAKE_ADDRESS); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci ret = ath10k_pci_wake_wait(ar); 5078c2ecf20Sopenharmony_ci if (ret == 0) 5088c2ecf20Sopenharmony_ci ar_pci->ps_awake = true; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ar_pci->ps_lock, flags); 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ci return ret; 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic void ath10k_pci_force_sleep(struct ath10k *ar) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 5198c2ecf20Sopenharmony_ci unsigned long flags; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci spin_lock_irqsave(&ar_pci->ps_lock, flags); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci iowrite32(PCIE_SOC_WAKE_RESET, 5248c2ecf20Sopenharmony_ci ar_pci->mem + PCIE_LOCAL_BASE_ADDRESS + 5258c2ecf20Sopenharmony_ci PCIE_SOC_WAKE_ADDRESS); 5268c2ecf20Sopenharmony_ci ar_pci->ps_awake = false; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ar_pci->ps_lock, flags); 5298c2ecf20Sopenharmony_ci} 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic int ath10k_pci_wake(struct ath10k *ar) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 5348c2ecf20Sopenharmony_ci unsigned long flags; 5358c2ecf20Sopenharmony_ci int ret = 0; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (ar_pci->pci_ps == 0) 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci spin_lock_irqsave(&ar_pci->ps_lock, flags); 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps wake refcount %lu awake %d\n", 5438c2ecf20Sopenharmony_ci ar_pci->ps_wake_refcount, ar_pci->ps_awake); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci /* This function can be called very frequently. To avoid excessive 5468c2ecf20Sopenharmony_ci * CPU stalls for MMIO reads use a cache var to hold the device state. 5478c2ecf20Sopenharmony_ci */ 5488c2ecf20Sopenharmony_ci if (!ar_pci->ps_awake) { 5498c2ecf20Sopenharmony_ci __ath10k_pci_wake(ar); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci ret = ath10k_pci_wake_wait(ar); 5528c2ecf20Sopenharmony_ci if (ret == 0) 5538c2ecf20Sopenharmony_ci ar_pci->ps_awake = true; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (ret == 0) { 5578c2ecf20Sopenharmony_ci ar_pci->ps_wake_refcount++; 5588c2ecf20Sopenharmony_ci WARN_ON(ar_pci->ps_wake_refcount == 0); 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ar_pci->ps_lock, flags); 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return ret; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic void ath10k_pci_sleep(struct ath10k *ar) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 5698c2ecf20Sopenharmony_ci unsigned long flags; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (ar_pci->pci_ps == 0) 5728c2ecf20Sopenharmony_ci return; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci spin_lock_irqsave(&ar_pci->ps_lock, flags); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps sleep refcount %lu awake %d\n", 5778c2ecf20Sopenharmony_ci ar_pci->ps_wake_refcount, ar_pci->ps_awake); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (WARN_ON(ar_pci->ps_wake_refcount == 0)) 5808c2ecf20Sopenharmony_ci goto skip; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci ar_pci->ps_wake_refcount--; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci mod_timer(&ar_pci->ps_timer, jiffies + 5858c2ecf20Sopenharmony_ci msecs_to_jiffies(ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC)); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ciskip: 5888c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ar_pci->ps_lock, flags); 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic void ath10k_pci_ps_timer(struct timer_list *t) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = from_timer(ar_pci, t, ps_timer); 5948c2ecf20Sopenharmony_ci struct ath10k *ar = ar_pci->ar; 5958c2ecf20Sopenharmony_ci unsigned long flags; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci spin_lock_irqsave(&ar_pci->ps_lock, flags); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI_PS, "pci ps timer refcount %lu awake %d\n", 6008c2ecf20Sopenharmony_ci ar_pci->ps_wake_refcount, ar_pci->ps_awake); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (ar_pci->ps_wake_refcount > 0) 6038c2ecf20Sopenharmony_ci goto skip; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci __ath10k_pci_sleep(ar); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ciskip: 6088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ar_pci->ps_lock, flags); 6098c2ecf20Sopenharmony_ci} 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_cistatic void ath10k_pci_sleep_sync(struct ath10k *ar) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 6148c2ecf20Sopenharmony_ci unsigned long flags; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (ar_pci->pci_ps == 0) { 6178c2ecf20Sopenharmony_ci ath10k_pci_force_sleep(ar); 6188c2ecf20Sopenharmony_ci return; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci del_timer_sync(&ar_pci->ps_timer); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci spin_lock_irqsave(&ar_pci->ps_lock, flags); 6248c2ecf20Sopenharmony_ci WARN_ON(ar_pci->ps_wake_refcount > 0); 6258c2ecf20Sopenharmony_ci __ath10k_pci_sleep(ar); 6268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ar_pci->ps_lock, flags); 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic void ath10k_bus_pci_write32(struct ath10k *ar, u32 offset, u32 value) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 6328c2ecf20Sopenharmony_ci int ret; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci if (unlikely(offset + sizeof(value) > ar_pci->mem_len)) { 6358c2ecf20Sopenharmony_ci ath10k_warn(ar, "refusing to write mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", 6368c2ecf20Sopenharmony_ci offset, offset + sizeof(value), ar_pci->mem_len); 6378c2ecf20Sopenharmony_ci return; 6388c2ecf20Sopenharmony_ci } 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_ci ret = ath10k_pci_wake(ar); 6418c2ecf20Sopenharmony_ci if (ret) { 6428c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n", 6438c2ecf20Sopenharmony_ci value, offset, ret); 6448c2ecf20Sopenharmony_ci return; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci iowrite32(value, ar_pci->mem + offset); 6488c2ecf20Sopenharmony_ci ath10k_pci_sleep(ar); 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_cistatic u32 ath10k_bus_pci_read32(struct ath10k *ar, u32 offset) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 6548c2ecf20Sopenharmony_ci u32 val; 6558c2ecf20Sopenharmony_ci int ret; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci if (unlikely(offset + sizeof(val) > ar_pci->mem_len)) { 6588c2ecf20Sopenharmony_ci ath10k_warn(ar, "refusing to read mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", 6598c2ecf20Sopenharmony_ci offset, offset + sizeof(val), ar_pci->mem_len); 6608c2ecf20Sopenharmony_ci return 0; 6618c2ecf20Sopenharmony_ci } 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci ret = ath10k_pci_wake(ar); 6648c2ecf20Sopenharmony_ci if (ret) { 6658c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n", 6668c2ecf20Sopenharmony_ci offset, ret); 6678c2ecf20Sopenharmony_ci return 0xffffffff; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci val = ioread32(ar_pci->mem + offset); 6718c2ecf20Sopenharmony_ci ath10k_pci_sleep(ar); 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return val; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ciinline void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci struct ath10k_ce *ce = ath10k_ce_priv(ar); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci ce->bus_ops->write32(ar, offset, value); 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ciinline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) 6848c2ecf20Sopenharmony_ci{ 6858c2ecf20Sopenharmony_ci struct ath10k_ce *ce = ath10k_ce_priv(ar); 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci return ce->bus_ops->read32(ar, offset); 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ciu32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr) 6918c2ecf20Sopenharmony_ci{ 6928c2ecf20Sopenharmony_ci return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr); 6938c2ecf20Sopenharmony_ci} 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_civoid ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val) 6968c2ecf20Sopenharmony_ci{ 6978c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, RTC_SOC_BASE_ADDRESS + addr, val); 6988c2ecf20Sopenharmony_ci} 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ciu32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr) 7018c2ecf20Sopenharmony_ci{ 7028c2ecf20Sopenharmony_ci return ath10k_pci_read32(ar, PCIE_LOCAL_BASE_ADDRESS + addr); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_civoid ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val) 7068c2ecf20Sopenharmony_ci{ 7078c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, PCIE_LOCAL_BASE_ADDRESS + addr, val); 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cibool ath10k_pci_irq_pending(struct ath10k *ar) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci u32 cause; 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Check if the shared legacy irq is for us */ 7158c2ecf20Sopenharmony_ci cause = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + 7168c2ecf20Sopenharmony_ci PCIE_INTR_CAUSE_ADDRESS); 7178c2ecf20Sopenharmony_ci if (cause & (PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL)) 7188c2ecf20Sopenharmony_ci return true; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci return false; 7218c2ecf20Sopenharmony_ci} 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_civoid ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci /* IMPORTANT: INTR_CLR register has to be set after 7268c2ecf20Sopenharmony_ci * INTR_ENABLE is set to 0, otherwise interrupt can not be 7278c2ecf20Sopenharmony_ci * really cleared. 7288c2ecf20Sopenharmony_ci */ 7298c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, 7308c2ecf20Sopenharmony_ci 0); 7318c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_CLR_ADDRESS, 7328c2ecf20Sopenharmony_ci PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci /* IMPORTANT: this extra read transaction is required to 7358c2ecf20Sopenharmony_ci * flush the posted write buffer. 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ci (void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + 7388c2ecf20Sopenharmony_ci PCIE_INTR_ENABLE_ADDRESS); 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_civoid ath10k_pci_enable_legacy_irq(struct ath10k *ar) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + 7448c2ecf20Sopenharmony_ci PCIE_INTR_ENABLE_ADDRESS, 7458c2ecf20Sopenharmony_ci PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci /* IMPORTANT: this extra read transaction is required to 7488c2ecf20Sopenharmony_ci * flush the posted write buffer. 7498c2ecf20Sopenharmony_ci */ 7508c2ecf20Sopenharmony_ci (void)ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + 7518c2ecf20Sopenharmony_ci PCIE_INTR_ENABLE_ADDRESS); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic inline const char *ath10k_pci_get_irq_method(struct ath10k *ar) 7558c2ecf20Sopenharmony_ci{ 7568c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_MSI) 7598c2ecf20Sopenharmony_ci return "msi"; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci return "legacy"; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe) 7658c2ecf20Sopenharmony_ci{ 7668c2ecf20Sopenharmony_ci struct ath10k *ar = pipe->hif_ce_state; 7678c2ecf20Sopenharmony_ci struct ath10k_ce *ce = ath10k_ce_priv(ar); 7688c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; 7698c2ecf20Sopenharmony_ci struct sk_buff *skb; 7708c2ecf20Sopenharmony_ci dma_addr_t paddr; 7718c2ecf20Sopenharmony_ci int ret; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci skb = dev_alloc_skb(pipe->buf_sz); 7748c2ecf20Sopenharmony_ci if (!skb) 7758c2ecf20Sopenharmony_ci return -ENOMEM; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb"); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci paddr = dma_map_single(ar->dev, skb->data, 7808c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 7818c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 7828c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(ar->dev, paddr))) { 7838c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to dma map pci rx buf\n"); 7848c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 7858c2ecf20Sopenharmony_ci return -EIO; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ATH10K_SKB_RXCB(skb)->paddr = paddr; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci spin_lock_bh(&ce->ce_lock); 7918c2ecf20Sopenharmony_ci ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr); 7928c2ecf20Sopenharmony_ci spin_unlock_bh(&ce->ce_lock); 7938c2ecf20Sopenharmony_ci if (ret) { 7948c2ecf20Sopenharmony_ci dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb), 7958c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 7968c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 7978c2ecf20Sopenharmony_ci return ret; 7988c2ecf20Sopenharmony_ci } 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci return 0; 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci struct ath10k *ar = pipe->hif_ce_state; 8068c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 8078c2ecf20Sopenharmony_ci struct ath10k_ce *ce = ath10k_ce_priv(ar); 8088c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl; 8098c2ecf20Sopenharmony_ci int ret, num; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci if (pipe->buf_sz == 0) 8128c2ecf20Sopenharmony_ci return; 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci if (!ce_pipe->dest_ring) 8158c2ecf20Sopenharmony_ci return; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci spin_lock_bh(&ce->ce_lock); 8188c2ecf20Sopenharmony_ci num = __ath10k_ce_rx_num_free_bufs(ce_pipe); 8198c2ecf20Sopenharmony_ci spin_unlock_bh(&ce->ce_lock); 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci while (num >= 0) { 8228c2ecf20Sopenharmony_ci ret = __ath10k_pci_rx_post_buf(pipe); 8238c2ecf20Sopenharmony_ci if (ret) { 8248c2ecf20Sopenharmony_ci if (ret == -ENOSPC) 8258c2ecf20Sopenharmony_ci break; 8268c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to post pci rx buf: %d\n", ret); 8278c2ecf20Sopenharmony_ci mod_timer(&ar_pci->rx_post_retry, jiffies + 8288c2ecf20Sopenharmony_ci ATH10K_PCI_RX_POST_RETRY_MS); 8298c2ecf20Sopenharmony_ci break; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci num--; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci} 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_civoid ath10k_pci_rx_post(struct ath10k *ar) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 8388c2ecf20Sopenharmony_ci int i; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci for (i = 0; i < CE_COUNT; i++) 8418c2ecf20Sopenharmony_ci ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]); 8428c2ecf20Sopenharmony_ci} 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_civoid ath10k_pci_rx_replenish_retry(struct timer_list *t) 8458c2ecf20Sopenharmony_ci{ 8468c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = from_timer(ar_pci, t, rx_post_retry); 8478c2ecf20Sopenharmony_ci struct ath10k *ar = ar_pci->ar; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci ath10k_pci_rx_post(ar); 8508c2ecf20Sopenharmony_ci} 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_cistatic u32 ath10k_pci_qca988x_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) 8538c2ecf20Sopenharmony_ci{ 8548c2ecf20Sopenharmony_ci u32 val = 0, region = addr & 0xfffff; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS) 8578c2ecf20Sopenharmony_ci & 0x7ff) << 21; 8588c2ecf20Sopenharmony_ci val |= 0x100000 | region; 8598c2ecf20Sopenharmony_ci return val; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci/* Refactor from ath10k_pci_qca988x_targ_cpu_to_ce_addr. 8638c2ecf20Sopenharmony_ci * Support to access target space below 1M for qca6174 and qca9377. 8648c2ecf20Sopenharmony_ci * If target space is below 1M, the bit[20] of converted CE addr is 0. 8658c2ecf20Sopenharmony_ci * Otherwise bit[20] of converted CE addr is 1. 8668c2ecf20Sopenharmony_ci */ 8678c2ecf20Sopenharmony_cistatic u32 ath10k_pci_qca6174_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) 8688c2ecf20Sopenharmony_ci{ 8698c2ecf20Sopenharmony_ci u32 val = 0, region = addr & 0xfffff; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS) 8728c2ecf20Sopenharmony_ci & 0x7ff) << 21; 8738c2ecf20Sopenharmony_ci val |= ((addr >= 0x100000) ? 0x100000 : 0) | region; 8748c2ecf20Sopenharmony_ci return val; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic u32 ath10k_pci_qca99x0_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci u32 val = 0, region = addr & 0xfffff; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); 8828c2ecf20Sopenharmony_ci val |= 0x100000 | region; 8838c2ecf20Sopenharmony_ci return val; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!ar_pci->targ_cpu_to_ce_addr)) 8918c2ecf20Sopenharmony_ci return -ENOTSUPP; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci return ar_pci->targ_cpu_to_ce_addr(ar, addr); 8948c2ecf20Sopenharmony_ci} 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci/* 8978c2ecf20Sopenharmony_ci * Diagnostic read/write access is provided for startup/config/debug usage. 8988c2ecf20Sopenharmony_ci * Caller must guarantee proper alignment, when applicable, and single user 8998c2ecf20Sopenharmony_ci * at any moment. 9008c2ecf20Sopenharmony_ci */ 9018c2ecf20Sopenharmony_cistatic int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, 9028c2ecf20Sopenharmony_ci int nbytes) 9038c2ecf20Sopenharmony_ci{ 9048c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 9058c2ecf20Sopenharmony_ci int ret = 0; 9068c2ecf20Sopenharmony_ci u32 *buf; 9078c2ecf20Sopenharmony_ci unsigned int completed_nbytes, alloc_nbytes, remaining_bytes; 9088c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_diag; 9098c2ecf20Sopenharmony_ci /* Host buffer address in CE space */ 9108c2ecf20Sopenharmony_ci u32 ce_data; 9118c2ecf20Sopenharmony_ci dma_addr_t ce_data_base = 0; 9128c2ecf20Sopenharmony_ci void *data_buf; 9138c2ecf20Sopenharmony_ci int i; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci mutex_lock(&ar_pci->ce_diag_mutex); 9168c2ecf20Sopenharmony_ci ce_diag = ar_pci->ce_diag; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci /* 9198c2ecf20Sopenharmony_ci * Allocate a temporary bounce buffer to hold caller's data 9208c2ecf20Sopenharmony_ci * to be DMA'ed from Target. This guarantees 9218c2ecf20Sopenharmony_ci * 1) 4-byte alignment 9228c2ecf20Sopenharmony_ci * 2) Buffer in DMA-able space 9238c2ecf20Sopenharmony_ci */ 9248c2ecf20Sopenharmony_ci alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci data_buf = dma_alloc_coherent(ar->dev, alloc_nbytes, &ce_data_base, 9278c2ecf20Sopenharmony_ci GFP_ATOMIC); 9288c2ecf20Sopenharmony_ci if (!data_buf) { 9298c2ecf20Sopenharmony_ci ret = -ENOMEM; 9308c2ecf20Sopenharmony_ci goto done; 9318c2ecf20Sopenharmony_ci } 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci /* The address supplied by the caller is in the 9348c2ecf20Sopenharmony_ci * Target CPU virtual address space. 9358c2ecf20Sopenharmony_ci * 9368c2ecf20Sopenharmony_ci * In order to use this address with the diagnostic CE, 9378c2ecf20Sopenharmony_ci * convert it from Target CPU virtual address space 9388c2ecf20Sopenharmony_ci * to CE address space 9398c2ecf20Sopenharmony_ci */ 9408c2ecf20Sopenharmony_ci address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci remaining_bytes = nbytes; 9438c2ecf20Sopenharmony_ci ce_data = ce_data_base; 9448c2ecf20Sopenharmony_ci while (remaining_bytes) { 9458c2ecf20Sopenharmony_ci nbytes = min_t(unsigned int, remaining_bytes, 9468c2ecf20Sopenharmony_ci DIAG_TRANSFER_LIMIT); 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci ret = ath10k_ce_rx_post_buf(ce_diag, &ce_data, ce_data); 9498c2ecf20Sopenharmony_ci if (ret != 0) 9508c2ecf20Sopenharmony_ci goto done; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* Request CE to send from Target(!) address to Host buffer */ 9538c2ecf20Sopenharmony_ci ret = ath10k_ce_send(ce_diag, NULL, (u32)address, nbytes, 0, 0); 9548c2ecf20Sopenharmony_ci if (ret) 9558c2ecf20Sopenharmony_ci goto done; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci i = 0; 9588c2ecf20Sopenharmony_ci while (ath10k_ce_completed_send_next(ce_diag, NULL) != 0) { 9598c2ecf20Sopenharmony_ci udelay(DIAG_ACCESS_CE_WAIT_US); 9608c2ecf20Sopenharmony_ci i += DIAG_ACCESS_CE_WAIT_US; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci if (i > DIAG_ACCESS_CE_TIMEOUT_US) { 9638c2ecf20Sopenharmony_ci ret = -EBUSY; 9648c2ecf20Sopenharmony_ci goto done; 9658c2ecf20Sopenharmony_ci } 9668c2ecf20Sopenharmony_ci } 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci i = 0; 9698c2ecf20Sopenharmony_ci while (ath10k_ce_completed_recv_next(ce_diag, (void **)&buf, 9708c2ecf20Sopenharmony_ci &completed_nbytes) != 0) { 9718c2ecf20Sopenharmony_ci udelay(DIAG_ACCESS_CE_WAIT_US); 9728c2ecf20Sopenharmony_ci i += DIAG_ACCESS_CE_WAIT_US; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (i > DIAG_ACCESS_CE_TIMEOUT_US) { 9758c2ecf20Sopenharmony_ci ret = -EBUSY; 9768c2ecf20Sopenharmony_ci goto done; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci } 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (nbytes != completed_nbytes) { 9818c2ecf20Sopenharmony_ci ret = -EIO; 9828c2ecf20Sopenharmony_ci goto done; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci if (*buf != ce_data) { 9868c2ecf20Sopenharmony_ci ret = -EIO; 9878c2ecf20Sopenharmony_ci goto done; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci 9908c2ecf20Sopenharmony_ci remaining_bytes -= nbytes; 9918c2ecf20Sopenharmony_ci memcpy(data, data_buf, nbytes); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci address += nbytes; 9948c2ecf20Sopenharmony_ci data += nbytes; 9958c2ecf20Sopenharmony_ci } 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cidone: 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci if (data_buf) 10008c2ecf20Sopenharmony_ci dma_free_coherent(ar->dev, alloc_nbytes, data_buf, 10018c2ecf20Sopenharmony_ci ce_data_base); 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci mutex_unlock(&ar_pci->ce_diag_mutex); 10048c2ecf20Sopenharmony_ci 10058c2ecf20Sopenharmony_ci return ret; 10068c2ecf20Sopenharmony_ci} 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_cistatic int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value) 10098c2ecf20Sopenharmony_ci{ 10108c2ecf20Sopenharmony_ci __le32 val = 0; 10118c2ecf20Sopenharmony_ci int ret; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read_mem(ar, address, &val, sizeof(val)); 10148c2ecf20Sopenharmony_ci *value = __le32_to_cpu(val); 10158c2ecf20Sopenharmony_ci 10168c2ecf20Sopenharmony_ci return ret; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest, 10208c2ecf20Sopenharmony_ci u32 src, u32 len) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci u32 host_addr, addr; 10238c2ecf20Sopenharmony_ci int ret; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci host_addr = host_interest_item_address(src); 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read32(ar, host_addr, &addr); 10288c2ecf20Sopenharmony_ci if (ret != 0) { 10298c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n", 10308c2ecf20Sopenharmony_ci src, ret); 10318c2ecf20Sopenharmony_ci return ret; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read_mem(ar, addr, dest, len); 10358c2ecf20Sopenharmony_ci if (ret != 0) { 10368c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to memcpy firmware memory from %d (%d B): %d\n", 10378c2ecf20Sopenharmony_ci addr, len, ret); 10388c2ecf20Sopenharmony_ci return ret; 10398c2ecf20Sopenharmony_ci } 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci return 0; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci#define ath10k_pci_diag_read_hi(ar, dest, src, len) \ 10458c2ecf20Sopenharmony_ci __ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len) 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ciint ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, 10488c2ecf20Sopenharmony_ci const void *data, int nbytes) 10498c2ecf20Sopenharmony_ci{ 10508c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 10518c2ecf20Sopenharmony_ci int ret = 0; 10528c2ecf20Sopenharmony_ci u32 *buf; 10538c2ecf20Sopenharmony_ci unsigned int completed_nbytes, alloc_nbytes, remaining_bytes; 10548c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_diag; 10558c2ecf20Sopenharmony_ci void *data_buf; 10568c2ecf20Sopenharmony_ci dma_addr_t ce_data_base = 0; 10578c2ecf20Sopenharmony_ci int i; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci mutex_lock(&ar_pci->ce_diag_mutex); 10608c2ecf20Sopenharmony_ci ce_diag = ar_pci->ce_diag; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* 10638c2ecf20Sopenharmony_ci * Allocate a temporary bounce buffer to hold caller's data 10648c2ecf20Sopenharmony_ci * to be DMA'ed to Target. This guarantees 10658c2ecf20Sopenharmony_ci * 1) 4-byte alignment 10668c2ecf20Sopenharmony_ci * 2) Buffer in DMA-able space 10678c2ecf20Sopenharmony_ci */ 10688c2ecf20Sopenharmony_ci alloc_nbytes = min_t(unsigned int, nbytes, DIAG_TRANSFER_LIMIT); 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci data_buf = dma_alloc_coherent(ar->dev, alloc_nbytes, &ce_data_base, 10718c2ecf20Sopenharmony_ci GFP_ATOMIC); 10728c2ecf20Sopenharmony_ci if (!data_buf) { 10738c2ecf20Sopenharmony_ci ret = -ENOMEM; 10748c2ecf20Sopenharmony_ci goto done; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci /* 10788c2ecf20Sopenharmony_ci * The address supplied by the caller is in the 10798c2ecf20Sopenharmony_ci * Target CPU virtual address space. 10808c2ecf20Sopenharmony_ci * 10818c2ecf20Sopenharmony_ci * In order to use this address with the diagnostic CE, 10828c2ecf20Sopenharmony_ci * convert it from 10838c2ecf20Sopenharmony_ci * Target CPU virtual address space 10848c2ecf20Sopenharmony_ci * to 10858c2ecf20Sopenharmony_ci * CE address space 10868c2ecf20Sopenharmony_ci */ 10878c2ecf20Sopenharmony_ci address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci remaining_bytes = nbytes; 10908c2ecf20Sopenharmony_ci while (remaining_bytes) { 10918c2ecf20Sopenharmony_ci /* FIXME: check cast */ 10928c2ecf20Sopenharmony_ci nbytes = min_t(int, remaining_bytes, DIAG_TRANSFER_LIMIT); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci /* Copy caller's data to allocated DMA buf */ 10958c2ecf20Sopenharmony_ci memcpy(data_buf, data, nbytes); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci /* Set up to receive directly into Target(!) address */ 10988c2ecf20Sopenharmony_ci ret = ath10k_ce_rx_post_buf(ce_diag, &address, address); 10998c2ecf20Sopenharmony_ci if (ret != 0) 11008c2ecf20Sopenharmony_ci goto done; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci /* 11038c2ecf20Sopenharmony_ci * Request CE to send caller-supplied data that 11048c2ecf20Sopenharmony_ci * was copied to bounce buffer to Target(!) address. 11058c2ecf20Sopenharmony_ci */ 11068c2ecf20Sopenharmony_ci ret = ath10k_ce_send(ce_diag, NULL, ce_data_base, nbytes, 0, 0); 11078c2ecf20Sopenharmony_ci if (ret != 0) 11088c2ecf20Sopenharmony_ci goto done; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci i = 0; 11118c2ecf20Sopenharmony_ci while (ath10k_ce_completed_send_next(ce_diag, NULL) != 0) { 11128c2ecf20Sopenharmony_ci udelay(DIAG_ACCESS_CE_WAIT_US); 11138c2ecf20Sopenharmony_ci i += DIAG_ACCESS_CE_WAIT_US; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (i > DIAG_ACCESS_CE_TIMEOUT_US) { 11168c2ecf20Sopenharmony_ci ret = -EBUSY; 11178c2ecf20Sopenharmony_ci goto done; 11188c2ecf20Sopenharmony_ci } 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci i = 0; 11228c2ecf20Sopenharmony_ci while (ath10k_ce_completed_recv_next(ce_diag, (void **)&buf, 11238c2ecf20Sopenharmony_ci &completed_nbytes) != 0) { 11248c2ecf20Sopenharmony_ci udelay(DIAG_ACCESS_CE_WAIT_US); 11258c2ecf20Sopenharmony_ci i += DIAG_ACCESS_CE_WAIT_US; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci if (i > DIAG_ACCESS_CE_TIMEOUT_US) { 11288c2ecf20Sopenharmony_ci ret = -EBUSY; 11298c2ecf20Sopenharmony_ci goto done; 11308c2ecf20Sopenharmony_ci } 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci if (nbytes != completed_nbytes) { 11348c2ecf20Sopenharmony_ci ret = -EIO; 11358c2ecf20Sopenharmony_ci goto done; 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci if (*buf != address) { 11398c2ecf20Sopenharmony_ci ret = -EIO; 11408c2ecf20Sopenharmony_ci goto done; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci remaining_bytes -= nbytes; 11448c2ecf20Sopenharmony_ci address += nbytes; 11458c2ecf20Sopenharmony_ci data += nbytes; 11468c2ecf20Sopenharmony_ci } 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_cidone: 11498c2ecf20Sopenharmony_ci if (data_buf) { 11508c2ecf20Sopenharmony_ci dma_free_coherent(ar->dev, alloc_nbytes, data_buf, 11518c2ecf20Sopenharmony_ci ce_data_base); 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci if (ret != 0) 11558c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to write diag value at 0x%x: %d\n", 11568c2ecf20Sopenharmony_ci address, ret); 11578c2ecf20Sopenharmony_ci 11588c2ecf20Sopenharmony_ci mutex_unlock(&ar_pci->ce_diag_mutex); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci return ret; 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic int ath10k_pci_diag_write32(struct ath10k *ar, u32 address, u32 value) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci __le32 val = __cpu_to_le32(value); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci return ath10k_pci_diag_write_mem(ar, address, &val, sizeof(val)); 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci/* Called by lower (CE) layer when a send to Target completes. */ 11718c2ecf20Sopenharmony_cistatic void ath10k_pci_htc_tx_cb(struct ath10k_ce_pipe *ce_state) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci struct ath10k *ar = ce_state->ar; 11748c2ecf20Sopenharmony_ci struct sk_buff_head list; 11758c2ecf20Sopenharmony_ci struct sk_buff *skb; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci __skb_queue_head_init(&list); 11788c2ecf20Sopenharmony_ci while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) { 11798c2ecf20Sopenharmony_ci /* no need to call tx completion for NULL pointers */ 11808c2ecf20Sopenharmony_ci if (skb == NULL) 11818c2ecf20Sopenharmony_ci continue; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci __skb_queue_tail(&list, skb); 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&list))) 11878c2ecf20Sopenharmony_ci ath10k_htc_tx_completion_handler(ar, skb); 11888c2ecf20Sopenharmony_ci} 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_cistatic void ath10k_pci_process_rx_cb(struct ath10k_ce_pipe *ce_state, 11918c2ecf20Sopenharmony_ci void (*callback)(struct ath10k *ar, 11928c2ecf20Sopenharmony_ci struct sk_buff *skb)) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci struct ath10k *ar = ce_state->ar; 11958c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 11968c2ecf20Sopenharmony_ci struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; 11978c2ecf20Sopenharmony_ci struct sk_buff *skb; 11988c2ecf20Sopenharmony_ci struct sk_buff_head list; 11998c2ecf20Sopenharmony_ci void *transfer_context; 12008c2ecf20Sopenharmony_ci unsigned int nbytes, max_nbytes; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci __skb_queue_head_init(&list); 12038c2ecf20Sopenharmony_ci while (ath10k_ce_completed_recv_next(ce_state, &transfer_context, 12048c2ecf20Sopenharmony_ci &nbytes) == 0) { 12058c2ecf20Sopenharmony_ci skb = transfer_context; 12068c2ecf20Sopenharmony_ci max_nbytes = skb->len + skb_tailroom(skb); 12078c2ecf20Sopenharmony_ci dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, 12088c2ecf20Sopenharmony_ci max_nbytes, DMA_FROM_DEVICE); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (unlikely(max_nbytes < nbytes)) { 12118c2ecf20Sopenharmony_ci ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)", 12128c2ecf20Sopenharmony_ci nbytes, max_nbytes); 12138c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 12148c2ecf20Sopenharmony_ci continue; 12158c2ecf20Sopenharmony_ci } 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci skb_put(skb, nbytes); 12188c2ecf20Sopenharmony_ci __skb_queue_tail(&list, skb); 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&list))) { 12228c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", 12238c2ecf20Sopenharmony_ci ce_state->id, skb->len); 12248c2ecf20Sopenharmony_ci ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", 12258c2ecf20Sopenharmony_ci skb->data, skb->len); 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci callback(ar, skb); 12288c2ecf20Sopenharmony_ci } 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci ath10k_pci_rx_post_pipe(pipe_info); 12318c2ecf20Sopenharmony_ci} 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_cistatic void ath10k_pci_process_htt_rx_cb(struct ath10k_ce_pipe *ce_state, 12348c2ecf20Sopenharmony_ci void (*callback)(struct ath10k *ar, 12358c2ecf20Sopenharmony_ci struct sk_buff *skb)) 12368c2ecf20Sopenharmony_ci{ 12378c2ecf20Sopenharmony_ci struct ath10k *ar = ce_state->ar; 12388c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 12398c2ecf20Sopenharmony_ci struct ath10k_pci_pipe *pipe_info = &ar_pci->pipe_info[ce_state->id]; 12408c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_pipe = pipe_info->ce_hdl; 12418c2ecf20Sopenharmony_ci struct sk_buff *skb; 12428c2ecf20Sopenharmony_ci struct sk_buff_head list; 12438c2ecf20Sopenharmony_ci void *transfer_context; 12448c2ecf20Sopenharmony_ci unsigned int nbytes, max_nbytes, nentries; 12458c2ecf20Sopenharmony_ci int orig_len; 12468c2ecf20Sopenharmony_ci 12478c2ecf20Sopenharmony_ci /* No need to aquire ce_lock for CE5, since this is the only place CE5 12488c2ecf20Sopenharmony_ci * is processed other than init and deinit. Before releasing CE5 12498c2ecf20Sopenharmony_ci * buffers, interrupts are disabled. Thus CE5 access is serialized. 12508c2ecf20Sopenharmony_ci */ 12518c2ecf20Sopenharmony_ci __skb_queue_head_init(&list); 12528c2ecf20Sopenharmony_ci while (ath10k_ce_completed_recv_next_nolock(ce_state, &transfer_context, 12538c2ecf20Sopenharmony_ci &nbytes) == 0) { 12548c2ecf20Sopenharmony_ci skb = transfer_context; 12558c2ecf20Sopenharmony_ci max_nbytes = skb->len + skb_tailroom(skb); 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_ci if (unlikely(max_nbytes < nbytes)) { 12588c2ecf20Sopenharmony_ci ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)", 12598c2ecf20Sopenharmony_ci nbytes, max_nbytes); 12608c2ecf20Sopenharmony_ci continue; 12618c2ecf20Sopenharmony_ci } 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, 12648c2ecf20Sopenharmony_ci max_nbytes, DMA_FROM_DEVICE); 12658c2ecf20Sopenharmony_ci skb_put(skb, nbytes); 12668c2ecf20Sopenharmony_ci __skb_queue_tail(&list, skb); 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci nentries = skb_queue_len(&list); 12708c2ecf20Sopenharmony_ci while ((skb = __skb_dequeue(&list))) { 12718c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, "pci rx ce pipe %d len %d\n", 12728c2ecf20Sopenharmony_ci ce_state->id, skb->len); 12738c2ecf20Sopenharmony_ci ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci rx: ", 12748c2ecf20Sopenharmony_ci skb->data, skb->len); 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci orig_len = skb->len; 12778c2ecf20Sopenharmony_ci callback(ar, skb); 12788c2ecf20Sopenharmony_ci skb_push(skb, orig_len - skb->len); 12798c2ecf20Sopenharmony_ci skb_reset_tail_pointer(skb); 12808c2ecf20Sopenharmony_ci skb_trim(skb, 0); 12818c2ecf20Sopenharmony_ci 12828c2ecf20Sopenharmony_ci /*let device gain the buffer again*/ 12838c2ecf20Sopenharmony_ci dma_sync_single_for_device(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, 12848c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 12858c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 12868c2ecf20Sopenharmony_ci } 12878c2ecf20Sopenharmony_ci ath10k_ce_rx_update_write_idx(ce_pipe, nentries); 12888c2ecf20Sopenharmony_ci} 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci/* Called by lower (CE) layer when data is received from the Target. */ 12918c2ecf20Sopenharmony_cistatic void ath10k_pci_htc_rx_cb(struct ath10k_ce_pipe *ce_state) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); 12948c2ecf20Sopenharmony_ci} 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_cistatic void ath10k_pci_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state) 12978c2ecf20Sopenharmony_ci{ 12988c2ecf20Sopenharmony_ci /* CE4 polling needs to be done whenever CE pipe which transports 12998c2ecf20Sopenharmony_ci * HTT Rx (target->host) is processed. 13008c2ecf20Sopenharmony_ci */ 13018c2ecf20Sopenharmony_ci ath10k_ce_per_engine_service(ce_state->ar, 4); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci ath10k_pci_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler); 13048c2ecf20Sopenharmony_ci} 13058c2ecf20Sopenharmony_ci 13068c2ecf20Sopenharmony_ci/* Called by lower (CE) layer when data is received from the Target. 13078c2ecf20Sopenharmony_ci * Only 10.4 firmware uses separate CE to transfer pktlog data. 13088c2ecf20Sopenharmony_ci */ 13098c2ecf20Sopenharmony_cistatic void ath10k_pci_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state) 13108c2ecf20Sopenharmony_ci{ 13118c2ecf20Sopenharmony_ci ath10k_pci_process_rx_cb(ce_state, 13128c2ecf20Sopenharmony_ci ath10k_htt_rx_pktlog_completion_handler); 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci/* Called by lower (CE) layer when a send to HTT Target completes. */ 13168c2ecf20Sopenharmony_cistatic void ath10k_pci_htt_tx_cb(struct ath10k_ce_pipe *ce_state) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci struct ath10k *ar = ce_state->ar; 13198c2ecf20Sopenharmony_ci struct sk_buff *skb; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) { 13228c2ecf20Sopenharmony_ci /* no need to call tx completion for NULL pointers */ 13238c2ecf20Sopenharmony_ci if (!skb) 13248c2ecf20Sopenharmony_ci continue; 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr, 13278c2ecf20Sopenharmony_ci skb->len, DMA_TO_DEVICE); 13288c2ecf20Sopenharmony_ci ath10k_htt_hif_tx_complete(ar, skb); 13298c2ecf20Sopenharmony_ci } 13308c2ecf20Sopenharmony_ci} 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_cistatic void ath10k_pci_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb) 13338c2ecf20Sopenharmony_ci{ 13348c2ecf20Sopenharmony_ci skb_pull(skb, sizeof(struct ath10k_htc_hdr)); 13358c2ecf20Sopenharmony_ci ath10k_htt_t2h_msg_handler(ar, skb); 13368c2ecf20Sopenharmony_ci} 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci/* Called by lower (CE) layer when HTT data is received from the Target. */ 13398c2ecf20Sopenharmony_cistatic void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci /* CE4 polling needs to be done whenever CE pipe which transports 13428c2ecf20Sopenharmony_ci * HTT Rx (target->host) is processed. 13438c2ecf20Sopenharmony_ci */ 13448c2ecf20Sopenharmony_ci ath10k_ce_per_engine_service(ce_state->ar, 4); 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci ath10k_pci_process_htt_rx_cb(ce_state, ath10k_pci_htt_rx_deliver); 13478c2ecf20Sopenharmony_ci} 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ciint ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id, 13508c2ecf20Sopenharmony_ci struct ath10k_hif_sg_item *items, int n_items) 13518c2ecf20Sopenharmony_ci{ 13528c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 13538c2ecf20Sopenharmony_ci struct ath10k_ce *ce = ath10k_ce_priv(ar); 13548c2ecf20Sopenharmony_ci struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id]; 13558c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_pipe = pci_pipe->ce_hdl; 13568c2ecf20Sopenharmony_ci struct ath10k_ce_ring *src_ring = ce_pipe->src_ring; 13578c2ecf20Sopenharmony_ci unsigned int nentries_mask; 13588c2ecf20Sopenharmony_ci unsigned int sw_index; 13598c2ecf20Sopenharmony_ci unsigned int write_index; 13608c2ecf20Sopenharmony_ci int err, i = 0; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci spin_lock_bh(&ce->ce_lock); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci nentries_mask = src_ring->nentries_mask; 13658c2ecf20Sopenharmony_ci sw_index = src_ring->sw_index; 13668c2ecf20Sopenharmony_ci write_index = src_ring->write_index; 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci if (unlikely(CE_RING_DELTA(nentries_mask, 13698c2ecf20Sopenharmony_ci write_index, sw_index - 1) < n_items)) { 13708c2ecf20Sopenharmony_ci err = -ENOBUFS; 13718c2ecf20Sopenharmony_ci goto err; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci for (i = 0; i < n_items - 1; i++) { 13758c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, 13768c2ecf20Sopenharmony_ci "pci tx item %d paddr %pad len %d n_items %d\n", 13778c2ecf20Sopenharmony_ci i, &items[i].paddr, items[i].len, n_items); 13788c2ecf20Sopenharmony_ci ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", 13798c2ecf20Sopenharmony_ci items[i].vaddr, items[i].len); 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci err = ath10k_ce_send_nolock(ce_pipe, 13828c2ecf20Sopenharmony_ci items[i].transfer_context, 13838c2ecf20Sopenharmony_ci items[i].paddr, 13848c2ecf20Sopenharmony_ci items[i].len, 13858c2ecf20Sopenharmony_ci items[i].transfer_id, 13868c2ecf20Sopenharmony_ci CE_SEND_FLAG_GATHER); 13878c2ecf20Sopenharmony_ci if (err) 13888c2ecf20Sopenharmony_ci goto err; 13898c2ecf20Sopenharmony_ci } 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_ci /* `i` is equal to `n_items -1` after for() */ 13928c2ecf20Sopenharmony_ci 13938c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, 13948c2ecf20Sopenharmony_ci "pci tx item %d paddr %pad len %d n_items %d\n", 13958c2ecf20Sopenharmony_ci i, &items[i].paddr, items[i].len, n_items); 13968c2ecf20Sopenharmony_ci ath10k_dbg_dump(ar, ATH10K_DBG_PCI_DUMP, NULL, "pci tx data: ", 13978c2ecf20Sopenharmony_ci items[i].vaddr, items[i].len); 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci err = ath10k_ce_send_nolock(ce_pipe, 14008c2ecf20Sopenharmony_ci items[i].transfer_context, 14018c2ecf20Sopenharmony_ci items[i].paddr, 14028c2ecf20Sopenharmony_ci items[i].len, 14038c2ecf20Sopenharmony_ci items[i].transfer_id, 14048c2ecf20Sopenharmony_ci 0); 14058c2ecf20Sopenharmony_ci if (err) 14068c2ecf20Sopenharmony_ci goto err; 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_ci spin_unlock_bh(&ce->ce_lock); 14098c2ecf20Sopenharmony_ci return 0; 14108c2ecf20Sopenharmony_ci 14118c2ecf20Sopenharmony_cierr: 14128c2ecf20Sopenharmony_ci for (; i > 0; i--) 14138c2ecf20Sopenharmony_ci __ath10k_ce_send_revert(ce_pipe); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci spin_unlock_bh(&ce->ce_lock); 14168c2ecf20Sopenharmony_ci return err; 14178c2ecf20Sopenharmony_ci} 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ciint ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf, 14208c2ecf20Sopenharmony_ci size_t buf_len) 14218c2ecf20Sopenharmony_ci{ 14228c2ecf20Sopenharmony_ci return ath10k_pci_diag_read_mem(ar, address, buf, buf_len); 14238c2ecf20Sopenharmony_ci} 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ciu16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe) 14268c2ecf20Sopenharmony_ci{ 14278c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get free queue number\n"); 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl); 14328c2ecf20Sopenharmony_ci} 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_cistatic void ath10k_pci_dump_registers(struct ath10k *ar, 14358c2ecf20Sopenharmony_ci struct ath10k_fw_crash_data *crash_data) 14368c2ecf20Sopenharmony_ci{ 14378c2ecf20Sopenharmony_ci __le32 reg_dump_values[REG_DUMP_COUNT_QCA988X] = {}; 14388c2ecf20Sopenharmony_ci int i, ret; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->dump_mutex); 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read_hi(ar, ®_dump_values[0], 14438c2ecf20Sopenharmony_ci hi_failure_state, 14448c2ecf20Sopenharmony_ci REG_DUMP_COUNT_QCA988X * sizeof(__le32)); 14458c2ecf20Sopenharmony_ci if (ret) { 14468c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to read firmware dump area: %d\n", ret); 14478c2ecf20Sopenharmony_ci return; 14488c2ecf20Sopenharmony_ci } 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci ath10k_err(ar, "firmware register dump:\n"); 14538c2ecf20Sopenharmony_ci for (i = 0; i < REG_DUMP_COUNT_QCA988X; i += 4) 14548c2ecf20Sopenharmony_ci ath10k_err(ar, "[%02d]: 0x%08X 0x%08X 0x%08X 0x%08X\n", 14558c2ecf20Sopenharmony_ci i, 14568c2ecf20Sopenharmony_ci __le32_to_cpu(reg_dump_values[i]), 14578c2ecf20Sopenharmony_ci __le32_to_cpu(reg_dump_values[i + 1]), 14588c2ecf20Sopenharmony_ci __le32_to_cpu(reg_dump_values[i + 2]), 14598c2ecf20Sopenharmony_ci __le32_to_cpu(reg_dump_values[i + 3])); 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if (!crash_data) 14628c2ecf20Sopenharmony_ci return; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci for (i = 0; i < REG_DUMP_COUNT_QCA988X; i++) 14658c2ecf20Sopenharmony_ci crash_data->registers[i] = reg_dump_values[i]; 14668c2ecf20Sopenharmony_ci} 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_cistatic int ath10k_pci_dump_memory_section(struct ath10k *ar, 14698c2ecf20Sopenharmony_ci const struct ath10k_mem_region *mem_region, 14708c2ecf20Sopenharmony_ci u8 *buf, size_t buf_len) 14718c2ecf20Sopenharmony_ci{ 14728c2ecf20Sopenharmony_ci const struct ath10k_mem_section *cur_section, *next_section; 14738c2ecf20Sopenharmony_ci unsigned int count, section_size, skip_size; 14748c2ecf20Sopenharmony_ci int ret, i, j; 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci if (!mem_region || !buf) 14778c2ecf20Sopenharmony_ci return 0; 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci cur_section = &mem_region->section_table.sections[0]; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (mem_region->start > cur_section->start) { 14828c2ecf20Sopenharmony_ci ath10k_warn(ar, "incorrect memdump region 0x%x with section start address 0x%x.\n", 14838c2ecf20Sopenharmony_ci mem_region->start, cur_section->start); 14848c2ecf20Sopenharmony_ci return 0; 14858c2ecf20Sopenharmony_ci } 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ci skip_size = cur_section->start - mem_region->start; 14888c2ecf20Sopenharmony_ci 14898c2ecf20Sopenharmony_ci /* fill the gap between the first register section and register 14908c2ecf20Sopenharmony_ci * start address 14918c2ecf20Sopenharmony_ci */ 14928c2ecf20Sopenharmony_ci for (i = 0; i < skip_size; i++) { 14938c2ecf20Sopenharmony_ci *buf = ATH10K_MAGIC_NOT_COPIED; 14948c2ecf20Sopenharmony_ci buf++; 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci count = 0; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci for (i = 0; cur_section != NULL; i++) { 15008c2ecf20Sopenharmony_ci section_size = cur_section->end - cur_section->start; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci if (section_size <= 0) { 15038c2ecf20Sopenharmony_ci ath10k_warn(ar, "incorrect ramdump format with start address 0x%x and stop address 0x%x\n", 15048c2ecf20Sopenharmony_ci cur_section->start, 15058c2ecf20Sopenharmony_ci cur_section->end); 15068c2ecf20Sopenharmony_ci break; 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci if ((i + 1) == mem_region->section_table.size) { 15108c2ecf20Sopenharmony_ci /* last section */ 15118c2ecf20Sopenharmony_ci next_section = NULL; 15128c2ecf20Sopenharmony_ci skip_size = 0; 15138c2ecf20Sopenharmony_ci } else { 15148c2ecf20Sopenharmony_ci next_section = cur_section + 1; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (cur_section->end > next_section->start) { 15178c2ecf20Sopenharmony_ci ath10k_warn(ar, "next ramdump section 0x%x is smaller than current end address 0x%x\n", 15188c2ecf20Sopenharmony_ci next_section->start, 15198c2ecf20Sopenharmony_ci cur_section->end); 15208c2ecf20Sopenharmony_ci break; 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci skip_size = next_section->start - cur_section->end; 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (buf_len < (skip_size + section_size)) { 15278c2ecf20Sopenharmony_ci ath10k_warn(ar, "ramdump buffer is too small: %zu\n", buf_len); 15288c2ecf20Sopenharmony_ci break; 15298c2ecf20Sopenharmony_ci } 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci buf_len -= skip_size + section_size; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci /* read section to dest memory */ 15348c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read_mem(ar, cur_section->start, 15358c2ecf20Sopenharmony_ci buf, section_size); 15368c2ecf20Sopenharmony_ci if (ret) { 15378c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to read ramdump from section 0x%x: %d\n", 15388c2ecf20Sopenharmony_ci cur_section->start, ret); 15398c2ecf20Sopenharmony_ci break; 15408c2ecf20Sopenharmony_ci } 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci buf += section_size; 15438c2ecf20Sopenharmony_ci count += section_size; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci /* fill in the gap between this section and the next */ 15468c2ecf20Sopenharmony_ci for (j = 0; j < skip_size; j++) { 15478c2ecf20Sopenharmony_ci *buf = ATH10K_MAGIC_NOT_COPIED; 15488c2ecf20Sopenharmony_ci buf++; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci count += skip_size; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (!next_section) 15548c2ecf20Sopenharmony_ci /* this was the last section */ 15558c2ecf20Sopenharmony_ci break; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci cur_section = next_section; 15588c2ecf20Sopenharmony_ci } 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci return count; 15618c2ecf20Sopenharmony_ci} 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_cistatic int ath10k_pci_set_ram_config(struct ath10k *ar, u32 config) 15648c2ecf20Sopenharmony_ci{ 15658c2ecf20Sopenharmony_ci u32 val; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + 15688c2ecf20Sopenharmony_ci FW_RAM_CONFIG_ADDRESS, config); 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + 15718c2ecf20Sopenharmony_ci FW_RAM_CONFIG_ADDRESS); 15728c2ecf20Sopenharmony_ci if (val != config) { 15738c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to set RAM config from 0x%x to 0x%x\n", 15748c2ecf20Sopenharmony_ci val, config); 15758c2ecf20Sopenharmony_ci return -EIO; 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci return 0; 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci/* Always returns the length */ 15828c2ecf20Sopenharmony_cistatic int ath10k_pci_dump_memory_sram(struct ath10k *ar, 15838c2ecf20Sopenharmony_ci const struct ath10k_mem_region *region, 15848c2ecf20Sopenharmony_ci u8 *buf) 15858c2ecf20Sopenharmony_ci{ 15868c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 15878c2ecf20Sopenharmony_ci u32 base_addr, i; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci base_addr = ioread32(ar_pci->mem + QCA99X0_PCIE_BAR0_START_REG); 15908c2ecf20Sopenharmony_ci base_addr += region->start; 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci for (i = 0; i < region->len; i += 4) { 15938c2ecf20Sopenharmony_ci iowrite32(base_addr + i, ar_pci->mem + QCA99X0_CPU_MEM_ADDR_REG); 15948c2ecf20Sopenharmony_ci *(u32 *)(buf + i) = ioread32(ar_pci->mem + QCA99X0_CPU_MEM_DATA_REG); 15958c2ecf20Sopenharmony_ci } 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci return region->len; 15988c2ecf20Sopenharmony_ci} 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci/* if an error happened returns < 0, otherwise the length */ 16018c2ecf20Sopenharmony_cistatic int ath10k_pci_dump_memory_reg(struct ath10k *ar, 16028c2ecf20Sopenharmony_ci const struct ath10k_mem_region *region, 16038c2ecf20Sopenharmony_ci u8 *buf) 16048c2ecf20Sopenharmony_ci{ 16058c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 16068c2ecf20Sopenharmony_ci u32 i; 16078c2ecf20Sopenharmony_ci int ret; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci mutex_lock(&ar->conf_mutex); 16108c2ecf20Sopenharmony_ci if (ar->state != ATH10K_STATE_ON) { 16118c2ecf20Sopenharmony_ci ath10k_warn(ar, "Skipping pci_dump_memory_reg invalid state\n"); 16128c2ecf20Sopenharmony_ci ret = -EIO; 16138c2ecf20Sopenharmony_ci goto done; 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci for (i = 0; i < region->len; i += 4) 16178c2ecf20Sopenharmony_ci *(u32 *)(buf + i) = ioread32(ar_pci->mem + region->start + i); 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci ret = region->len; 16208c2ecf20Sopenharmony_cidone: 16218c2ecf20Sopenharmony_ci mutex_unlock(&ar->conf_mutex); 16228c2ecf20Sopenharmony_ci return ret; 16238c2ecf20Sopenharmony_ci} 16248c2ecf20Sopenharmony_ci 16258c2ecf20Sopenharmony_ci/* if an error happened returns < 0, otherwise the length */ 16268c2ecf20Sopenharmony_cistatic int ath10k_pci_dump_memory_generic(struct ath10k *ar, 16278c2ecf20Sopenharmony_ci const struct ath10k_mem_region *current_region, 16288c2ecf20Sopenharmony_ci u8 *buf) 16298c2ecf20Sopenharmony_ci{ 16308c2ecf20Sopenharmony_ci int ret; 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci if (current_region->section_table.size > 0) 16338c2ecf20Sopenharmony_ci /* Copy each section individually. */ 16348c2ecf20Sopenharmony_ci return ath10k_pci_dump_memory_section(ar, 16358c2ecf20Sopenharmony_ci current_region, 16368c2ecf20Sopenharmony_ci buf, 16378c2ecf20Sopenharmony_ci current_region->len); 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci /* No individiual memory sections defined so we can 16408c2ecf20Sopenharmony_ci * copy the entire memory region. 16418c2ecf20Sopenharmony_ci */ 16428c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read_mem(ar, 16438c2ecf20Sopenharmony_ci current_region->start, 16448c2ecf20Sopenharmony_ci buf, 16458c2ecf20Sopenharmony_ci current_region->len); 16468c2ecf20Sopenharmony_ci if (ret) { 16478c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to copy ramdump region %s: %d\n", 16488c2ecf20Sopenharmony_ci current_region->name, ret); 16498c2ecf20Sopenharmony_ci return ret; 16508c2ecf20Sopenharmony_ci } 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci return current_region->len; 16538c2ecf20Sopenharmony_ci} 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_cistatic void ath10k_pci_dump_memory(struct ath10k *ar, 16568c2ecf20Sopenharmony_ci struct ath10k_fw_crash_data *crash_data) 16578c2ecf20Sopenharmony_ci{ 16588c2ecf20Sopenharmony_ci const struct ath10k_hw_mem_layout *mem_layout; 16598c2ecf20Sopenharmony_ci const struct ath10k_mem_region *current_region; 16608c2ecf20Sopenharmony_ci struct ath10k_dump_ram_data_hdr *hdr; 16618c2ecf20Sopenharmony_ci u32 count, shift; 16628c2ecf20Sopenharmony_ci size_t buf_len; 16638c2ecf20Sopenharmony_ci int ret, i; 16648c2ecf20Sopenharmony_ci u8 *buf; 16658c2ecf20Sopenharmony_ci 16668c2ecf20Sopenharmony_ci lockdep_assert_held(&ar->dump_mutex); 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_ci if (!crash_data) 16698c2ecf20Sopenharmony_ci return; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci mem_layout = ath10k_coredump_get_mem_layout(ar); 16728c2ecf20Sopenharmony_ci if (!mem_layout) 16738c2ecf20Sopenharmony_ci return; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci current_region = &mem_layout->region_table.regions[0]; 16768c2ecf20Sopenharmony_ci 16778c2ecf20Sopenharmony_ci buf = crash_data->ramdump_buf; 16788c2ecf20Sopenharmony_ci buf_len = crash_data->ramdump_buf_len; 16798c2ecf20Sopenharmony_ci 16808c2ecf20Sopenharmony_ci memset(buf, 0, buf_len); 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci for (i = 0; i < mem_layout->region_table.size; i++) { 16838c2ecf20Sopenharmony_ci count = 0; 16848c2ecf20Sopenharmony_ci 16858c2ecf20Sopenharmony_ci if (current_region->len > buf_len) { 16868c2ecf20Sopenharmony_ci ath10k_warn(ar, "memory region %s size %d is larger that remaining ramdump buffer size %zu\n", 16878c2ecf20Sopenharmony_ci current_region->name, 16888c2ecf20Sopenharmony_ci current_region->len, 16898c2ecf20Sopenharmony_ci buf_len); 16908c2ecf20Sopenharmony_ci break; 16918c2ecf20Sopenharmony_ci } 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_ci /* To get IRAM dump, the host driver needs to switch target 16948c2ecf20Sopenharmony_ci * ram config from DRAM to IRAM. 16958c2ecf20Sopenharmony_ci */ 16968c2ecf20Sopenharmony_ci if (current_region->type == ATH10K_MEM_REGION_TYPE_IRAM1 || 16978c2ecf20Sopenharmony_ci current_region->type == ATH10K_MEM_REGION_TYPE_IRAM2) { 16988c2ecf20Sopenharmony_ci shift = current_region->start >> 20; 16998c2ecf20Sopenharmony_ci 17008c2ecf20Sopenharmony_ci ret = ath10k_pci_set_ram_config(ar, shift); 17018c2ecf20Sopenharmony_ci if (ret) { 17028c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to switch ram config to IRAM for section %s: %d\n", 17038c2ecf20Sopenharmony_ci current_region->name, ret); 17048c2ecf20Sopenharmony_ci break; 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci } 17078c2ecf20Sopenharmony_ci 17088c2ecf20Sopenharmony_ci /* Reserve space for the header. */ 17098c2ecf20Sopenharmony_ci hdr = (void *)buf; 17108c2ecf20Sopenharmony_ci buf += sizeof(*hdr); 17118c2ecf20Sopenharmony_ci buf_len -= sizeof(*hdr); 17128c2ecf20Sopenharmony_ci 17138c2ecf20Sopenharmony_ci switch (current_region->type) { 17148c2ecf20Sopenharmony_ci case ATH10K_MEM_REGION_TYPE_IOSRAM: 17158c2ecf20Sopenharmony_ci count = ath10k_pci_dump_memory_sram(ar, current_region, buf); 17168c2ecf20Sopenharmony_ci break; 17178c2ecf20Sopenharmony_ci case ATH10K_MEM_REGION_TYPE_IOREG: 17188c2ecf20Sopenharmony_ci ret = ath10k_pci_dump_memory_reg(ar, current_region, buf); 17198c2ecf20Sopenharmony_ci if (ret < 0) 17208c2ecf20Sopenharmony_ci break; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci count = ret; 17238c2ecf20Sopenharmony_ci break; 17248c2ecf20Sopenharmony_ci default: 17258c2ecf20Sopenharmony_ci ret = ath10k_pci_dump_memory_generic(ar, current_region, buf); 17268c2ecf20Sopenharmony_ci if (ret < 0) 17278c2ecf20Sopenharmony_ci break; 17288c2ecf20Sopenharmony_ci 17298c2ecf20Sopenharmony_ci count = ret; 17308c2ecf20Sopenharmony_ci break; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci hdr->region_type = cpu_to_le32(current_region->type); 17348c2ecf20Sopenharmony_ci hdr->start = cpu_to_le32(current_region->start); 17358c2ecf20Sopenharmony_ci hdr->length = cpu_to_le32(count); 17368c2ecf20Sopenharmony_ci 17378c2ecf20Sopenharmony_ci if (count == 0) 17388c2ecf20Sopenharmony_ci /* Note: the header remains, just with zero length. */ 17398c2ecf20Sopenharmony_ci break; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci buf += count; 17428c2ecf20Sopenharmony_ci buf_len -= count; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci current_region++; 17458c2ecf20Sopenharmony_ci } 17468c2ecf20Sopenharmony_ci} 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_cistatic void ath10k_pci_fw_dump_work(struct work_struct *work) 17498c2ecf20Sopenharmony_ci{ 17508c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = container_of(work, struct ath10k_pci, 17518c2ecf20Sopenharmony_ci dump_work); 17528c2ecf20Sopenharmony_ci struct ath10k_fw_crash_data *crash_data; 17538c2ecf20Sopenharmony_ci struct ath10k *ar = ar_pci->ar; 17548c2ecf20Sopenharmony_ci char guid[UUID_STRING_LEN + 1]; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci mutex_lock(&ar->dump_mutex); 17578c2ecf20Sopenharmony_ci 17588c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 17598c2ecf20Sopenharmony_ci ar->stats.fw_crash_counter++; 17608c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci crash_data = ath10k_coredump_new(ar); 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci if (crash_data) 17658c2ecf20Sopenharmony_ci scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid); 17668c2ecf20Sopenharmony_ci else 17678c2ecf20Sopenharmony_ci scnprintf(guid, sizeof(guid), "n/a"); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci ath10k_err(ar, "firmware crashed! (guid %s)\n", guid); 17708c2ecf20Sopenharmony_ci ath10k_print_driver_info(ar); 17718c2ecf20Sopenharmony_ci ath10k_pci_dump_registers(ar, crash_data); 17728c2ecf20Sopenharmony_ci ath10k_ce_dump_registers(ar, crash_data); 17738c2ecf20Sopenharmony_ci ath10k_pci_dump_memory(ar, crash_data); 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci mutex_unlock(&ar->dump_mutex); 17768c2ecf20Sopenharmony_ci 17778c2ecf20Sopenharmony_ci queue_work(ar->workqueue, &ar->restart_work); 17788c2ecf20Sopenharmony_ci} 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_cistatic void ath10k_pci_fw_crashed_dump(struct ath10k *ar) 17818c2ecf20Sopenharmony_ci{ 17828c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 17838c2ecf20Sopenharmony_ci 17848c2ecf20Sopenharmony_ci queue_work(ar->workqueue, &ar_pci->dump_work); 17858c2ecf20Sopenharmony_ci} 17868c2ecf20Sopenharmony_ci 17878c2ecf20Sopenharmony_civoid ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe, 17888c2ecf20Sopenharmony_ci int force) 17898c2ecf20Sopenharmony_ci{ 17908c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n"); 17938c2ecf20Sopenharmony_ci 17948c2ecf20Sopenharmony_ci if (!force) { 17958c2ecf20Sopenharmony_ci int resources; 17968c2ecf20Sopenharmony_ci /* 17978c2ecf20Sopenharmony_ci * Decide whether to actually poll for completions, or just 17988c2ecf20Sopenharmony_ci * wait for a later chance. 17998c2ecf20Sopenharmony_ci * If there seem to be plenty of resources left, then just wait 18008c2ecf20Sopenharmony_ci * since checking involves reading a CE register, which is a 18018c2ecf20Sopenharmony_ci * relatively expensive operation. 18028c2ecf20Sopenharmony_ci */ 18038c2ecf20Sopenharmony_ci resources = ath10k_pci_hif_get_free_queue_number(ar, pipe); 18048c2ecf20Sopenharmony_ci 18058c2ecf20Sopenharmony_ci /* 18068c2ecf20Sopenharmony_ci * If at least 50% of the total resources are still available, 18078c2ecf20Sopenharmony_ci * don't bother checking again yet. 18088c2ecf20Sopenharmony_ci */ 18098c2ecf20Sopenharmony_ci if (resources > (ar_pci->attr[pipe].src_nentries >> 1)) 18108c2ecf20Sopenharmony_ci return; 18118c2ecf20Sopenharmony_ci } 18128c2ecf20Sopenharmony_ci ath10k_ce_per_engine_service(ar, pipe); 18138c2ecf20Sopenharmony_ci} 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_cistatic void ath10k_pci_rx_retry_sync(struct ath10k *ar) 18168c2ecf20Sopenharmony_ci{ 18178c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci del_timer_sync(&ar_pci->rx_post_retry); 18208c2ecf20Sopenharmony_ci} 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ciint ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id, 18238c2ecf20Sopenharmony_ci u8 *ul_pipe, u8 *dl_pipe) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 18268c2ecf20Sopenharmony_ci const struct ce_service_to_pipe *entry; 18278c2ecf20Sopenharmony_ci bool ul_set = false, dl_set = false; 18288c2ecf20Sopenharmony_ci int i; 18298c2ecf20Sopenharmony_ci 18308c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif map service\n"); 18318c2ecf20Sopenharmony_ci 18328c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(pci_target_service_to_ce_map_wlan); i++) { 18338c2ecf20Sopenharmony_ci entry = &ar_pci->serv_to_pipe[i]; 18348c2ecf20Sopenharmony_ci 18358c2ecf20Sopenharmony_ci if (__le32_to_cpu(entry->service_id) != service_id) 18368c2ecf20Sopenharmony_ci continue; 18378c2ecf20Sopenharmony_ci 18388c2ecf20Sopenharmony_ci switch (__le32_to_cpu(entry->pipedir)) { 18398c2ecf20Sopenharmony_ci case PIPEDIR_NONE: 18408c2ecf20Sopenharmony_ci break; 18418c2ecf20Sopenharmony_ci case PIPEDIR_IN: 18428c2ecf20Sopenharmony_ci WARN_ON(dl_set); 18438c2ecf20Sopenharmony_ci *dl_pipe = __le32_to_cpu(entry->pipenum); 18448c2ecf20Sopenharmony_ci dl_set = true; 18458c2ecf20Sopenharmony_ci break; 18468c2ecf20Sopenharmony_ci case PIPEDIR_OUT: 18478c2ecf20Sopenharmony_ci WARN_ON(ul_set); 18488c2ecf20Sopenharmony_ci *ul_pipe = __le32_to_cpu(entry->pipenum); 18498c2ecf20Sopenharmony_ci ul_set = true; 18508c2ecf20Sopenharmony_ci break; 18518c2ecf20Sopenharmony_ci case PIPEDIR_INOUT: 18528c2ecf20Sopenharmony_ci WARN_ON(dl_set); 18538c2ecf20Sopenharmony_ci WARN_ON(ul_set); 18548c2ecf20Sopenharmony_ci *dl_pipe = __le32_to_cpu(entry->pipenum); 18558c2ecf20Sopenharmony_ci *ul_pipe = __le32_to_cpu(entry->pipenum); 18568c2ecf20Sopenharmony_ci dl_set = true; 18578c2ecf20Sopenharmony_ci ul_set = true; 18588c2ecf20Sopenharmony_ci break; 18598c2ecf20Sopenharmony_ci } 18608c2ecf20Sopenharmony_ci } 18618c2ecf20Sopenharmony_ci 18628c2ecf20Sopenharmony_ci if (!ul_set || !dl_set) 18638c2ecf20Sopenharmony_ci return -ENOENT; 18648c2ecf20Sopenharmony_ci 18658c2ecf20Sopenharmony_ci return 0; 18668c2ecf20Sopenharmony_ci} 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_civoid ath10k_pci_hif_get_default_pipe(struct ath10k *ar, 18698c2ecf20Sopenharmony_ci u8 *ul_pipe, u8 *dl_pipe) 18708c2ecf20Sopenharmony_ci{ 18718c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n"); 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci (void)ath10k_pci_hif_map_service_to_pipe(ar, 18748c2ecf20Sopenharmony_ci ATH10K_HTC_SVC_ID_RSVD_CTRL, 18758c2ecf20Sopenharmony_ci ul_pipe, dl_pipe); 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_civoid ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci u32 val; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci switch (ar->hw_rev) { 18838c2ecf20Sopenharmony_ci case ATH10K_HW_QCA988X: 18848c2ecf20Sopenharmony_ci case ATH10K_HW_QCA9887: 18858c2ecf20Sopenharmony_ci case ATH10K_HW_QCA6174: 18868c2ecf20Sopenharmony_ci case ATH10K_HW_QCA9377: 18878c2ecf20Sopenharmony_ci val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + 18888c2ecf20Sopenharmony_ci CORE_CTRL_ADDRESS); 18898c2ecf20Sopenharmony_ci val &= ~CORE_CTRL_PCIE_REG_31_MASK; 18908c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + 18918c2ecf20Sopenharmony_ci CORE_CTRL_ADDRESS, val); 18928c2ecf20Sopenharmony_ci break; 18938c2ecf20Sopenharmony_ci case ATH10K_HW_QCA99X0: 18948c2ecf20Sopenharmony_ci case ATH10K_HW_QCA9984: 18958c2ecf20Sopenharmony_ci case ATH10K_HW_QCA9888: 18968c2ecf20Sopenharmony_ci case ATH10K_HW_QCA4019: 18978c2ecf20Sopenharmony_ci /* TODO: Find appropriate register configuration for QCA99X0 18988c2ecf20Sopenharmony_ci * to mask irq/MSI. 18998c2ecf20Sopenharmony_ci */ 19008c2ecf20Sopenharmony_ci break; 19018c2ecf20Sopenharmony_ci case ATH10K_HW_WCN3990: 19028c2ecf20Sopenharmony_ci break; 19038c2ecf20Sopenharmony_ci } 19048c2ecf20Sopenharmony_ci} 19058c2ecf20Sopenharmony_ci 19068c2ecf20Sopenharmony_cistatic void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) 19078c2ecf20Sopenharmony_ci{ 19088c2ecf20Sopenharmony_ci u32 val; 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci switch (ar->hw_rev) { 19118c2ecf20Sopenharmony_ci case ATH10K_HW_QCA988X: 19128c2ecf20Sopenharmony_ci case ATH10K_HW_QCA9887: 19138c2ecf20Sopenharmony_ci case ATH10K_HW_QCA6174: 19148c2ecf20Sopenharmony_ci case ATH10K_HW_QCA9377: 19158c2ecf20Sopenharmony_ci val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + 19168c2ecf20Sopenharmony_ci CORE_CTRL_ADDRESS); 19178c2ecf20Sopenharmony_ci val |= CORE_CTRL_PCIE_REG_31_MASK; 19188c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + 19198c2ecf20Sopenharmony_ci CORE_CTRL_ADDRESS, val); 19208c2ecf20Sopenharmony_ci break; 19218c2ecf20Sopenharmony_ci case ATH10K_HW_QCA99X0: 19228c2ecf20Sopenharmony_ci case ATH10K_HW_QCA9984: 19238c2ecf20Sopenharmony_ci case ATH10K_HW_QCA9888: 19248c2ecf20Sopenharmony_ci case ATH10K_HW_QCA4019: 19258c2ecf20Sopenharmony_ci /* TODO: Find appropriate register configuration for QCA99X0 19268c2ecf20Sopenharmony_ci * to unmask irq/MSI. 19278c2ecf20Sopenharmony_ci */ 19288c2ecf20Sopenharmony_ci break; 19298c2ecf20Sopenharmony_ci case ATH10K_HW_WCN3990: 19308c2ecf20Sopenharmony_ci break; 19318c2ecf20Sopenharmony_ci } 19328c2ecf20Sopenharmony_ci} 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_cistatic void ath10k_pci_irq_disable(struct ath10k *ar) 19358c2ecf20Sopenharmony_ci{ 19368c2ecf20Sopenharmony_ci ath10k_ce_disable_interrupts(ar); 19378c2ecf20Sopenharmony_ci ath10k_pci_disable_and_clear_legacy_irq(ar); 19388c2ecf20Sopenharmony_ci ath10k_pci_irq_msi_fw_mask(ar); 19398c2ecf20Sopenharmony_ci} 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_cistatic void ath10k_pci_irq_sync(struct ath10k *ar) 19428c2ecf20Sopenharmony_ci{ 19438c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 19448c2ecf20Sopenharmony_ci 19458c2ecf20Sopenharmony_ci synchronize_irq(ar_pci->pdev->irq); 19468c2ecf20Sopenharmony_ci} 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_cistatic void ath10k_pci_irq_enable(struct ath10k *ar) 19498c2ecf20Sopenharmony_ci{ 19508c2ecf20Sopenharmony_ci ath10k_ce_enable_interrupts(ar); 19518c2ecf20Sopenharmony_ci ath10k_pci_enable_legacy_irq(ar); 19528c2ecf20Sopenharmony_ci ath10k_pci_irq_msi_fw_unmask(ar); 19538c2ecf20Sopenharmony_ci} 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_cistatic int ath10k_pci_hif_start(struct ath10k *ar) 19568c2ecf20Sopenharmony_ci{ 19578c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n"); 19608c2ecf20Sopenharmony_ci 19618c2ecf20Sopenharmony_ci napi_enable(&ar->napi); 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci ath10k_pci_irq_enable(ar); 19648c2ecf20Sopenharmony_ci ath10k_pci_rx_post(ar); 19658c2ecf20Sopenharmony_ci 19668c2ecf20Sopenharmony_ci pcie_capability_clear_and_set_word(ar_pci->pdev, PCI_EXP_LNKCTL, 19678c2ecf20Sopenharmony_ci PCI_EXP_LNKCTL_ASPMC, 19688c2ecf20Sopenharmony_ci ar_pci->link_ctl & PCI_EXP_LNKCTL_ASPMC); 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci return 0; 19718c2ecf20Sopenharmony_ci} 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_cistatic void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) 19748c2ecf20Sopenharmony_ci{ 19758c2ecf20Sopenharmony_ci struct ath10k *ar; 19768c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_pipe; 19778c2ecf20Sopenharmony_ci struct ath10k_ce_ring *ce_ring; 19788c2ecf20Sopenharmony_ci struct sk_buff *skb; 19798c2ecf20Sopenharmony_ci int i; 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ci ar = pci_pipe->hif_ce_state; 19828c2ecf20Sopenharmony_ci ce_pipe = pci_pipe->ce_hdl; 19838c2ecf20Sopenharmony_ci ce_ring = ce_pipe->dest_ring; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci if (!ce_ring) 19868c2ecf20Sopenharmony_ci return; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci if (!pci_pipe->buf_sz) 19898c2ecf20Sopenharmony_ci return; 19908c2ecf20Sopenharmony_ci 19918c2ecf20Sopenharmony_ci for (i = 0; i < ce_ring->nentries; i++) { 19928c2ecf20Sopenharmony_ci skb = ce_ring->per_transfer_context[i]; 19938c2ecf20Sopenharmony_ci if (!skb) 19948c2ecf20Sopenharmony_ci continue; 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci ce_ring->per_transfer_context[i] = NULL; 19978c2ecf20Sopenharmony_ci 19988c2ecf20Sopenharmony_ci dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr, 19998c2ecf20Sopenharmony_ci skb->len + skb_tailroom(skb), 20008c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 20018c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 20028c2ecf20Sopenharmony_ci } 20038c2ecf20Sopenharmony_ci} 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_cistatic void ath10k_pci_tx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe) 20068c2ecf20Sopenharmony_ci{ 20078c2ecf20Sopenharmony_ci struct ath10k *ar; 20088c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_pipe; 20098c2ecf20Sopenharmony_ci struct ath10k_ce_ring *ce_ring; 20108c2ecf20Sopenharmony_ci struct sk_buff *skb; 20118c2ecf20Sopenharmony_ci int i; 20128c2ecf20Sopenharmony_ci 20138c2ecf20Sopenharmony_ci ar = pci_pipe->hif_ce_state; 20148c2ecf20Sopenharmony_ci ce_pipe = pci_pipe->ce_hdl; 20158c2ecf20Sopenharmony_ci ce_ring = ce_pipe->src_ring; 20168c2ecf20Sopenharmony_ci 20178c2ecf20Sopenharmony_ci if (!ce_ring) 20188c2ecf20Sopenharmony_ci return; 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci if (!pci_pipe->buf_sz) 20218c2ecf20Sopenharmony_ci return; 20228c2ecf20Sopenharmony_ci 20238c2ecf20Sopenharmony_ci for (i = 0; i < ce_ring->nentries; i++) { 20248c2ecf20Sopenharmony_ci skb = ce_ring->per_transfer_context[i]; 20258c2ecf20Sopenharmony_ci if (!skb) 20268c2ecf20Sopenharmony_ci continue; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci ce_ring->per_transfer_context[i] = NULL; 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci ath10k_htc_tx_completion_handler(ar, skb); 20318c2ecf20Sopenharmony_ci } 20328c2ecf20Sopenharmony_ci} 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci/* 20358c2ecf20Sopenharmony_ci * Cleanup residual buffers for device shutdown: 20368c2ecf20Sopenharmony_ci * buffers that were enqueued for receive 20378c2ecf20Sopenharmony_ci * buffers that were to be sent 20388c2ecf20Sopenharmony_ci * Note: Buffers that had completed but which were 20398c2ecf20Sopenharmony_ci * not yet processed are on a completion queue. They 20408c2ecf20Sopenharmony_ci * are handled when the completion thread shuts down. 20418c2ecf20Sopenharmony_ci */ 20428c2ecf20Sopenharmony_cistatic void ath10k_pci_buffer_cleanup(struct ath10k *ar) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 20458c2ecf20Sopenharmony_ci int pipe_num; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) { 20488c2ecf20Sopenharmony_ci struct ath10k_pci_pipe *pipe_info; 20498c2ecf20Sopenharmony_ci 20508c2ecf20Sopenharmony_ci pipe_info = &ar_pci->pipe_info[pipe_num]; 20518c2ecf20Sopenharmony_ci ath10k_pci_rx_pipe_cleanup(pipe_info); 20528c2ecf20Sopenharmony_ci ath10k_pci_tx_pipe_cleanup(pipe_info); 20538c2ecf20Sopenharmony_ci } 20548c2ecf20Sopenharmony_ci} 20558c2ecf20Sopenharmony_ci 20568c2ecf20Sopenharmony_civoid ath10k_pci_ce_deinit(struct ath10k *ar) 20578c2ecf20Sopenharmony_ci{ 20588c2ecf20Sopenharmony_ci int i; 20598c2ecf20Sopenharmony_ci 20608c2ecf20Sopenharmony_ci for (i = 0; i < CE_COUNT; i++) 20618c2ecf20Sopenharmony_ci ath10k_ce_deinit_pipe(ar, i); 20628c2ecf20Sopenharmony_ci} 20638c2ecf20Sopenharmony_ci 20648c2ecf20Sopenharmony_civoid ath10k_pci_flush(struct ath10k *ar) 20658c2ecf20Sopenharmony_ci{ 20668c2ecf20Sopenharmony_ci ath10k_pci_rx_retry_sync(ar); 20678c2ecf20Sopenharmony_ci ath10k_pci_buffer_cleanup(ar); 20688c2ecf20Sopenharmony_ci} 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_cistatic void ath10k_pci_hif_stop(struct ath10k *ar) 20718c2ecf20Sopenharmony_ci{ 20728c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 20738c2ecf20Sopenharmony_ci unsigned long flags; 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n"); 20768c2ecf20Sopenharmony_ci 20778c2ecf20Sopenharmony_ci ath10k_pci_irq_disable(ar); 20788c2ecf20Sopenharmony_ci ath10k_pci_irq_sync(ar); 20798c2ecf20Sopenharmony_ci napi_synchronize(&ar->napi); 20808c2ecf20Sopenharmony_ci napi_disable(&ar->napi); 20818c2ecf20Sopenharmony_ci cancel_work_sync(&ar_pci->dump_work); 20828c2ecf20Sopenharmony_ci 20838c2ecf20Sopenharmony_ci /* Most likely the device has HTT Rx ring configured. The only way to 20848c2ecf20Sopenharmony_ci * prevent the device from accessing (and possible corrupting) host 20858c2ecf20Sopenharmony_ci * memory is to reset the chip now. 20868c2ecf20Sopenharmony_ci * 20878c2ecf20Sopenharmony_ci * There's also no known way of masking MSI interrupts on the device. 20888c2ecf20Sopenharmony_ci * For ranged MSI the CE-related interrupts can be masked. However 20898c2ecf20Sopenharmony_ci * regardless how many MSI interrupts are assigned the first one 20908c2ecf20Sopenharmony_ci * is always used for firmware indications (crashes) and cannot be 20918c2ecf20Sopenharmony_ci * masked. To prevent the device from asserting the interrupt reset it 20928c2ecf20Sopenharmony_ci * before proceeding with cleanup. 20938c2ecf20Sopenharmony_ci */ 20948c2ecf20Sopenharmony_ci ath10k_pci_safe_chip_reset(ar); 20958c2ecf20Sopenharmony_ci 20968c2ecf20Sopenharmony_ci ath10k_pci_flush(ar); 20978c2ecf20Sopenharmony_ci 20988c2ecf20Sopenharmony_ci spin_lock_irqsave(&ar_pci->ps_lock, flags); 20998c2ecf20Sopenharmony_ci WARN_ON(ar_pci->ps_wake_refcount > 0); 21008c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ar_pci->ps_lock, flags); 21018c2ecf20Sopenharmony_ci} 21028c2ecf20Sopenharmony_ci 21038c2ecf20Sopenharmony_ciint ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, 21048c2ecf20Sopenharmony_ci void *req, u32 req_len, 21058c2ecf20Sopenharmony_ci void *resp, u32 *resp_len) 21068c2ecf20Sopenharmony_ci{ 21078c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 21088c2ecf20Sopenharmony_ci struct ath10k_pci_pipe *pci_tx = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG]; 21098c2ecf20Sopenharmony_ci struct ath10k_pci_pipe *pci_rx = &ar_pci->pipe_info[BMI_CE_NUM_TO_HOST]; 21108c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_tx = pci_tx->ce_hdl; 21118c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *ce_rx = pci_rx->ce_hdl; 21128c2ecf20Sopenharmony_ci dma_addr_t req_paddr = 0; 21138c2ecf20Sopenharmony_ci dma_addr_t resp_paddr = 0; 21148c2ecf20Sopenharmony_ci struct bmi_xfer xfer = {}; 21158c2ecf20Sopenharmony_ci void *treq, *tresp = NULL; 21168c2ecf20Sopenharmony_ci int ret = 0; 21178c2ecf20Sopenharmony_ci 21188c2ecf20Sopenharmony_ci might_sleep(); 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (resp && !resp_len) 21218c2ecf20Sopenharmony_ci return -EINVAL; 21228c2ecf20Sopenharmony_ci 21238c2ecf20Sopenharmony_ci if (resp && resp_len && *resp_len == 0) 21248c2ecf20Sopenharmony_ci return -EINVAL; 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_ci treq = kmemdup(req, req_len, GFP_KERNEL); 21278c2ecf20Sopenharmony_ci if (!treq) 21288c2ecf20Sopenharmony_ci return -ENOMEM; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci req_paddr = dma_map_single(ar->dev, treq, req_len, DMA_TO_DEVICE); 21318c2ecf20Sopenharmony_ci ret = dma_mapping_error(ar->dev, req_paddr); 21328c2ecf20Sopenharmony_ci if (ret) { 21338c2ecf20Sopenharmony_ci ret = -EIO; 21348c2ecf20Sopenharmony_ci goto err_dma; 21358c2ecf20Sopenharmony_ci } 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci if (resp && resp_len) { 21388c2ecf20Sopenharmony_ci tresp = kzalloc(*resp_len, GFP_KERNEL); 21398c2ecf20Sopenharmony_ci if (!tresp) { 21408c2ecf20Sopenharmony_ci ret = -ENOMEM; 21418c2ecf20Sopenharmony_ci goto err_req; 21428c2ecf20Sopenharmony_ci } 21438c2ecf20Sopenharmony_ci 21448c2ecf20Sopenharmony_ci resp_paddr = dma_map_single(ar->dev, tresp, *resp_len, 21458c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 21468c2ecf20Sopenharmony_ci ret = dma_mapping_error(ar->dev, resp_paddr); 21478c2ecf20Sopenharmony_ci if (ret) { 21488c2ecf20Sopenharmony_ci ret = -EIO; 21498c2ecf20Sopenharmony_ci goto err_req; 21508c2ecf20Sopenharmony_ci } 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci xfer.wait_for_resp = true; 21538c2ecf20Sopenharmony_ci xfer.resp_len = 0; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci ath10k_ce_rx_post_buf(ce_rx, &xfer, resp_paddr); 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci ret = ath10k_ce_send(ce_tx, &xfer, req_paddr, req_len, -1, 0); 21598c2ecf20Sopenharmony_ci if (ret) 21608c2ecf20Sopenharmony_ci goto err_resp; 21618c2ecf20Sopenharmony_ci 21628c2ecf20Sopenharmony_ci ret = ath10k_pci_bmi_wait(ar, ce_tx, ce_rx, &xfer); 21638c2ecf20Sopenharmony_ci if (ret) { 21648c2ecf20Sopenharmony_ci dma_addr_t unused_buffer; 21658c2ecf20Sopenharmony_ci unsigned int unused_nbytes; 21668c2ecf20Sopenharmony_ci unsigned int unused_id; 21678c2ecf20Sopenharmony_ci 21688c2ecf20Sopenharmony_ci ath10k_ce_cancel_send_next(ce_tx, NULL, &unused_buffer, 21698c2ecf20Sopenharmony_ci &unused_nbytes, &unused_id); 21708c2ecf20Sopenharmony_ci } else { 21718c2ecf20Sopenharmony_ci /* non-zero means we did not time out */ 21728c2ecf20Sopenharmony_ci ret = 0; 21738c2ecf20Sopenharmony_ci } 21748c2ecf20Sopenharmony_ci 21758c2ecf20Sopenharmony_cierr_resp: 21768c2ecf20Sopenharmony_ci if (resp) { 21778c2ecf20Sopenharmony_ci dma_addr_t unused_buffer; 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci ath10k_ce_revoke_recv_next(ce_rx, NULL, &unused_buffer); 21808c2ecf20Sopenharmony_ci dma_unmap_single(ar->dev, resp_paddr, 21818c2ecf20Sopenharmony_ci *resp_len, DMA_FROM_DEVICE); 21828c2ecf20Sopenharmony_ci } 21838c2ecf20Sopenharmony_cierr_req: 21848c2ecf20Sopenharmony_ci dma_unmap_single(ar->dev, req_paddr, req_len, DMA_TO_DEVICE); 21858c2ecf20Sopenharmony_ci 21868c2ecf20Sopenharmony_ci if (ret == 0 && resp_len) { 21878c2ecf20Sopenharmony_ci *resp_len = min(*resp_len, xfer.resp_len); 21888c2ecf20Sopenharmony_ci memcpy(resp, tresp, *resp_len); 21898c2ecf20Sopenharmony_ci } 21908c2ecf20Sopenharmony_cierr_dma: 21918c2ecf20Sopenharmony_ci kfree(treq); 21928c2ecf20Sopenharmony_ci kfree(tresp); 21938c2ecf20Sopenharmony_ci 21948c2ecf20Sopenharmony_ci return ret; 21958c2ecf20Sopenharmony_ci} 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_cistatic void ath10k_pci_bmi_send_done(struct ath10k_ce_pipe *ce_state) 21988c2ecf20Sopenharmony_ci{ 21998c2ecf20Sopenharmony_ci struct bmi_xfer *xfer; 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci if (ath10k_ce_completed_send_next(ce_state, (void **)&xfer)) 22028c2ecf20Sopenharmony_ci return; 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci xfer->tx_done = true; 22058c2ecf20Sopenharmony_ci} 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_cistatic void ath10k_pci_bmi_recv_data(struct ath10k_ce_pipe *ce_state) 22088c2ecf20Sopenharmony_ci{ 22098c2ecf20Sopenharmony_ci struct ath10k *ar = ce_state->ar; 22108c2ecf20Sopenharmony_ci struct bmi_xfer *xfer; 22118c2ecf20Sopenharmony_ci unsigned int nbytes; 22128c2ecf20Sopenharmony_ci 22138c2ecf20Sopenharmony_ci if (ath10k_ce_completed_recv_next(ce_state, (void **)&xfer, 22148c2ecf20Sopenharmony_ci &nbytes)) 22158c2ecf20Sopenharmony_ci return; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!xfer)) 22188c2ecf20Sopenharmony_ci return; 22198c2ecf20Sopenharmony_ci 22208c2ecf20Sopenharmony_ci if (!xfer->wait_for_resp) { 22218c2ecf20Sopenharmony_ci ath10k_warn(ar, "unexpected: BMI data received; ignoring\n"); 22228c2ecf20Sopenharmony_ci return; 22238c2ecf20Sopenharmony_ci } 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci xfer->resp_len = nbytes; 22268c2ecf20Sopenharmony_ci xfer->rx_done = true; 22278c2ecf20Sopenharmony_ci} 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_cistatic int ath10k_pci_bmi_wait(struct ath10k *ar, 22308c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *tx_pipe, 22318c2ecf20Sopenharmony_ci struct ath10k_ce_pipe *rx_pipe, 22328c2ecf20Sopenharmony_ci struct bmi_xfer *xfer) 22338c2ecf20Sopenharmony_ci{ 22348c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + BMI_COMMUNICATION_TIMEOUT_HZ; 22358c2ecf20Sopenharmony_ci unsigned long started = jiffies; 22368c2ecf20Sopenharmony_ci unsigned long dur; 22378c2ecf20Sopenharmony_ci int ret; 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_ci while (time_before_eq(jiffies, timeout)) { 22408c2ecf20Sopenharmony_ci ath10k_pci_bmi_send_done(tx_pipe); 22418c2ecf20Sopenharmony_ci ath10k_pci_bmi_recv_data(rx_pipe); 22428c2ecf20Sopenharmony_ci 22438c2ecf20Sopenharmony_ci if (xfer->tx_done && (xfer->rx_done == xfer->wait_for_resp)) { 22448c2ecf20Sopenharmony_ci ret = 0; 22458c2ecf20Sopenharmony_ci goto out; 22468c2ecf20Sopenharmony_ci } 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci schedule(); 22498c2ecf20Sopenharmony_ci } 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci ret = -ETIMEDOUT; 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ciout: 22548c2ecf20Sopenharmony_ci dur = jiffies - started; 22558c2ecf20Sopenharmony_ci if (dur > HZ) 22568c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BMI, 22578c2ecf20Sopenharmony_ci "bmi cmd took %lu jiffies hz %d ret %d\n", 22588c2ecf20Sopenharmony_ci dur, HZ, ret); 22598c2ecf20Sopenharmony_ci return ret; 22608c2ecf20Sopenharmony_ci} 22618c2ecf20Sopenharmony_ci 22628c2ecf20Sopenharmony_ci/* 22638c2ecf20Sopenharmony_ci * Send an interrupt to the device to wake up the Target CPU 22648c2ecf20Sopenharmony_ci * so it has an opportunity to notice any changed state. 22658c2ecf20Sopenharmony_ci */ 22668c2ecf20Sopenharmony_cistatic int ath10k_pci_wake_target_cpu(struct ath10k *ar) 22678c2ecf20Sopenharmony_ci{ 22688c2ecf20Sopenharmony_ci u32 addr, val; 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci addr = SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS; 22718c2ecf20Sopenharmony_ci val = ath10k_pci_read32(ar, addr); 22728c2ecf20Sopenharmony_ci val |= CORE_CTRL_CPU_INTR_MASK; 22738c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, addr, val); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci return 0; 22768c2ecf20Sopenharmony_ci} 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_cistatic int ath10k_pci_get_num_banks(struct ath10k *ar) 22798c2ecf20Sopenharmony_ci{ 22808c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 22818c2ecf20Sopenharmony_ci 22828c2ecf20Sopenharmony_ci switch (ar_pci->pdev->device) { 22838c2ecf20Sopenharmony_ci case QCA988X_2_0_DEVICE_ID_UBNT: 22848c2ecf20Sopenharmony_ci case QCA988X_2_0_DEVICE_ID: 22858c2ecf20Sopenharmony_ci case QCA99X0_2_0_DEVICE_ID: 22868c2ecf20Sopenharmony_ci case QCA9888_2_0_DEVICE_ID: 22878c2ecf20Sopenharmony_ci case QCA9984_1_0_DEVICE_ID: 22888c2ecf20Sopenharmony_ci case QCA9887_1_0_DEVICE_ID: 22898c2ecf20Sopenharmony_ci return 1; 22908c2ecf20Sopenharmony_ci case QCA6164_2_1_DEVICE_ID: 22918c2ecf20Sopenharmony_ci case QCA6174_2_1_DEVICE_ID: 22928c2ecf20Sopenharmony_ci switch (MS(ar->bus_param.chip_id, SOC_CHIP_ID_REV)) { 22938c2ecf20Sopenharmony_ci case QCA6174_HW_1_0_CHIP_ID_REV: 22948c2ecf20Sopenharmony_ci case QCA6174_HW_1_1_CHIP_ID_REV: 22958c2ecf20Sopenharmony_ci case QCA6174_HW_2_1_CHIP_ID_REV: 22968c2ecf20Sopenharmony_ci case QCA6174_HW_2_2_CHIP_ID_REV: 22978c2ecf20Sopenharmony_ci return 3; 22988c2ecf20Sopenharmony_ci case QCA6174_HW_1_3_CHIP_ID_REV: 22998c2ecf20Sopenharmony_ci return 2; 23008c2ecf20Sopenharmony_ci case QCA6174_HW_3_0_CHIP_ID_REV: 23018c2ecf20Sopenharmony_ci case QCA6174_HW_3_1_CHIP_ID_REV: 23028c2ecf20Sopenharmony_ci case QCA6174_HW_3_2_CHIP_ID_REV: 23038c2ecf20Sopenharmony_ci return 9; 23048c2ecf20Sopenharmony_ci } 23058c2ecf20Sopenharmony_ci break; 23068c2ecf20Sopenharmony_ci case QCA9377_1_0_DEVICE_ID: 23078c2ecf20Sopenharmony_ci return 9; 23088c2ecf20Sopenharmony_ci } 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_ci ath10k_warn(ar, "unknown number of banks, assuming 1\n"); 23118c2ecf20Sopenharmony_ci return 1; 23128c2ecf20Sopenharmony_ci} 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_cistatic int ath10k_bus_get_num_banks(struct ath10k *ar) 23158c2ecf20Sopenharmony_ci{ 23168c2ecf20Sopenharmony_ci struct ath10k_ce *ce = ath10k_ce_priv(ar); 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci return ce->bus_ops->get_num_banks(ar); 23198c2ecf20Sopenharmony_ci} 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ciint ath10k_pci_init_config(struct ath10k *ar) 23228c2ecf20Sopenharmony_ci{ 23238c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 23248c2ecf20Sopenharmony_ci u32 interconnect_targ_addr; 23258c2ecf20Sopenharmony_ci u32 pcie_state_targ_addr = 0; 23268c2ecf20Sopenharmony_ci u32 pipe_cfg_targ_addr = 0; 23278c2ecf20Sopenharmony_ci u32 svc_to_pipe_map = 0; 23288c2ecf20Sopenharmony_ci u32 pcie_config_flags = 0; 23298c2ecf20Sopenharmony_ci u32 ealloc_value; 23308c2ecf20Sopenharmony_ci u32 ealloc_targ_addr; 23318c2ecf20Sopenharmony_ci u32 flag2_value; 23328c2ecf20Sopenharmony_ci u32 flag2_targ_addr; 23338c2ecf20Sopenharmony_ci int ret = 0; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci /* Download to Target the CE Config and the service-to-CE map */ 23368c2ecf20Sopenharmony_ci interconnect_targ_addr = 23378c2ecf20Sopenharmony_ci host_interest_item_address(HI_ITEM(hi_interconnect_state)); 23388c2ecf20Sopenharmony_ci 23398c2ecf20Sopenharmony_ci /* Supply Target-side CE configuration */ 23408c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read32(ar, interconnect_targ_addr, 23418c2ecf20Sopenharmony_ci &pcie_state_targ_addr); 23428c2ecf20Sopenharmony_ci if (ret != 0) { 23438c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to get pcie state addr: %d\n", ret); 23448c2ecf20Sopenharmony_ci return ret; 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci if (pcie_state_targ_addr == 0) { 23488c2ecf20Sopenharmony_ci ret = -EIO; 23498c2ecf20Sopenharmony_ci ath10k_err(ar, "Invalid pcie state addr\n"); 23508c2ecf20Sopenharmony_ci return ret; 23518c2ecf20Sopenharmony_ci } 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr + 23548c2ecf20Sopenharmony_ci offsetof(struct pcie_state, 23558c2ecf20Sopenharmony_ci pipe_cfg_addr)), 23568c2ecf20Sopenharmony_ci &pipe_cfg_targ_addr); 23578c2ecf20Sopenharmony_ci if (ret != 0) { 23588c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to get pipe cfg addr: %d\n", ret); 23598c2ecf20Sopenharmony_ci return ret; 23608c2ecf20Sopenharmony_ci } 23618c2ecf20Sopenharmony_ci 23628c2ecf20Sopenharmony_ci if (pipe_cfg_targ_addr == 0) { 23638c2ecf20Sopenharmony_ci ret = -EIO; 23648c2ecf20Sopenharmony_ci ath10k_err(ar, "Invalid pipe cfg addr\n"); 23658c2ecf20Sopenharmony_ci return ret; 23668c2ecf20Sopenharmony_ci } 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr, 23698c2ecf20Sopenharmony_ci ar_pci->pipe_config, 23708c2ecf20Sopenharmony_ci sizeof(struct ce_pipe_config) * 23718c2ecf20Sopenharmony_ci NUM_TARGET_CE_CONFIG_WLAN); 23728c2ecf20Sopenharmony_ci 23738c2ecf20Sopenharmony_ci if (ret != 0) { 23748c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret); 23758c2ecf20Sopenharmony_ci return ret; 23768c2ecf20Sopenharmony_ci } 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr + 23798c2ecf20Sopenharmony_ci offsetof(struct pcie_state, 23808c2ecf20Sopenharmony_ci svc_to_pipe_map)), 23818c2ecf20Sopenharmony_ci &svc_to_pipe_map); 23828c2ecf20Sopenharmony_ci if (ret != 0) { 23838c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to get svc/pipe map: %d\n", ret); 23848c2ecf20Sopenharmony_ci return ret; 23858c2ecf20Sopenharmony_ci } 23868c2ecf20Sopenharmony_ci 23878c2ecf20Sopenharmony_ci if (svc_to_pipe_map == 0) { 23888c2ecf20Sopenharmony_ci ret = -EIO; 23898c2ecf20Sopenharmony_ci ath10k_err(ar, "Invalid svc_to_pipe map\n"); 23908c2ecf20Sopenharmony_ci return ret; 23918c2ecf20Sopenharmony_ci } 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_write_mem(ar, svc_to_pipe_map, 23948c2ecf20Sopenharmony_ci ar_pci->serv_to_pipe, 23958c2ecf20Sopenharmony_ci sizeof(pci_target_service_to_ce_map_wlan)); 23968c2ecf20Sopenharmony_ci if (ret != 0) { 23978c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to write svc/pipe map: %d\n", ret); 23988c2ecf20Sopenharmony_ci return ret; 23998c2ecf20Sopenharmony_ci } 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read32(ar, (pcie_state_targ_addr + 24028c2ecf20Sopenharmony_ci offsetof(struct pcie_state, 24038c2ecf20Sopenharmony_ci config_flags)), 24048c2ecf20Sopenharmony_ci &pcie_config_flags); 24058c2ecf20Sopenharmony_ci if (ret != 0) { 24068c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to get pcie config_flags: %d\n", ret); 24078c2ecf20Sopenharmony_ci return ret; 24088c2ecf20Sopenharmony_ci } 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci pcie_config_flags &= ~PCIE_CONFIG_FLAG_ENABLE_L1; 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_write32(ar, (pcie_state_targ_addr + 24138c2ecf20Sopenharmony_ci offsetof(struct pcie_state, 24148c2ecf20Sopenharmony_ci config_flags)), 24158c2ecf20Sopenharmony_ci pcie_config_flags); 24168c2ecf20Sopenharmony_ci if (ret != 0) { 24178c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to write pcie config_flags: %d\n", ret); 24188c2ecf20Sopenharmony_ci return ret; 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci 24218c2ecf20Sopenharmony_ci /* configure early allocation */ 24228c2ecf20Sopenharmony_ci ealloc_targ_addr = host_interest_item_address(HI_ITEM(hi_early_alloc)); 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read32(ar, ealloc_targ_addr, &ealloc_value); 24258c2ecf20Sopenharmony_ci if (ret != 0) { 24268c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to get early alloc val: %d\n", ret); 24278c2ecf20Sopenharmony_ci return ret; 24288c2ecf20Sopenharmony_ci } 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci /* first bank is switched to IRAM */ 24318c2ecf20Sopenharmony_ci ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) & 24328c2ecf20Sopenharmony_ci HI_EARLY_ALLOC_MAGIC_MASK); 24338c2ecf20Sopenharmony_ci ealloc_value |= ((ath10k_bus_get_num_banks(ar) << 24348c2ecf20Sopenharmony_ci HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) & 24358c2ecf20Sopenharmony_ci HI_EARLY_ALLOC_IRAM_BANKS_MASK); 24368c2ecf20Sopenharmony_ci 24378c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_write32(ar, ealloc_targ_addr, ealloc_value); 24388c2ecf20Sopenharmony_ci if (ret != 0) { 24398c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to set early alloc val: %d\n", ret); 24408c2ecf20Sopenharmony_ci return ret; 24418c2ecf20Sopenharmony_ci } 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci /* Tell Target to proceed with initialization */ 24448c2ecf20Sopenharmony_ci flag2_targ_addr = host_interest_item_address(HI_ITEM(hi_option_flag2)); 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read32(ar, flag2_targ_addr, &flag2_value); 24478c2ecf20Sopenharmony_ci if (ret != 0) { 24488c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to get option val: %d\n", ret); 24498c2ecf20Sopenharmony_ci return ret; 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci flag2_value |= HI_OPTION_EARLY_CFG_DONE; 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_write32(ar, flag2_targ_addr, flag2_value); 24558c2ecf20Sopenharmony_ci if (ret != 0) { 24568c2ecf20Sopenharmony_ci ath10k_err(ar, "Failed to set option val: %d\n", ret); 24578c2ecf20Sopenharmony_ci return ret; 24588c2ecf20Sopenharmony_ci } 24598c2ecf20Sopenharmony_ci 24608c2ecf20Sopenharmony_ci return 0; 24618c2ecf20Sopenharmony_ci} 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_cistatic void ath10k_pci_override_ce_config(struct ath10k *ar) 24648c2ecf20Sopenharmony_ci{ 24658c2ecf20Sopenharmony_ci struct ce_attr *attr; 24668c2ecf20Sopenharmony_ci struct ce_pipe_config *config; 24678c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci /* For QCA6174 we're overriding the Copy Engine 5 configuration, 24708c2ecf20Sopenharmony_ci * since it is currently used for other feature. 24718c2ecf20Sopenharmony_ci */ 24728c2ecf20Sopenharmony_ci 24738c2ecf20Sopenharmony_ci /* Override Host's Copy Engine 5 configuration */ 24748c2ecf20Sopenharmony_ci attr = &ar_pci->attr[5]; 24758c2ecf20Sopenharmony_ci attr->src_sz_max = 0; 24768c2ecf20Sopenharmony_ci attr->dest_nentries = 0; 24778c2ecf20Sopenharmony_ci 24788c2ecf20Sopenharmony_ci /* Override Target firmware's Copy Engine configuration */ 24798c2ecf20Sopenharmony_ci config = &ar_pci->pipe_config[5]; 24808c2ecf20Sopenharmony_ci config->pipedir = __cpu_to_le32(PIPEDIR_OUT); 24818c2ecf20Sopenharmony_ci config->nbytes_max = __cpu_to_le32(2048); 24828c2ecf20Sopenharmony_ci 24838c2ecf20Sopenharmony_ci /* Map from service/endpoint to Copy Engine */ 24848c2ecf20Sopenharmony_ci ar_pci->serv_to_pipe[15].pipenum = __cpu_to_le32(1); 24858c2ecf20Sopenharmony_ci} 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ciint ath10k_pci_alloc_pipes(struct ath10k *ar) 24888c2ecf20Sopenharmony_ci{ 24898c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 24908c2ecf20Sopenharmony_ci struct ath10k_pci_pipe *pipe; 24918c2ecf20Sopenharmony_ci struct ath10k_ce *ce = ath10k_ce_priv(ar); 24928c2ecf20Sopenharmony_ci int i, ret; 24938c2ecf20Sopenharmony_ci 24948c2ecf20Sopenharmony_ci for (i = 0; i < CE_COUNT; i++) { 24958c2ecf20Sopenharmony_ci pipe = &ar_pci->pipe_info[i]; 24968c2ecf20Sopenharmony_ci pipe->ce_hdl = &ce->ce_states[i]; 24978c2ecf20Sopenharmony_ci pipe->pipe_num = i; 24988c2ecf20Sopenharmony_ci pipe->hif_ce_state = ar; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci ret = ath10k_ce_alloc_pipe(ar, i, &ar_pci->attr[i]); 25018c2ecf20Sopenharmony_ci if (ret) { 25028c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n", 25038c2ecf20Sopenharmony_ci i, ret); 25048c2ecf20Sopenharmony_ci return ret; 25058c2ecf20Sopenharmony_ci } 25068c2ecf20Sopenharmony_ci 25078c2ecf20Sopenharmony_ci /* Last CE is Diagnostic Window */ 25088c2ecf20Sopenharmony_ci if (i == CE_DIAG_PIPE) { 25098c2ecf20Sopenharmony_ci ar_pci->ce_diag = pipe->ce_hdl; 25108c2ecf20Sopenharmony_ci continue; 25118c2ecf20Sopenharmony_ci } 25128c2ecf20Sopenharmony_ci 25138c2ecf20Sopenharmony_ci pipe->buf_sz = (size_t)(ar_pci->attr[i].src_sz_max); 25148c2ecf20Sopenharmony_ci } 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci return 0; 25178c2ecf20Sopenharmony_ci} 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_civoid ath10k_pci_free_pipes(struct ath10k *ar) 25208c2ecf20Sopenharmony_ci{ 25218c2ecf20Sopenharmony_ci int i; 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci for (i = 0; i < CE_COUNT; i++) 25248c2ecf20Sopenharmony_ci ath10k_ce_free_pipe(ar, i); 25258c2ecf20Sopenharmony_ci} 25268c2ecf20Sopenharmony_ci 25278c2ecf20Sopenharmony_ciint ath10k_pci_init_pipes(struct ath10k *ar) 25288c2ecf20Sopenharmony_ci{ 25298c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 25308c2ecf20Sopenharmony_ci int i, ret; 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci for (i = 0; i < CE_COUNT; i++) { 25338c2ecf20Sopenharmony_ci ret = ath10k_ce_init_pipe(ar, i, &ar_pci->attr[i]); 25348c2ecf20Sopenharmony_ci if (ret) { 25358c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n", 25368c2ecf20Sopenharmony_ci i, ret); 25378c2ecf20Sopenharmony_ci return ret; 25388c2ecf20Sopenharmony_ci } 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci 25418c2ecf20Sopenharmony_ci return 0; 25428c2ecf20Sopenharmony_ci} 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_cistatic bool ath10k_pci_has_fw_crashed(struct ath10k *ar) 25458c2ecf20Sopenharmony_ci{ 25468c2ecf20Sopenharmony_ci return ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS) & 25478c2ecf20Sopenharmony_ci FW_IND_EVENT_PENDING; 25488c2ecf20Sopenharmony_ci} 25498c2ecf20Sopenharmony_ci 25508c2ecf20Sopenharmony_cistatic void ath10k_pci_fw_crashed_clear(struct ath10k *ar) 25518c2ecf20Sopenharmony_ci{ 25528c2ecf20Sopenharmony_ci u32 val; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); 25558c2ecf20Sopenharmony_ci val &= ~FW_IND_EVENT_PENDING; 25568c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val); 25578c2ecf20Sopenharmony_ci} 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_cistatic bool ath10k_pci_has_device_gone(struct ath10k *ar) 25608c2ecf20Sopenharmony_ci{ 25618c2ecf20Sopenharmony_ci u32 val; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); 25648c2ecf20Sopenharmony_ci return (val == 0xffffffff); 25658c2ecf20Sopenharmony_ci} 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci/* this function effectively clears target memory controller assert line */ 25688c2ecf20Sopenharmony_cistatic void ath10k_pci_warm_reset_si0(struct ath10k *ar) 25698c2ecf20Sopenharmony_ci{ 25708c2ecf20Sopenharmony_ci u32 val; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); 25738c2ecf20Sopenharmony_ci ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, 25748c2ecf20Sopenharmony_ci val | SOC_RESET_CONTROL_SI0_RST_MASK); 25758c2ecf20Sopenharmony_ci val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci msleep(10); 25788c2ecf20Sopenharmony_ci 25798c2ecf20Sopenharmony_ci val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); 25808c2ecf20Sopenharmony_ci ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, 25818c2ecf20Sopenharmony_ci val & ~SOC_RESET_CONTROL_SI0_RST_MASK); 25828c2ecf20Sopenharmony_ci val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci msleep(10); 25858c2ecf20Sopenharmony_ci} 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_cistatic void ath10k_pci_warm_reset_cpu(struct ath10k *ar) 25888c2ecf20Sopenharmony_ci{ 25898c2ecf20Sopenharmony_ci u32 val; 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, 0); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); 25948c2ecf20Sopenharmony_ci ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, 25958c2ecf20Sopenharmony_ci val | SOC_RESET_CONTROL_CPU_WARM_RST_MASK); 25968c2ecf20Sopenharmony_ci} 25978c2ecf20Sopenharmony_ci 25988c2ecf20Sopenharmony_cistatic void ath10k_pci_warm_reset_ce(struct ath10k *ar) 25998c2ecf20Sopenharmony_ci{ 26008c2ecf20Sopenharmony_ci u32 val; 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci val = ath10k_pci_soc_read32(ar, SOC_RESET_CONTROL_ADDRESS); 26038c2ecf20Sopenharmony_ci 26048c2ecf20Sopenharmony_ci ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, 26058c2ecf20Sopenharmony_ci val | SOC_RESET_CONTROL_CE_RST_MASK); 26068c2ecf20Sopenharmony_ci msleep(10); 26078c2ecf20Sopenharmony_ci ath10k_pci_soc_write32(ar, SOC_RESET_CONTROL_ADDRESS, 26088c2ecf20Sopenharmony_ci val & ~SOC_RESET_CONTROL_CE_RST_MASK); 26098c2ecf20Sopenharmony_ci} 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_cistatic void ath10k_pci_warm_reset_clear_lf(struct ath10k *ar) 26128c2ecf20Sopenharmony_ci{ 26138c2ecf20Sopenharmony_ci u32 val; 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci val = ath10k_pci_soc_read32(ar, SOC_LF_TIMER_CONTROL0_ADDRESS); 26168c2ecf20Sopenharmony_ci ath10k_pci_soc_write32(ar, SOC_LF_TIMER_CONTROL0_ADDRESS, 26178c2ecf20Sopenharmony_ci val & ~SOC_LF_TIMER_CONTROL0_ENABLE_MASK); 26188c2ecf20Sopenharmony_ci} 26198c2ecf20Sopenharmony_ci 26208c2ecf20Sopenharmony_cistatic int ath10k_pci_warm_reset(struct ath10k *ar) 26218c2ecf20Sopenharmony_ci{ 26228c2ecf20Sopenharmony_ci int ret; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset\n"); 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 26278c2ecf20Sopenharmony_ci ar->stats.fw_warm_reset_counter++; 26288c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci ath10k_pci_irq_disable(ar); 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci /* Make sure the target CPU is not doing anything dangerous, e.g. if it 26338c2ecf20Sopenharmony_ci * were to access copy engine while host performs copy engine reset 26348c2ecf20Sopenharmony_ci * then it is possible for the device to confuse pci-e controller to 26358c2ecf20Sopenharmony_ci * the point of bringing host system to a complete stop (i.e. hang). 26368c2ecf20Sopenharmony_ci */ 26378c2ecf20Sopenharmony_ci ath10k_pci_warm_reset_si0(ar); 26388c2ecf20Sopenharmony_ci ath10k_pci_warm_reset_cpu(ar); 26398c2ecf20Sopenharmony_ci ath10k_pci_init_pipes(ar); 26408c2ecf20Sopenharmony_ci ath10k_pci_wait_for_target_init(ar); 26418c2ecf20Sopenharmony_ci 26428c2ecf20Sopenharmony_ci ath10k_pci_warm_reset_clear_lf(ar); 26438c2ecf20Sopenharmony_ci ath10k_pci_warm_reset_ce(ar); 26448c2ecf20Sopenharmony_ci ath10k_pci_warm_reset_cpu(ar); 26458c2ecf20Sopenharmony_ci ath10k_pci_init_pipes(ar); 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci ret = ath10k_pci_wait_for_target_init(ar); 26488c2ecf20Sopenharmony_ci if (ret) { 26498c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to wait for target init: %d\n", ret); 26508c2ecf20Sopenharmony_ci return ret; 26518c2ecf20Sopenharmony_ci } 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot warm reset complete\n"); 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci return 0; 26568c2ecf20Sopenharmony_ci} 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_cistatic int ath10k_pci_qca99x0_soft_chip_reset(struct ath10k *ar) 26598c2ecf20Sopenharmony_ci{ 26608c2ecf20Sopenharmony_ci ath10k_pci_irq_disable(ar); 26618c2ecf20Sopenharmony_ci return ath10k_pci_qca99x0_chip_reset(ar); 26628c2ecf20Sopenharmony_ci} 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_cistatic int ath10k_pci_safe_chip_reset(struct ath10k *ar) 26658c2ecf20Sopenharmony_ci{ 26668c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci if (!ar_pci->pci_soft_reset) 26698c2ecf20Sopenharmony_ci return -ENOTSUPP; 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci return ar_pci->pci_soft_reset(ar); 26728c2ecf20Sopenharmony_ci} 26738c2ecf20Sopenharmony_ci 26748c2ecf20Sopenharmony_cistatic int ath10k_pci_qca988x_chip_reset(struct ath10k *ar) 26758c2ecf20Sopenharmony_ci{ 26768c2ecf20Sopenharmony_ci int i, ret; 26778c2ecf20Sopenharmony_ci u32 val; 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot 988x chip reset\n"); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci /* Some hardware revisions (e.g. CUS223v2) has issues with cold reset. 26828c2ecf20Sopenharmony_ci * It is thus preferred to use warm reset which is safer but may not be 26838c2ecf20Sopenharmony_ci * able to recover the device from all possible fail scenarios. 26848c2ecf20Sopenharmony_ci * 26858c2ecf20Sopenharmony_ci * Warm reset doesn't always work on first try so attempt it a few 26868c2ecf20Sopenharmony_ci * times before giving up. 26878c2ecf20Sopenharmony_ci */ 26888c2ecf20Sopenharmony_ci for (i = 0; i < ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS; i++) { 26898c2ecf20Sopenharmony_ci ret = ath10k_pci_warm_reset(ar); 26908c2ecf20Sopenharmony_ci if (ret) { 26918c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to warm reset attempt %d of %d: %d\n", 26928c2ecf20Sopenharmony_ci i + 1, ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS, 26938c2ecf20Sopenharmony_ci ret); 26948c2ecf20Sopenharmony_ci continue; 26958c2ecf20Sopenharmony_ci } 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci /* FIXME: Sometimes copy engine doesn't recover after warm 26988c2ecf20Sopenharmony_ci * reset. In most cases this needs cold reset. In some of these 26998c2ecf20Sopenharmony_ci * cases the device is in such a state that a cold reset may 27008c2ecf20Sopenharmony_ci * lock up the host. 27018c2ecf20Sopenharmony_ci * 27028c2ecf20Sopenharmony_ci * Reading any host interest register via copy engine is 27038c2ecf20Sopenharmony_ci * sufficient to verify if device is capable of booting 27048c2ecf20Sopenharmony_ci * firmware blob. 27058c2ecf20Sopenharmony_ci */ 27068c2ecf20Sopenharmony_ci ret = ath10k_pci_init_pipes(ar); 27078c2ecf20Sopenharmony_ci if (ret) { 27088c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to init copy engine: %d\n", 27098c2ecf20Sopenharmony_ci ret); 27108c2ecf20Sopenharmony_ci continue; 27118c2ecf20Sopenharmony_ci } 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci ret = ath10k_pci_diag_read32(ar, QCA988X_HOST_INTEREST_ADDRESS, 27148c2ecf20Sopenharmony_ci &val); 27158c2ecf20Sopenharmony_ci if (ret) { 27168c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to poke copy engine: %d\n", 27178c2ecf20Sopenharmony_ci ret); 27188c2ecf20Sopenharmony_ci continue; 27198c2ecf20Sopenharmony_ci } 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (warm)\n"); 27228c2ecf20Sopenharmony_ci return 0; 27238c2ecf20Sopenharmony_ci } 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci if (ath10k_pci_reset_mode == ATH10K_PCI_RESET_WARM_ONLY) { 27268c2ecf20Sopenharmony_ci ath10k_warn(ar, "refusing cold reset as requested\n"); 27278c2ecf20Sopenharmony_ci return -EPERM; 27288c2ecf20Sopenharmony_ci } 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci ret = ath10k_pci_cold_reset(ar); 27318c2ecf20Sopenharmony_ci if (ret) { 27328c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to cold reset: %d\n", ret); 27338c2ecf20Sopenharmony_ci return ret; 27348c2ecf20Sopenharmony_ci } 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci ret = ath10k_pci_wait_for_target_init(ar); 27378c2ecf20Sopenharmony_ci if (ret) { 27388c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", 27398c2ecf20Sopenharmony_ci ret); 27408c2ecf20Sopenharmony_ci return ret; 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci 27438c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca988x chip reset complete (cold)\n"); 27448c2ecf20Sopenharmony_ci 27458c2ecf20Sopenharmony_ci return 0; 27468c2ecf20Sopenharmony_ci} 27478c2ecf20Sopenharmony_ci 27488c2ecf20Sopenharmony_cistatic int ath10k_pci_qca6174_chip_reset(struct ath10k *ar) 27498c2ecf20Sopenharmony_ci{ 27508c2ecf20Sopenharmony_ci int ret; 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset\n"); 27538c2ecf20Sopenharmony_ci 27548c2ecf20Sopenharmony_ci /* FIXME: QCA6174 requires cold + warm reset to work. */ 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci ret = ath10k_pci_cold_reset(ar); 27578c2ecf20Sopenharmony_ci if (ret) { 27588c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to cold reset: %d\n", ret); 27598c2ecf20Sopenharmony_ci return ret; 27608c2ecf20Sopenharmony_ci } 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_ci ret = ath10k_pci_wait_for_target_init(ar); 27638c2ecf20Sopenharmony_ci if (ret) { 27648c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", 27658c2ecf20Sopenharmony_ci ret); 27668c2ecf20Sopenharmony_ci return ret; 27678c2ecf20Sopenharmony_ci } 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci ret = ath10k_pci_warm_reset(ar); 27708c2ecf20Sopenharmony_ci if (ret) { 27718c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to warm reset: %d\n", ret); 27728c2ecf20Sopenharmony_ci return ret; 27738c2ecf20Sopenharmony_ci } 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset complete (cold)\n"); 27768c2ecf20Sopenharmony_ci 27778c2ecf20Sopenharmony_ci return 0; 27788c2ecf20Sopenharmony_ci} 27798c2ecf20Sopenharmony_ci 27808c2ecf20Sopenharmony_cistatic int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar) 27818c2ecf20Sopenharmony_ci{ 27828c2ecf20Sopenharmony_ci int ret; 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset\n"); 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci ret = ath10k_pci_cold_reset(ar); 27878c2ecf20Sopenharmony_ci if (ret) { 27888c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to cold reset: %d\n", ret); 27898c2ecf20Sopenharmony_ci return ret; 27908c2ecf20Sopenharmony_ci } 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci ret = ath10k_pci_wait_for_target_init(ar); 27938c2ecf20Sopenharmony_ci if (ret) { 27948c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", 27958c2ecf20Sopenharmony_ci ret); 27968c2ecf20Sopenharmony_ci return ret; 27978c2ecf20Sopenharmony_ci } 27988c2ecf20Sopenharmony_ci 27998c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset complete (cold)\n"); 28008c2ecf20Sopenharmony_ci 28018c2ecf20Sopenharmony_ci return 0; 28028c2ecf20Sopenharmony_ci} 28038c2ecf20Sopenharmony_ci 28048c2ecf20Sopenharmony_cistatic int ath10k_pci_chip_reset(struct ath10k *ar) 28058c2ecf20Sopenharmony_ci{ 28068c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ci if (WARN_ON(!ar_pci->pci_hard_reset)) 28098c2ecf20Sopenharmony_ci return -ENOTSUPP; 28108c2ecf20Sopenharmony_ci 28118c2ecf20Sopenharmony_ci return ar_pci->pci_hard_reset(ar); 28128c2ecf20Sopenharmony_ci} 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_cistatic int ath10k_pci_hif_power_up(struct ath10k *ar, 28158c2ecf20Sopenharmony_ci enum ath10k_firmware_mode fw_mode) 28168c2ecf20Sopenharmony_ci{ 28178c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 28188c2ecf20Sopenharmony_ci int ret; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power up\n"); 28218c2ecf20Sopenharmony_ci 28228c2ecf20Sopenharmony_ci pcie_capability_read_word(ar_pci->pdev, PCI_EXP_LNKCTL, 28238c2ecf20Sopenharmony_ci &ar_pci->link_ctl); 28248c2ecf20Sopenharmony_ci pcie_capability_clear_word(ar_pci->pdev, PCI_EXP_LNKCTL, 28258c2ecf20Sopenharmony_ci PCI_EXP_LNKCTL_ASPMC); 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci /* 28288c2ecf20Sopenharmony_ci * Bring the target up cleanly. 28298c2ecf20Sopenharmony_ci * 28308c2ecf20Sopenharmony_ci * The target may be in an undefined state with an AUX-powered Target 28318c2ecf20Sopenharmony_ci * and a Host in WoW mode. If the Host crashes, loses power, or is 28328c2ecf20Sopenharmony_ci * restarted (without unloading the driver) then the Target is left 28338c2ecf20Sopenharmony_ci * (aux) powered and running. On a subsequent driver load, the Target 28348c2ecf20Sopenharmony_ci * is in an unexpected state. We try to catch that here in order to 28358c2ecf20Sopenharmony_ci * reset the Target and retry the probe. 28368c2ecf20Sopenharmony_ci */ 28378c2ecf20Sopenharmony_ci ret = ath10k_pci_chip_reset(ar); 28388c2ecf20Sopenharmony_ci if (ret) { 28398c2ecf20Sopenharmony_ci if (ath10k_pci_has_fw_crashed(ar)) { 28408c2ecf20Sopenharmony_ci ath10k_warn(ar, "firmware crashed during chip reset\n"); 28418c2ecf20Sopenharmony_ci ath10k_pci_fw_crashed_clear(ar); 28428c2ecf20Sopenharmony_ci ath10k_pci_fw_crashed_dump(ar); 28438c2ecf20Sopenharmony_ci } 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to reset chip: %d\n", ret); 28468c2ecf20Sopenharmony_ci goto err_sleep; 28478c2ecf20Sopenharmony_ci } 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci ret = ath10k_pci_init_pipes(ar); 28508c2ecf20Sopenharmony_ci if (ret) { 28518c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to initialize CE: %d\n", ret); 28528c2ecf20Sopenharmony_ci goto err_sleep; 28538c2ecf20Sopenharmony_ci } 28548c2ecf20Sopenharmony_ci 28558c2ecf20Sopenharmony_ci ret = ath10k_pci_init_config(ar); 28568c2ecf20Sopenharmony_ci if (ret) { 28578c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to setup init config: %d\n", ret); 28588c2ecf20Sopenharmony_ci goto err_ce; 28598c2ecf20Sopenharmony_ci } 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci ret = ath10k_pci_wake_target_cpu(ar); 28628c2ecf20Sopenharmony_ci if (ret) { 28638c2ecf20Sopenharmony_ci ath10k_err(ar, "could not wake up target CPU: %d\n", ret); 28648c2ecf20Sopenharmony_ci goto err_ce; 28658c2ecf20Sopenharmony_ci } 28668c2ecf20Sopenharmony_ci 28678c2ecf20Sopenharmony_ci return 0; 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_cierr_ce: 28708c2ecf20Sopenharmony_ci ath10k_pci_ce_deinit(ar); 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_cierr_sleep: 28738c2ecf20Sopenharmony_ci return ret; 28748c2ecf20Sopenharmony_ci} 28758c2ecf20Sopenharmony_ci 28768c2ecf20Sopenharmony_civoid ath10k_pci_hif_power_down(struct ath10k *ar) 28778c2ecf20Sopenharmony_ci{ 28788c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n"); 28798c2ecf20Sopenharmony_ci 28808c2ecf20Sopenharmony_ci /* Currently hif_power_up performs effectively a reset and hif_stop 28818c2ecf20Sopenharmony_ci * resets the chip as well so there's no point in resetting here. 28828c2ecf20Sopenharmony_ci */ 28838c2ecf20Sopenharmony_ci} 28848c2ecf20Sopenharmony_ci 28858c2ecf20Sopenharmony_cistatic int ath10k_pci_hif_suspend(struct ath10k *ar) 28868c2ecf20Sopenharmony_ci{ 28878c2ecf20Sopenharmony_ci /* Nothing to do; the important stuff is in the driver suspend. */ 28888c2ecf20Sopenharmony_ci return 0; 28898c2ecf20Sopenharmony_ci} 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_cistatic int ath10k_pci_suspend(struct ath10k *ar) 28928c2ecf20Sopenharmony_ci{ 28938c2ecf20Sopenharmony_ci /* The grace timer can still be counting down and ar->ps_awake be true. 28948c2ecf20Sopenharmony_ci * It is known that the device may be asleep after resuming regardless 28958c2ecf20Sopenharmony_ci * of the SoC powersave state before suspending. Hence make sure the 28968c2ecf20Sopenharmony_ci * device is asleep before proceeding. 28978c2ecf20Sopenharmony_ci */ 28988c2ecf20Sopenharmony_ci ath10k_pci_sleep_sync(ar); 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci return 0; 29018c2ecf20Sopenharmony_ci} 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_cistatic int ath10k_pci_hif_resume(struct ath10k *ar) 29048c2ecf20Sopenharmony_ci{ 29058c2ecf20Sopenharmony_ci /* Nothing to do; the important stuff is in the driver resume. */ 29068c2ecf20Sopenharmony_ci return 0; 29078c2ecf20Sopenharmony_ci} 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_cistatic int ath10k_pci_resume(struct ath10k *ar) 29108c2ecf20Sopenharmony_ci{ 29118c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 29128c2ecf20Sopenharmony_ci struct pci_dev *pdev = ar_pci->pdev; 29138c2ecf20Sopenharmony_ci u32 val; 29148c2ecf20Sopenharmony_ci int ret = 0; 29158c2ecf20Sopenharmony_ci 29168c2ecf20Sopenharmony_ci ret = ath10k_pci_force_wake(ar); 29178c2ecf20Sopenharmony_ci if (ret) { 29188c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to wake up target: %d\n", ret); 29198c2ecf20Sopenharmony_ci return ret; 29208c2ecf20Sopenharmony_ci } 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci /* Suspend/Resume resets the PCI configuration space, so we have to 29238c2ecf20Sopenharmony_ci * re-disable the RETRY_TIMEOUT register (0x41) to keep PCI Tx retries 29248c2ecf20Sopenharmony_ci * from interfering with C3 CPU state. pci_restore_state won't help 29258c2ecf20Sopenharmony_ci * here since it only restores the first 64 bytes pci config header. 29268c2ecf20Sopenharmony_ci */ 29278c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, 0x40, &val); 29288c2ecf20Sopenharmony_ci if ((val & 0x0000ff00) != 0) 29298c2ecf20Sopenharmony_ci pci_write_config_dword(pdev, 0x40, val & 0xffff00ff); 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci return ret; 29328c2ecf20Sopenharmony_ci} 29338c2ecf20Sopenharmony_ci 29348c2ecf20Sopenharmony_cistatic bool ath10k_pci_validate_cal(void *data, size_t size) 29358c2ecf20Sopenharmony_ci{ 29368c2ecf20Sopenharmony_ci __le16 *cal_words = data; 29378c2ecf20Sopenharmony_ci u16 checksum = 0; 29388c2ecf20Sopenharmony_ci size_t i; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci if (size % 2 != 0) 29418c2ecf20Sopenharmony_ci return false; 29428c2ecf20Sopenharmony_ci 29438c2ecf20Sopenharmony_ci for (i = 0; i < size / 2; i++) 29448c2ecf20Sopenharmony_ci checksum ^= le16_to_cpu(cal_words[i]); 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci return checksum == 0xffff; 29478c2ecf20Sopenharmony_ci} 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_cistatic void ath10k_pci_enable_eeprom(struct ath10k *ar) 29508c2ecf20Sopenharmony_ci{ 29518c2ecf20Sopenharmony_ci /* Enable SI clock */ 29528c2ecf20Sopenharmony_ci ath10k_pci_soc_write32(ar, CLOCK_CONTROL_OFFSET, 0x0); 29538c2ecf20Sopenharmony_ci 29548c2ecf20Sopenharmony_ci /* Configure GPIOs for I2C operation */ 29558c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, 29568c2ecf20Sopenharmony_ci GPIO_BASE_ADDRESS + GPIO_PIN0_OFFSET + 29578c2ecf20Sopenharmony_ci 4 * QCA9887_1_0_I2C_SDA_GPIO_PIN, 29588c2ecf20Sopenharmony_ci SM(QCA9887_1_0_I2C_SDA_PIN_CONFIG, 29598c2ecf20Sopenharmony_ci GPIO_PIN0_CONFIG) | 29608c2ecf20Sopenharmony_ci SM(1, GPIO_PIN0_PAD_PULL)); 29618c2ecf20Sopenharmony_ci 29628c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, 29638c2ecf20Sopenharmony_ci GPIO_BASE_ADDRESS + GPIO_PIN0_OFFSET + 29648c2ecf20Sopenharmony_ci 4 * QCA9887_1_0_SI_CLK_GPIO_PIN, 29658c2ecf20Sopenharmony_ci SM(QCA9887_1_0_SI_CLK_PIN_CONFIG, GPIO_PIN0_CONFIG) | 29668c2ecf20Sopenharmony_ci SM(1, GPIO_PIN0_PAD_PULL)); 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, 29698c2ecf20Sopenharmony_ci GPIO_BASE_ADDRESS + 29708c2ecf20Sopenharmony_ci QCA9887_1_0_GPIO_ENABLE_W1TS_LOW_ADDRESS, 29718c2ecf20Sopenharmony_ci 1u << QCA9887_1_0_SI_CLK_GPIO_PIN); 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci /* In Swift ASIC - EEPROM clock will be (110MHz/512) = 214KHz */ 29748c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, 29758c2ecf20Sopenharmony_ci SI_BASE_ADDRESS + SI_CONFIG_OFFSET, 29768c2ecf20Sopenharmony_ci SM(1, SI_CONFIG_ERR_INT) | 29778c2ecf20Sopenharmony_ci SM(1, SI_CONFIG_BIDIR_OD_DATA) | 29788c2ecf20Sopenharmony_ci SM(1, SI_CONFIG_I2C) | 29798c2ecf20Sopenharmony_ci SM(1, SI_CONFIG_POS_SAMPLE) | 29808c2ecf20Sopenharmony_ci SM(1, SI_CONFIG_INACTIVE_DATA) | 29818c2ecf20Sopenharmony_ci SM(1, SI_CONFIG_INACTIVE_CLK) | 29828c2ecf20Sopenharmony_ci SM(8, SI_CONFIG_DIVIDER)); 29838c2ecf20Sopenharmony_ci} 29848c2ecf20Sopenharmony_ci 29858c2ecf20Sopenharmony_cistatic int ath10k_pci_read_eeprom(struct ath10k *ar, u16 addr, u8 *out) 29868c2ecf20Sopenharmony_ci{ 29878c2ecf20Sopenharmony_ci u32 reg; 29888c2ecf20Sopenharmony_ci int wait_limit; 29898c2ecf20Sopenharmony_ci 29908c2ecf20Sopenharmony_ci /* set device select byte and for the read operation */ 29918c2ecf20Sopenharmony_ci reg = QCA9887_EEPROM_SELECT_READ | 29928c2ecf20Sopenharmony_ci SM(addr, QCA9887_EEPROM_ADDR_LO) | 29938c2ecf20Sopenharmony_ci SM(addr >> 8, QCA9887_EEPROM_ADDR_HI); 29948c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_TX_DATA0_OFFSET, reg); 29958c2ecf20Sopenharmony_ci 29968c2ecf20Sopenharmony_ci /* write transmit data, transfer length, and START bit */ 29978c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET, 29988c2ecf20Sopenharmony_ci SM(1, SI_CS_START) | SM(1, SI_CS_RX_CNT) | 29998c2ecf20Sopenharmony_ci SM(4, SI_CS_TX_CNT)); 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci /* wait max 1 sec */ 30028c2ecf20Sopenharmony_ci wait_limit = 100000; 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci /* wait for SI_CS_DONE_INT */ 30058c2ecf20Sopenharmony_ci do { 30068c2ecf20Sopenharmony_ci reg = ath10k_pci_read32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET); 30078c2ecf20Sopenharmony_ci if (MS(reg, SI_CS_DONE_INT)) 30088c2ecf20Sopenharmony_ci break; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci wait_limit--; 30118c2ecf20Sopenharmony_ci udelay(10); 30128c2ecf20Sopenharmony_ci } while (wait_limit > 0); 30138c2ecf20Sopenharmony_ci 30148c2ecf20Sopenharmony_ci if (!MS(reg, SI_CS_DONE_INT)) { 30158c2ecf20Sopenharmony_ci ath10k_err(ar, "timeout while reading device EEPROM at %04x\n", 30168c2ecf20Sopenharmony_ci addr); 30178c2ecf20Sopenharmony_ci return -ETIMEDOUT; 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci /* clear SI_CS_DONE_INT */ 30218c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SI_BASE_ADDRESS + SI_CS_OFFSET, reg); 30228c2ecf20Sopenharmony_ci 30238c2ecf20Sopenharmony_ci if (MS(reg, SI_CS_DONE_ERR)) { 30248c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to read device EEPROM at %04x\n", addr); 30258c2ecf20Sopenharmony_ci return -EIO; 30268c2ecf20Sopenharmony_ci } 30278c2ecf20Sopenharmony_ci 30288c2ecf20Sopenharmony_ci /* extract receive data */ 30298c2ecf20Sopenharmony_ci reg = ath10k_pci_read32(ar, SI_BASE_ADDRESS + SI_RX_DATA0_OFFSET); 30308c2ecf20Sopenharmony_ci *out = reg; 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci return 0; 30338c2ecf20Sopenharmony_ci} 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_cistatic int ath10k_pci_hif_fetch_cal_eeprom(struct ath10k *ar, void **data, 30368c2ecf20Sopenharmony_ci size_t *data_len) 30378c2ecf20Sopenharmony_ci{ 30388c2ecf20Sopenharmony_ci u8 *caldata = NULL; 30398c2ecf20Sopenharmony_ci size_t calsize, i; 30408c2ecf20Sopenharmony_ci int ret; 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci if (!QCA_REV_9887(ar)) 30438c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 30448c2ecf20Sopenharmony_ci 30458c2ecf20Sopenharmony_ci calsize = ar->hw_params.cal_data_len; 30468c2ecf20Sopenharmony_ci caldata = kmalloc(calsize, GFP_KERNEL); 30478c2ecf20Sopenharmony_ci if (!caldata) 30488c2ecf20Sopenharmony_ci return -ENOMEM; 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci ath10k_pci_enable_eeprom(ar); 30518c2ecf20Sopenharmony_ci 30528c2ecf20Sopenharmony_ci for (i = 0; i < calsize; i++) { 30538c2ecf20Sopenharmony_ci ret = ath10k_pci_read_eeprom(ar, i, &caldata[i]); 30548c2ecf20Sopenharmony_ci if (ret) 30558c2ecf20Sopenharmony_ci goto err_free; 30568c2ecf20Sopenharmony_ci } 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci if (!ath10k_pci_validate_cal(caldata, calsize)) 30598c2ecf20Sopenharmony_ci goto err_free; 30608c2ecf20Sopenharmony_ci 30618c2ecf20Sopenharmony_ci *data = caldata; 30628c2ecf20Sopenharmony_ci *data_len = calsize; 30638c2ecf20Sopenharmony_ci 30648c2ecf20Sopenharmony_ci return 0; 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_cierr_free: 30678c2ecf20Sopenharmony_ci kfree(caldata); 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci return -EINVAL; 30708c2ecf20Sopenharmony_ci} 30718c2ecf20Sopenharmony_ci 30728c2ecf20Sopenharmony_cistatic const struct ath10k_hif_ops ath10k_pci_hif_ops = { 30738c2ecf20Sopenharmony_ci .tx_sg = ath10k_pci_hif_tx_sg, 30748c2ecf20Sopenharmony_ci .diag_read = ath10k_pci_hif_diag_read, 30758c2ecf20Sopenharmony_ci .diag_write = ath10k_pci_diag_write_mem, 30768c2ecf20Sopenharmony_ci .exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg, 30778c2ecf20Sopenharmony_ci .start = ath10k_pci_hif_start, 30788c2ecf20Sopenharmony_ci .stop = ath10k_pci_hif_stop, 30798c2ecf20Sopenharmony_ci .map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe, 30808c2ecf20Sopenharmony_ci .get_default_pipe = ath10k_pci_hif_get_default_pipe, 30818c2ecf20Sopenharmony_ci .send_complete_check = ath10k_pci_hif_send_complete_check, 30828c2ecf20Sopenharmony_ci .get_free_queue_number = ath10k_pci_hif_get_free_queue_number, 30838c2ecf20Sopenharmony_ci .power_up = ath10k_pci_hif_power_up, 30848c2ecf20Sopenharmony_ci .power_down = ath10k_pci_hif_power_down, 30858c2ecf20Sopenharmony_ci .read32 = ath10k_pci_read32, 30868c2ecf20Sopenharmony_ci .write32 = ath10k_pci_write32, 30878c2ecf20Sopenharmony_ci .suspend = ath10k_pci_hif_suspend, 30888c2ecf20Sopenharmony_ci .resume = ath10k_pci_hif_resume, 30898c2ecf20Sopenharmony_ci .fetch_cal_eeprom = ath10k_pci_hif_fetch_cal_eeprom, 30908c2ecf20Sopenharmony_ci}; 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci/* 30938c2ecf20Sopenharmony_ci * Top-level interrupt handler for all PCI interrupts from a Target. 30948c2ecf20Sopenharmony_ci * When a block of MSI interrupts is allocated, this top-level handler 30958c2ecf20Sopenharmony_ci * is not used; instead, we directly call the correct sub-handler. 30968c2ecf20Sopenharmony_ci */ 30978c2ecf20Sopenharmony_cistatic irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg) 30988c2ecf20Sopenharmony_ci{ 30998c2ecf20Sopenharmony_ci struct ath10k *ar = arg; 31008c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 31018c2ecf20Sopenharmony_ci int ret; 31028c2ecf20Sopenharmony_ci 31038c2ecf20Sopenharmony_ci if (ath10k_pci_has_device_gone(ar)) 31048c2ecf20Sopenharmony_ci return IRQ_NONE; 31058c2ecf20Sopenharmony_ci 31068c2ecf20Sopenharmony_ci ret = ath10k_pci_force_wake(ar); 31078c2ecf20Sopenharmony_ci if (ret) { 31088c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to wake device up on irq: %d\n", ret); 31098c2ecf20Sopenharmony_ci return IRQ_NONE; 31108c2ecf20Sopenharmony_ci } 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci if ((ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) && 31138c2ecf20Sopenharmony_ci !ath10k_pci_irq_pending(ar)) 31148c2ecf20Sopenharmony_ci return IRQ_NONE; 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci ath10k_pci_disable_and_clear_legacy_irq(ar); 31178c2ecf20Sopenharmony_ci ath10k_pci_irq_msi_fw_mask(ar); 31188c2ecf20Sopenharmony_ci napi_schedule(&ar->napi); 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci return IRQ_HANDLED; 31218c2ecf20Sopenharmony_ci} 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_cistatic int ath10k_pci_napi_poll(struct napi_struct *ctx, int budget) 31248c2ecf20Sopenharmony_ci{ 31258c2ecf20Sopenharmony_ci struct ath10k *ar = container_of(ctx, struct ath10k, napi); 31268c2ecf20Sopenharmony_ci int done = 0; 31278c2ecf20Sopenharmony_ci 31288c2ecf20Sopenharmony_ci if (ath10k_pci_has_fw_crashed(ar)) { 31298c2ecf20Sopenharmony_ci ath10k_pci_fw_crashed_clear(ar); 31308c2ecf20Sopenharmony_ci ath10k_pci_fw_crashed_dump(ar); 31318c2ecf20Sopenharmony_ci napi_complete(ctx); 31328c2ecf20Sopenharmony_ci return done; 31338c2ecf20Sopenharmony_ci } 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci ath10k_ce_per_engine_service_any(ar); 31368c2ecf20Sopenharmony_ci 31378c2ecf20Sopenharmony_ci done = ath10k_htt_txrx_compl_task(ar, budget); 31388c2ecf20Sopenharmony_ci 31398c2ecf20Sopenharmony_ci if (done < budget) { 31408c2ecf20Sopenharmony_ci napi_complete_done(ctx, done); 31418c2ecf20Sopenharmony_ci /* In case of MSI, it is possible that interrupts are received 31428c2ecf20Sopenharmony_ci * while NAPI poll is inprogress. So pending interrupts that are 31438c2ecf20Sopenharmony_ci * received after processing all copy engine pipes by NAPI poll 31448c2ecf20Sopenharmony_ci * will not be handled again. This is causing failure to 31458c2ecf20Sopenharmony_ci * complete boot sequence in x86 platform. So before enabling 31468c2ecf20Sopenharmony_ci * interrupts safer to check for pending interrupts for 31478c2ecf20Sopenharmony_ci * immediate servicing. 31488c2ecf20Sopenharmony_ci */ 31498c2ecf20Sopenharmony_ci if (ath10k_ce_interrupt_summary(ar)) { 31508c2ecf20Sopenharmony_ci napi_reschedule(ctx); 31518c2ecf20Sopenharmony_ci goto out; 31528c2ecf20Sopenharmony_ci } 31538c2ecf20Sopenharmony_ci ath10k_pci_enable_legacy_irq(ar); 31548c2ecf20Sopenharmony_ci ath10k_pci_irq_msi_fw_unmask(ar); 31558c2ecf20Sopenharmony_ci } 31568c2ecf20Sopenharmony_ci 31578c2ecf20Sopenharmony_ciout: 31588c2ecf20Sopenharmony_ci return done; 31598c2ecf20Sopenharmony_ci} 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_cistatic int ath10k_pci_request_irq_msi(struct ath10k *ar) 31628c2ecf20Sopenharmony_ci{ 31638c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 31648c2ecf20Sopenharmony_ci int ret; 31658c2ecf20Sopenharmony_ci 31668c2ecf20Sopenharmony_ci ret = request_irq(ar_pci->pdev->irq, 31678c2ecf20Sopenharmony_ci ath10k_pci_interrupt_handler, 31688c2ecf20Sopenharmony_ci IRQF_SHARED, "ath10k_pci", ar); 31698c2ecf20Sopenharmony_ci if (ret) { 31708c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to request MSI irq %d: %d\n", 31718c2ecf20Sopenharmony_ci ar_pci->pdev->irq, ret); 31728c2ecf20Sopenharmony_ci return ret; 31738c2ecf20Sopenharmony_ci } 31748c2ecf20Sopenharmony_ci 31758c2ecf20Sopenharmony_ci return 0; 31768c2ecf20Sopenharmony_ci} 31778c2ecf20Sopenharmony_ci 31788c2ecf20Sopenharmony_cistatic int ath10k_pci_request_irq_legacy(struct ath10k *ar) 31798c2ecf20Sopenharmony_ci{ 31808c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 31818c2ecf20Sopenharmony_ci int ret; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci ret = request_irq(ar_pci->pdev->irq, 31848c2ecf20Sopenharmony_ci ath10k_pci_interrupt_handler, 31858c2ecf20Sopenharmony_ci IRQF_SHARED, "ath10k_pci", ar); 31868c2ecf20Sopenharmony_ci if (ret) { 31878c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to request legacy irq %d: %d\n", 31888c2ecf20Sopenharmony_ci ar_pci->pdev->irq, ret); 31898c2ecf20Sopenharmony_ci return ret; 31908c2ecf20Sopenharmony_ci } 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci return 0; 31938c2ecf20Sopenharmony_ci} 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_cistatic int ath10k_pci_request_irq(struct ath10k *ar) 31968c2ecf20Sopenharmony_ci{ 31978c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci switch (ar_pci->oper_irq_mode) { 32008c2ecf20Sopenharmony_ci case ATH10K_PCI_IRQ_LEGACY: 32018c2ecf20Sopenharmony_ci return ath10k_pci_request_irq_legacy(ar); 32028c2ecf20Sopenharmony_ci case ATH10K_PCI_IRQ_MSI: 32038c2ecf20Sopenharmony_ci return ath10k_pci_request_irq_msi(ar); 32048c2ecf20Sopenharmony_ci default: 32058c2ecf20Sopenharmony_ci return -EINVAL; 32068c2ecf20Sopenharmony_ci } 32078c2ecf20Sopenharmony_ci} 32088c2ecf20Sopenharmony_ci 32098c2ecf20Sopenharmony_cistatic void ath10k_pci_free_irq(struct ath10k *ar) 32108c2ecf20Sopenharmony_ci{ 32118c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 32128c2ecf20Sopenharmony_ci 32138c2ecf20Sopenharmony_ci free_irq(ar_pci->pdev->irq, ar); 32148c2ecf20Sopenharmony_ci} 32158c2ecf20Sopenharmony_ci 32168c2ecf20Sopenharmony_civoid ath10k_pci_init_napi(struct ath10k *ar) 32178c2ecf20Sopenharmony_ci{ 32188c2ecf20Sopenharmony_ci netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_pci_napi_poll, 32198c2ecf20Sopenharmony_ci ATH10K_NAPI_BUDGET); 32208c2ecf20Sopenharmony_ci} 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_cistatic int ath10k_pci_init_irq(struct ath10k *ar) 32238c2ecf20Sopenharmony_ci{ 32248c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 32258c2ecf20Sopenharmony_ci int ret; 32268c2ecf20Sopenharmony_ci 32278c2ecf20Sopenharmony_ci ath10k_pci_init_napi(ar); 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO) 32308c2ecf20Sopenharmony_ci ath10k_info(ar, "limiting irq mode to: %d\n", 32318c2ecf20Sopenharmony_ci ath10k_pci_irq_mode); 32328c2ecf20Sopenharmony_ci 32338c2ecf20Sopenharmony_ci /* Try MSI */ 32348c2ecf20Sopenharmony_ci if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) { 32358c2ecf20Sopenharmony_ci ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_MSI; 32368c2ecf20Sopenharmony_ci ret = pci_enable_msi(ar_pci->pdev); 32378c2ecf20Sopenharmony_ci if (ret == 0) 32388c2ecf20Sopenharmony_ci return 0; 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci /* fall-through */ 32418c2ecf20Sopenharmony_ci } 32428c2ecf20Sopenharmony_ci 32438c2ecf20Sopenharmony_ci /* Try legacy irq 32448c2ecf20Sopenharmony_ci * 32458c2ecf20Sopenharmony_ci * A potential race occurs here: The CORE_BASE write 32468c2ecf20Sopenharmony_ci * depends on target correctly decoding AXI address but 32478c2ecf20Sopenharmony_ci * host won't know when target writes BAR to CORE_CTRL. 32488c2ecf20Sopenharmony_ci * This write might get lost if target has NOT written BAR. 32498c2ecf20Sopenharmony_ci * For now, fix the race by repeating the write in below 32508c2ecf20Sopenharmony_ci * synchronization checking. 32518c2ecf20Sopenharmony_ci */ 32528c2ecf20Sopenharmony_ci ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY; 32538c2ecf20Sopenharmony_ci 32548c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, 32558c2ecf20Sopenharmony_ci PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); 32568c2ecf20Sopenharmony_ci 32578c2ecf20Sopenharmony_ci return 0; 32588c2ecf20Sopenharmony_ci} 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_cistatic void ath10k_pci_deinit_irq_legacy(struct ath10k *ar) 32618c2ecf20Sopenharmony_ci{ 32628c2ecf20Sopenharmony_ci ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS, 32638c2ecf20Sopenharmony_ci 0); 32648c2ecf20Sopenharmony_ci} 32658c2ecf20Sopenharmony_ci 32668c2ecf20Sopenharmony_cistatic int ath10k_pci_deinit_irq(struct ath10k *ar) 32678c2ecf20Sopenharmony_ci{ 32688c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 32698c2ecf20Sopenharmony_ci 32708c2ecf20Sopenharmony_ci switch (ar_pci->oper_irq_mode) { 32718c2ecf20Sopenharmony_ci case ATH10K_PCI_IRQ_LEGACY: 32728c2ecf20Sopenharmony_ci ath10k_pci_deinit_irq_legacy(ar); 32738c2ecf20Sopenharmony_ci break; 32748c2ecf20Sopenharmony_ci default: 32758c2ecf20Sopenharmony_ci pci_disable_msi(ar_pci->pdev); 32768c2ecf20Sopenharmony_ci break; 32778c2ecf20Sopenharmony_ci } 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci return 0; 32808c2ecf20Sopenharmony_ci} 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ciint ath10k_pci_wait_for_target_init(struct ath10k *ar) 32838c2ecf20Sopenharmony_ci{ 32848c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 32858c2ecf20Sopenharmony_ci unsigned long timeout; 32868c2ecf20Sopenharmony_ci u32 val; 32878c2ecf20Sopenharmony_ci 32888c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot waiting target to initialise\n"); 32898c2ecf20Sopenharmony_ci 32908c2ecf20Sopenharmony_ci timeout = jiffies + msecs_to_jiffies(ATH10K_PCI_TARGET_WAIT); 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci do { 32938c2ecf20Sopenharmony_ci val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS); 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target indicator %x\n", 32968c2ecf20Sopenharmony_ci val); 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci /* target should never return this */ 32998c2ecf20Sopenharmony_ci if (val == 0xffffffff) 33008c2ecf20Sopenharmony_ci continue; 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci /* the device has crashed so don't bother trying anymore */ 33038c2ecf20Sopenharmony_ci if (val & FW_IND_EVENT_PENDING) 33048c2ecf20Sopenharmony_ci break; 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci if (val & FW_IND_INITIALIZED) 33078c2ecf20Sopenharmony_ci break; 33088c2ecf20Sopenharmony_ci 33098c2ecf20Sopenharmony_ci if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) 33108c2ecf20Sopenharmony_ci /* Fix potential race by repeating CORE_BASE writes */ 33118c2ecf20Sopenharmony_ci ath10k_pci_enable_legacy_irq(ar); 33128c2ecf20Sopenharmony_ci 33138c2ecf20Sopenharmony_ci mdelay(10); 33148c2ecf20Sopenharmony_ci } while (time_before(jiffies, timeout)); 33158c2ecf20Sopenharmony_ci 33168c2ecf20Sopenharmony_ci ath10k_pci_disable_and_clear_legacy_irq(ar); 33178c2ecf20Sopenharmony_ci ath10k_pci_irq_msi_fw_mask(ar); 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci if (val == 0xffffffff) { 33208c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to read device register, device is gone\n"); 33218c2ecf20Sopenharmony_ci return -EIO; 33228c2ecf20Sopenharmony_ci } 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci if (val & FW_IND_EVENT_PENDING) { 33258c2ecf20Sopenharmony_ci ath10k_warn(ar, "device has crashed during init\n"); 33268c2ecf20Sopenharmony_ci return -ECOMM; 33278c2ecf20Sopenharmony_ci } 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_ci if (!(val & FW_IND_INITIALIZED)) { 33308c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to receive initialized event from target: %08x\n", 33318c2ecf20Sopenharmony_ci val); 33328c2ecf20Sopenharmony_ci return -ETIMEDOUT; 33338c2ecf20Sopenharmony_ci } 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot target initialised\n"); 33368c2ecf20Sopenharmony_ci return 0; 33378c2ecf20Sopenharmony_ci} 33388c2ecf20Sopenharmony_ci 33398c2ecf20Sopenharmony_cistatic int ath10k_pci_cold_reset(struct ath10k *ar) 33408c2ecf20Sopenharmony_ci{ 33418c2ecf20Sopenharmony_ci u32 val; 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_ci spin_lock_bh(&ar->data_lock); 33468c2ecf20Sopenharmony_ci 33478c2ecf20Sopenharmony_ci ar->stats.fw_cold_reset_counter++; 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci spin_unlock_bh(&ar->data_lock); 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci /* Put Target, including PCIe, into RESET. */ 33528c2ecf20Sopenharmony_ci val = ath10k_pci_reg_read32(ar, SOC_GLOBAL_RESET_ADDRESS); 33538c2ecf20Sopenharmony_ci val |= 1; 33548c2ecf20Sopenharmony_ci ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); 33558c2ecf20Sopenharmony_ci 33568c2ecf20Sopenharmony_ci /* After writing into SOC_GLOBAL_RESET to put device into 33578c2ecf20Sopenharmony_ci * reset and pulling out of reset pcie may not be stable 33588c2ecf20Sopenharmony_ci * for any immediate pcie register access and cause bus error, 33598c2ecf20Sopenharmony_ci * add delay before any pcie access request to fix this issue. 33608c2ecf20Sopenharmony_ci */ 33618c2ecf20Sopenharmony_ci msleep(20); 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci /* Pull Target, including PCIe, out of RESET. */ 33648c2ecf20Sopenharmony_ci val &= ~1; 33658c2ecf20Sopenharmony_ci ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); 33668c2ecf20Sopenharmony_ci 33678c2ecf20Sopenharmony_ci msleep(20); 33688c2ecf20Sopenharmony_ci 33698c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n"); 33708c2ecf20Sopenharmony_ci 33718c2ecf20Sopenharmony_ci return 0; 33728c2ecf20Sopenharmony_ci} 33738c2ecf20Sopenharmony_ci 33748c2ecf20Sopenharmony_cistatic int ath10k_pci_claim(struct ath10k *ar) 33758c2ecf20Sopenharmony_ci{ 33768c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 33778c2ecf20Sopenharmony_ci struct pci_dev *pdev = ar_pci->pdev; 33788c2ecf20Sopenharmony_ci int ret; 33798c2ecf20Sopenharmony_ci 33808c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, ar); 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci ret = pci_enable_device(pdev); 33838c2ecf20Sopenharmony_ci if (ret) { 33848c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to enable pci device: %d\n", ret); 33858c2ecf20Sopenharmony_ci return ret; 33868c2ecf20Sopenharmony_ci } 33878c2ecf20Sopenharmony_ci 33888c2ecf20Sopenharmony_ci ret = pci_request_region(pdev, BAR_NUM, "ath"); 33898c2ecf20Sopenharmony_ci if (ret) { 33908c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to request region BAR%d: %d\n", BAR_NUM, 33918c2ecf20Sopenharmony_ci ret); 33928c2ecf20Sopenharmony_ci goto err_device; 33938c2ecf20Sopenharmony_ci } 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci /* Target expects 32 bit DMA. Enforce it. */ 33968c2ecf20Sopenharmony_ci ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); 33978c2ecf20Sopenharmony_ci if (ret) { 33988c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to set dma mask to 32-bit: %d\n", ret); 33998c2ecf20Sopenharmony_ci goto err_region; 34008c2ecf20Sopenharmony_ci } 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ci ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); 34038c2ecf20Sopenharmony_ci if (ret) { 34048c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to set consistent dma mask to 32-bit: %d\n", 34058c2ecf20Sopenharmony_ci ret); 34068c2ecf20Sopenharmony_ci goto err_region; 34078c2ecf20Sopenharmony_ci } 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci pci_set_master(pdev); 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci /* Arrange for access to Target SoC registers. */ 34128c2ecf20Sopenharmony_ci ar_pci->mem_len = pci_resource_len(pdev, BAR_NUM); 34138c2ecf20Sopenharmony_ci ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0); 34148c2ecf20Sopenharmony_ci if (!ar_pci->mem) { 34158c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM); 34168c2ecf20Sopenharmony_ci ret = -EIO; 34178c2ecf20Sopenharmony_ci goto err_master; 34188c2ecf20Sopenharmony_ci } 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot pci_mem 0x%pK\n", ar_pci->mem); 34218c2ecf20Sopenharmony_ci return 0; 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_cierr_master: 34248c2ecf20Sopenharmony_ci pci_clear_master(pdev); 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_cierr_region: 34278c2ecf20Sopenharmony_ci pci_release_region(pdev, BAR_NUM); 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_cierr_device: 34308c2ecf20Sopenharmony_ci pci_disable_device(pdev); 34318c2ecf20Sopenharmony_ci 34328c2ecf20Sopenharmony_ci return ret; 34338c2ecf20Sopenharmony_ci} 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_cistatic void ath10k_pci_release(struct ath10k *ar) 34368c2ecf20Sopenharmony_ci{ 34378c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 34388c2ecf20Sopenharmony_ci struct pci_dev *pdev = ar_pci->pdev; 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci pci_iounmap(pdev, ar_pci->mem); 34418c2ecf20Sopenharmony_ci pci_release_region(pdev, BAR_NUM); 34428c2ecf20Sopenharmony_ci pci_clear_master(pdev); 34438c2ecf20Sopenharmony_ci pci_disable_device(pdev); 34448c2ecf20Sopenharmony_ci} 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_cistatic bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id) 34478c2ecf20Sopenharmony_ci{ 34488c2ecf20Sopenharmony_ci const struct ath10k_pci_supp_chip *supp_chip; 34498c2ecf20Sopenharmony_ci int i; 34508c2ecf20Sopenharmony_ci u32 rev_id = MS(chip_id, SOC_CHIP_ID_REV); 34518c2ecf20Sopenharmony_ci 34528c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ath10k_pci_supp_chips); i++) { 34538c2ecf20Sopenharmony_ci supp_chip = &ath10k_pci_supp_chips[i]; 34548c2ecf20Sopenharmony_ci 34558c2ecf20Sopenharmony_ci if (supp_chip->dev_id == dev_id && 34568c2ecf20Sopenharmony_ci supp_chip->rev_id == rev_id) 34578c2ecf20Sopenharmony_ci return true; 34588c2ecf20Sopenharmony_ci } 34598c2ecf20Sopenharmony_ci 34608c2ecf20Sopenharmony_ci return false; 34618c2ecf20Sopenharmony_ci} 34628c2ecf20Sopenharmony_ci 34638c2ecf20Sopenharmony_ciint ath10k_pci_setup_resource(struct ath10k *ar) 34648c2ecf20Sopenharmony_ci{ 34658c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 34668c2ecf20Sopenharmony_ci struct ath10k_ce *ce = ath10k_ce_priv(ar); 34678c2ecf20Sopenharmony_ci int ret; 34688c2ecf20Sopenharmony_ci 34698c2ecf20Sopenharmony_ci spin_lock_init(&ce->ce_lock); 34708c2ecf20Sopenharmony_ci spin_lock_init(&ar_pci->ps_lock); 34718c2ecf20Sopenharmony_ci mutex_init(&ar_pci->ce_diag_mutex); 34728c2ecf20Sopenharmony_ci 34738c2ecf20Sopenharmony_ci INIT_WORK(&ar_pci->dump_work, ath10k_pci_fw_dump_work); 34748c2ecf20Sopenharmony_ci 34758c2ecf20Sopenharmony_ci timer_setup(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry, 0); 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_ci ar_pci->attr = kmemdup(pci_host_ce_config_wlan, 34788c2ecf20Sopenharmony_ci sizeof(pci_host_ce_config_wlan), 34798c2ecf20Sopenharmony_ci GFP_KERNEL); 34808c2ecf20Sopenharmony_ci if (!ar_pci->attr) 34818c2ecf20Sopenharmony_ci return -ENOMEM; 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci ar_pci->pipe_config = kmemdup(pci_target_ce_config_wlan, 34848c2ecf20Sopenharmony_ci sizeof(pci_target_ce_config_wlan), 34858c2ecf20Sopenharmony_ci GFP_KERNEL); 34868c2ecf20Sopenharmony_ci if (!ar_pci->pipe_config) { 34878c2ecf20Sopenharmony_ci ret = -ENOMEM; 34888c2ecf20Sopenharmony_ci goto err_free_attr; 34898c2ecf20Sopenharmony_ci } 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci ar_pci->serv_to_pipe = kmemdup(pci_target_service_to_ce_map_wlan, 34928c2ecf20Sopenharmony_ci sizeof(pci_target_service_to_ce_map_wlan), 34938c2ecf20Sopenharmony_ci GFP_KERNEL); 34948c2ecf20Sopenharmony_ci if (!ar_pci->serv_to_pipe) { 34958c2ecf20Sopenharmony_ci ret = -ENOMEM; 34968c2ecf20Sopenharmony_ci goto err_free_pipe_config; 34978c2ecf20Sopenharmony_ci } 34988c2ecf20Sopenharmony_ci 34998c2ecf20Sopenharmony_ci if (QCA_REV_6174(ar) || QCA_REV_9377(ar)) 35008c2ecf20Sopenharmony_ci ath10k_pci_override_ce_config(ar); 35018c2ecf20Sopenharmony_ci 35028c2ecf20Sopenharmony_ci ret = ath10k_pci_alloc_pipes(ar); 35038c2ecf20Sopenharmony_ci if (ret) { 35048c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to allocate copy engine pipes: %d\n", 35058c2ecf20Sopenharmony_ci ret); 35068c2ecf20Sopenharmony_ci goto err_free_serv_to_pipe; 35078c2ecf20Sopenharmony_ci } 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci return 0; 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_cierr_free_serv_to_pipe: 35128c2ecf20Sopenharmony_ci kfree(ar_pci->serv_to_pipe); 35138c2ecf20Sopenharmony_cierr_free_pipe_config: 35148c2ecf20Sopenharmony_ci kfree(ar_pci->pipe_config); 35158c2ecf20Sopenharmony_cierr_free_attr: 35168c2ecf20Sopenharmony_ci kfree(ar_pci->attr); 35178c2ecf20Sopenharmony_ci return ret; 35188c2ecf20Sopenharmony_ci} 35198c2ecf20Sopenharmony_ci 35208c2ecf20Sopenharmony_civoid ath10k_pci_release_resource(struct ath10k *ar) 35218c2ecf20Sopenharmony_ci{ 35228c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci ath10k_pci_rx_retry_sync(ar); 35258c2ecf20Sopenharmony_ci netif_napi_del(&ar->napi); 35268c2ecf20Sopenharmony_ci ath10k_pci_ce_deinit(ar); 35278c2ecf20Sopenharmony_ci ath10k_pci_free_pipes(ar); 35288c2ecf20Sopenharmony_ci kfree(ar_pci->attr); 35298c2ecf20Sopenharmony_ci kfree(ar_pci->pipe_config); 35308c2ecf20Sopenharmony_ci kfree(ar_pci->serv_to_pipe); 35318c2ecf20Sopenharmony_ci} 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_cistatic const struct ath10k_bus_ops ath10k_pci_bus_ops = { 35348c2ecf20Sopenharmony_ci .read32 = ath10k_bus_pci_read32, 35358c2ecf20Sopenharmony_ci .write32 = ath10k_bus_pci_write32, 35368c2ecf20Sopenharmony_ci .get_num_banks = ath10k_pci_get_num_banks, 35378c2ecf20Sopenharmony_ci}; 35388c2ecf20Sopenharmony_ci 35398c2ecf20Sopenharmony_cistatic int ath10k_pci_probe(struct pci_dev *pdev, 35408c2ecf20Sopenharmony_ci const struct pci_device_id *pci_dev) 35418c2ecf20Sopenharmony_ci{ 35428c2ecf20Sopenharmony_ci int ret = 0; 35438c2ecf20Sopenharmony_ci struct ath10k *ar; 35448c2ecf20Sopenharmony_ci struct ath10k_pci *ar_pci; 35458c2ecf20Sopenharmony_ci enum ath10k_hw_rev hw_rev; 35468c2ecf20Sopenharmony_ci struct ath10k_bus_params bus_params = {}; 35478c2ecf20Sopenharmony_ci bool pci_ps, is_qca988x = false; 35488c2ecf20Sopenharmony_ci int (*pci_soft_reset)(struct ath10k *ar); 35498c2ecf20Sopenharmony_ci int (*pci_hard_reset)(struct ath10k *ar); 35508c2ecf20Sopenharmony_ci u32 (*targ_cpu_to_ce_addr)(struct ath10k *ar, u32 addr); 35518c2ecf20Sopenharmony_ci 35528c2ecf20Sopenharmony_ci switch (pci_dev->device) { 35538c2ecf20Sopenharmony_ci case QCA988X_2_0_DEVICE_ID_UBNT: 35548c2ecf20Sopenharmony_ci case QCA988X_2_0_DEVICE_ID: 35558c2ecf20Sopenharmony_ci hw_rev = ATH10K_HW_QCA988X; 35568c2ecf20Sopenharmony_ci pci_ps = false; 35578c2ecf20Sopenharmony_ci is_qca988x = true; 35588c2ecf20Sopenharmony_ci pci_soft_reset = ath10k_pci_warm_reset; 35598c2ecf20Sopenharmony_ci pci_hard_reset = ath10k_pci_qca988x_chip_reset; 35608c2ecf20Sopenharmony_ci targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr; 35618c2ecf20Sopenharmony_ci break; 35628c2ecf20Sopenharmony_ci case QCA9887_1_0_DEVICE_ID: 35638c2ecf20Sopenharmony_ci hw_rev = ATH10K_HW_QCA9887; 35648c2ecf20Sopenharmony_ci pci_ps = false; 35658c2ecf20Sopenharmony_ci pci_soft_reset = ath10k_pci_warm_reset; 35668c2ecf20Sopenharmony_ci pci_hard_reset = ath10k_pci_qca988x_chip_reset; 35678c2ecf20Sopenharmony_ci targ_cpu_to_ce_addr = ath10k_pci_qca988x_targ_cpu_to_ce_addr; 35688c2ecf20Sopenharmony_ci break; 35698c2ecf20Sopenharmony_ci case QCA6164_2_1_DEVICE_ID: 35708c2ecf20Sopenharmony_ci case QCA6174_2_1_DEVICE_ID: 35718c2ecf20Sopenharmony_ci hw_rev = ATH10K_HW_QCA6174; 35728c2ecf20Sopenharmony_ci pci_ps = true; 35738c2ecf20Sopenharmony_ci pci_soft_reset = ath10k_pci_warm_reset; 35748c2ecf20Sopenharmony_ci pci_hard_reset = ath10k_pci_qca6174_chip_reset; 35758c2ecf20Sopenharmony_ci targ_cpu_to_ce_addr = ath10k_pci_qca6174_targ_cpu_to_ce_addr; 35768c2ecf20Sopenharmony_ci break; 35778c2ecf20Sopenharmony_ci case QCA99X0_2_0_DEVICE_ID: 35788c2ecf20Sopenharmony_ci hw_rev = ATH10K_HW_QCA99X0; 35798c2ecf20Sopenharmony_ci pci_ps = false; 35808c2ecf20Sopenharmony_ci pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset; 35818c2ecf20Sopenharmony_ci pci_hard_reset = ath10k_pci_qca99x0_chip_reset; 35828c2ecf20Sopenharmony_ci targ_cpu_to_ce_addr = ath10k_pci_qca99x0_targ_cpu_to_ce_addr; 35838c2ecf20Sopenharmony_ci break; 35848c2ecf20Sopenharmony_ci case QCA9984_1_0_DEVICE_ID: 35858c2ecf20Sopenharmony_ci hw_rev = ATH10K_HW_QCA9984; 35868c2ecf20Sopenharmony_ci pci_ps = false; 35878c2ecf20Sopenharmony_ci pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset; 35888c2ecf20Sopenharmony_ci pci_hard_reset = ath10k_pci_qca99x0_chip_reset; 35898c2ecf20Sopenharmony_ci targ_cpu_to_ce_addr = ath10k_pci_qca99x0_targ_cpu_to_ce_addr; 35908c2ecf20Sopenharmony_ci break; 35918c2ecf20Sopenharmony_ci case QCA9888_2_0_DEVICE_ID: 35928c2ecf20Sopenharmony_ci hw_rev = ATH10K_HW_QCA9888; 35938c2ecf20Sopenharmony_ci pci_ps = false; 35948c2ecf20Sopenharmony_ci pci_soft_reset = ath10k_pci_qca99x0_soft_chip_reset; 35958c2ecf20Sopenharmony_ci pci_hard_reset = ath10k_pci_qca99x0_chip_reset; 35968c2ecf20Sopenharmony_ci targ_cpu_to_ce_addr = ath10k_pci_qca99x0_targ_cpu_to_ce_addr; 35978c2ecf20Sopenharmony_ci break; 35988c2ecf20Sopenharmony_ci case QCA9377_1_0_DEVICE_ID: 35998c2ecf20Sopenharmony_ci hw_rev = ATH10K_HW_QCA9377; 36008c2ecf20Sopenharmony_ci pci_ps = true; 36018c2ecf20Sopenharmony_ci pci_soft_reset = ath10k_pci_warm_reset; 36028c2ecf20Sopenharmony_ci pci_hard_reset = ath10k_pci_qca6174_chip_reset; 36038c2ecf20Sopenharmony_ci targ_cpu_to_ce_addr = ath10k_pci_qca6174_targ_cpu_to_ce_addr; 36048c2ecf20Sopenharmony_ci break; 36058c2ecf20Sopenharmony_ci default: 36068c2ecf20Sopenharmony_ci WARN_ON(1); 36078c2ecf20Sopenharmony_ci return -ENOTSUPP; 36088c2ecf20Sopenharmony_ci } 36098c2ecf20Sopenharmony_ci 36108c2ecf20Sopenharmony_ci ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI, 36118c2ecf20Sopenharmony_ci hw_rev, &ath10k_pci_hif_ops); 36128c2ecf20Sopenharmony_ci if (!ar) { 36138c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to allocate core\n"); 36148c2ecf20Sopenharmony_ci return -ENOMEM; 36158c2ecf20Sopenharmony_ci } 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_BOOT, "pci probe %04x:%04x %04x:%04x\n", 36188c2ecf20Sopenharmony_ci pdev->vendor, pdev->device, 36198c2ecf20Sopenharmony_ci pdev->subsystem_vendor, pdev->subsystem_device); 36208c2ecf20Sopenharmony_ci 36218c2ecf20Sopenharmony_ci ar_pci = ath10k_pci_priv(ar); 36228c2ecf20Sopenharmony_ci ar_pci->pdev = pdev; 36238c2ecf20Sopenharmony_ci ar_pci->dev = &pdev->dev; 36248c2ecf20Sopenharmony_ci ar_pci->ar = ar; 36258c2ecf20Sopenharmony_ci ar->dev_id = pci_dev->device; 36268c2ecf20Sopenharmony_ci ar_pci->pci_ps = pci_ps; 36278c2ecf20Sopenharmony_ci ar_pci->ce.bus_ops = &ath10k_pci_bus_ops; 36288c2ecf20Sopenharmony_ci ar_pci->pci_soft_reset = pci_soft_reset; 36298c2ecf20Sopenharmony_ci ar_pci->pci_hard_reset = pci_hard_reset; 36308c2ecf20Sopenharmony_ci ar_pci->targ_cpu_to_ce_addr = targ_cpu_to_ce_addr; 36318c2ecf20Sopenharmony_ci ar->ce_priv = &ar_pci->ce; 36328c2ecf20Sopenharmony_ci 36338c2ecf20Sopenharmony_ci ar->id.vendor = pdev->vendor; 36348c2ecf20Sopenharmony_ci ar->id.device = pdev->device; 36358c2ecf20Sopenharmony_ci ar->id.subsystem_vendor = pdev->subsystem_vendor; 36368c2ecf20Sopenharmony_ci ar->id.subsystem_device = pdev->subsystem_device; 36378c2ecf20Sopenharmony_ci 36388c2ecf20Sopenharmony_ci timer_setup(&ar_pci->ps_timer, ath10k_pci_ps_timer, 0); 36398c2ecf20Sopenharmony_ci 36408c2ecf20Sopenharmony_ci ret = ath10k_pci_setup_resource(ar); 36418c2ecf20Sopenharmony_ci if (ret) { 36428c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to setup resource: %d\n", ret); 36438c2ecf20Sopenharmony_ci goto err_core_destroy; 36448c2ecf20Sopenharmony_ci } 36458c2ecf20Sopenharmony_ci 36468c2ecf20Sopenharmony_ci ret = ath10k_pci_claim(ar); 36478c2ecf20Sopenharmony_ci if (ret) { 36488c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to claim device: %d\n", ret); 36498c2ecf20Sopenharmony_ci goto err_free_pipes; 36508c2ecf20Sopenharmony_ci } 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci ret = ath10k_pci_force_wake(ar); 36538c2ecf20Sopenharmony_ci if (ret) { 36548c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to wake up device : %d\n", ret); 36558c2ecf20Sopenharmony_ci goto err_sleep; 36568c2ecf20Sopenharmony_ci } 36578c2ecf20Sopenharmony_ci 36588c2ecf20Sopenharmony_ci ath10k_pci_ce_deinit(ar); 36598c2ecf20Sopenharmony_ci ath10k_pci_irq_disable(ar); 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci ret = ath10k_pci_init_irq(ar); 36628c2ecf20Sopenharmony_ci if (ret) { 36638c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to init irqs: %d\n", ret); 36648c2ecf20Sopenharmony_ci goto err_sleep; 36658c2ecf20Sopenharmony_ci } 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci ath10k_info(ar, "pci irq %s oper_irq_mode %d irq_mode %d reset_mode %d\n", 36688c2ecf20Sopenharmony_ci ath10k_pci_get_irq_method(ar), ar_pci->oper_irq_mode, 36698c2ecf20Sopenharmony_ci ath10k_pci_irq_mode, ath10k_pci_reset_mode); 36708c2ecf20Sopenharmony_ci 36718c2ecf20Sopenharmony_ci ret = ath10k_pci_request_irq(ar); 36728c2ecf20Sopenharmony_ci if (ret) { 36738c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to request irqs: %d\n", ret); 36748c2ecf20Sopenharmony_ci goto err_deinit_irq; 36758c2ecf20Sopenharmony_ci } 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_ci bus_params.dev_type = ATH10K_DEV_TYPE_LL; 36788c2ecf20Sopenharmony_ci bus_params.link_can_suspend = true; 36798c2ecf20Sopenharmony_ci /* Read CHIP_ID before reset to catch QCA9880-AR1A v1 devices that 36808c2ecf20Sopenharmony_ci * fall off the bus during chip_reset. These chips have the same pci 36818c2ecf20Sopenharmony_ci * device id as the QCA9880 BR4A or 2R4E. So that's why the check. 36828c2ecf20Sopenharmony_ci */ 36838c2ecf20Sopenharmony_ci if (is_qca988x) { 36848c2ecf20Sopenharmony_ci bus_params.chip_id = 36858c2ecf20Sopenharmony_ci ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); 36868c2ecf20Sopenharmony_ci if (bus_params.chip_id != 0xffffffff) { 36878c2ecf20Sopenharmony_ci if (!ath10k_pci_chip_is_supported(pdev->device, 36888c2ecf20Sopenharmony_ci bus_params.chip_id)) { 36898c2ecf20Sopenharmony_ci ret = -ENODEV; 36908c2ecf20Sopenharmony_ci goto err_unsupported; 36918c2ecf20Sopenharmony_ci } 36928c2ecf20Sopenharmony_ci } 36938c2ecf20Sopenharmony_ci } 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_ci ret = ath10k_pci_chip_reset(ar); 36968c2ecf20Sopenharmony_ci if (ret) { 36978c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to reset chip: %d\n", ret); 36988c2ecf20Sopenharmony_ci goto err_free_irq; 36998c2ecf20Sopenharmony_ci } 37008c2ecf20Sopenharmony_ci 37018c2ecf20Sopenharmony_ci bus_params.chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS); 37028c2ecf20Sopenharmony_ci if (bus_params.chip_id == 0xffffffff) { 37038c2ecf20Sopenharmony_ci ret = -ENODEV; 37048c2ecf20Sopenharmony_ci goto err_unsupported; 37058c2ecf20Sopenharmony_ci } 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_ci if (!ath10k_pci_chip_is_supported(pdev->device, bus_params.chip_id)) { 37088c2ecf20Sopenharmony_ci ret = -ENODEV; 37098c2ecf20Sopenharmony_ci goto err_unsupported; 37108c2ecf20Sopenharmony_ci } 37118c2ecf20Sopenharmony_ci 37128c2ecf20Sopenharmony_ci ret = ath10k_core_register(ar, &bus_params); 37138c2ecf20Sopenharmony_ci if (ret) { 37148c2ecf20Sopenharmony_ci ath10k_err(ar, "failed to register driver core: %d\n", ret); 37158c2ecf20Sopenharmony_ci goto err_free_irq; 37168c2ecf20Sopenharmony_ci } 37178c2ecf20Sopenharmony_ci 37188c2ecf20Sopenharmony_ci return 0; 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_cierr_unsupported: 37218c2ecf20Sopenharmony_ci ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n", 37228c2ecf20Sopenharmony_ci pdev->device, bus_params.chip_id); 37238c2ecf20Sopenharmony_ci 37248c2ecf20Sopenharmony_cierr_free_irq: 37258c2ecf20Sopenharmony_ci ath10k_pci_free_irq(ar); 37268c2ecf20Sopenharmony_ci 37278c2ecf20Sopenharmony_cierr_deinit_irq: 37288c2ecf20Sopenharmony_ci ath10k_pci_release_resource(ar); 37298c2ecf20Sopenharmony_ci 37308c2ecf20Sopenharmony_cierr_sleep: 37318c2ecf20Sopenharmony_ci ath10k_pci_sleep_sync(ar); 37328c2ecf20Sopenharmony_ci ath10k_pci_release(ar); 37338c2ecf20Sopenharmony_ci 37348c2ecf20Sopenharmony_cierr_free_pipes: 37358c2ecf20Sopenharmony_ci ath10k_pci_free_pipes(ar); 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_cierr_core_destroy: 37388c2ecf20Sopenharmony_ci ath10k_core_destroy(ar); 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci return ret; 37418c2ecf20Sopenharmony_ci} 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_cistatic void ath10k_pci_remove(struct pci_dev *pdev) 37448c2ecf20Sopenharmony_ci{ 37458c2ecf20Sopenharmony_ci struct ath10k *ar = pci_get_drvdata(pdev); 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_ci ath10k_dbg(ar, ATH10K_DBG_PCI, "pci remove\n"); 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_ci if (!ar) 37508c2ecf20Sopenharmony_ci return; 37518c2ecf20Sopenharmony_ci 37528c2ecf20Sopenharmony_ci ath10k_core_unregister(ar); 37538c2ecf20Sopenharmony_ci ath10k_pci_free_irq(ar); 37548c2ecf20Sopenharmony_ci ath10k_pci_deinit_irq(ar); 37558c2ecf20Sopenharmony_ci ath10k_pci_release_resource(ar); 37568c2ecf20Sopenharmony_ci ath10k_pci_sleep_sync(ar); 37578c2ecf20Sopenharmony_ci ath10k_pci_release(ar); 37588c2ecf20Sopenharmony_ci ath10k_core_destroy(ar); 37598c2ecf20Sopenharmony_ci} 37608c2ecf20Sopenharmony_ci 37618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, ath10k_pci_id_table); 37628c2ecf20Sopenharmony_ci 37638c2ecf20Sopenharmony_cistatic __maybe_unused int ath10k_pci_pm_suspend(struct device *dev) 37648c2ecf20Sopenharmony_ci{ 37658c2ecf20Sopenharmony_ci struct ath10k *ar = dev_get_drvdata(dev); 37668c2ecf20Sopenharmony_ci int ret; 37678c2ecf20Sopenharmony_ci 37688c2ecf20Sopenharmony_ci ret = ath10k_pci_suspend(ar); 37698c2ecf20Sopenharmony_ci if (ret) 37708c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to suspend hif: %d\n", ret); 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci return ret; 37738c2ecf20Sopenharmony_ci} 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_cistatic __maybe_unused int ath10k_pci_pm_resume(struct device *dev) 37768c2ecf20Sopenharmony_ci{ 37778c2ecf20Sopenharmony_ci struct ath10k *ar = dev_get_drvdata(dev); 37788c2ecf20Sopenharmony_ci int ret; 37798c2ecf20Sopenharmony_ci 37808c2ecf20Sopenharmony_ci ret = ath10k_pci_resume(ar); 37818c2ecf20Sopenharmony_ci if (ret) 37828c2ecf20Sopenharmony_ci ath10k_warn(ar, "failed to resume hif: %d\n", ret); 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci return ret; 37858c2ecf20Sopenharmony_ci} 37868c2ecf20Sopenharmony_ci 37878c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(ath10k_pci_pm_ops, 37888c2ecf20Sopenharmony_ci ath10k_pci_pm_suspend, 37898c2ecf20Sopenharmony_ci ath10k_pci_pm_resume); 37908c2ecf20Sopenharmony_ci 37918c2ecf20Sopenharmony_cistatic struct pci_driver ath10k_pci_driver = { 37928c2ecf20Sopenharmony_ci .name = "ath10k_pci", 37938c2ecf20Sopenharmony_ci .id_table = ath10k_pci_id_table, 37948c2ecf20Sopenharmony_ci .probe = ath10k_pci_probe, 37958c2ecf20Sopenharmony_ci .remove = ath10k_pci_remove, 37968c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 37978c2ecf20Sopenharmony_ci .driver.pm = &ath10k_pci_pm_ops, 37988c2ecf20Sopenharmony_ci#endif 37998c2ecf20Sopenharmony_ci}; 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_cistatic int __init ath10k_pci_init(void) 38028c2ecf20Sopenharmony_ci{ 38038c2ecf20Sopenharmony_ci int ret1, ret2; 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci ret1 = pci_register_driver(&ath10k_pci_driver); 38068c2ecf20Sopenharmony_ci if (ret1) 38078c2ecf20Sopenharmony_ci printk(KERN_ERR "failed to register ath10k pci driver: %d\n", 38088c2ecf20Sopenharmony_ci ret1); 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci ret2 = ath10k_ahb_init(); 38118c2ecf20Sopenharmony_ci if (ret2) 38128c2ecf20Sopenharmony_ci printk(KERN_ERR "ahb init failed: %d\n", ret2); 38138c2ecf20Sopenharmony_ci 38148c2ecf20Sopenharmony_ci if (ret1 && ret2) 38158c2ecf20Sopenharmony_ci return ret1; 38168c2ecf20Sopenharmony_ci 38178c2ecf20Sopenharmony_ci /* registered to at least one bus */ 38188c2ecf20Sopenharmony_ci return 0; 38198c2ecf20Sopenharmony_ci} 38208c2ecf20Sopenharmony_cimodule_init(ath10k_pci_init); 38218c2ecf20Sopenharmony_ci 38228c2ecf20Sopenharmony_cistatic void __exit ath10k_pci_exit(void) 38238c2ecf20Sopenharmony_ci{ 38248c2ecf20Sopenharmony_ci pci_unregister_driver(&ath10k_pci_driver); 38258c2ecf20Sopenharmony_ci ath10k_ahb_exit(); 38268c2ecf20Sopenharmony_ci} 38278c2ecf20Sopenharmony_ci 38288c2ecf20Sopenharmony_cimodule_exit(ath10k_pci_exit); 38298c2ecf20Sopenharmony_ci 38308c2ecf20Sopenharmony_ciMODULE_AUTHOR("Qualcomm Atheros"); 38318c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver support for Qualcomm Atheros 802.11ac WLAN PCIe/AHB devices"); 38328c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 38338c2ecf20Sopenharmony_ci 38348c2ecf20Sopenharmony_ci/* QCA988x 2.0 firmware files */ 38358c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE); 38368c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE); 38378c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE); 38388c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API5_FILE); 38398c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_BOARD_DATA_FILE); 38408c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); 38418c2ecf20Sopenharmony_ci 38428c2ecf20Sopenharmony_ci/* QCA9887 1.0 firmware files */ 38438c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE); 38448c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" QCA9887_HW_1_0_BOARD_DATA_FILE); 38458c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA9887_HW_1_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); 38468c2ecf20Sopenharmony_ci 38478c2ecf20Sopenharmony_ci/* QCA6174 2.1 firmware files */ 38488c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API4_FILE); 38498c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_FW_API5_FILE); 38508c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" QCA6174_HW_2_1_BOARD_DATA_FILE); 38518c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_2_1_FW_DIR "/" ATH10K_BOARD_API2_FILE); 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci/* QCA6174 3.1 firmware files */ 38548c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API4_FILE); 38558c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API5_FILE); 38568c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_FW_API6_FILE); 38578c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" QCA6174_HW_3_0_BOARD_DATA_FILE); 38588c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA6174_HW_3_0_FW_DIR "/" ATH10K_BOARD_API2_FILE); 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci/* QCA9377 1.0 firmware files */ 38618c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API6_FILE); 38628c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" ATH10K_FW_API5_FILE); 38638c2ecf20Sopenharmony_ciMODULE_FIRMWARE(QCA9377_HW_1_0_FW_DIR "/" QCA9377_HW_1_0_BOARD_DATA_FILE); 3864