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, &reg_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