18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * NXP Wireless LAN device driver: PCIE specific handling
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright 2011-2020 NXP
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * This software file (the "File") is distributed by NXP
78c2ecf20Sopenharmony_ci * under the terms of the GNU General Public License Version 2, June 1991
88c2ecf20Sopenharmony_ci * (the "License").  You may use, redistribute and/or modify this File in
98c2ecf20Sopenharmony_ci * accordance with the terms and conditions of the License, a copy of which
108c2ecf20Sopenharmony_ci * is available by writing to the Free Software Foundation, Inc.,
118c2ecf20Sopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
128c2ecf20Sopenharmony_ci * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
158c2ecf20Sopenharmony_ci * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
168c2ecf20Sopenharmony_ci * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
178c2ecf20Sopenharmony_ci * this warranty disclaimer.
188c2ecf20Sopenharmony_ci */
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <linux/iopoll.h>
218c2ecf20Sopenharmony_ci#include <linux/firmware.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "decl.h"
248c2ecf20Sopenharmony_ci#include "ioctl.h"
258c2ecf20Sopenharmony_ci#include "util.h"
268c2ecf20Sopenharmony_ci#include "fw.h"
278c2ecf20Sopenharmony_ci#include "main.h"
288c2ecf20Sopenharmony_ci#include "wmm.h"
298c2ecf20Sopenharmony_ci#include "11n.h"
308c2ecf20Sopenharmony_ci#include "pcie.h"
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define PCIE_VERSION	"1.0"
338c2ecf20Sopenharmony_ci#define DRV_NAME        "Marvell mwifiex PCIe"
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistatic struct mwifiex_if_ops pcie_ops;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
388c2ecf20Sopenharmony_ci	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
398c2ecf20Sopenharmony_ci	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
408c2ecf20Sopenharmony_ci	.cmd_size = PCIE_SCRATCH_2_REG,
418c2ecf20Sopenharmony_ci	.fw_status = PCIE_SCRATCH_3_REG,
428c2ecf20Sopenharmony_ci	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
438c2ecf20Sopenharmony_ci	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
448c2ecf20Sopenharmony_ci	.tx_rdptr = PCIE_SCRATCH_6_REG,
458c2ecf20Sopenharmony_ci	.tx_wrptr = PCIE_SCRATCH_7_REG,
468c2ecf20Sopenharmony_ci	.rx_rdptr = PCIE_SCRATCH_8_REG,
478c2ecf20Sopenharmony_ci	.rx_wrptr = PCIE_SCRATCH_9_REG,
488c2ecf20Sopenharmony_ci	.evt_rdptr = PCIE_SCRATCH_10_REG,
498c2ecf20Sopenharmony_ci	.evt_wrptr = PCIE_SCRATCH_11_REG,
508c2ecf20Sopenharmony_ci	.drv_rdy = PCIE_SCRATCH_12_REG,
518c2ecf20Sopenharmony_ci	.tx_start_ptr = 0,
528c2ecf20Sopenharmony_ci	.tx_mask = MWIFIEX_TXBD_MASK,
538c2ecf20Sopenharmony_ci	.tx_wrap_mask = 0,
548c2ecf20Sopenharmony_ci	.rx_mask = MWIFIEX_RXBD_MASK,
558c2ecf20Sopenharmony_ci	.rx_wrap_mask = 0,
568c2ecf20Sopenharmony_ci	.tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
578c2ecf20Sopenharmony_ci	.rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
588c2ecf20Sopenharmony_ci	.evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
598c2ecf20Sopenharmony_ci	.ring_flag_sop = 0,
608c2ecf20Sopenharmony_ci	.ring_flag_eop = 0,
618c2ecf20Sopenharmony_ci	.ring_flag_xs_sop = 0,
628c2ecf20Sopenharmony_ci	.ring_flag_xs_eop = 0,
638c2ecf20Sopenharmony_ci	.ring_tx_start_ptr = 0,
648c2ecf20Sopenharmony_ci	.pfu_enabled = 0,
658c2ecf20Sopenharmony_ci	.sleep_cookie = 1,
668c2ecf20Sopenharmony_ci	.msix_support = 0,
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
708c2ecf20Sopenharmony_ci	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
718c2ecf20Sopenharmony_ci	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
728c2ecf20Sopenharmony_ci	.cmd_size = PCIE_SCRATCH_2_REG,
738c2ecf20Sopenharmony_ci	.fw_status = PCIE_SCRATCH_3_REG,
748c2ecf20Sopenharmony_ci	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
758c2ecf20Sopenharmony_ci	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
768c2ecf20Sopenharmony_ci	.tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1,
778c2ecf20Sopenharmony_ci	.tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1,
788c2ecf20Sopenharmony_ci	.rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1,
798c2ecf20Sopenharmony_ci	.rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1,
808c2ecf20Sopenharmony_ci	.evt_rdptr = PCIE_SCRATCH_10_REG,
818c2ecf20Sopenharmony_ci	.evt_wrptr = PCIE_SCRATCH_11_REG,
828c2ecf20Sopenharmony_ci	.drv_rdy = PCIE_SCRATCH_12_REG,
838c2ecf20Sopenharmony_ci	.tx_start_ptr = 16,
848c2ecf20Sopenharmony_ci	.tx_mask = 0x03FF0000,
858c2ecf20Sopenharmony_ci	.tx_wrap_mask = 0x07FF0000,
868c2ecf20Sopenharmony_ci	.rx_mask = 0x000003FF,
878c2ecf20Sopenharmony_ci	.rx_wrap_mask = 0x000007FF,
888c2ecf20Sopenharmony_ci	.tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND,
898c2ecf20Sopenharmony_ci	.rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND,
908c2ecf20Sopenharmony_ci	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND,
918c2ecf20Sopenharmony_ci	.ring_flag_sop = MWIFIEX_BD_FLAG_SOP,
928c2ecf20Sopenharmony_ci	.ring_flag_eop = MWIFIEX_BD_FLAG_EOP,
938c2ecf20Sopenharmony_ci	.ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP,
948c2ecf20Sopenharmony_ci	.ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP,
958c2ecf20Sopenharmony_ci	.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
968c2ecf20Sopenharmony_ci	.pfu_enabled = 1,
978c2ecf20Sopenharmony_ci	.sleep_cookie = 0,
988c2ecf20Sopenharmony_ci	.fw_dump_ctrl = PCIE_SCRATCH_13_REG,
998c2ecf20Sopenharmony_ci	.fw_dump_start = PCIE_SCRATCH_14_REG,
1008c2ecf20Sopenharmony_ci	.fw_dump_end = 0xcff,
1018c2ecf20Sopenharmony_ci	.fw_dump_host_ready = 0xee,
1028c2ecf20Sopenharmony_ci	.fw_dump_read_done = 0xfe,
1038c2ecf20Sopenharmony_ci	.msix_support = 0,
1048c2ecf20Sopenharmony_ci};
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
1078c2ecf20Sopenharmony_ci	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
1088c2ecf20Sopenharmony_ci	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
1098c2ecf20Sopenharmony_ci	.cmd_size = PCIE_SCRATCH_2_REG,
1108c2ecf20Sopenharmony_ci	.fw_status = PCIE_SCRATCH_3_REG,
1118c2ecf20Sopenharmony_ci	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
1128c2ecf20Sopenharmony_ci	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
1138c2ecf20Sopenharmony_ci	.tx_rdptr = 0xC1A4,
1148c2ecf20Sopenharmony_ci	.tx_wrptr = 0xC174,
1158c2ecf20Sopenharmony_ci	.rx_rdptr = 0xC174,
1168c2ecf20Sopenharmony_ci	.rx_wrptr = 0xC1A4,
1178c2ecf20Sopenharmony_ci	.evt_rdptr = PCIE_SCRATCH_10_REG,
1188c2ecf20Sopenharmony_ci	.evt_wrptr = PCIE_SCRATCH_11_REG,
1198c2ecf20Sopenharmony_ci	.drv_rdy = PCIE_SCRATCH_12_REG,
1208c2ecf20Sopenharmony_ci	.tx_start_ptr = 16,
1218c2ecf20Sopenharmony_ci	.tx_mask = 0x0FFF0000,
1228c2ecf20Sopenharmony_ci	.tx_wrap_mask = 0x1FFF0000,
1238c2ecf20Sopenharmony_ci	.rx_mask = 0x00000FFF,
1248c2ecf20Sopenharmony_ci	.rx_wrap_mask = 0x00001FFF,
1258c2ecf20Sopenharmony_ci	.tx_rollover_ind = BIT(28),
1268c2ecf20Sopenharmony_ci	.rx_rollover_ind = BIT(12),
1278c2ecf20Sopenharmony_ci	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND,
1288c2ecf20Sopenharmony_ci	.ring_flag_sop = MWIFIEX_BD_FLAG_SOP,
1298c2ecf20Sopenharmony_ci	.ring_flag_eop = MWIFIEX_BD_FLAG_EOP,
1308c2ecf20Sopenharmony_ci	.ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP,
1318c2ecf20Sopenharmony_ci	.ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP,
1328c2ecf20Sopenharmony_ci	.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
1338c2ecf20Sopenharmony_ci	.pfu_enabled = 1,
1348c2ecf20Sopenharmony_ci	.sleep_cookie = 0,
1358c2ecf20Sopenharmony_ci	.fw_dump_ctrl = PCIE_SCRATCH_13_REG,
1368c2ecf20Sopenharmony_ci	.fw_dump_start = PCIE_SCRATCH_14_REG,
1378c2ecf20Sopenharmony_ci	.fw_dump_end = 0xcff,
1388c2ecf20Sopenharmony_ci	.fw_dump_host_ready = 0xcc,
1398c2ecf20Sopenharmony_ci	.fw_dump_read_done = 0xdd,
1408c2ecf20Sopenharmony_ci	.msix_support = 0,
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic struct memory_type_mapping mem_type_mapping_tbl_w8897[] = {
1448c2ecf20Sopenharmony_ci	{"ITCM", NULL, 0, 0xF0},
1458c2ecf20Sopenharmony_ci	{"DTCM", NULL, 0, 0xF1},
1468c2ecf20Sopenharmony_ci	{"SQRAM", NULL, 0, 0xF2},
1478c2ecf20Sopenharmony_ci	{"IRAM", NULL, 0, 0xF3},
1488c2ecf20Sopenharmony_ci	{"APU", NULL, 0, 0xF4},
1498c2ecf20Sopenharmony_ci	{"CIU", NULL, 0, 0xF5},
1508c2ecf20Sopenharmony_ci	{"ICU", NULL, 0, 0xF6},
1518c2ecf20Sopenharmony_ci	{"MAC", NULL, 0, 0xF7},
1528c2ecf20Sopenharmony_ci};
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_cistatic struct memory_type_mapping mem_type_mapping_tbl_w8997[] = {
1558c2ecf20Sopenharmony_ci	{"DUMP", NULL, 0, 0xDD},
1568c2ecf20Sopenharmony_ci};
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic const struct mwifiex_pcie_device mwifiex_pcie8766 = {
1598c2ecf20Sopenharmony_ci	.reg            = &mwifiex_reg_8766,
1608c2ecf20Sopenharmony_ci	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
1618c2ecf20Sopenharmony_ci	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
1628c2ecf20Sopenharmony_ci	.can_dump_fw = false,
1638c2ecf20Sopenharmony_ci	.can_ext_scan = true,
1648c2ecf20Sopenharmony_ci};
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic const struct mwifiex_pcie_device mwifiex_pcie8897 = {
1678c2ecf20Sopenharmony_ci	.reg            = &mwifiex_reg_8897,
1688c2ecf20Sopenharmony_ci	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
1698c2ecf20Sopenharmony_ci	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
1708c2ecf20Sopenharmony_ci	.can_dump_fw = true,
1718c2ecf20Sopenharmony_ci	.mem_type_mapping_tbl = mem_type_mapping_tbl_w8897,
1728c2ecf20Sopenharmony_ci	.num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8897),
1738c2ecf20Sopenharmony_ci	.can_ext_scan = true,
1748c2ecf20Sopenharmony_ci};
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic const struct mwifiex_pcie_device mwifiex_pcie8997 = {
1778c2ecf20Sopenharmony_ci	.reg            = &mwifiex_reg_8997,
1788c2ecf20Sopenharmony_ci	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
1798c2ecf20Sopenharmony_ci	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
1808c2ecf20Sopenharmony_ci	.can_dump_fw = true,
1818c2ecf20Sopenharmony_ci	.mem_type_mapping_tbl = mem_type_mapping_tbl_w8997,
1828c2ecf20Sopenharmony_ci	.num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8997),
1838c2ecf20Sopenharmony_ci	.can_ext_scan = true,
1848c2ecf20Sopenharmony_ci};
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic const struct of_device_id mwifiex_pcie_of_match_table[] __maybe_unused = {
1878c2ecf20Sopenharmony_ci	{ .compatible = "pci11ab,2b42" },
1888c2ecf20Sopenharmony_ci	{ .compatible = "pci1b4b,2b42" },
1898c2ecf20Sopenharmony_ci	{ }
1908c2ecf20Sopenharmony_ci};
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic int mwifiex_pcie_probe_of(struct device *dev)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	if (!of_match_node(mwifiex_pcie_of_match_table, dev->of_node)) {
1958c2ecf20Sopenharmony_ci		dev_err(dev, "required compatible string missing\n");
1968c2ecf20Sopenharmony_ci		return -EINVAL;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_cistatic void mwifiex_pcie_work(struct work_struct *work);
2038c2ecf20Sopenharmony_cistatic int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter);
2048c2ecf20Sopenharmony_cistatic int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int
2078c2ecf20Sopenharmony_cimwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
2088c2ecf20Sopenharmony_ci		       size_t size, int flags)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
2118c2ecf20Sopenharmony_ci	struct mwifiex_dma_mapping mapping;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	mapping.addr = dma_map_single(&card->dev->dev, skb->data, size, flags);
2148c2ecf20Sopenharmony_ci	if (dma_mapping_error(&card->dev->dev, mapping.addr)) {
2158c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "failed to map pci memory!\n");
2168c2ecf20Sopenharmony_ci		return -1;
2178c2ecf20Sopenharmony_ci	}
2188c2ecf20Sopenharmony_ci	mapping.len = size;
2198c2ecf20Sopenharmony_ci	mwifiex_store_mapping(skb, &mapping);
2208c2ecf20Sopenharmony_ci	return 0;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic void mwifiex_unmap_pci_memory(struct mwifiex_adapter *adapter,
2248c2ecf20Sopenharmony_ci				     struct sk_buff *skb, int flags)
2258c2ecf20Sopenharmony_ci{
2268c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
2278c2ecf20Sopenharmony_ci	struct mwifiex_dma_mapping mapping;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	mwifiex_get_mapping(skb, &mapping);
2308c2ecf20Sopenharmony_ci	dma_unmap_single(&card->dev->dev, mapping.addr, mapping.len, flags);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/*
2348c2ecf20Sopenharmony_ci * This function writes data into PCIE card register.
2358c2ecf20Sopenharmony_ci */
2368c2ecf20Sopenharmony_cistatic int mwifiex_write_reg(struct mwifiex_adapter *adapter, int reg, u32 data)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	iowrite32(data, card->pci_mmap1 + reg);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	return 0;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci/* This function reads data from PCIE card register.
2468c2ecf20Sopenharmony_ci */
2478c2ecf20Sopenharmony_cistatic int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	*data = ioread32(card->pci_mmap1 + reg);
2528c2ecf20Sopenharmony_ci	if (*data == 0xffffffff)
2538c2ecf20Sopenharmony_ci		return 0xffffffff;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	return 0;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_ci/* This function reads u8 data from PCIE card register. */
2598c2ecf20Sopenharmony_cistatic int mwifiex_read_reg_byte(struct mwifiex_adapter *adapter,
2608c2ecf20Sopenharmony_ci				 int reg, u8 *data)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	*data = ioread8(card->pci_mmap1 + reg);
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	return 0;
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci/*
2708c2ecf20Sopenharmony_ci * This function reads sleep cookie and checks if FW is ready
2718c2ecf20Sopenharmony_ci */
2728c2ecf20Sopenharmony_cistatic bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
2738c2ecf20Sopenharmony_ci{
2748c2ecf20Sopenharmony_ci	u32 cookie_value;
2758c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
2768c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (!reg->sleep_cookie)
2798c2ecf20Sopenharmony_ci		return true;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	if (card->sleep_cookie_vbase) {
2828c2ecf20Sopenharmony_ci		cookie_value = get_unaligned_le32(card->sleep_cookie_vbase);
2838c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
2848c2ecf20Sopenharmony_ci			    "info: ACCESS_HW: sleep cookie=0x%x\n",
2858c2ecf20Sopenharmony_ci			    cookie_value);
2868c2ecf20Sopenharmony_ci		if (cookie_value == FW_AWAKE_COOKIE)
2878c2ecf20Sopenharmony_ci			return true;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	return false;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
2948c2ecf20Sopenharmony_ci/*
2958c2ecf20Sopenharmony_ci * Kernel needs to suspend all functions separately. Therefore all
2968c2ecf20Sopenharmony_ci * registered functions must have drivers with suspend and resume
2978c2ecf20Sopenharmony_ci * methods. Failing that the kernel simply removes the whole card.
2988c2ecf20Sopenharmony_ci *
2998c2ecf20Sopenharmony_ci * If already not suspended, this function allocates and sends a host
3008c2ecf20Sopenharmony_ci * sleep activate request to the firmware and turns off the traffic.
3018c2ecf20Sopenharmony_ci */
3028c2ecf20Sopenharmony_cistatic int mwifiex_pcie_suspend(struct device *dev)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter;
3058c2ecf20Sopenharmony_ci	struct pcie_service_card *card = dev_get_drvdata(dev);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	/* Might still be loading firmware */
3098c2ecf20Sopenharmony_ci	wait_for_completion(&card->fw_done);
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	adapter = card->adapter;
3128c2ecf20Sopenharmony_ci	if (!adapter) {
3138c2ecf20Sopenharmony_ci		dev_err(dev, "adapter is not valid\n");
3148c2ecf20Sopenharmony_ci		return 0;
3158c2ecf20Sopenharmony_ci	}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	mwifiex_enable_wake(adapter);
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	/* Enable the Host Sleep */
3208c2ecf20Sopenharmony_ci	if (!mwifiex_enable_hs(adapter)) {
3218c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
3228c2ecf20Sopenharmony_ci			    "cmd: failed to suspend\n");
3238c2ecf20Sopenharmony_ci		clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);
3248c2ecf20Sopenharmony_ci		mwifiex_disable_wake(adapter);
3258c2ecf20Sopenharmony_ci		return -EFAULT;
3268c2ecf20Sopenharmony_ci	}
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	flush_workqueue(adapter->workqueue);
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	/* Indicate device suspended */
3318c2ecf20Sopenharmony_ci	set_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags);
3328c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci	return 0;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci/*
3388c2ecf20Sopenharmony_ci * Kernel needs to suspend all functions separately. Therefore all
3398c2ecf20Sopenharmony_ci * registered functions must have drivers with suspend and resume
3408c2ecf20Sopenharmony_ci * methods. Failing that the kernel simply removes the whole card.
3418c2ecf20Sopenharmony_ci *
3428c2ecf20Sopenharmony_ci * If already not resumed, this function turns on the traffic and
3438c2ecf20Sopenharmony_ci * sends a host sleep cancel request to the firmware.
3448c2ecf20Sopenharmony_ci */
3458c2ecf20Sopenharmony_cistatic int mwifiex_pcie_resume(struct device *dev)
3468c2ecf20Sopenharmony_ci{
3478c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter;
3488c2ecf20Sopenharmony_ci	struct pcie_service_card *card = dev_get_drvdata(dev);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	if (!card->adapter) {
3528c2ecf20Sopenharmony_ci		dev_err(dev, "adapter structure is not valid\n");
3538c2ecf20Sopenharmony_ci		return 0;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	adapter = card->adapter;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (!test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) {
3598c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, WARN,
3608c2ecf20Sopenharmony_ci			    "Device already resumed\n");
3618c2ecf20Sopenharmony_ci		return 0;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags);
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
3678c2ecf20Sopenharmony_ci			  MWIFIEX_ASYNC_CMD);
3688c2ecf20Sopenharmony_ci	mwifiex_disable_wake(adapter);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return 0;
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci#endif
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci/*
3758c2ecf20Sopenharmony_ci * This function probes an mwifiex device and registers it. It allocates
3768c2ecf20Sopenharmony_ci * the card structure, enables PCIE function number and initiates the
3778c2ecf20Sopenharmony_ci * device registration and initialization procedure by adding a logical
3788c2ecf20Sopenharmony_ci * interface.
3798c2ecf20Sopenharmony_ci */
3808c2ecf20Sopenharmony_cistatic int mwifiex_pcie_probe(struct pci_dev *pdev,
3818c2ecf20Sopenharmony_ci					const struct pci_device_id *ent)
3828c2ecf20Sopenharmony_ci{
3838c2ecf20Sopenharmony_ci	struct pcie_service_card *card;
3848c2ecf20Sopenharmony_ci	int ret;
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
3878c2ecf20Sopenharmony_ci		 pdev->vendor, pdev->device, pdev->revision);
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
3908c2ecf20Sopenharmony_ci	if (!card)
3918c2ecf20Sopenharmony_ci		return -ENOMEM;
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	init_completion(&card->fw_done);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	card->dev = pdev;
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (ent->driver_data) {
3988c2ecf20Sopenharmony_ci		struct mwifiex_pcie_device *data = (void *)ent->driver_data;
3998c2ecf20Sopenharmony_ci		card->pcie.reg = data->reg;
4008c2ecf20Sopenharmony_ci		card->pcie.blksz_fw_dl = data->blksz_fw_dl;
4018c2ecf20Sopenharmony_ci		card->pcie.tx_buf_size = data->tx_buf_size;
4028c2ecf20Sopenharmony_ci		card->pcie.can_dump_fw = data->can_dump_fw;
4038c2ecf20Sopenharmony_ci		card->pcie.mem_type_mapping_tbl = data->mem_type_mapping_tbl;
4048c2ecf20Sopenharmony_ci		card->pcie.num_mem_types = data->num_mem_types;
4058c2ecf20Sopenharmony_ci		card->pcie.can_ext_scan = data->can_ext_scan;
4068c2ecf20Sopenharmony_ci		INIT_WORK(&card->work, mwifiex_pcie_work);
4078c2ecf20Sopenharmony_ci	}
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	/* device tree node parsing and platform specific configuration*/
4108c2ecf20Sopenharmony_ci	if (pdev->dev.of_node) {
4118c2ecf20Sopenharmony_ci		ret = mwifiex_pcie_probe_of(&pdev->dev);
4128c2ecf20Sopenharmony_ci		if (ret)
4138c2ecf20Sopenharmony_ci			return ret;
4148c2ecf20Sopenharmony_ci	}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	if (mwifiex_add_card(card, &card->fw_done, &pcie_ops,
4178c2ecf20Sopenharmony_ci			     MWIFIEX_PCIE, &pdev->dev)) {
4188c2ecf20Sopenharmony_ci		pr_err("%s failed\n", __func__);
4198c2ecf20Sopenharmony_ci		return -1;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	return 0;
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci/*
4268c2ecf20Sopenharmony_ci * This function removes the interface and frees up the card structure.
4278c2ecf20Sopenharmony_ci */
4288c2ecf20Sopenharmony_cistatic void mwifiex_pcie_remove(struct pci_dev *pdev)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	struct pcie_service_card *card;
4318c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter;
4328c2ecf20Sopenharmony_ci	struct mwifiex_private *priv;
4338c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg;
4348c2ecf20Sopenharmony_ci	u32 fw_status;
4358c2ecf20Sopenharmony_ci	int ret;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	card = pci_get_drvdata(pdev);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	wait_for_completion(&card->fw_done);
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	adapter = card->adapter;
4428c2ecf20Sopenharmony_ci	if (!adapter || !adapter->priv_num)
4438c2ecf20Sopenharmony_ci		return;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	reg = card->pcie.reg;
4468c2ecf20Sopenharmony_ci	if (reg)
4478c2ecf20Sopenharmony_ci		ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
4488c2ecf20Sopenharmony_ci	else
4498c2ecf20Sopenharmony_ci		fw_status = -1;
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (fw_status == FIRMWARE_READY_PCIE && !adapter->mfg_mode) {
4528c2ecf20Sopenharmony_ci		mwifiex_deauthenticate_all(adapter);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci		mwifiex_disable_auto_ds(priv);
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_ci		mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN);
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	mwifiex_remove_card(adapter);
4628c2ecf20Sopenharmony_ci}
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic void mwifiex_pcie_shutdown(struct pci_dev *pdev)
4658c2ecf20Sopenharmony_ci{
4668c2ecf20Sopenharmony_ci	mwifiex_pcie_remove(pdev);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	return;
4698c2ecf20Sopenharmony_ci}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_cistatic void mwifiex_pcie_coredump(struct device *dev)
4728c2ecf20Sopenharmony_ci{
4738c2ecf20Sopenharmony_ci	struct pci_dev *pdev;
4748c2ecf20Sopenharmony_ci	struct pcie_service_card *card;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	pdev = container_of(dev, struct pci_dev, dev);
4778c2ecf20Sopenharmony_ci	card = pci_get_drvdata(pdev);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
4808c2ecf20Sopenharmony_ci			      &card->work_flags))
4818c2ecf20Sopenharmony_ci		schedule_work(&card->work);
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_cistatic const struct pci_device_id mwifiex_ids[] = {
4858c2ecf20Sopenharmony_ci	{
4868c2ecf20Sopenharmony_ci		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
4878c2ecf20Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
4888c2ecf20Sopenharmony_ci		.driver_data = (unsigned long)&mwifiex_pcie8766,
4898c2ecf20Sopenharmony_ci	},
4908c2ecf20Sopenharmony_ci	{
4918c2ecf20Sopenharmony_ci		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897,
4928c2ecf20Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
4938c2ecf20Sopenharmony_ci		.driver_data = (unsigned long)&mwifiex_pcie8897,
4948c2ecf20Sopenharmony_ci	},
4958c2ecf20Sopenharmony_ci	{
4968c2ecf20Sopenharmony_ci		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8997,
4978c2ecf20Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
4988c2ecf20Sopenharmony_ci		.driver_data = (unsigned long)&mwifiex_pcie8997,
4998c2ecf20Sopenharmony_ci	},
5008c2ecf20Sopenharmony_ci	{
5018c2ecf20Sopenharmony_ci		PCIE_VENDOR_ID_V2_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8997,
5028c2ecf20Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
5038c2ecf20Sopenharmony_ci		.driver_data = (unsigned long)&mwifiex_pcie8997,
5048c2ecf20Sopenharmony_ci	},
5058c2ecf20Sopenharmony_ci	{},
5068c2ecf20Sopenharmony_ci};
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mwifiex_ids);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/*
5118c2ecf20Sopenharmony_ci * Cleanup all software without cleaning anything related to PCIe and HW.
5128c2ecf20Sopenharmony_ci */
5138c2ecf20Sopenharmony_cistatic void mwifiex_pcie_reset_prepare(struct pci_dev *pdev)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct pcie_service_card *card = pci_get_drvdata(pdev);
5168c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = card->adapter;
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (!adapter) {
5198c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "%s: adapter structure is not valid\n",
5208c2ecf20Sopenharmony_ci			__func__);
5218c2ecf20Sopenharmony_ci		return;
5228c2ecf20Sopenharmony_ci	}
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
5258c2ecf20Sopenharmony_ci		    "%s: vendor=0x%4.04x device=0x%4.04x rev=%d Pre-FLR\n",
5268c2ecf20Sopenharmony_ci		    __func__, pdev->vendor, pdev->device, pdev->revision);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	mwifiex_shutdown_sw(adapter);
5298c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
5308c2ecf20Sopenharmony_ci	clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
5318c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	card->pci_reset_ongoing = true;
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci/*
5378c2ecf20Sopenharmony_ci * Kernel stores and restores PCIe function context before and after performing
5388c2ecf20Sopenharmony_ci * FLR respectively. Reconfigure the software and firmware including firmware
5398c2ecf20Sopenharmony_ci * redownload.
5408c2ecf20Sopenharmony_ci */
5418c2ecf20Sopenharmony_cistatic void mwifiex_pcie_reset_done(struct pci_dev *pdev)
5428c2ecf20Sopenharmony_ci{
5438c2ecf20Sopenharmony_ci	struct pcie_service_card *card = pci_get_drvdata(pdev);
5448c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter = card->adapter;
5458c2ecf20Sopenharmony_ci	int ret;
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	if (!adapter) {
5488c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "%s: adapter structure is not valid\n",
5498c2ecf20Sopenharmony_ci			__func__);
5508c2ecf20Sopenharmony_ci		return;
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
5548c2ecf20Sopenharmony_ci		    "%s: vendor=0x%4.04x device=0x%4.04x rev=%d Post-FLR\n",
5558c2ecf20Sopenharmony_ci		    __func__, pdev->vendor, pdev->device, pdev->revision);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	ret = mwifiex_reinit_sw(adapter);
5588c2ecf20Sopenharmony_ci	if (ret)
5598c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "reinit failed: %d\n", ret);
5608c2ecf20Sopenharmony_ci	else
5618c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
5628c2ecf20Sopenharmony_ci
5638c2ecf20Sopenharmony_ci	card->pci_reset_ongoing = false;
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_cistatic const struct pci_error_handlers mwifiex_pcie_err_handler = {
5678c2ecf20Sopenharmony_ci	.reset_prepare		= mwifiex_pcie_reset_prepare,
5688c2ecf20Sopenharmony_ci	.reset_done		= mwifiex_pcie_reset_done,
5698c2ecf20Sopenharmony_ci};
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
5728c2ecf20Sopenharmony_ci/* Power Management Hooks */
5738c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mwifiex_pcie_pm_ops, mwifiex_pcie_suspend,
5748c2ecf20Sopenharmony_ci				mwifiex_pcie_resume);
5758c2ecf20Sopenharmony_ci#endif
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_ci/* PCI Device Driver */
5788c2ecf20Sopenharmony_cistatic struct pci_driver __refdata mwifiex_pcie = {
5798c2ecf20Sopenharmony_ci	.name     = "mwifiex_pcie",
5808c2ecf20Sopenharmony_ci	.id_table = mwifiex_ids,
5818c2ecf20Sopenharmony_ci	.probe    = mwifiex_pcie_probe,
5828c2ecf20Sopenharmony_ci	.remove   = mwifiex_pcie_remove,
5838c2ecf20Sopenharmony_ci	.driver   = {
5848c2ecf20Sopenharmony_ci		.coredump = mwifiex_pcie_coredump,
5858c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
5868c2ecf20Sopenharmony_ci		.pm = &mwifiex_pcie_pm_ops,
5878c2ecf20Sopenharmony_ci#endif
5888c2ecf20Sopenharmony_ci	},
5898c2ecf20Sopenharmony_ci	.shutdown = mwifiex_pcie_shutdown,
5908c2ecf20Sopenharmony_ci	.err_handler = &mwifiex_pcie_err_handler,
5918c2ecf20Sopenharmony_ci};
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ci/*
5948c2ecf20Sopenharmony_ci * This function adds delay loop to ensure FW is awake before proceeding.
5958c2ecf20Sopenharmony_ci */
5968c2ecf20Sopenharmony_cistatic void mwifiex_pcie_dev_wakeup_delay(struct mwifiex_adapter *adapter)
5978c2ecf20Sopenharmony_ci{
5988c2ecf20Sopenharmony_ci	int i = 0;
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	while (mwifiex_pcie_ok_to_access_hw(adapter)) {
6018c2ecf20Sopenharmony_ci		i++;
6028c2ecf20Sopenharmony_ci		usleep_range(10, 20);
6038c2ecf20Sopenharmony_ci		/* 50ms max wait */
6048c2ecf20Sopenharmony_ci		if (i == 5000)
6058c2ecf20Sopenharmony_ci			break;
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	return;
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter,
6128c2ecf20Sopenharmony_ci					   u32 max_delay_loop_cnt)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
6158c2ecf20Sopenharmony_ci	u8 *buffer;
6168c2ecf20Sopenharmony_ci	u32 sleep_cookie, count;
6178c2ecf20Sopenharmony_ci	struct sk_buff *cmdrsp = card->cmdrsp_buf;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	for (count = 0; count < max_delay_loop_cnt; count++) {
6208c2ecf20Sopenharmony_ci		dma_sync_single_for_cpu(&card->dev->dev,
6218c2ecf20Sopenharmony_ci					MWIFIEX_SKB_DMA_ADDR(cmdrsp),
6228c2ecf20Sopenharmony_ci					sizeof(sleep_cookie), DMA_FROM_DEVICE);
6238c2ecf20Sopenharmony_ci		buffer = cmdrsp->data;
6248c2ecf20Sopenharmony_ci		sleep_cookie = get_unaligned_le32(buffer);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci		if (sleep_cookie == MWIFIEX_DEF_SLEEP_COOKIE) {
6278c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INFO,
6288c2ecf20Sopenharmony_ci				    "sleep cookie found at count %d\n", count);
6298c2ecf20Sopenharmony_ci			break;
6308c2ecf20Sopenharmony_ci		}
6318c2ecf20Sopenharmony_ci		dma_sync_single_for_device(&card->dev->dev,
6328c2ecf20Sopenharmony_ci					   MWIFIEX_SKB_DMA_ADDR(cmdrsp),
6338c2ecf20Sopenharmony_ci					   sizeof(sleep_cookie),
6348c2ecf20Sopenharmony_ci					   DMA_FROM_DEVICE);
6358c2ecf20Sopenharmony_ci		usleep_range(20, 30);
6368c2ecf20Sopenharmony_ci	}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	if (count >= max_delay_loop_cnt)
6398c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
6408c2ecf20Sopenharmony_ci			    "max count reached while accessing sleep cookie\n");
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci#define N_WAKEUP_TRIES_SHORT_INTERVAL 15
6448c2ecf20Sopenharmony_ci#define N_WAKEUP_TRIES_LONG_INTERVAL 35
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci/* This function wakes up the card by reading fw_status register. */
6478c2ecf20Sopenharmony_cistatic int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
6488c2ecf20Sopenharmony_ci{
6498c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
6508c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
6518c2ecf20Sopenharmony_ci	int retval;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
6548c2ecf20Sopenharmony_ci		    "event: Wakeup device...\n");
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	if (reg->sleep_cookie)
6578c2ecf20Sopenharmony_ci		mwifiex_pcie_dev_wakeup_delay(adapter);
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci	/* The 88W8897 PCIe+USB firmware (latest version 15.68.19.p21) sometimes
6608c2ecf20Sopenharmony_ci	 * appears to ignore or miss our wakeup request, so we continue trying
6618c2ecf20Sopenharmony_ci	 * until we receive an interrupt from the card.
6628c2ecf20Sopenharmony_ci	 */
6638c2ecf20Sopenharmony_ci	if (read_poll_timeout(mwifiex_write_reg, retval,
6648c2ecf20Sopenharmony_ci			      READ_ONCE(adapter->int_status) != 0,
6658c2ecf20Sopenharmony_ci			      500, 500 * N_WAKEUP_TRIES_SHORT_INTERVAL,
6668c2ecf20Sopenharmony_ci			      false,
6678c2ecf20Sopenharmony_ci			      adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {
6688c2ecf20Sopenharmony_ci		if (read_poll_timeout(mwifiex_write_reg, retval,
6698c2ecf20Sopenharmony_ci				      READ_ONCE(adapter->int_status) != 0,
6708c2ecf20Sopenharmony_ci				      10000, 10000 * N_WAKEUP_TRIES_LONG_INTERVAL,
6718c2ecf20Sopenharmony_ci				      false,
6728c2ecf20Sopenharmony_ci				      adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {
6738c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
6748c2ecf20Sopenharmony_ci				    "Firmware didn't wake up\n");
6758c2ecf20Sopenharmony_ci			return -EIO;
6768c2ecf20Sopenharmony_ci		}
6778c2ecf20Sopenharmony_ci	}
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	if (reg->sleep_cookie) {
6808c2ecf20Sopenharmony_ci		mwifiex_pcie_dev_wakeup_delay(adapter);
6818c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
6828c2ecf20Sopenharmony_ci			    "PCIE wakeup: Setting PS_STATE_AWAKE\n");
6838c2ecf20Sopenharmony_ci		adapter->ps_state = PS_STATE_AWAKE;
6848c2ecf20Sopenharmony_ci	}
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	return 0;
6878c2ecf20Sopenharmony_ci}
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci/*
6908c2ecf20Sopenharmony_ci * This function is called after the card has woken up.
6918c2ecf20Sopenharmony_ci *
6928c2ecf20Sopenharmony_ci * The card configuration register is reset.
6938c2ecf20Sopenharmony_ci */
6948c2ecf20Sopenharmony_cistatic int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
6958c2ecf20Sopenharmony_ci{
6968c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, CMD,
6978c2ecf20Sopenharmony_ci		    "cmd: Wakeup device completed\n");
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	return 0;
7008c2ecf20Sopenharmony_ci}
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci/*
7038c2ecf20Sopenharmony_ci * This function disables the host interrupt.
7048c2ecf20Sopenharmony_ci *
7058c2ecf20Sopenharmony_ci * The host interrupt mask is read, the disable bit is reset and
7068c2ecf20Sopenharmony_ci * written back to the card host interrupt mask register.
7078c2ecf20Sopenharmony_ci */
7088c2ecf20Sopenharmony_cistatic int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	if (mwifiex_pcie_ok_to_access_hw(adapter)) {
7118c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
7128c2ecf20Sopenharmony_ci				      0x00000000)) {
7138c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
7148c2ecf20Sopenharmony_ci				    "Disable host interrupt failed\n");
7158c2ecf20Sopenharmony_ci			return -1;
7168c2ecf20Sopenharmony_ci		}
7178c2ecf20Sopenharmony_ci	}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	atomic_set(&adapter->tx_hw_pending, 0);
7208c2ecf20Sopenharmony_ci	return 0;
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_cistatic void mwifiex_pcie_disable_host_int_noerr(struct mwifiex_adapter *adapter)
7248c2ecf20Sopenharmony_ci{
7258c2ecf20Sopenharmony_ci	WARN_ON(mwifiex_pcie_disable_host_int(adapter));
7268c2ecf20Sopenharmony_ci}
7278c2ecf20Sopenharmony_ci
7288c2ecf20Sopenharmony_ci/*
7298c2ecf20Sopenharmony_ci * This function enables the host interrupt.
7308c2ecf20Sopenharmony_ci *
7318c2ecf20Sopenharmony_ci * The host interrupt enable mask is written to the card
7328c2ecf20Sopenharmony_ci * host interrupt mask register.
7338c2ecf20Sopenharmony_ci */
7348c2ecf20Sopenharmony_cistatic int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
7358c2ecf20Sopenharmony_ci{
7368c2ecf20Sopenharmony_ci	if (mwifiex_pcie_ok_to_access_hw(adapter)) {
7378c2ecf20Sopenharmony_ci		/* Simply write the mask to the register */
7388c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
7398c2ecf20Sopenharmony_ci				      HOST_INTR_MASK)) {
7408c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
7418c2ecf20Sopenharmony_ci				    "Enable host interrupt failed\n");
7428c2ecf20Sopenharmony_ci			return -1;
7438c2ecf20Sopenharmony_ci		}
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	return 0;
7478c2ecf20Sopenharmony_ci}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci/*
7508c2ecf20Sopenharmony_ci * This function initializes TX buffer ring descriptors
7518c2ecf20Sopenharmony_ci */
7528c2ecf20Sopenharmony_cistatic int mwifiex_init_txq_ring(struct mwifiex_adapter *adapter)
7538c2ecf20Sopenharmony_ci{
7548c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
7558c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
7568c2ecf20Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
7578c2ecf20Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
7588c2ecf20Sopenharmony_ci	int i;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
7618c2ecf20Sopenharmony_ci		card->tx_buf_list[i] = NULL;
7628c2ecf20Sopenharmony_ci		if (reg->pfu_enabled) {
7638c2ecf20Sopenharmony_ci			card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
7648c2ecf20Sopenharmony_ci					     (sizeof(*desc2) * i);
7658c2ecf20Sopenharmony_ci			desc2 = card->txbd_ring[i];
7668c2ecf20Sopenharmony_ci			memset(desc2, 0, sizeof(*desc2));
7678c2ecf20Sopenharmony_ci		} else {
7688c2ecf20Sopenharmony_ci			card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
7698c2ecf20Sopenharmony_ci					     (sizeof(*desc) * i);
7708c2ecf20Sopenharmony_ci			desc = card->txbd_ring[i];
7718c2ecf20Sopenharmony_ci			memset(desc, 0, sizeof(*desc));
7728c2ecf20Sopenharmony_ci		}
7738c2ecf20Sopenharmony_ci	}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	return 0;
7768c2ecf20Sopenharmony_ci}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci/* This function initializes RX buffer ring descriptors. Each SKB is allocated
7798c2ecf20Sopenharmony_ci * here and after mapping PCI memory, its physical address is assigned to
7808c2ecf20Sopenharmony_ci * PCIE Rx buffer descriptor's physical address.
7818c2ecf20Sopenharmony_ci */
7828c2ecf20Sopenharmony_cistatic int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
7838c2ecf20Sopenharmony_ci{
7848c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
7858c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
7868c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7878c2ecf20Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
7888c2ecf20Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
7898c2ecf20Sopenharmony_ci	dma_addr_t buf_pa;
7908c2ecf20Sopenharmony_ci	int i;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
7938c2ecf20Sopenharmony_ci		/* Allocate skb here so that firmware can DMA data from it */
7948c2ecf20Sopenharmony_ci		skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
7958c2ecf20Sopenharmony_ci						  GFP_KERNEL);
7968c2ecf20Sopenharmony_ci		if (!skb) {
7978c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
7988c2ecf20Sopenharmony_ci				    "Unable to allocate skb for RX ring.\n");
7998c2ecf20Sopenharmony_ci			return -ENOMEM;
8008c2ecf20Sopenharmony_ci		}
8018c2ecf20Sopenharmony_ci
8028c2ecf20Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb,
8038c2ecf20Sopenharmony_ci					   MWIFIEX_RX_DATA_BUF_SIZE,
8048c2ecf20Sopenharmony_ci					   DMA_FROM_DEVICE)) {
8058c2ecf20Sopenharmony_ci			kfree_skb(skb);
8068c2ecf20Sopenharmony_ci			return -ENOMEM;
8078c2ecf20Sopenharmony_ci		}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
8128c2ecf20Sopenharmony_ci			    "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
8138c2ecf20Sopenharmony_ci			    skb, skb->len, skb->data, (u32)buf_pa,
8148c2ecf20Sopenharmony_ci			    (u32)((u64)buf_pa >> 32));
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci		card->rx_buf_list[i] = skb;
8178c2ecf20Sopenharmony_ci		if (reg->pfu_enabled) {
8188c2ecf20Sopenharmony_ci			card->rxbd_ring[i] = (void *)card->rxbd_ring_vbase +
8198c2ecf20Sopenharmony_ci					     (sizeof(*desc2) * i);
8208c2ecf20Sopenharmony_ci			desc2 = card->rxbd_ring[i];
8218c2ecf20Sopenharmony_ci			desc2->paddr = buf_pa;
8228c2ecf20Sopenharmony_ci			desc2->len = (u16)skb->len;
8238c2ecf20Sopenharmony_ci			desc2->frag_len = (u16)skb->len;
8248c2ecf20Sopenharmony_ci			desc2->flags = reg->ring_flag_eop | reg->ring_flag_sop;
8258c2ecf20Sopenharmony_ci			desc2->offset = 0;
8268c2ecf20Sopenharmony_ci		} else {
8278c2ecf20Sopenharmony_ci			card->rxbd_ring[i] = (void *)(card->rxbd_ring_vbase +
8288c2ecf20Sopenharmony_ci					     (sizeof(*desc) * i));
8298c2ecf20Sopenharmony_ci			desc = card->rxbd_ring[i];
8308c2ecf20Sopenharmony_ci			desc->paddr = buf_pa;
8318c2ecf20Sopenharmony_ci			desc->len = (u16)skb->len;
8328c2ecf20Sopenharmony_ci			desc->flags = 0;
8338c2ecf20Sopenharmony_ci		}
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	return 0;
8378c2ecf20Sopenharmony_ci}
8388c2ecf20Sopenharmony_ci
8398c2ecf20Sopenharmony_ci/* This function initializes event buffer ring descriptors. Each SKB is
8408c2ecf20Sopenharmony_ci * allocated here and after mapping PCI memory, its physical address is assigned
8418c2ecf20Sopenharmony_ci * to PCIE Rx buffer descriptor's physical address
8428c2ecf20Sopenharmony_ci */
8438c2ecf20Sopenharmony_cistatic int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
8448c2ecf20Sopenharmony_ci{
8458c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
8468c2ecf20Sopenharmony_ci	struct mwifiex_evt_buf_desc *desc;
8478c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8488c2ecf20Sopenharmony_ci	dma_addr_t buf_pa;
8498c2ecf20Sopenharmony_ci	int i;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
8528c2ecf20Sopenharmony_ci		/* Allocate skb here so that firmware can DMA data from it */
8538c2ecf20Sopenharmony_ci		skb = dev_alloc_skb(MAX_EVENT_SIZE);
8548c2ecf20Sopenharmony_ci		if (!skb) {
8558c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
8568c2ecf20Sopenharmony_ci				    "Unable to allocate skb for EVENT buf.\n");
8578c2ecf20Sopenharmony_ci			return -ENOMEM;
8588c2ecf20Sopenharmony_ci		}
8598c2ecf20Sopenharmony_ci		skb_put(skb, MAX_EVENT_SIZE);
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
8628c2ecf20Sopenharmony_ci					   DMA_FROM_DEVICE)) {
8638c2ecf20Sopenharmony_ci			kfree_skb(skb);
8648c2ecf20Sopenharmony_ci			return -ENOMEM;
8658c2ecf20Sopenharmony_ci		}
8668c2ecf20Sopenharmony_ci
8678c2ecf20Sopenharmony_ci		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, EVENT,
8708c2ecf20Sopenharmony_ci			    "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
8718c2ecf20Sopenharmony_ci			    skb, skb->len, skb->data, (u32)buf_pa,
8728c2ecf20Sopenharmony_ci			    (u32)((u64)buf_pa >> 32));
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci		card->evt_buf_list[i] = skb;
8758c2ecf20Sopenharmony_ci		card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase +
8768c2ecf20Sopenharmony_ci				      (sizeof(*desc) * i));
8778c2ecf20Sopenharmony_ci		desc = card->evtbd_ring[i];
8788c2ecf20Sopenharmony_ci		desc->paddr = buf_pa;
8798c2ecf20Sopenharmony_ci		desc->len = (u16)skb->len;
8808c2ecf20Sopenharmony_ci		desc->flags = 0;
8818c2ecf20Sopenharmony_ci	}
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	return 0;
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci/* This function cleans up TX buffer rings. If any of the buffer list has valid
8878c2ecf20Sopenharmony_ci * SKB address, associated SKB is freed.
8888c2ecf20Sopenharmony_ci */
8898c2ecf20Sopenharmony_cistatic void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
8908c2ecf20Sopenharmony_ci{
8918c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
8928c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
8938c2ecf20Sopenharmony_ci	struct sk_buff *skb;
8948c2ecf20Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
8958c2ecf20Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
8968c2ecf20Sopenharmony_ci	int i;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
8998c2ecf20Sopenharmony_ci		if (reg->pfu_enabled) {
9008c2ecf20Sopenharmony_ci			desc2 = card->txbd_ring[i];
9018c2ecf20Sopenharmony_ci			if (card->tx_buf_list[i]) {
9028c2ecf20Sopenharmony_ci				skb = card->tx_buf_list[i];
9038c2ecf20Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
9048c2ecf20Sopenharmony_ci							 DMA_TO_DEVICE);
9058c2ecf20Sopenharmony_ci				dev_kfree_skb_any(skb);
9068c2ecf20Sopenharmony_ci			}
9078c2ecf20Sopenharmony_ci			memset(desc2, 0, sizeof(*desc2));
9088c2ecf20Sopenharmony_ci		} else {
9098c2ecf20Sopenharmony_ci			desc = card->txbd_ring[i];
9108c2ecf20Sopenharmony_ci			if (card->tx_buf_list[i]) {
9118c2ecf20Sopenharmony_ci				skb = card->tx_buf_list[i];
9128c2ecf20Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
9138c2ecf20Sopenharmony_ci							 DMA_TO_DEVICE);
9148c2ecf20Sopenharmony_ci				dev_kfree_skb_any(skb);
9158c2ecf20Sopenharmony_ci			}
9168c2ecf20Sopenharmony_ci			memset(desc, 0, sizeof(*desc));
9178c2ecf20Sopenharmony_ci		}
9188c2ecf20Sopenharmony_ci		card->tx_buf_list[i] = NULL;
9198c2ecf20Sopenharmony_ci	}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci	atomic_set(&adapter->tx_hw_pending, 0);
9228c2ecf20Sopenharmony_ci	return;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci/* This function cleans up RX buffer rings. If any of the buffer list has valid
9268c2ecf20Sopenharmony_ci * SKB address, associated SKB is freed.
9278c2ecf20Sopenharmony_ci */
9288c2ecf20Sopenharmony_cistatic void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
9298c2ecf20Sopenharmony_ci{
9308c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
9318c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
9328c2ecf20Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
9338c2ecf20Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
9348c2ecf20Sopenharmony_ci	struct sk_buff *skb;
9358c2ecf20Sopenharmony_ci	int i;
9368c2ecf20Sopenharmony_ci
9378c2ecf20Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
9388c2ecf20Sopenharmony_ci		if (reg->pfu_enabled) {
9398c2ecf20Sopenharmony_ci			desc2 = card->rxbd_ring[i];
9408c2ecf20Sopenharmony_ci			if (card->rx_buf_list[i]) {
9418c2ecf20Sopenharmony_ci				skb = card->rx_buf_list[i];
9428c2ecf20Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
9438c2ecf20Sopenharmony_ci							 DMA_FROM_DEVICE);
9448c2ecf20Sopenharmony_ci				dev_kfree_skb_any(skb);
9458c2ecf20Sopenharmony_ci			}
9468c2ecf20Sopenharmony_ci			memset(desc2, 0, sizeof(*desc2));
9478c2ecf20Sopenharmony_ci		} else {
9488c2ecf20Sopenharmony_ci			desc = card->rxbd_ring[i];
9498c2ecf20Sopenharmony_ci			if (card->rx_buf_list[i]) {
9508c2ecf20Sopenharmony_ci				skb = card->rx_buf_list[i];
9518c2ecf20Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
9528c2ecf20Sopenharmony_ci							 DMA_FROM_DEVICE);
9538c2ecf20Sopenharmony_ci				dev_kfree_skb_any(skb);
9548c2ecf20Sopenharmony_ci			}
9558c2ecf20Sopenharmony_ci			memset(desc, 0, sizeof(*desc));
9568c2ecf20Sopenharmony_ci		}
9578c2ecf20Sopenharmony_ci		card->rx_buf_list[i] = NULL;
9588c2ecf20Sopenharmony_ci	}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci	return;
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci/* This function cleans up event buffer rings. If any of the buffer list has
9648c2ecf20Sopenharmony_ci * valid SKB address, associated SKB is freed.
9658c2ecf20Sopenharmony_ci */
9668c2ecf20Sopenharmony_cistatic void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter)
9678c2ecf20Sopenharmony_ci{
9688c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
9698c2ecf20Sopenharmony_ci	struct mwifiex_evt_buf_desc *desc;
9708c2ecf20Sopenharmony_ci	struct sk_buff *skb;
9718c2ecf20Sopenharmony_ci	int i;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
9748c2ecf20Sopenharmony_ci		desc = card->evtbd_ring[i];
9758c2ecf20Sopenharmony_ci		if (card->evt_buf_list[i]) {
9768c2ecf20Sopenharmony_ci			skb = card->evt_buf_list[i];
9778c2ecf20Sopenharmony_ci			mwifiex_unmap_pci_memory(adapter, skb,
9788c2ecf20Sopenharmony_ci						 DMA_FROM_DEVICE);
9798c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb);
9808c2ecf20Sopenharmony_ci		}
9818c2ecf20Sopenharmony_ci		card->evt_buf_list[i] = NULL;
9828c2ecf20Sopenharmony_ci		memset(desc, 0, sizeof(*desc));
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	return;
9868c2ecf20Sopenharmony_ci}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_ci/* This function creates buffer descriptor ring for TX
9898c2ecf20Sopenharmony_ci */
9908c2ecf20Sopenharmony_cistatic int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
9918c2ecf20Sopenharmony_ci{
9928c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
9938c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	/*
9968c2ecf20Sopenharmony_ci	 * driver maintaines the write pointer and firmware maintaines the read
9978c2ecf20Sopenharmony_ci	 * pointer. The write pointer starts at 0 (zero) while the read pointer
9988c2ecf20Sopenharmony_ci	 * starts at zero with rollover bit set
9998c2ecf20Sopenharmony_ci	 */
10008c2ecf20Sopenharmony_ci	card->txbd_wrptr = 0;
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	if (reg->pfu_enabled)
10038c2ecf20Sopenharmony_ci		card->txbd_rdptr = 0;
10048c2ecf20Sopenharmony_ci	else
10058c2ecf20Sopenharmony_ci		card->txbd_rdptr |= reg->tx_rollover_ind;
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci	/* allocate shared memory for the BD ring and divide the same in to
10088c2ecf20Sopenharmony_ci	   several descriptors */
10098c2ecf20Sopenharmony_ci	if (reg->pfu_enabled)
10108c2ecf20Sopenharmony_ci		card->txbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
10118c2ecf20Sopenharmony_ci				       MWIFIEX_MAX_TXRX_BD;
10128c2ecf20Sopenharmony_ci	else
10138c2ecf20Sopenharmony_ci		card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
10148c2ecf20Sopenharmony_ci				       MWIFIEX_MAX_TXRX_BD;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
10178c2ecf20Sopenharmony_ci		    "info: txbd_ring: Allocating %d bytes\n",
10188c2ecf20Sopenharmony_ci		    card->txbd_ring_size);
10198c2ecf20Sopenharmony_ci	card->txbd_ring_vbase = dma_alloc_coherent(&card->dev->dev,
10208c2ecf20Sopenharmony_ci						   card->txbd_ring_size,
10218c2ecf20Sopenharmony_ci						   &card->txbd_ring_pbase,
10228c2ecf20Sopenharmony_ci						   GFP_KERNEL);
10238c2ecf20Sopenharmony_ci	if (!card->txbd_ring_vbase) {
10248c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
10258c2ecf20Sopenharmony_ci			    "allocate coherent memory (%d bytes) failed!\n",
10268c2ecf20Sopenharmony_ci			    card->txbd_ring_size);
10278c2ecf20Sopenharmony_ci		return -ENOMEM;
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, DATA,
10318c2ecf20Sopenharmony_ci		    "info: txbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
10328c2ecf20Sopenharmony_ci		    card->txbd_ring_vbase, (u32)card->txbd_ring_pbase,
10338c2ecf20Sopenharmony_ci		    (u32)((u64)card->txbd_ring_pbase >> 32),
10348c2ecf20Sopenharmony_ci		    card->txbd_ring_size);
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	return mwifiex_init_txq_ring(adapter);
10378c2ecf20Sopenharmony_ci}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_cistatic int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
10428c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	mwifiex_cleanup_txq_ring(adapter);
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	if (card->txbd_ring_vbase)
10478c2ecf20Sopenharmony_ci		dma_free_coherent(&card->dev->dev, card->txbd_ring_size,
10488c2ecf20Sopenharmony_ci				  card->txbd_ring_vbase,
10498c2ecf20Sopenharmony_ci				  card->txbd_ring_pbase);
10508c2ecf20Sopenharmony_ci	card->txbd_ring_size = 0;
10518c2ecf20Sopenharmony_ci	card->txbd_wrptr = 0;
10528c2ecf20Sopenharmony_ci	card->txbd_rdptr = 0 | reg->tx_rollover_ind;
10538c2ecf20Sopenharmony_ci	card->txbd_ring_vbase = NULL;
10548c2ecf20Sopenharmony_ci	card->txbd_ring_pbase = 0;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	return 0;
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci/*
10608c2ecf20Sopenharmony_ci * This function creates buffer descriptor ring for RX
10618c2ecf20Sopenharmony_ci */
10628c2ecf20Sopenharmony_cistatic int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	int ret;
10658c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
10668c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	/*
10698c2ecf20Sopenharmony_ci	 * driver maintaines the read pointer and firmware maintaines the write
10708c2ecf20Sopenharmony_ci	 * pointer. The write pointer starts at 0 (zero) while the read pointer
10718c2ecf20Sopenharmony_ci	 * starts at zero with rollover bit set
10728c2ecf20Sopenharmony_ci	 */
10738c2ecf20Sopenharmony_ci	card->rxbd_wrptr = 0;
10748c2ecf20Sopenharmony_ci	card->rxbd_rdptr = reg->rx_rollover_ind;
10758c2ecf20Sopenharmony_ci
10768c2ecf20Sopenharmony_ci	if (reg->pfu_enabled)
10778c2ecf20Sopenharmony_ci		card->rxbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
10788c2ecf20Sopenharmony_ci				       MWIFIEX_MAX_TXRX_BD;
10798c2ecf20Sopenharmony_ci	else
10808c2ecf20Sopenharmony_ci		card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
10818c2ecf20Sopenharmony_ci				       MWIFIEX_MAX_TXRX_BD;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
10848c2ecf20Sopenharmony_ci		    "info: rxbd_ring: Allocating %d bytes\n",
10858c2ecf20Sopenharmony_ci		    card->rxbd_ring_size);
10868c2ecf20Sopenharmony_ci	card->rxbd_ring_vbase = dma_alloc_coherent(&card->dev->dev,
10878c2ecf20Sopenharmony_ci						   card->rxbd_ring_size,
10888c2ecf20Sopenharmony_ci						   &card->rxbd_ring_pbase,
10898c2ecf20Sopenharmony_ci						   GFP_KERNEL);
10908c2ecf20Sopenharmony_ci	if (!card->rxbd_ring_vbase) {
10918c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
10928c2ecf20Sopenharmony_ci			    "allocate coherent memory (%d bytes) failed!\n",
10938c2ecf20Sopenharmony_ci			    card->rxbd_ring_size);
10948c2ecf20Sopenharmony_ci		return -ENOMEM;
10958c2ecf20Sopenharmony_ci	}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, DATA,
10988c2ecf20Sopenharmony_ci		    "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
10998c2ecf20Sopenharmony_ci		    card->rxbd_ring_vbase, (u32)card->rxbd_ring_pbase,
11008c2ecf20Sopenharmony_ci		    (u32)((u64)card->rxbd_ring_pbase >> 32),
11018c2ecf20Sopenharmony_ci		    card->rxbd_ring_size);
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	ret = mwifiex_init_rxq_ring(adapter);
11048c2ecf20Sopenharmony_ci	if (ret)
11058c2ecf20Sopenharmony_ci		mwifiex_pcie_delete_rxbd_ring(adapter);
11068c2ecf20Sopenharmony_ci	return ret;
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci/*
11108c2ecf20Sopenharmony_ci * This function deletes Buffer descriptor ring for RX
11118c2ecf20Sopenharmony_ci */
11128c2ecf20Sopenharmony_cistatic int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
11138c2ecf20Sopenharmony_ci{
11148c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
11158c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	mwifiex_cleanup_rxq_ring(adapter);
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_ci	if (card->rxbd_ring_vbase)
11208c2ecf20Sopenharmony_ci		dma_free_coherent(&card->dev->dev, card->rxbd_ring_size,
11218c2ecf20Sopenharmony_ci				  card->rxbd_ring_vbase,
11228c2ecf20Sopenharmony_ci				  card->rxbd_ring_pbase);
11238c2ecf20Sopenharmony_ci	card->rxbd_ring_size = 0;
11248c2ecf20Sopenharmony_ci	card->rxbd_wrptr = 0;
11258c2ecf20Sopenharmony_ci	card->rxbd_rdptr = 0 | reg->rx_rollover_ind;
11268c2ecf20Sopenharmony_ci	card->rxbd_ring_vbase = NULL;
11278c2ecf20Sopenharmony_ci	card->rxbd_ring_pbase = 0;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	return 0;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci/*
11338c2ecf20Sopenharmony_ci * This function creates buffer descriptor ring for Events
11348c2ecf20Sopenharmony_ci */
11358c2ecf20Sopenharmony_cistatic int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
11368c2ecf20Sopenharmony_ci{
11378c2ecf20Sopenharmony_ci	int ret;
11388c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
11398c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci	/*
11428c2ecf20Sopenharmony_ci	 * driver maintaines the read pointer and firmware maintaines the write
11438c2ecf20Sopenharmony_ci	 * pointer. The write pointer starts at 0 (zero) while the read pointer
11448c2ecf20Sopenharmony_ci	 * starts at zero with rollover bit set
11458c2ecf20Sopenharmony_ci	 */
11468c2ecf20Sopenharmony_ci	card->evtbd_wrptr = 0;
11478c2ecf20Sopenharmony_ci	card->evtbd_rdptr = reg->evt_rollover_ind;
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ci	card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) *
11508c2ecf20Sopenharmony_ci				MWIFIEX_MAX_EVT_BD;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
11538c2ecf20Sopenharmony_ci		    "info: evtbd_ring: Allocating %d bytes\n",
11548c2ecf20Sopenharmony_ci		    card->evtbd_ring_size);
11558c2ecf20Sopenharmony_ci	card->evtbd_ring_vbase = dma_alloc_coherent(&card->dev->dev,
11568c2ecf20Sopenharmony_ci						    card->evtbd_ring_size,
11578c2ecf20Sopenharmony_ci						    &card->evtbd_ring_pbase,
11588c2ecf20Sopenharmony_ci						    GFP_KERNEL);
11598c2ecf20Sopenharmony_ci	if (!card->evtbd_ring_vbase) {
11608c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
11618c2ecf20Sopenharmony_ci			    "allocate coherent memory (%d bytes) failed!\n",
11628c2ecf20Sopenharmony_ci			    card->evtbd_ring_size);
11638c2ecf20Sopenharmony_ci		return -ENOMEM;
11648c2ecf20Sopenharmony_ci	}
11658c2ecf20Sopenharmony_ci
11668c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
11678c2ecf20Sopenharmony_ci		    "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
11688c2ecf20Sopenharmony_ci		    card->evtbd_ring_vbase, (u32)card->evtbd_ring_pbase,
11698c2ecf20Sopenharmony_ci		    (u32)((u64)card->evtbd_ring_pbase >> 32),
11708c2ecf20Sopenharmony_ci		    card->evtbd_ring_size);
11718c2ecf20Sopenharmony_ci
11728c2ecf20Sopenharmony_ci	ret = mwifiex_pcie_init_evt_ring(adapter);
11738c2ecf20Sopenharmony_ci	if (ret)
11748c2ecf20Sopenharmony_ci		mwifiex_pcie_delete_evtbd_ring(adapter);
11758c2ecf20Sopenharmony_ci	return ret;
11768c2ecf20Sopenharmony_ci}
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci/*
11798c2ecf20Sopenharmony_ci * This function deletes Buffer descriptor ring for Events
11808c2ecf20Sopenharmony_ci */
11818c2ecf20Sopenharmony_cistatic int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
11828c2ecf20Sopenharmony_ci{
11838c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
11848c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_ci	mwifiex_cleanup_evt_ring(adapter);
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (card->evtbd_ring_vbase)
11898c2ecf20Sopenharmony_ci		dma_free_coherent(&card->dev->dev, card->evtbd_ring_size,
11908c2ecf20Sopenharmony_ci				  card->evtbd_ring_vbase,
11918c2ecf20Sopenharmony_ci				  card->evtbd_ring_pbase);
11928c2ecf20Sopenharmony_ci	card->evtbd_wrptr = 0;
11938c2ecf20Sopenharmony_ci	card->evtbd_rdptr = 0 | reg->evt_rollover_ind;
11948c2ecf20Sopenharmony_ci	card->evtbd_ring_size = 0;
11958c2ecf20Sopenharmony_ci	card->evtbd_ring_vbase = NULL;
11968c2ecf20Sopenharmony_ci	card->evtbd_ring_pbase = 0;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	return 0;
11998c2ecf20Sopenharmony_ci}
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci/*
12028c2ecf20Sopenharmony_ci * This function allocates a buffer for CMDRSP
12038c2ecf20Sopenharmony_ci */
12048c2ecf20Sopenharmony_cistatic int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
12078c2ecf20Sopenharmony_ci	struct sk_buff *skb;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	/* Allocate memory for receiving command response data */
12108c2ecf20Sopenharmony_ci	skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
12118c2ecf20Sopenharmony_ci	if (!skb) {
12128c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
12138c2ecf20Sopenharmony_ci			    "Unable to allocate skb for command response data.\n");
12148c2ecf20Sopenharmony_ci		return -ENOMEM;
12158c2ecf20Sopenharmony_ci	}
12168c2ecf20Sopenharmony_ci	skb_put(skb, MWIFIEX_UPLD_SIZE);
12178c2ecf20Sopenharmony_ci	if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
12188c2ecf20Sopenharmony_ci				   DMA_FROM_DEVICE)) {
12198c2ecf20Sopenharmony_ci		kfree_skb(skb);
12208c2ecf20Sopenharmony_ci		return -1;
12218c2ecf20Sopenharmony_ci	}
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci	card->cmdrsp_buf = skb;
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci	return 0;
12268c2ecf20Sopenharmony_ci}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci/*
12298c2ecf20Sopenharmony_ci * This function deletes a buffer for CMDRSP
12308c2ecf20Sopenharmony_ci */
12318c2ecf20Sopenharmony_cistatic int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
12328c2ecf20Sopenharmony_ci{
12338c2ecf20Sopenharmony_ci	struct pcie_service_card *card;
12348c2ecf20Sopenharmony_ci
12358c2ecf20Sopenharmony_ci	if (!adapter)
12368c2ecf20Sopenharmony_ci		return 0;
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_ci	card = adapter->card;
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	if (card && card->cmdrsp_buf) {
12418c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, card->cmdrsp_buf,
12428c2ecf20Sopenharmony_ci					 DMA_FROM_DEVICE);
12438c2ecf20Sopenharmony_ci		dev_kfree_skb_any(card->cmdrsp_buf);
12448c2ecf20Sopenharmony_ci		card->cmdrsp_buf = NULL;
12458c2ecf20Sopenharmony_ci	}
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	if (card && card->cmd_buf) {
12488c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, card->cmd_buf,
12498c2ecf20Sopenharmony_ci					 DMA_TO_DEVICE);
12508c2ecf20Sopenharmony_ci		dev_kfree_skb_any(card->cmd_buf);
12518c2ecf20Sopenharmony_ci		card->cmd_buf = NULL;
12528c2ecf20Sopenharmony_ci	}
12538c2ecf20Sopenharmony_ci	return 0;
12548c2ecf20Sopenharmony_ci}
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci/*
12578c2ecf20Sopenharmony_ci * This function allocates a buffer for sleep cookie
12588c2ecf20Sopenharmony_ci */
12598c2ecf20Sopenharmony_cistatic int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
12608c2ecf20Sopenharmony_ci{
12618c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
12628c2ecf20Sopenharmony_ci	u32 *cookie;
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	card->sleep_cookie_vbase = dma_alloc_coherent(&card->dev->dev,
12658c2ecf20Sopenharmony_ci						      sizeof(u32),
12668c2ecf20Sopenharmony_ci						      &card->sleep_cookie_pbase,
12678c2ecf20Sopenharmony_ci						      GFP_KERNEL);
12688c2ecf20Sopenharmony_ci	if (!card->sleep_cookie_vbase) {
12698c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
12708c2ecf20Sopenharmony_ci			    "dma_alloc_coherent failed!\n");
12718c2ecf20Sopenharmony_ci		return -ENOMEM;
12728c2ecf20Sopenharmony_ci	}
12738c2ecf20Sopenharmony_ci	cookie = (u32 *)card->sleep_cookie_vbase;
12748c2ecf20Sopenharmony_ci	/* Init val of Sleep Cookie */
12758c2ecf20Sopenharmony_ci	*cookie = FW_AWAKE_COOKIE;
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "alloc_scook: sleep cookie=0x%x\n", *cookie);
12788c2ecf20Sopenharmony_ci
12798c2ecf20Sopenharmony_ci	return 0;
12808c2ecf20Sopenharmony_ci}
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci/*
12838c2ecf20Sopenharmony_ci * This function deletes buffer for sleep cookie
12848c2ecf20Sopenharmony_ci */
12858c2ecf20Sopenharmony_cistatic int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	struct pcie_service_card *card;
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	if (!adapter)
12908c2ecf20Sopenharmony_ci		return 0;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	card = adapter->card;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	if (card && card->sleep_cookie_vbase) {
12958c2ecf20Sopenharmony_ci		dma_free_coherent(&card->dev->dev, sizeof(u32),
12968c2ecf20Sopenharmony_ci				  card->sleep_cookie_vbase,
12978c2ecf20Sopenharmony_ci				  card->sleep_cookie_pbase);
12988c2ecf20Sopenharmony_ci		card->sleep_cookie_vbase = NULL;
12998c2ecf20Sopenharmony_ci	}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	return 0;
13028c2ecf20Sopenharmony_ci}
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci/* This function flushes the TX buffer descriptor ring
13058c2ecf20Sopenharmony_ci * This function defined as handler is also called while cleaning TXRX
13068c2ecf20Sopenharmony_ci * during disconnect/ bss stop.
13078c2ecf20Sopenharmony_ci */
13088c2ecf20Sopenharmony_cistatic int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
13098c2ecf20Sopenharmony_ci{
13108c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	if (!mwifiex_pcie_txbd_empty(card, card->txbd_rdptr)) {
13138c2ecf20Sopenharmony_ci		card->txbd_flush = 1;
13148c2ecf20Sopenharmony_ci		/* write pointer already set at last send
13158c2ecf20Sopenharmony_ci		 * send dnld-rdy intr again, wait for completion.
13168c2ecf20Sopenharmony_ci		 */
13178c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
13188c2ecf20Sopenharmony_ci				      CPU_INTR_DNLD_RDY)) {
13198c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
13208c2ecf20Sopenharmony_ci				    "failed to assert dnld-rdy interrupt.\n");
13218c2ecf20Sopenharmony_ci			return -1;
13228c2ecf20Sopenharmony_ci		}
13238c2ecf20Sopenharmony_ci	}
13248c2ecf20Sopenharmony_ci	return 0;
13258c2ecf20Sopenharmony_ci}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci/*
13288c2ecf20Sopenharmony_ci * This function unmaps and frees downloaded data buffer
13298c2ecf20Sopenharmony_ci */
13308c2ecf20Sopenharmony_cistatic int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
13318c2ecf20Sopenharmony_ci{
13328c2ecf20Sopenharmony_ci	struct sk_buff *skb;
13338c2ecf20Sopenharmony_ci	u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0;
13348c2ecf20Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
13358c2ecf20Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
13368c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
13378c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
13408c2ecf20Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	/* Read the TX ring read pointer set by firmware */
13438c2ecf20Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
13448c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
13458c2ecf20Sopenharmony_ci			    "SEND COMP: failed to read reg->tx_rdptr\n");
13468c2ecf20Sopenharmony_ci		return -1;
13478c2ecf20Sopenharmony_ci	}
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, DATA,
13508c2ecf20Sopenharmony_ci		    "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
13518c2ecf20Sopenharmony_ci		    card->txbd_rdptr, rdptr);
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci	num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
13548c2ecf20Sopenharmony_ci	/* free from previous txbd_rdptr to current txbd_rdptr */
13558c2ecf20Sopenharmony_ci	while (((card->txbd_rdptr & reg->tx_mask) !=
13568c2ecf20Sopenharmony_ci		(rdptr & reg->tx_mask)) ||
13578c2ecf20Sopenharmony_ci	       ((card->txbd_rdptr & reg->tx_rollover_ind) !=
13588c2ecf20Sopenharmony_ci		(rdptr & reg->tx_rollover_ind))) {
13598c2ecf20Sopenharmony_ci		wrdoneidx = (card->txbd_rdptr & reg->tx_mask) >>
13608c2ecf20Sopenharmony_ci			    reg->tx_start_ptr;
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci		skb = card->tx_buf_list[wrdoneidx];
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci		if (skb) {
13658c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, DATA,
13668c2ecf20Sopenharmony_ci				    "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
13678c2ecf20Sopenharmony_ci				    skb, wrdoneidx);
13688c2ecf20Sopenharmony_ci			mwifiex_unmap_pci_memory(adapter, skb,
13698c2ecf20Sopenharmony_ci						 DMA_TO_DEVICE);
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci			unmap_count++;
13728c2ecf20Sopenharmony_ci
13738c2ecf20Sopenharmony_ci			if (card->txbd_flush)
13748c2ecf20Sopenharmony_ci				mwifiex_write_data_complete(adapter, skb, 0,
13758c2ecf20Sopenharmony_ci							    -1);
13768c2ecf20Sopenharmony_ci			else
13778c2ecf20Sopenharmony_ci				mwifiex_write_data_complete(adapter, skb, 0, 0);
13788c2ecf20Sopenharmony_ci			atomic_dec(&adapter->tx_hw_pending);
13798c2ecf20Sopenharmony_ci		}
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		card->tx_buf_list[wrdoneidx] = NULL;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci		if (reg->pfu_enabled) {
13848c2ecf20Sopenharmony_ci			desc2 = card->txbd_ring[wrdoneidx];
13858c2ecf20Sopenharmony_ci			memset(desc2, 0, sizeof(*desc2));
13868c2ecf20Sopenharmony_ci		} else {
13878c2ecf20Sopenharmony_ci			desc = card->txbd_ring[wrdoneidx];
13888c2ecf20Sopenharmony_ci			memset(desc, 0, sizeof(*desc));
13898c2ecf20Sopenharmony_ci		}
13908c2ecf20Sopenharmony_ci		switch (card->dev->device) {
13918c2ecf20Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8766P:
13928c2ecf20Sopenharmony_ci			card->txbd_rdptr++;
13938c2ecf20Sopenharmony_ci			break;
13948c2ecf20Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8897:
13958c2ecf20Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8997:
13968c2ecf20Sopenharmony_ci			card->txbd_rdptr += reg->ring_tx_start_ptr;
13978c2ecf20Sopenharmony_ci			break;
13988c2ecf20Sopenharmony_ci		}
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci
14018c2ecf20Sopenharmony_ci		if ((card->txbd_rdptr & reg->tx_mask) == num_tx_buffs)
14028c2ecf20Sopenharmony_ci			card->txbd_rdptr = ((card->txbd_rdptr &
14038c2ecf20Sopenharmony_ci					     reg->tx_rollover_ind) ^
14048c2ecf20Sopenharmony_ci					     reg->tx_rollover_ind);
14058c2ecf20Sopenharmony_ci	}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	if (unmap_count)
14088c2ecf20Sopenharmony_ci		adapter->data_sent = false;
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	if (card->txbd_flush) {
14118c2ecf20Sopenharmony_ci		if (mwifiex_pcie_txbd_empty(card, card->txbd_rdptr))
14128c2ecf20Sopenharmony_ci			card->txbd_flush = 0;
14138c2ecf20Sopenharmony_ci		else
14148c2ecf20Sopenharmony_ci			mwifiex_clean_pcie_ring_buf(adapter);
14158c2ecf20Sopenharmony_ci	}
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	return 0;
14188c2ecf20Sopenharmony_ci}
14198c2ecf20Sopenharmony_ci
14208c2ecf20Sopenharmony_ci/* This function sends data buffer to device. First 4 bytes of payload
14218c2ecf20Sopenharmony_ci * are filled with payload length and payload type. Then this payload
14228c2ecf20Sopenharmony_ci * is mapped to PCI device memory. Tx ring pointers are advanced accordingly.
14238c2ecf20Sopenharmony_ci * Download ready interrupt to FW is deffered if Tx ring is not full and
14248c2ecf20Sopenharmony_ci * additional payload can be accomodated.
14258c2ecf20Sopenharmony_ci * Caller must ensure tx_param parameter to this function is not NULL.
14268c2ecf20Sopenharmony_ci */
14278c2ecf20Sopenharmony_cistatic int
14288c2ecf20Sopenharmony_cimwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
14298c2ecf20Sopenharmony_ci		       struct mwifiex_tx_param *tx_param)
14308c2ecf20Sopenharmony_ci{
14318c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
14328c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
14338c2ecf20Sopenharmony_ci	u32 wrindx, num_tx_buffs, rx_val;
14348c2ecf20Sopenharmony_ci	int ret;
14358c2ecf20Sopenharmony_ci	dma_addr_t buf_pa;
14368c2ecf20Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc = NULL;
14378c2ecf20Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2 = NULL;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	if (!(skb->data && skb->len)) {
14408c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
14418c2ecf20Sopenharmony_ci			    "%s(): invalid parameter <%p, %#x>\n",
14428c2ecf20Sopenharmony_ci			    __func__, skb->data, skb->len);
14438c2ecf20Sopenharmony_ci		return -1;
14448c2ecf20Sopenharmony_ci	}
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
14478c2ecf20Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_ci	num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
14508c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, DATA,
14518c2ecf20Sopenharmony_ci		    "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
14528c2ecf20Sopenharmony_ci		card->txbd_rdptr, card->txbd_wrptr);
14538c2ecf20Sopenharmony_ci	if (mwifiex_pcie_txbd_not_full(card)) {
14548c2ecf20Sopenharmony_ci		u8 *payload;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci		adapter->data_sent = true;
14578c2ecf20Sopenharmony_ci		payload = skb->data;
14588c2ecf20Sopenharmony_ci		put_unaligned_le16((u16)skb->len, payload + 0);
14598c2ecf20Sopenharmony_ci		put_unaligned_le16(MWIFIEX_TYPE_DATA, payload + 2);
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb, skb->len,
14628c2ecf20Sopenharmony_ci					   DMA_TO_DEVICE))
14638c2ecf20Sopenharmony_ci			return -1;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci		wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr;
14668c2ecf20Sopenharmony_ci		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
14678c2ecf20Sopenharmony_ci		card->tx_buf_list[wrindx] = skb;
14688c2ecf20Sopenharmony_ci		atomic_inc(&adapter->tx_hw_pending);
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci		if (reg->pfu_enabled) {
14718c2ecf20Sopenharmony_ci			desc2 = card->txbd_ring[wrindx];
14728c2ecf20Sopenharmony_ci			desc2->paddr = buf_pa;
14738c2ecf20Sopenharmony_ci			desc2->len = (u16)skb->len;
14748c2ecf20Sopenharmony_ci			desc2->frag_len = (u16)skb->len;
14758c2ecf20Sopenharmony_ci			desc2->offset = 0;
14768c2ecf20Sopenharmony_ci			desc2->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
14778c2ecf20Sopenharmony_ci					 MWIFIEX_BD_FLAG_LAST_DESC;
14788c2ecf20Sopenharmony_ci		} else {
14798c2ecf20Sopenharmony_ci			desc = card->txbd_ring[wrindx];
14808c2ecf20Sopenharmony_ci			desc->paddr = buf_pa;
14818c2ecf20Sopenharmony_ci			desc->len = (u16)skb->len;
14828c2ecf20Sopenharmony_ci			desc->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
14838c2ecf20Sopenharmony_ci				      MWIFIEX_BD_FLAG_LAST_DESC;
14848c2ecf20Sopenharmony_ci		}
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci		switch (card->dev->device) {
14878c2ecf20Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8766P:
14888c2ecf20Sopenharmony_ci			card->txbd_wrptr++;
14898c2ecf20Sopenharmony_ci			break;
14908c2ecf20Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8897:
14918c2ecf20Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8997:
14928c2ecf20Sopenharmony_ci			card->txbd_wrptr += reg->ring_tx_start_ptr;
14938c2ecf20Sopenharmony_ci			break;
14948c2ecf20Sopenharmony_ci		}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci		if ((card->txbd_wrptr & reg->tx_mask) == num_tx_buffs)
14978c2ecf20Sopenharmony_ci			card->txbd_wrptr = ((card->txbd_wrptr &
14988c2ecf20Sopenharmony_ci						reg->tx_rollover_ind) ^
14998c2ecf20Sopenharmony_ci						reg->tx_rollover_ind);
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci		rx_val = card->rxbd_rdptr & reg->rx_wrap_mask;
15028c2ecf20Sopenharmony_ci		/* Write the TX ring write pointer in to reg->tx_wrptr */
15038c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->tx_wrptr,
15048c2ecf20Sopenharmony_ci				      card->txbd_wrptr | rx_val)) {
15058c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
15068c2ecf20Sopenharmony_ci				    "SEND DATA: failed to write reg->tx_wrptr\n");
15078c2ecf20Sopenharmony_ci			ret = -1;
15088c2ecf20Sopenharmony_ci			goto done_unmap;
15098c2ecf20Sopenharmony_ci		}
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci		/* The firmware (latest version 15.68.19.p21) of the 88W8897 PCIe+USB card
15128c2ecf20Sopenharmony_ci		 * seems to crash randomly after setting the TX ring write pointer when
15138c2ecf20Sopenharmony_ci		 * ASPM powersaving is enabled. A workaround seems to be keeping the bus
15148c2ecf20Sopenharmony_ci		 * busy by reading a random register afterwards.
15158c2ecf20Sopenharmony_ci		 */
15168c2ecf20Sopenharmony_ci		mwifiex_read_reg(adapter, PCI_VENDOR_ID, &rx_val);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci		if ((mwifiex_pcie_txbd_not_full(card)) &&
15198c2ecf20Sopenharmony_ci		    tx_param->next_pkt_len) {
15208c2ecf20Sopenharmony_ci			/* have more packets and TxBD still can hold more */
15218c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, DATA,
15228c2ecf20Sopenharmony_ci				    "SEND DATA: delay dnld-rdy interrupt.\n");
15238c2ecf20Sopenharmony_ci			adapter->data_sent = false;
15248c2ecf20Sopenharmony_ci		} else {
15258c2ecf20Sopenharmony_ci			/* Send the TX ready interrupt */
15268c2ecf20Sopenharmony_ci			if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
15278c2ecf20Sopenharmony_ci					      CPU_INTR_DNLD_RDY)) {
15288c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
15298c2ecf20Sopenharmony_ci					    "SEND DATA: failed to assert dnld-rdy interrupt.\n");
15308c2ecf20Sopenharmony_ci				ret = -1;
15318c2ecf20Sopenharmony_ci				goto done_unmap;
15328c2ecf20Sopenharmony_ci			}
15338c2ecf20Sopenharmony_ci		}
15348c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, DATA,
15358c2ecf20Sopenharmony_ci			    "info: SEND DATA: Updated <Rd: %#x, Wr:\t"
15368c2ecf20Sopenharmony_ci			    "%#x> and sent packet to firmware successfully\n",
15378c2ecf20Sopenharmony_ci			    card->txbd_rdptr, card->txbd_wrptr);
15388c2ecf20Sopenharmony_ci	} else {
15398c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, DATA,
15408c2ecf20Sopenharmony_ci			    "info: TX Ring full, can't send packets to fw\n");
15418c2ecf20Sopenharmony_ci		adapter->data_sent = true;
15428c2ecf20Sopenharmony_ci		/* Send the TX ready interrupt */
15438c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
15448c2ecf20Sopenharmony_ci				      CPU_INTR_DNLD_RDY))
15458c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
15468c2ecf20Sopenharmony_ci				    "SEND DATA: failed to assert door-bell intr\n");
15478c2ecf20Sopenharmony_ci		return -EBUSY;
15488c2ecf20Sopenharmony_ci	}
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	return -EINPROGRESS;
15518c2ecf20Sopenharmony_cidone_unmap:
15528c2ecf20Sopenharmony_ci	mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
15538c2ecf20Sopenharmony_ci	card->tx_buf_list[wrindx] = NULL;
15548c2ecf20Sopenharmony_ci	atomic_dec(&adapter->tx_hw_pending);
15558c2ecf20Sopenharmony_ci	if (reg->pfu_enabled)
15568c2ecf20Sopenharmony_ci		memset(desc2, 0, sizeof(*desc2));
15578c2ecf20Sopenharmony_ci	else
15588c2ecf20Sopenharmony_ci		memset(desc, 0, sizeof(*desc));
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	return ret;
15618c2ecf20Sopenharmony_ci}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_ci/*
15648c2ecf20Sopenharmony_ci * This function handles received buffer ring and
15658c2ecf20Sopenharmony_ci * dispatches packets to upper
15668c2ecf20Sopenharmony_ci */
15678c2ecf20Sopenharmony_cistatic int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
15708c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
15718c2ecf20Sopenharmony_ci	u32 wrptr, rd_index, tx_val;
15728c2ecf20Sopenharmony_ci	dma_addr_t buf_pa;
15738c2ecf20Sopenharmony_ci	int ret = 0;
15748c2ecf20Sopenharmony_ci	struct sk_buff *skb_tmp = NULL;
15758c2ecf20Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
15768c2ecf20Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
15778c2ecf20Sopenharmony_ci
15788c2ecf20Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
15798c2ecf20Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	/* Read the RX ring Write pointer set by firmware */
15828c2ecf20Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
15838c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
15848c2ecf20Sopenharmony_ci			    "RECV DATA: failed to read reg->rx_wrptr\n");
15858c2ecf20Sopenharmony_ci		ret = -1;
15868c2ecf20Sopenharmony_ci		goto done;
15878c2ecf20Sopenharmony_ci	}
15888c2ecf20Sopenharmony_ci	card->rxbd_wrptr = wrptr;
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	while (((wrptr & reg->rx_mask) !=
15918c2ecf20Sopenharmony_ci		(card->rxbd_rdptr & reg->rx_mask)) ||
15928c2ecf20Sopenharmony_ci	       ((wrptr & reg->rx_rollover_ind) ==
15938c2ecf20Sopenharmony_ci		(card->rxbd_rdptr & reg->rx_rollover_ind))) {
15948c2ecf20Sopenharmony_ci		struct sk_buff *skb_data;
15958c2ecf20Sopenharmony_ci		u16 rx_len;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci		rd_index = card->rxbd_rdptr & reg->rx_mask;
15988c2ecf20Sopenharmony_ci		skb_data = card->rx_buf_list[rd_index];
15998c2ecf20Sopenharmony_ci
16008c2ecf20Sopenharmony_ci		/* If skb allocation was failed earlier for Rx packet,
16018c2ecf20Sopenharmony_ci		 * rx_buf_list[rd_index] would have been left with a NULL.
16028c2ecf20Sopenharmony_ci		 */
16038c2ecf20Sopenharmony_ci		if (!skb_data)
16048c2ecf20Sopenharmony_ci			return -ENOMEM;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb_data, DMA_FROM_DEVICE);
16078c2ecf20Sopenharmony_ci		card->rx_buf_list[rd_index] = NULL;
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci		/* Get data length from interface header -
16108c2ecf20Sopenharmony_ci		 * first 2 bytes for len, next 2 bytes is for type
16118c2ecf20Sopenharmony_ci		 */
16128c2ecf20Sopenharmony_ci		rx_len = get_unaligned_le16(skb_data->data);
16138c2ecf20Sopenharmony_ci		if (WARN_ON(rx_len <= adapter->intf_hdr_len ||
16148c2ecf20Sopenharmony_ci			    rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) {
16158c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
16168c2ecf20Sopenharmony_ci				    "Invalid RX len %d, Rd=%#x, Wr=%#x\n",
16178c2ecf20Sopenharmony_ci				    rx_len, card->rxbd_rdptr, wrptr);
16188c2ecf20Sopenharmony_ci			dev_kfree_skb_any(skb_data);
16198c2ecf20Sopenharmony_ci		} else {
16208c2ecf20Sopenharmony_ci			skb_put(skb_data, rx_len);
16218c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, DATA,
16228c2ecf20Sopenharmony_ci				    "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
16238c2ecf20Sopenharmony_ci				    card->rxbd_rdptr, wrptr, rx_len);
16248c2ecf20Sopenharmony_ci			skb_pull(skb_data, adapter->intf_hdr_len);
16258c2ecf20Sopenharmony_ci			if (adapter->rx_work_enabled) {
16268c2ecf20Sopenharmony_ci				skb_queue_tail(&adapter->rx_data_q, skb_data);
16278c2ecf20Sopenharmony_ci				adapter->data_received = true;
16288c2ecf20Sopenharmony_ci				atomic_inc(&adapter->rx_pending);
16298c2ecf20Sopenharmony_ci			} else {
16308c2ecf20Sopenharmony_ci				mwifiex_handle_rx_packet(adapter, skb_data);
16318c2ecf20Sopenharmony_ci			}
16328c2ecf20Sopenharmony_ci		}
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci		skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
16358c2ecf20Sopenharmony_ci						      GFP_KERNEL);
16368c2ecf20Sopenharmony_ci		if (!skb_tmp) {
16378c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
16388c2ecf20Sopenharmony_ci				    "Unable to allocate skb.\n");
16398c2ecf20Sopenharmony_ci			return -ENOMEM;
16408c2ecf20Sopenharmony_ci		}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb_tmp,
16438c2ecf20Sopenharmony_ci					   MWIFIEX_RX_DATA_BUF_SIZE,
16448c2ecf20Sopenharmony_ci					   DMA_FROM_DEVICE))
16458c2ecf20Sopenharmony_ci			return -1;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb_tmp);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
16508c2ecf20Sopenharmony_ci			    "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
16518c2ecf20Sopenharmony_ci			    skb_tmp, rd_index);
16528c2ecf20Sopenharmony_ci		card->rx_buf_list[rd_index] = skb_tmp;
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci		if (reg->pfu_enabled) {
16558c2ecf20Sopenharmony_ci			desc2 = card->rxbd_ring[rd_index];
16568c2ecf20Sopenharmony_ci			desc2->paddr = buf_pa;
16578c2ecf20Sopenharmony_ci			desc2->len = skb_tmp->len;
16588c2ecf20Sopenharmony_ci			desc2->frag_len = skb_tmp->len;
16598c2ecf20Sopenharmony_ci			desc2->offset = 0;
16608c2ecf20Sopenharmony_ci			desc2->flags = reg->ring_flag_sop | reg->ring_flag_eop;
16618c2ecf20Sopenharmony_ci		} else {
16628c2ecf20Sopenharmony_ci			desc = card->rxbd_ring[rd_index];
16638c2ecf20Sopenharmony_ci			desc->paddr = buf_pa;
16648c2ecf20Sopenharmony_ci			desc->len = skb_tmp->len;
16658c2ecf20Sopenharmony_ci			desc->flags = 0;
16668c2ecf20Sopenharmony_ci		}
16678c2ecf20Sopenharmony_ci
16688c2ecf20Sopenharmony_ci		if ((++card->rxbd_rdptr & reg->rx_mask) ==
16698c2ecf20Sopenharmony_ci							MWIFIEX_MAX_TXRX_BD) {
16708c2ecf20Sopenharmony_ci			card->rxbd_rdptr = ((card->rxbd_rdptr &
16718c2ecf20Sopenharmony_ci					     reg->rx_rollover_ind) ^
16728c2ecf20Sopenharmony_ci					     reg->rx_rollover_ind);
16738c2ecf20Sopenharmony_ci		}
16748c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, DATA,
16758c2ecf20Sopenharmony_ci			    "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
16768c2ecf20Sopenharmony_ci			    card->rxbd_rdptr, wrptr);
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci		tx_val = card->txbd_wrptr & reg->tx_wrap_mask;
16798c2ecf20Sopenharmony_ci		/* Write the RX ring read pointer in to reg->rx_rdptr */
16808c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->rx_rdptr,
16818c2ecf20Sopenharmony_ci				      card->rxbd_rdptr | tx_val)) {
16828c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, DATA,
16838c2ecf20Sopenharmony_ci				    "RECV DATA: failed to write reg->rx_rdptr\n");
16848c2ecf20Sopenharmony_ci			ret = -1;
16858c2ecf20Sopenharmony_ci			goto done;
16868c2ecf20Sopenharmony_ci		}
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci		/* Read the RX ring Write pointer set by firmware */
16898c2ecf20Sopenharmony_ci		if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
16908c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
16918c2ecf20Sopenharmony_ci				    "RECV DATA: failed to read reg->rx_wrptr\n");
16928c2ecf20Sopenharmony_ci			ret = -1;
16938c2ecf20Sopenharmony_ci			goto done;
16948c2ecf20Sopenharmony_ci		}
16958c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, DATA,
16968c2ecf20Sopenharmony_ci			    "info: RECV DATA: Rcvd packet from fw successfully\n");
16978c2ecf20Sopenharmony_ci		card->rxbd_wrptr = wrptr;
16988c2ecf20Sopenharmony_ci	}
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_cidone:
17018c2ecf20Sopenharmony_ci	return ret;
17028c2ecf20Sopenharmony_ci}
17038c2ecf20Sopenharmony_ci
17048c2ecf20Sopenharmony_ci/*
17058c2ecf20Sopenharmony_ci * This function downloads the boot command to device
17068c2ecf20Sopenharmony_ci */
17078c2ecf20Sopenharmony_cistatic int
17088c2ecf20Sopenharmony_cimwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
17098c2ecf20Sopenharmony_ci{
17108c2ecf20Sopenharmony_ci	dma_addr_t buf_pa;
17118c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
17128c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
17138c2ecf20Sopenharmony_ci
17148c2ecf20Sopenharmony_ci	if (!(skb->data && skb->len)) {
17158c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
17168c2ecf20Sopenharmony_ci			    "Invalid parameter in %s <%p. len %d>\n",
17178c2ecf20Sopenharmony_ci			    __func__, skb->data, skb->len);
17188c2ecf20Sopenharmony_ci		return -1;
17198c2ecf20Sopenharmony_ci	}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_ci	if (mwifiex_map_pci_memory(adapter, skb, skb->len, DMA_TO_DEVICE))
17228c2ecf20Sopenharmony_ci		return -1;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci	/* Write the lower 32bits of the physical address to low command
17278c2ecf20Sopenharmony_ci	 * address scratch register
17288c2ecf20Sopenharmony_ci	 */
17298c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) {
17308c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
17318c2ecf20Sopenharmony_ci			    "%s: failed to write download command to boot code.\n",
17328c2ecf20Sopenharmony_ci			    __func__);
17338c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
17348c2ecf20Sopenharmony_ci		return -1;
17358c2ecf20Sopenharmony_ci	}
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_ci	/* Write the upper 32bits of the physical address to high command
17388c2ecf20Sopenharmony_ci	 * address scratch register
17398c2ecf20Sopenharmony_ci	 */
17408c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
17418c2ecf20Sopenharmony_ci			      (u32)((u64)buf_pa >> 32))) {
17428c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
17438c2ecf20Sopenharmony_ci			    "%s: failed to write download command to boot code.\n",
17448c2ecf20Sopenharmony_ci			    __func__);
17458c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
17468c2ecf20Sopenharmony_ci		return -1;
17478c2ecf20Sopenharmony_ci	}
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci	/* Write the command length to cmd_size scratch register */
17508c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) {
17518c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
17528c2ecf20Sopenharmony_ci			    "%s: failed to write command len to cmd_size scratch reg\n",
17538c2ecf20Sopenharmony_ci			    __func__);
17548c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
17558c2ecf20Sopenharmony_ci		return -1;
17568c2ecf20Sopenharmony_ci	}
17578c2ecf20Sopenharmony_ci
17588c2ecf20Sopenharmony_ci	/* Ring the door bell */
17598c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
17608c2ecf20Sopenharmony_ci			      CPU_INTR_DOOR_BELL)) {
17618c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
17628c2ecf20Sopenharmony_ci			    "%s: failed to assert door-bell intr\n", __func__);
17638c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
17648c2ecf20Sopenharmony_ci		return -1;
17658c2ecf20Sopenharmony_ci	}
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	return 0;
17688c2ecf20Sopenharmony_ci}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci/* This function init rx port in firmware which in turn enables to receive data
17718c2ecf20Sopenharmony_ci * from device before transmitting any packet.
17728c2ecf20Sopenharmony_ci */
17738c2ecf20Sopenharmony_cistatic int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
17748c2ecf20Sopenharmony_ci{
17758c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
17768c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
17778c2ecf20Sopenharmony_ci	int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask;
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci	/* Write the RX ring read pointer in to reg->rx_rdptr */
17808c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
17818c2ecf20Sopenharmony_ci			      tx_wrap)) {
17828c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
17838c2ecf20Sopenharmony_ci			    "RECV DATA: failed to write reg->rx_rdptr\n");
17848c2ecf20Sopenharmony_ci		return -1;
17858c2ecf20Sopenharmony_ci	}
17868c2ecf20Sopenharmony_ci	return 0;
17878c2ecf20Sopenharmony_ci}
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci/* This function downloads commands to the device
17908c2ecf20Sopenharmony_ci */
17918c2ecf20Sopenharmony_cistatic int
17928c2ecf20Sopenharmony_cimwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
17938c2ecf20Sopenharmony_ci{
17948c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
17958c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
17968c2ecf20Sopenharmony_ci	int ret = 0;
17978c2ecf20Sopenharmony_ci	dma_addr_t cmd_buf_pa, cmdrsp_buf_pa;
17988c2ecf20Sopenharmony_ci	u8 *payload = (u8 *)skb->data;
17998c2ecf20Sopenharmony_ci
18008c2ecf20Sopenharmony_ci	if (!(skb->data && skb->len)) {
18018c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
18028c2ecf20Sopenharmony_ci			    "Invalid parameter in %s <%p, %#x>\n",
18038c2ecf20Sopenharmony_ci			    __func__, skb->data, skb->len);
18048c2ecf20Sopenharmony_ci		return -1;
18058c2ecf20Sopenharmony_ci	}
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	/* Make sure a command response buffer is available */
18088c2ecf20Sopenharmony_ci	if (!card->cmdrsp_buf) {
18098c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
18108c2ecf20Sopenharmony_ci			    "No response buffer available, send command failed\n");
18118c2ecf20Sopenharmony_ci		return -EBUSY;
18128c2ecf20Sopenharmony_ci	}
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
18158c2ecf20Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	adapter->cmd_sent = true;
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	put_unaligned_le16((u16)skb->len, &payload[0]);
18208c2ecf20Sopenharmony_ci	put_unaligned_le16(MWIFIEX_TYPE_CMD, &payload[2]);
18218c2ecf20Sopenharmony_ci
18228c2ecf20Sopenharmony_ci	if (mwifiex_map_pci_memory(adapter, skb, skb->len, DMA_TO_DEVICE))
18238c2ecf20Sopenharmony_ci		return -1;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	card->cmd_buf = skb;
18268c2ecf20Sopenharmony_ci	/*
18278c2ecf20Sopenharmony_ci	 * Need to keep a reference, since core driver might free up this
18288c2ecf20Sopenharmony_ci	 * buffer before we've unmapped it.
18298c2ecf20Sopenharmony_ci	 */
18308c2ecf20Sopenharmony_ci	skb_get(skb);
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci	/* To send a command, the driver will:
18338c2ecf20Sopenharmony_ci		1. Write the 64bit physical address of the data buffer to
18348c2ecf20Sopenharmony_ci		   cmd response address low  + cmd response address high
18358c2ecf20Sopenharmony_ci		2. Ring the door bell (i.e. set the door bell interrupt)
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci		In response to door bell interrupt, the firmware will perform
18388c2ecf20Sopenharmony_ci		the DMA of the command packet (first header to obtain the total
18398c2ecf20Sopenharmony_ci		length and then rest of the command).
18408c2ecf20Sopenharmony_ci	*/
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	if (card->cmdrsp_buf) {
18438c2ecf20Sopenharmony_ci		cmdrsp_buf_pa = MWIFIEX_SKB_DMA_ADDR(card->cmdrsp_buf);
18448c2ecf20Sopenharmony_ci		/* Write the lower 32bits of the cmdrsp buffer physical
18458c2ecf20Sopenharmony_ci		   address */
18468c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo,
18478c2ecf20Sopenharmony_ci				      (u32)cmdrsp_buf_pa)) {
18488c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
18498c2ecf20Sopenharmony_ci				    "Failed to write download cmd to boot code.\n");
18508c2ecf20Sopenharmony_ci			ret = -1;
18518c2ecf20Sopenharmony_ci			goto done;
18528c2ecf20Sopenharmony_ci		}
18538c2ecf20Sopenharmony_ci		/* Write the upper 32bits of the cmdrsp buffer physical
18548c2ecf20Sopenharmony_ci		   address */
18558c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi,
18568c2ecf20Sopenharmony_ci				      (u32)((u64)cmdrsp_buf_pa >> 32))) {
18578c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
18588c2ecf20Sopenharmony_ci				    "Failed to write download cmd to boot code.\n");
18598c2ecf20Sopenharmony_ci			ret = -1;
18608c2ecf20Sopenharmony_ci			goto done;
18618c2ecf20Sopenharmony_ci		}
18628c2ecf20Sopenharmony_ci	}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	cmd_buf_pa = MWIFIEX_SKB_DMA_ADDR(card->cmd_buf);
18658c2ecf20Sopenharmony_ci	/* Write the lower 32bits of the physical address to reg->cmd_addr_lo */
18668c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_addr_lo,
18678c2ecf20Sopenharmony_ci			      (u32)cmd_buf_pa)) {
18688c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
18698c2ecf20Sopenharmony_ci			    "Failed to write download cmd to boot code.\n");
18708c2ecf20Sopenharmony_ci		ret = -1;
18718c2ecf20Sopenharmony_ci		goto done;
18728c2ecf20Sopenharmony_ci	}
18738c2ecf20Sopenharmony_ci	/* Write the upper 32bits of the physical address to reg->cmd_addr_hi */
18748c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
18758c2ecf20Sopenharmony_ci			      (u32)((u64)cmd_buf_pa >> 32))) {
18768c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
18778c2ecf20Sopenharmony_ci			    "Failed to write download cmd to boot code.\n");
18788c2ecf20Sopenharmony_ci		ret = -1;
18798c2ecf20Sopenharmony_ci		goto done;
18808c2ecf20Sopenharmony_ci	}
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	/* Write the command length to reg->cmd_size */
18838c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_size,
18848c2ecf20Sopenharmony_ci			      card->cmd_buf->len)) {
18858c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
18868c2ecf20Sopenharmony_ci			    "Failed to write cmd len to reg->cmd_size\n");
18878c2ecf20Sopenharmony_ci		ret = -1;
18888c2ecf20Sopenharmony_ci		goto done;
18898c2ecf20Sopenharmony_ci	}
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	/* Ring the door bell */
18928c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
18938c2ecf20Sopenharmony_ci			      CPU_INTR_DOOR_BELL)) {
18948c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
18958c2ecf20Sopenharmony_ci			    "Failed to assert door-bell intr\n");
18968c2ecf20Sopenharmony_ci		ret = -1;
18978c2ecf20Sopenharmony_ci		goto done;
18988c2ecf20Sopenharmony_ci	}
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_cidone:
19018c2ecf20Sopenharmony_ci	if (ret)
19028c2ecf20Sopenharmony_ci		adapter->cmd_sent = false;
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_ci	return 0;
19058c2ecf20Sopenharmony_ci}
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci/*
19088c2ecf20Sopenharmony_ci * This function handles command complete interrupt
19098c2ecf20Sopenharmony_ci */
19108c2ecf20Sopenharmony_cistatic int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
19118c2ecf20Sopenharmony_ci{
19128c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
19138c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
19148c2ecf20Sopenharmony_ci	struct sk_buff *skb = card->cmdrsp_buf;
19158c2ecf20Sopenharmony_ci	int count = 0;
19168c2ecf20Sopenharmony_ci	u16 rx_len;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, CMD,
19198c2ecf20Sopenharmony_ci		    "info: Rx CMD Response\n");
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_ci	if (adapter->curr_cmd)
19228c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_FROM_DEVICE);
19238c2ecf20Sopenharmony_ci	else
19248c2ecf20Sopenharmony_ci		dma_sync_single_for_cpu(&card->dev->dev,
19258c2ecf20Sopenharmony_ci					MWIFIEX_SKB_DMA_ADDR(skb),
19268c2ecf20Sopenharmony_ci					MWIFIEX_UPLD_SIZE, DMA_FROM_DEVICE);
19278c2ecf20Sopenharmony_ci
19288c2ecf20Sopenharmony_ci	/* Unmap the command as a response has been received. */
19298c2ecf20Sopenharmony_ci	if (card->cmd_buf) {
19308c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, card->cmd_buf,
19318c2ecf20Sopenharmony_ci					 DMA_TO_DEVICE);
19328c2ecf20Sopenharmony_ci		dev_kfree_skb_any(card->cmd_buf);
19338c2ecf20Sopenharmony_ci		card->cmd_buf = NULL;
19348c2ecf20Sopenharmony_ci	}
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci	rx_len = get_unaligned_le16(skb->data);
19378c2ecf20Sopenharmony_ci	skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
19388c2ecf20Sopenharmony_ci	skb_trim(skb, rx_len);
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	if (!adapter->curr_cmd) {
19418c2ecf20Sopenharmony_ci		if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
19428c2ecf20Sopenharmony_ci			dma_sync_single_for_device(&card->dev->dev,
19438c2ecf20Sopenharmony_ci						   MWIFIEX_SKB_DMA_ADDR(skb),
19448c2ecf20Sopenharmony_ci						   MWIFIEX_SLEEP_COOKIE_SIZE,
19458c2ecf20Sopenharmony_ci						   DMA_FROM_DEVICE);
19468c2ecf20Sopenharmony_ci			if (mwifiex_write_reg(adapter,
19478c2ecf20Sopenharmony_ci					      PCIE_CPU_INT_EVENT,
19488c2ecf20Sopenharmony_ci					      CPU_INTR_SLEEP_CFM_DONE)) {
19498c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
19508c2ecf20Sopenharmony_ci					    "Write register failed\n");
19518c2ecf20Sopenharmony_ci				return -1;
19528c2ecf20Sopenharmony_ci			}
19538c2ecf20Sopenharmony_ci			mwifiex_delay_for_sleep_cookie(adapter,
19548c2ecf20Sopenharmony_ci						       MWIFIEX_MAX_DELAY_COUNT);
19558c2ecf20Sopenharmony_ci			mwifiex_unmap_pci_memory(adapter, skb,
19568c2ecf20Sopenharmony_ci						 DMA_FROM_DEVICE);
19578c2ecf20Sopenharmony_ci			skb_pull(skb, adapter->intf_hdr_len);
19588c2ecf20Sopenharmony_ci			while (reg->sleep_cookie && (count++ < 10) &&
19598c2ecf20Sopenharmony_ci			       mwifiex_pcie_ok_to_access_hw(adapter))
19608c2ecf20Sopenharmony_ci				usleep_range(50, 60);
19618c2ecf20Sopenharmony_ci			mwifiex_pcie_enable_host_int(adapter);
19628c2ecf20Sopenharmony_ci			mwifiex_process_sleep_confirm_resp(adapter, skb->data,
19638c2ecf20Sopenharmony_ci							   skb->len);
19648c2ecf20Sopenharmony_ci		} else {
19658c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
19668c2ecf20Sopenharmony_ci				    "There is no command but got cmdrsp\n");
19678c2ecf20Sopenharmony_ci		}
19688c2ecf20Sopenharmony_ci		memcpy(adapter->upld_buf, skb->data,
19698c2ecf20Sopenharmony_ci		       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
19708c2ecf20Sopenharmony_ci		skb_push(skb, adapter->intf_hdr_len);
19718c2ecf20Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
19728c2ecf20Sopenharmony_ci					   DMA_FROM_DEVICE))
19738c2ecf20Sopenharmony_ci			return -1;
19748c2ecf20Sopenharmony_ci	} else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
19758c2ecf20Sopenharmony_ci		skb_pull(skb, adapter->intf_hdr_len);
19768c2ecf20Sopenharmony_ci		adapter->curr_cmd->resp_skb = skb;
19778c2ecf20Sopenharmony_ci		adapter->cmd_resp_received = true;
19788c2ecf20Sopenharmony_ci		/* Take the pointer and set it to CMD node and will
19798c2ecf20Sopenharmony_ci		   return in the response complete callback */
19808c2ecf20Sopenharmony_ci		card->cmdrsp_buf = NULL;
19818c2ecf20Sopenharmony_ci
19828c2ecf20Sopenharmony_ci		/* Clear the cmd-rsp buffer address in scratch registers. This
19838c2ecf20Sopenharmony_ci		   will prevent firmware from writing to the same response
19848c2ecf20Sopenharmony_ci		   buffer again. */
19858c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) {
19868c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
19878c2ecf20Sopenharmony_ci				    "cmd_done: failed to clear cmd_rsp_addr_lo\n");
19888c2ecf20Sopenharmony_ci			return -1;
19898c2ecf20Sopenharmony_ci		}
19908c2ecf20Sopenharmony_ci		/* Write the upper 32bits of the cmdrsp buffer physical
19918c2ecf20Sopenharmony_ci		   address */
19928c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) {
19938c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
19948c2ecf20Sopenharmony_ci				    "cmd_done: failed to clear cmd_rsp_addr_hi\n");
19958c2ecf20Sopenharmony_ci			return -1;
19968c2ecf20Sopenharmony_ci		}
19978c2ecf20Sopenharmony_ci	}
19988c2ecf20Sopenharmony_ci
19998c2ecf20Sopenharmony_ci	return 0;
20008c2ecf20Sopenharmony_ci}
20018c2ecf20Sopenharmony_ci
20028c2ecf20Sopenharmony_ci/*
20038c2ecf20Sopenharmony_ci * Command Response processing complete handler
20048c2ecf20Sopenharmony_ci */
20058c2ecf20Sopenharmony_cistatic int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
20068c2ecf20Sopenharmony_ci					struct sk_buff *skb)
20078c2ecf20Sopenharmony_ci{
20088c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	if (skb) {
20118c2ecf20Sopenharmony_ci		card->cmdrsp_buf = skb;
20128c2ecf20Sopenharmony_ci		skb_push(card->cmdrsp_buf, adapter->intf_hdr_len);
20138c2ecf20Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
20148c2ecf20Sopenharmony_ci					   DMA_FROM_DEVICE))
20158c2ecf20Sopenharmony_ci			return -1;
20168c2ecf20Sopenharmony_ci	}
20178c2ecf20Sopenharmony_ci
20188c2ecf20Sopenharmony_ci	return 0;
20198c2ecf20Sopenharmony_ci}
20208c2ecf20Sopenharmony_ci
20218c2ecf20Sopenharmony_ci/*
20228c2ecf20Sopenharmony_ci * This function handles firmware event ready interrupt
20238c2ecf20Sopenharmony_ci */
20248c2ecf20Sopenharmony_cistatic int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
20258c2ecf20Sopenharmony_ci{
20268c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
20278c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
20288c2ecf20Sopenharmony_ci	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
20298c2ecf20Sopenharmony_ci	u32 wrptr, event;
20308c2ecf20Sopenharmony_ci	struct mwifiex_evt_buf_desc *desc;
20318c2ecf20Sopenharmony_ci
20328c2ecf20Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
20338c2ecf20Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	if (adapter->event_received) {
20368c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, EVENT,
20378c2ecf20Sopenharmony_ci			    "info: Event being processed,\t"
20388c2ecf20Sopenharmony_ci			    "do not process this interrupt just yet\n");
20398c2ecf20Sopenharmony_ci		return 0;
20408c2ecf20Sopenharmony_ci	}
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	if (rdptr >= MWIFIEX_MAX_EVT_BD) {
20438c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
20448c2ecf20Sopenharmony_ci			    "info: Invalid read pointer...\n");
20458c2ecf20Sopenharmony_ci		return -1;
20468c2ecf20Sopenharmony_ci	}
20478c2ecf20Sopenharmony_ci
20488c2ecf20Sopenharmony_ci	/* Read the event ring write pointer set by firmware */
20498c2ecf20Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
20508c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
20518c2ecf20Sopenharmony_ci			    "EventReady: failed to read reg->evt_wrptr\n");
20528c2ecf20Sopenharmony_ci		return -1;
20538c2ecf20Sopenharmony_ci	}
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
20568c2ecf20Sopenharmony_ci		    "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
20578c2ecf20Sopenharmony_ci		    card->evtbd_rdptr, wrptr);
20588c2ecf20Sopenharmony_ci	if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr
20598c2ecf20Sopenharmony_ci					      & MWIFIEX_EVTBD_MASK)) ||
20608c2ecf20Sopenharmony_ci	    ((wrptr & reg->evt_rollover_ind) ==
20618c2ecf20Sopenharmony_ci	     (card->evtbd_rdptr & reg->evt_rollover_ind))) {
20628c2ecf20Sopenharmony_ci		struct sk_buff *skb_cmd;
20638c2ecf20Sopenharmony_ci		__le16 data_len = 0;
20648c2ecf20Sopenharmony_ci		u16 evt_len;
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
20678c2ecf20Sopenharmony_ci			    "info: Read Index: %d\n", rdptr);
20688c2ecf20Sopenharmony_ci		skb_cmd = card->evt_buf_list[rdptr];
20698c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb_cmd, DMA_FROM_DEVICE);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci		/* Take the pointer and set it to event pointer in adapter
20728c2ecf20Sopenharmony_ci		   and will return back after event handling callback */
20738c2ecf20Sopenharmony_ci		card->evt_buf_list[rdptr] = NULL;
20748c2ecf20Sopenharmony_ci		desc = card->evtbd_ring[rdptr];
20758c2ecf20Sopenharmony_ci		memset(desc, 0, sizeof(*desc));
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci		event = get_unaligned_le32(
20788c2ecf20Sopenharmony_ci			&skb_cmd->data[adapter->intf_hdr_len]);
20798c2ecf20Sopenharmony_ci		adapter->event_cause = event;
20808c2ecf20Sopenharmony_ci		/* The first 4bytes will be the event transfer header
20818c2ecf20Sopenharmony_ci		   len is 2 bytes followed by type which is 2 bytes */
20828c2ecf20Sopenharmony_ci		memcpy(&data_len, skb_cmd->data, sizeof(__le16));
20838c2ecf20Sopenharmony_ci		evt_len = le16_to_cpu(data_len);
20848c2ecf20Sopenharmony_ci		skb_trim(skb_cmd, evt_len);
20858c2ecf20Sopenharmony_ci		skb_pull(skb_cmd, adapter->intf_hdr_len);
20868c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, EVENT,
20878c2ecf20Sopenharmony_ci			    "info: Event length: %d\n", evt_len);
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci		if (evt_len > MWIFIEX_EVENT_HEADER_LEN &&
20908c2ecf20Sopenharmony_ci		    evt_len < MAX_EVENT_SIZE)
20918c2ecf20Sopenharmony_ci			memcpy(adapter->event_body, skb_cmd->data +
20928c2ecf20Sopenharmony_ci			       MWIFIEX_EVENT_HEADER_LEN, evt_len -
20938c2ecf20Sopenharmony_ci			       MWIFIEX_EVENT_HEADER_LEN);
20948c2ecf20Sopenharmony_ci
20958c2ecf20Sopenharmony_ci		adapter->event_received = true;
20968c2ecf20Sopenharmony_ci		adapter->event_skb = skb_cmd;
20978c2ecf20Sopenharmony_ci
20988c2ecf20Sopenharmony_ci		/* Do not update the event read pointer here, wait till the
20998c2ecf20Sopenharmony_ci		   buffer is released. This is just to make things simpler,
21008c2ecf20Sopenharmony_ci		   we need to find a better method of managing these buffers.
21018c2ecf20Sopenharmony_ci		*/
21028c2ecf20Sopenharmony_ci	} else {
21038c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
21048c2ecf20Sopenharmony_ci				      CPU_INTR_EVENT_DONE)) {
21058c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
21068c2ecf20Sopenharmony_ci				    "Write register failed\n");
21078c2ecf20Sopenharmony_ci			return -1;
21088c2ecf20Sopenharmony_ci		}
21098c2ecf20Sopenharmony_ci	}
21108c2ecf20Sopenharmony_ci
21118c2ecf20Sopenharmony_ci	return 0;
21128c2ecf20Sopenharmony_ci}
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci/*
21158c2ecf20Sopenharmony_ci * Event processing complete handler
21168c2ecf20Sopenharmony_ci */
21178c2ecf20Sopenharmony_cistatic int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
21188c2ecf20Sopenharmony_ci				       struct sk_buff *skb)
21198c2ecf20Sopenharmony_ci{
21208c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
21218c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
21228c2ecf20Sopenharmony_ci	int ret = 0;
21238c2ecf20Sopenharmony_ci	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
21248c2ecf20Sopenharmony_ci	u32 wrptr;
21258c2ecf20Sopenharmony_ci	struct mwifiex_evt_buf_desc *desc;
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	if (!skb)
21288c2ecf20Sopenharmony_ci		return 0;
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	if (rdptr >= MWIFIEX_MAX_EVT_BD) {
21318c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
21328c2ecf20Sopenharmony_ci			    "event_complete: Invalid rdptr 0x%x\n",
21338c2ecf20Sopenharmony_ci			    rdptr);
21348c2ecf20Sopenharmony_ci		return -EINVAL;
21358c2ecf20Sopenharmony_ci	}
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	/* Read the event ring write pointer set by firmware */
21388c2ecf20Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
21398c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
21408c2ecf20Sopenharmony_ci			    "event_complete: failed to read reg->evt_wrptr\n");
21418c2ecf20Sopenharmony_ci		return -1;
21428c2ecf20Sopenharmony_ci	}
21438c2ecf20Sopenharmony_ci
21448c2ecf20Sopenharmony_ci	if (!card->evt_buf_list[rdptr]) {
21458c2ecf20Sopenharmony_ci		skb_push(skb, adapter->intf_hdr_len);
21468c2ecf20Sopenharmony_ci		skb_put(skb, MAX_EVENT_SIZE - skb->len);
21478c2ecf20Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb,
21488c2ecf20Sopenharmony_ci					   MAX_EVENT_SIZE,
21498c2ecf20Sopenharmony_ci					   DMA_FROM_DEVICE))
21508c2ecf20Sopenharmony_ci			return -1;
21518c2ecf20Sopenharmony_ci		card->evt_buf_list[rdptr] = skb;
21528c2ecf20Sopenharmony_ci		desc = card->evtbd_ring[rdptr];
21538c2ecf20Sopenharmony_ci		desc->paddr = MWIFIEX_SKB_DMA_ADDR(skb);
21548c2ecf20Sopenharmony_ci		desc->len = (u16)skb->len;
21558c2ecf20Sopenharmony_ci		desc->flags = 0;
21568c2ecf20Sopenharmony_ci		skb = NULL;
21578c2ecf20Sopenharmony_ci	} else {
21588c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
21598c2ecf20Sopenharmony_ci			    "info: ERROR: buf still valid at index %d, <%p, %p>\n",
21608c2ecf20Sopenharmony_ci			    rdptr, card->evt_buf_list[rdptr], skb);
21618c2ecf20Sopenharmony_ci	}
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
21648c2ecf20Sopenharmony_ci		card->evtbd_rdptr = ((card->evtbd_rdptr &
21658c2ecf20Sopenharmony_ci					reg->evt_rollover_ind) ^
21668c2ecf20Sopenharmony_ci					reg->evt_rollover_ind);
21678c2ecf20Sopenharmony_ci	}
21688c2ecf20Sopenharmony_ci
21698c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
21708c2ecf20Sopenharmony_ci		    "info: Updated <Rd: 0x%x, Wr: 0x%x>",
21718c2ecf20Sopenharmony_ci		    card->evtbd_rdptr, wrptr);
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci	/* Write the event ring read pointer in to reg->evt_rdptr */
21748c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->evt_rdptr,
21758c2ecf20Sopenharmony_ci			      card->evtbd_rdptr)) {
21768c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
21778c2ecf20Sopenharmony_ci			    "event_complete: failed to read reg->evt_rdptr\n");
21788c2ecf20Sopenharmony_ci		return -1;
21798c2ecf20Sopenharmony_ci	}
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
21828c2ecf20Sopenharmony_ci		    "info: Check Events Again\n");
21838c2ecf20Sopenharmony_ci	ret = mwifiex_pcie_process_event_ready(adapter);
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	return ret;
21868c2ecf20Sopenharmony_ci}
21878c2ecf20Sopenharmony_ci
21888c2ecf20Sopenharmony_ci/* Combo firmware image is a combination of
21898c2ecf20Sopenharmony_ci * (1) combo crc heaer, start with CMD5
21908c2ecf20Sopenharmony_ci * (2) bluetooth image, start with CMD7, end with CMD6, data wrapped in CMD1.
21918c2ecf20Sopenharmony_ci * (3) wifi image.
21928c2ecf20Sopenharmony_ci *
21938c2ecf20Sopenharmony_ci * This function bypass the header and bluetooth part, return
21948c2ecf20Sopenharmony_ci * the offset of tail wifi-only part. If the image is already wifi-only,
21958c2ecf20Sopenharmony_ci * that is start with CMD1, return 0.
21968c2ecf20Sopenharmony_ci */
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_cistatic int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter,
21998c2ecf20Sopenharmony_ci				   const void *firmware, u32 firmware_len) {
22008c2ecf20Sopenharmony_ci	const struct mwifiex_fw_data *fwdata;
22018c2ecf20Sopenharmony_ci	u32 offset = 0, data_len, dnld_cmd;
22028c2ecf20Sopenharmony_ci	int ret = 0;
22038c2ecf20Sopenharmony_ci	bool cmd7_before = false, first_cmd = false;
22048c2ecf20Sopenharmony_ci
22058c2ecf20Sopenharmony_ci	while (1) {
22068c2ecf20Sopenharmony_ci		/* Check for integer and buffer overflow */
22078c2ecf20Sopenharmony_ci		if (offset + sizeof(fwdata->header) < sizeof(fwdata->header) ||
22088c2ecf20Sopenharmony_ci		    offset + sizeof(fwdata->header) >= firmware_len) {
22098c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
22108c2ecf20Sopenharmony_ci				    "extract wifi-only fw failure!\n");
22118c2ecf20Sopenharmony_ci			ret = -1;
22128c2ecf20Sopenharmony_ci			goto done;
22138c2ecf20Sopenharmony_ci		}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_ci		fwdata = firmware + offset;
22168c2ecf20Sopenharmony_ci		dnld_cmd = le32_to_cpu(fwdata->header.dnld_cmd);
22178c2ecf20Sopenharmony_ci		data_len = le32_to_cpu(fwdata->header.data_length);
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci		/* Skip past header */
22208c2ecf20Sopenharmony_ci		offset += sizeof(fwdata->header);
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci		switch (dnld_cmd) {
22238c2ecf20Sopenharmony_ci		case MWIFIEX_FW_DNLD_CMD_1:
22248c2ecf20Sopenharmony_ci			if (offset + data_len < data_len) {
22258c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
22268c2ecf20Sopenharmony_ci				ret = -1;
22278c2ecf20Sopenharmony_ci				goto done;
22288c2ecf20Sopenharmony_ci			}
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci			/* Image start with cmd1, already wifi-only firmware */
22318c2ecf20Sopenharmony_ci			if (!first_cmd) {
22328c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, MSG,
22338c2ecf20Sopenharmony_ci					    "input wifi-only firmware\n");
22348c2ecf20Sopenharmony_ci				return 0;
22358c2ecf20Sopenharmony_ci			}
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci			if (!cmd7_before) {
22388c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
22398c2ecf20Sopenharmony_ci					    "no cmd7 before cmd1!\n");
22408c2ecf20Sopenharmony_ci				ret = -1;
22418c2ecf20Sopenharmony_ci				goto done;
22428c2ecf20Sopenharmony_ci			}
22438c2ecf20Sopenharmony_ci			offset += data_len;
22448c2ecf20Sopenharmony_ci			break;
22458c2ecf20Sopenharmony_ci		case MWIFIEX_FW_DNLD_CMD_5:
22468c2ecf20Sopenharmony_ci			first_cmd = true;
22478c2ecf20Sopenharmony_ci			/* Check for integer overflow */
22488c2ecf20Sopenharmony_ci			if (offset + data_len < data_len) {
22498c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
22508c2ecf20Sopenharmony_ci				ret = -1;
22518c2ecf20Sopenharmony_ci				goto done;
22528c2ecf20Sopenharmony_ci			}
22538c2ecf20Sopenharmony_ci			offset += data_len;
22548c2ecf20Sopenharmony_ci			break;
22558c2ecf20Sopenharmony_ci		case MWIFIEX_FW_DNLD_CMD_6:
22568c2ecf20Sopenharmony_ci			first_cmd = true;
22578c2ecf20Sopenharmony_ci			/* Check for integer overflow */
22588c2ecf20Sopenharmony_ci			if (offset + data_len < data_len) {
22598c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
22608c2ecf20Sopenharmony_ci				ret = -1;
22618c2ecf20Sopenharmony_ci				goto done;
22628c2ecf20Sopenharmony_ci			}
22638c2ecf20Sopenharmony_ci			offset += data_len;
22648c2ecf20Sopenharmony_ci			if (offset >= firmware_len) {
22658c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
22668c2ecf20Sopenharmony_ci					    "extract wifi-only fw failure!\n");
22678c2ecf20Sopenharmony_ci				ret = -1;
22688c2ecf20Sopenharmony_ci			} else {
22698c2ecf20Sopenharmony_ci				ret = offset;
22708c2ecf20Sopenharmony_ci			}
22718c2ecf20Sopenharmony_ci			goto done;
22728c2ecf20Sopenharmony_ci		case MWIFIEX_FW_DNLD_CMD_7:
22738c2ecf20Sopenharmony_ci			first_cmd = true;
22748c2ecf20Sopenharmony_ci			cmd7_before = true;
22758c2ecf20Sopenharmony_ci			break;
22768c2ecf20Sopenharmony_ci		default:
22778c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "unknown dnld_cmd %d\n",
22788c2ecf20Sopenharmony_ci				    dnld_cmd);
22798c2ecf20Sopenharmony_ci			ret = -1;
22808c2ecf20Sopenharmony_ci			goto done;
22818c2ecf20Sopenharmony_ci		}
22828c2ecf20Sopenharmony_ci	}
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_cidone:
22858c2ecf20Sopenharmony_ci	return ret;
22868c2ecf20Sopenharmony_ci}
22878c2ecf20Sopenharmony_ci
22888c2ecf20Sopenharmony_ci/*
22898c2ecf20Sopenharmony_ci * This function downloads the firmware to the card.
22908c2ecf20Sopenharmony_ci *
22918c2ecf20Sopenharmony_ci * Firmware is downloaded to the card in blocks. Every block download
22928c2ecf20Sopenharmony_ci * is tested for CRC errors, and retried a number of times before
22938c2ecf20Sopenharmony_ci * returning failure.
22948c2ecf20Sopenharmony_ci */
22958c2ecf20Sopenharmony_cistatic int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
22968c2ecf20Sopenharmony_ci				    struct mwifiex_fw_image *fw)
22978c2ecf20Sopenharmony_ci{
22988c2ecf20Sopenharmony_ci	int ret;
22998c2ecf20Sopenharmony_ci	u8 *firmware = fw->fw_buf;
23008c2ecf20Sopenharmony_ci	u32 firmware_len = fw->fw_len;
23018c2ecf20Sopenharmony_ci	u32 offset = 0;
23028c2ecf20Sopenharmony_ci	struct sk_buff *skb;
23038c2ecf20Sopenharmony_ci	u32 txlen, tx_blocks = 0, tries, len, val;
23048c2ecf20Sopenharmony_ci	u32 block_retry_cnt = 0;
23058c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
23068c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci	if (!firmware || !firmware_len) {
23098c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
23108c2ecf20Sopenharmony_ci			    "No firmware image found! Terminating download\n");
23118c2ecf20Sopenharmony_ci		return -1;
23128c2ecf20Sopenharmony_ci	}
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
23158c2ecf20Sopenharmony_ci		    "info: Downloading FW image (%d bytes)\n",
23168c2ecf20Sopenharmony_ci		    firmware_len);
23178c2ecf20Sopenharmony_ci
23188c2ecf20Sopenharmony_ci	if (mwifiex_pcie_disable_host_int(adapter)) {
23198c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
23208c2ecf20Sopenharmony_ci			    "%s: Disabling interrupts failed.\n", __func__);
23218c2ecf20Sopenharmony_ci		return -1;
23228c2ecf20Sopenharmony_ci	}
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci	skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
23258c2ecf20Sopenharmony_ci	if (!skb) {
23268c2ecf20Sopenharmony_ci		ret = -ENOMEM;
23278c2ecf20Sopenharmony_ci		goto done;
23288c2ecf20Sopenharmony_ci	}
23298c2ecf20Sopenharmony_ci
23308c2ecf20Sopenharmony_ci	ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_13_REG, &val);
23318c2ecf20Sopenharmony_ci	if (ret) {
23328c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, FATAL, "Failed to read scratch register 13\n");
23338c2ecf20Sopenharmony_ci		goto done;
23348c2ecf20Sopenharmony_ci	}
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci	/* PCIE FLR case: extract wifi part from combo firmware*/
23378c2ecf20Sopenharmony_ci	if (val == MWIFIEX_PCIE_FLR_HAPPENS) {
23388c2ecf20Sopenharmony_ci		ret = mwifiex_extract_wifi_fw(adapter, firmware, firmware_len);
23398c2ecf20Sopenharmony_ci		if (ret < 0) {
23408c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "Failed to extract wifi fw\n");
23418c2ecf20Sopenharmony_ci			goto done;
23428c2ecf20Sopenharmony_ci		}
23438c2ecf20Sopenharmony_ci		offset = ret;
23448c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, MSG,
23458c2ecf20Sopenharmony_ci			    "info: dnld wifi firmware from %d bytes\n", offset);
23468c2ecf20Sopenharmony_ci	}
23478c2ecf20Sopenharmony_ci
23488c2ecf20Sopenharmony_ci	/* Perform firmware data transfer */
23498c2ecf20Sopenharmony_ci	do {
23508c2ecf20Sopenharmony_ci		u32 ireg_intr = 0;
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci		/* More data? */
23538c2ecf20Sopenharmony_ci		if (offset >= firmware_len)
23548c2ecf20Sopenharmony_ci			break;
23558c2ecf20Sopenharmony_ci
23568c2ecf20Sopenharmony_ci		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
23578c2ecf20Sopenharmony_ci			ret = mwifiex_read_reg(adapter, reg->cmd_size,
23588c2ecf20Sopenharmony_ci					       &len);
23598c2ecf20Sopenharmony_ci			if (ret) {
23608c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, FATAL,
23618c2ecf20Sopenharmony_ci					    "Failed reading len from boot code\n");
23628c2ecf20Sopenharmony_ci				goto done;
23638c2ecf20Sopenharmony_ci			}
23648c2ecf20Sopenharmony_ci			if (len)
23658c2ecf20Sopenharmony_ci				break;
23668c2ecf20Sopenharmony_ci			usleep_range(10, 20);
23678c2ecf20Sopenharmony_ci		}
23688c2ecf20Sopenharmony_ci
23698c2ecf20Sopenharmony_ci		if (!len) {
23708c2ecf20Sopenharmony_ci			break;
23718c2ecf20Sopenharmony_ci		} else if (len > MWIFIEX_UPLD_SIZE) {
23728c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
23738c2ecf20Sopenharmony_ci				    "FW download failure @ %d, invalid length %d\n",
23748c2ecf20Sopenharmony_ci				    offset, len);
23758c2ecf20Sopenharmony_ci			ret = -1;
23768c2ecf20Sopenharmony_ci			goto done;
23778c2ecf20Sopenharmony_ci		}
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci		txlen = len;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci		if (len & BIT(0)) {
23828c2ecf20Sopenharmony_ci			block_retry_cnt++;
23838c2ecf20Sopenharmony_ci			if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
23848c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
23858c2ecf20Sopenharmony_ci					    "FW download failure @ %d, over max\t"
23868c2ecf20Sopenharmony_ci					    "retry count\n", offset);
23878c2ecf20Sopenharmony_ci				ret = -1;
23888c2ecf20Sopenharmony_ci				goto done;
23898c2ecf20Sopenharmony_ci			}
23908c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
23918c2ecf20Sopenharmony_ci				    "FW CRC error indicated by the\t"
23928c2ecf20Sopenharmony_ci				    "helper: len = 0x%04X, txlen = %d\n",
23938c2ecf20Sopenharmony_ci				    len, txlen);
23948c2ecf20Sopenharmony_ci			len &= ~BIT(0);
23958c2ecf20Sopenharmony_ci			/* Setting this to 0 to resend from same offset */
23968c2ecf20Sopenharmony_ci			txlen = 0;
23978c2ecf20Sopenharmony_ci		} else {
23988c2ecf20Sopenharmony_ci			block_retry_cnt = 0;
23998c2ecf20Sopenharmony_ci			/* Set blocksize to transfer - checking for
24008c2ecf20Sopenharmony_ci			   last block */
24018c2ecf20Sopenharmony_ci			if (firmware_len - offset < txlen)
24028c2ecf20Sopenharmony_ci				txlen = firmware_len - offset;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci			tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) /
24058c2ecf20Sopenharmony_ci				    card->pcie.blksz_fw_dl;
24068c2ecf20Sopenharmony_ci
24078c2ecf20Sopenharmony_ci			/* Copy payload to buffer */
24088c2ecf20Sopenharmony_ci			memmove(skb->data, &firmware[offset], txlen);
24098c2ecf20Sopenharmony_ci		}
24108c2ecf20Sopenharmony_ci
24118c2ecf20Sopenharmony_ci		skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
24128c2ecf20Sopenharmony_ci		skb_trim(skb, tx_blocks * card->pcie.blksz_fw_dl);
24138c2ecf20Sopenharmony_ci
24148c2ecf20Sopenharmony_ci		/* Send the boot command to device */
24158c2ecf20Sopenharmony_ci		if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
24168c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
24178c2ecf20Sopenharmony_ci				    "Failed to send firmware download command\n");
24188c2ecf20Sopenharmony_ci			ret = -1;
24198c2ecf20Sopenharmony_ci			goto done;
24208c2ecf20Sopenharmony_ci		}
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci		/* Wait for the command done interrupt */
24238c2ecf20Sopenharmony_ci		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
24248c2ecf20Sopenharmony_ci			if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
24258c2ecf20Sopenharmony_ci					     &ireg_intr)) {
24268c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
24278c2ecf20Sopenharmony_ci					    "%s: Failed to read\t"
24288c2ecf20Sopenharmony_ci					    "interrupt status during fw dnld.\n",
24298c2ecf20Sopenharmony_ci					    __func__);
24308c2ecf20Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
24318c2ecf20Sopenharmony_ci							 DMA_TO_DEVICE);
24328c2ecf20Sopenharmony_ci				ret = -1;
24338c2ecf20Sopenharmony_ci				goto done;
24348c2ecf20Sopenharmony_ci			}
24358c2ecf20Sopenharmony_ci			if (!(ireg_intr & CPU_INTR_DOOR_BELL))
24368c2ecf20Sopenharmony_ci				break;
24378c2ecf20Sopenharmony_ci			usleep_range(10, 20);
24388c2ecf20Sopenharmony_ci		}
24398c2ecf20Sopenharmony_ci		if (ireg_intr & CPU_INTR_DOOR_BELL) {
24408c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "%s: Card failed to ACK download\n",
24418c2ecf20Sopenharmony_ci				    __func__);
24428c2ecf20Sopenharmony_ci			mwifiex_unmap_pci_memory(adapter, skb,
24438c2ecf20Sopenharmony_ci						 DMA_TO_DEVICE);
24448c2ecf20Sopenharmony_ci			ret = -1;
24458c2ecf20Sopenharmony_ci			goto done;
24468c2ecf20Sopenharmony_ci		}
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
24498c2ecf20Sopenharmony_ci
24508c2ecf20Sopenharmony_ci		offset += txlen;
24518c2ecf20Sopenharmony_ci	} while (true);
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG,
24548c2ecf20Sopenharmony_ci		    "info: FW download over, size %d bytes\n", offset);
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	ret = 0;
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_cidone:
24598c2ecf20Sopenharmony_ci	dev_kfree_skb_any(skb);
24608c2ecf20Sopenharmony_ci	return ret;
24618c2ecf20Sopenharmony_ci}
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci/*
24648c2ecf20Sopenharmony_ci * This function checks the firmware status in card.
24658c2ecf20Sopenharmony_ci */
24668c2ecf20Sopenharmony_cistatic int
24678c2ecf20Sopenharmony_cimwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
24688c2ecf20Sopenharmony_ci{
24698c2ecf20Sopenharmony_ci	int ret = 0;
24708c2ecf20Sopenharmony_ci	u32 firmware_stat;
24718c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
24728c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
24738c2ecf20Sopenharmony_ci	u32 tries;
24748c2ecf20Sopenharmony_ci
24758c2ecf20Sopenharmony_ci	/* Mask spurios interrupts */
24768c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS_MASK,
24778c2ecf20Sopenharmony_ci			      HOST_INTR_MASK)) {
24788c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
24798c2ecf20Sopenharmony_ci			    "Write register failed\n");
24808c2ecf20Sopenharmony_ci		return -1;
24818c2ecf20Sopenharmony_ci	}
24828c2ecf20Sopenharmony_ci
24838c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
24848c2ecf20Sopenharmony_ci		    "Setting driver ready signature\n");
24858c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->drv_rdy,
24868c2ecf20Sopenharmony_ci			      FIRMWARE_READY_PCIE)) {
24878c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
24888c2ecf20Sopenharmony_ci			    "Failed to write driver ready signature\n");
24898c2ecf20Sopenharmony_ci		return -1;
24908c2ecf20Sopenharmony_ci	}
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci	/* Wait for firmware initialization event */
24938c2ecf20Sopenharmony_ci	for (tries = 0; tries < poll_num; tries++) {
24948c2ecf20Sopenharmony_ci		if (mwifiex_read_reg(adapter, reg->fw_status,
24958c2ecf20Sopenharmony_ci				     &firmware_stat))
24968c2ecf20Sopenharmony_ci			ret = -1;
24978c2ecf20Sopenharmony_ci		else
24988c2ecf20Sopenharmony_ci			ret = 0;
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO, "Try %d if FW is ready <%d,%#x>",
25018c2ecf20Sopenharmony_ci			    tries, ret, firmware_stat);
25028c2ecf20Sopenharmony_ci
25038c2ecf20Sopenharmony_ci		if (ret)
25048c2ecf20Sopenharmony_ci			continue;
25058c2ecf20Sopenharmony_ci		if (firmware_stat == FIRMWARE_READY_PCIE) {
25068c2ecf20Sopenharmony_ci			ret = 0;
25078c2ecf20Sopenharmony_ci			break;
25088c2ecf20Sopenharmony_ci		} else {
25098c2ecf20Sopenharmony_ci			msleep(100);
25108c2ecf20Sopenharmony_ci			ret = -1;
25118c2ecf20Sopenharmony_ci		}
25128c2ecf20Sopenharmony_ci	}
25138c2ecf20Sopenharmony_ci
25148c2ecf20Sopenharmony_ci	return ret;
25158c2ecf20Sopenharmony_ci}
25168c2ecf20Sopenharmony_ci
25178c2ecf20Sopenharmony_ci/* This function checks if WLAN is the winner.
25188c2ecf20Sopenharmony_ci */
25198c2ecf20Sopenharmony_cistatic int
25208c2ecf20Sopenharmony_cimwifiex_check_winner_status(struct mwifiex_adapter *adapter)
25218c2ecf20Sopenharmony_ci{
25228c2ecf20Sopenharmony_ci	u32 winner = 0;
25238c2ecf20Sopenharmony_ci	int ret = 0;
25248c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
25258c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->fw_status, &winner)) {
25288c2ecf20Sopenharmony_ci		ret = -1;
25298c2ecf20Sopenharmony_ci	} else if (!winner) {
25308c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO, "PCI-E is the winner\n");
25318c2ecf20Sopenharmony_ci		adapter->winner = 1;
25328c2ecf20Sopenharmony_ci	} else {
25338c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
25348c2ecf20Sopenharmony_ci			    "PCI-E is not the winner <%#x>", winner);
25358c2ecf20Sopenharmony_ci	}
25368c2ecf20Sopenharmony_ci
25378c2ecf20Sopenharmony_ci	return ret;
25388c2ecf20Sopenharmony_ci}
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci/*
25418c2ecf20Sopenharmony_ci * This function reads the interrupt status from card.
25428c2ecf20Sopenharmony_ci */
25438c2ecf20Sopenharmony_cistatic void mwifiex_interrupt_status(struct mwifiex_adapter *adapter,
25448c2ecf20Sopenharmony_ci				     int msg_id)
25458c2ecf20Sopenharmony_ci{
25468c2ecf20Sopenharmony_ci	u32 pcie_ireg;
25478c2ecf20Sopenharmony_ci	unsigned long flags;
25488c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
25498c2ecf20Sopenharmony_ci
25508c2ecf20Sopenharmony_ci	if (card->msi_enable) {
25518c2ecf20Sopenharmony_ci		spin_lock_irqsave(&adapter->int_lock, flags);
25528c2ecf20Sopenharmony_ci		adapter->int_status = 1;
25538c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&adapter->int_lock, flags);
25548c2ecf20Sopenharmony_ci		return;
25558c2ecf20Sopenharmony_ci	}
25568c2ecf20Sopenharmony_ci
25578c2ecf20Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
25588c2ecf20Sopenharmony_ci		return;
25598c2ecf20Sopenharmony_ci
25608c2ecf20Sopenharmony_ci	if (card->msix_enable && msg_id >= 0) {
25618c2ecf20Sopenharmony_ci		pcie_ireg = BIT(msg_id);
25628c2ecf20Sopenharmony_ci	} else {
25638c2ecf20Sopenharmony_ci		if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
25648c2ecf20Sopenharmony_ci				     &pcie_ireg)) {
25658c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "Read register failed\n");
25668c2ecf20Sopenharmony_ci			return;
25678c2ecf20Sopenharmony_ci		}
25688c2ecf20Sopenharmony_ci
25698c2ecf20Sopenharmony_ci		if ((pcie_ireg == 0xFFFFFFFF) || !pcie_ireg)
25708c2ecf20Sopenharmony_ci			return;
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci
25738c2ecf20Sopenharmony_ci		mwifiex_pcie_disable_host_int(adapter);
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci		/* Clear the pending interrupts */
25768c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS,
25778c2ecf20Sopenharmony_ci				      ~pcie_ireg)) {
25788c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
25798c2ecf20Sopenharmony_ci				    "Write register failed\n");
25808c2ecf20Sopenharmony_ci			return;
25818c2ecf20Sopenharmony_ci		}
25828c2ecf20Sopenharmony_ci	}
25838c2ecf20Sopenharmony_ci
25848c2ecf20Sopenharmony_ci	if (!adapter->pps_uapsd_mode &&
25858c2ecf20Sopenharmony_ci	    adapter->ps_state == PS_STATE_SLEEP &&
25868c2ecf20Sopenharmony_ci	    mwifiex_pcie_ok_to_access_hw(adapter)) {
25878c2ecf20Sopenharmony_ci		/* Potentially for PCIe we could get other
25888c2ecf20Sopenharmony_ci		 * interrupts like shared. Don't change power
25898c2ecf20Sopenharmony_ci		 * state until cookie is set
25908c2ecf20Sopenharmony_ci		 */
25918c2ecf20Sopenharmony_ci		adapter->ps_state = PS_STATE_AWAKE;
25928c2ecf20Sopenharmony_ci		adapter->pm_wakeup_fw_try = false;
25938c2ecf20Sopenharmony_ci		del_timer(&adapter->wakeup_timer);
25948c2ecf20Sopenharmony_ci	}
25958c2ecf20Sopenharmony_ci
25968c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adapter->int_lock, flags);
25978c2ecf20Sopenharmony_ci	adapter->int_status |= pcie_ireg;
25988c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adapter->int_lock, flags);
25998c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg);
26008c2ecf20Sopenharmony_ci}
26018c2ecf20Sopenharmony_ci
26028c2ecf20Sopenharmony_ci/*
26038c2ecf20Sopenharmony_ci * Interrupt handler for PCIe root port
26048c2ecf20Sopenharmony_ci *
26058c2ecf20Sopenharmony_ci * This function reads the interrupt status from firmware and assigns
26068c2ecf20Sopenharmony_ci * the main process in workqueue which will handle the interrupt.
26078c2ecf20Sopenharmony_ci */
26088c2ecf20Sopenharmony_cistatic irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
26098c2ecf20Sopenharmony_ci{
26108c2ecf20Sopenharmony_ci	struct mwifiex_msix_context *ctx = context;
26118c2ecf20Sopenharmony_ci	struct pci_dev *pdev = ctx->dev;
26128c2ecf20Sopenharmony_ci	struct pcie_service_card *card;
26138c2ecf20Sopenharmony_ci	struct mwifiex_adapter *adapter;
26148c2ecf20Sopenharmony_ci
26158c2ecf20Sopenharmony_ci	card = pci_get_drvdata(pdev);
26168c2ecf20Sopenharmony_ci
26178c2ecf20Sopenharmony_ci	if (!card->adapter) {
26188c2ecf20Sopenharmony_ci		pr_err("info: %s: card=%p adapter=%p\n", __func__, card,
26198c2ecf20Sopenharmony_ci		       card ? card->adapter : NULL);
26208c2ecf20Sopenharmony_ci		goto exit;
26218c2ecf20Sopenharmony_ci	}
26228c2ecf20Sopenharmony_ci	adapter = card->adapter;
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags))
26258c2ecf20Sopenharmony_ci		goto exit;
26268c2ecf20Sopenharmony_ci
26278c2ecf20Sopenharmony_ci	if (card->msix_enable)
26288c2ecf20Sopenharmony_ci		mwifiex_interrupt_status(adapter, ctx->msg_id);
26298c2ecf20Sopenharmony_ci	else
26308c2ecf20Sopenharmony_ci		mwifiex_interrupt_status(adapter, -1);
26318c2ecf20Sopenharmony_ci
26328c2ecf20Sopenharmony_ci	mwifiex_queue_main_work(adapter);
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ciexit:
26358c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
26368c2ecf20Sopenharmony_ci}
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci/*
26398c2ecf20Sopenharmony_ci * This function checks the current interrupt status.
26408c2ecf20Sopenharmony_ci *
26418c2ecf20Sopenharmony_ci * The following interrupts are checked and handled by this function -
26428c2ecf20Sopenharmony_ci *      - Data sent
26438c2ecf20Sopenharmony_ci *      - Command sent
26448c2ecf20Sopenharmony_ci *      - Command received
26458c2ecf20Sopenharmony_ci *      - Packets received
26468c2ecf20Sopenharmony_ci *      - Events received
26478c2ecf20Sopenharmony_ci *
26488c2ecf20Sopenharmony_ci * In case of Rx packets received, the packets are uploaded from card to
26498c2ecf20Sopenharmony_ci * host and processed accordingly.
26508c2ecf20Sopenharmony_ci */
26518c2ecf20Sopenharmony_cistatic int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
26528c2ecf20Sopenharmony_ci{
26538c2ecf20Sopenharmony_ci	int ret;
26548c2ecf20Sopenharmony_ci	u32 pcie_ireg = 0;
26558c2ecf20Sopenharmony_ci	unsigned long flags;
26568c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
26578c2ecf20Sopenharmony_ci
26588c2ecf20Sopenharmony_ci	spin_lock_irqsave(&adapter->int_lock, flags);
26598c2ecf20Sopenharmony_ci	if (!card->msi_enable) {
26608c2ecf20Sopenharmony_ci		/* Clear out unused interrupts */
26618c2ecf20Sopenharmony_ci		pcie_ireg = adapter->int_status;
26628c2ecf20Sopenharmony_ci	}
26638c2ecf20Sopenharmony_ci	adapter->int_status = 0;
26648c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&adapter->int_lock, flags);
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	if (card->msi_enable) {
26678c2ecf20Sopenharmony_ci		if (mwifiex_pcie_ok_to_access_hw(adapter)) {
26688c2ecf20Sopenharmony_ci			if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
26698c2ecf20Sopenharmony_ci					     &pcie_ireg)) {
26708c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
26718c2ecf20Sopenharmony_ci					    "Read register failed\n");
26728c2ecf20Sopenharmony_ci				return -1;
26738c2ecf20Sopenharmony_ci			}
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_ci			if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
26768c2ecf20Sopenharmony_ci				if (mwifiex_write_reg(adapter,
26778c2ecf20Sopenharmony_ci						      PCIE_HOST_INT_STATUS,
26788c2ecf20Sopenharmony_ci						      ~pcie_ireg)) {
26798c2ecf20Sopenharmony_ci					mwifiex_dbg(adapter, ERROR,
26808c2ecf20Sopenharmony_ci						    "Write register failed\n");
26818c2ecf20Sopenharmony_ci					return -1;
26828c2ecf20Sopenharmony_ci				}
26838c2ecf20Sopenharmony_ci				if (!adapter->pps_uapsd_mode &&
26848c2ecf20Sopenharmony_ci				    adapter->ps_state == PS_STATE_SLEEP) {
26858c2ecf20Sopenharmony_ci					adapter->ps_state = PS_STATE_AWAKE;
26868c2ecf20Sopenharmony_ci					adapter->pm_wakeup_fw_try = false;
26878c2ecf20Sopenharmony_ci					del_timer(&adapter->wakeup_timer);
26888c2ecf20Sopenharmony_ci				}
26898c2ecf20Sopenharmony_ci			}
26908c2ecf20Sopenharmony_ci		}
26918c2ecf20Sopenharmony_ci	}
26928c2ecf20Sopenharmony_ci
26938c2ecf20Sopenharmony_ci	if (pcie_ireg & HOST_INTR_DNLD_DONE) {
26948c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INTR, "info: TX DNLD Done\n");
26958c2ecf20Sopenharmony_ci		ret = mwifiex_pcie_send_data_complete(adapter);
26968c2ecf20Sopenharmony_ci		if (ret)
26978c2ecf20Sopenharmony_ci			return ret;
26988c2ecf20Sopenharmony_ci	}
26998c2ecf20Sopenharmony_ci	if (pcie_ireg & HOST_INTR_UPLD_RDY) {
27008c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INTR, "info: Rx DATA\n");
27018c2ecf20Sopenharmony_ci		ret = mwifiex_pcie_process_recv_data(adapter);
27028c2ecf20Sopenharmony_ci		if (ret)
27038c2ecf20Sopenharmony_ci			return ret;
27048c2ecf20Sopenharmony_ci	}
27058c2ecf20Sopenharmony_ci	if (pcie_ireg & HOST_INTR_EVENT_RDY) {
27068c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INTR, "info: Rx EVENT\n");
27078c2ecf20Sopenharmony_ci		ret = mwifiex_pcie_process_event_ready(adapter);
27088c2ecf20Sopenharmony_ci		if (ret)
27098c2ecf20Sopenharmony_ci			return ret;
27108c2ecf20Sopenharmony_ci	}
27118c2ecf20Sopenharmony_ci	if (pcie_ireg & HOST_INTR_CMD_DONE) {
27128c2ecf20Sopenharmony_ci		if (adapter->cmd_sent) {
27138c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, INTR,
27148c2ecf20Sopenharmony_ci				    "info: CMD sent Interrupt\n");
27158c2ecf20Sopenharmony_ci			adapter->cmd_sent = false;
27168c2ecf20Sopenharmony_ci		}
27178c2ecf20Sopenharmony_ci		/* Handle command response */
27188c2ecf20Sopenharmony_ci		ret = mwifiex_pcie_process_cmd_complete(adapter);
27198c2ecf20Sopenharmony_ci		if (ret)
27208c2ecf20Sopenharmony_ci			return ret;
27218c2ecf20Sopenharmony_ci	}
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INTR,
27248c2ecf20Sopenharmony_ci		    "info: cmd_sent=%d data_sent=%d\n",
27258c2ecf20Sopenharmony_ci		    adapter->cmd_sent, adapter->data_sent);
27268c2ecf20Sopenharmony_ci	if (!card->msi_enable && !card->msix_enable &&
27278c2ecf20Sopenharmony_ci				 adapter->ps_state != PS_STATE_SLEEP)
27288c2ecf20Sopenharmony_ci		mwifiex_pcie_enable_host_int(adapter);
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci	return 0;
27318c2ecf20Sopenharmony_ci}
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci/*
27348c2ecf20Sopenharmony_ci * This function downloads data from driver to card.
27358c2ecf20Sopenharmony_ci *
27368c2ecf20Sopenharmony_ci * Both commands and data packets are transferred to the card by this
27378c2ecf20Sopenharmony_ci * function.
27388c2ecf20Sopenharmony_ci *
27398c2ecf20Sopenharmony_ci * This function adds the PCIE specific header to the front of the buffer
27408c2ecf20Sopenharmony_ci * before transferring. The header contains the length of the packet and
27418c2ecf20Sopenharmony_ci * the type. The firmware handles the packets based upon this set type.
27428c2ecf20Sopenharmony_ci */
27438c2ecf20Sopenharmony_cistatic int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
27448c2ecf20Sopenharmony_ci				     struct sk_buff *skb,
27458c2ecf20Sopenharmony_ci				     struct mwifiex_tx_param *tx_param)
27468c2ecf20Sopenharmony_ci{
27478c2ecf20Sopenharmony_ci	if (!skb) {
27488c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
27498c2ecf20Sopenharmony_ci			    "Passed NULL skb to %s\n", __func__);
27508c2ecf20Sopenharmony_ci		return -1;
27518c2ecf20Sopenharmony_ci	}
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	if (type == MWIFIEX_TYPE_DATA)
27548c2ecf20Sopenharmony_ci		return mwifiex_pcie_send_data(adapter, skb, tx_param);
27558c2ecf20Sopenharmony_ci	else if (type == MWIFIEX_TYPE_CMD)
27568c2ecf20Sopenharmony_ci		return mwifiex_pcie_send_cmd(adapter, skb);
27578c2ecf20Sopenharmony_ci
27588c2ecf20Sopenharmony_ci	return 0;
27598c2ecf20Sopenharmony_ci}
27608c2ecf20Sopenharmony_ci
27618c2ecf20Sopenharmony_ci/* Function to dump PCIE scratch registers in case of FW crash
27628c2ecf20Sopenharmony_ci */
27638c2ecf20Sopenharmony_cistatic int
27648c2ecf20Sopenharmony_cimwifiex_pcie_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf)
27658c2ecf20Sopenharmony_ci{
27668c2ecf20Sopenharmony_ci	char *p = drv_buf;
27678c2ecf20Sopenharmony_ci	char buf[256], *ptr;
27688c2ecf20Sopenharmony_ci	int i;
27698c2ecf20Sopenharmony_ci	u32 value;
27708c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
27718c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
27728c2ecf20Sopenharmony_ci	int pcie_scratch_reg[] = {PCIE_SCRATCH_12_REG,
27738c2ecf20Sopenharmony_ci				  PCIE_SCRATCH_14_REG,
27748c2ecf20Sopenharmony_ci				  PCIE_SCRATCH_15_REG};
27758c2ecf20Sopenharmony_ci
27768c2ecf20Sopenharmony_ci	if (!p)
27778c2ecf20Sopenharmony_ci		return 0;
27788c2ecf20Sopenharmony_ci
27798c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "PCIE register dump start\n");
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->fw_status, &value)) {
27828c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "failed to read firmware status");
27838c2ecf20Sopenharmony_ci		return 0;
27848c2ecf20Sopenharmony_ci	}
27858c2ecf20Sopenharmony_ci
27868c2ecf20Sopenharmony_ci	ptr = buf;
27878c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "pcie scratch register:");
27888c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcie_scratch_reg); i++) {
27898c2ecf20Sopenharmony_ci		mwifiex_read_reg(adapter, pcie_scratch_reg[i], &value);
27908c2ecf20Sopenharmony_ci		ptr += sprintf(ptr, "reg:0x%x, value=0x%x\n",
27918c2ecf20Sopenharmony_ci			       pcie_scratch_reg[i], value);
27928c2ecf20Sopenharmony_ci	}
27938c2ecf20Sopenharmony_ci
27948c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "%s\n", buf);
27958c2ecf20Sopenharmony_ci	p += sprintf(p, "%s\n", buf);
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "PCIE register dump end\n");
27988c2ecf20Sopenharmony_ci
27998c2ecf20Sopenharmony_ci	return p - drv_buf;
28008c2ecf20Sopenharmony_ci}
28018c2ecf20Sopenharmony_ci
28028c2ecf20Sopenharmony_ci/* This function read/write firmware */
28038c2ecf20Sopenharmony_cistatic enum rdwr_status
28048c2ecf20Sopenharmony_cimwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
28058c2ecf20Sopenharmony_ci{
28068c2ecf20Sopenharmony_ci	int ret, tries;
28078c2ecf20Sopenharmony_ci	u8 ctrl_data;
28088c2ecf20Sopenharmony_ci	u32 fw_status;
28098c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
28108c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status))
28138c2ecf20Sopenharmony_ci		return RDWR_STATUS_FAILURE;
28148c2ecf20Sopenharmony_ci
28158c2ecf20Sopenharmony_ci	ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
28168c2ecf20Sopenharmony_ci				reg->fw_dump_host_ready);
28178c2ecf20Sopenharmony_ci	if (ret) {
28188c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
28198c2ecf20Sopenharmony_ci			    "PCIE write err\n");
28208c2ecf20Sopenharmony_ci		return RDWR_STATUS_FAILURE;
28218c2ecf20Sopenharmony_ci	}
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
28248c2ecf20Sopenharmony_ci		mwifiex_read_reg_byte(adapter, reg->fw_dump_ctrl, &ctrl_data);
28258c2ecf20Sopenharmony_ci		if (ctrl_data == FW_DUMP_DONE)
28268c2ecf20Sopenharmony_ci			return RDWR_STATUS_SUCCESS;
28278c2ecf20Sopenharmony_ci		if (doneflag && ctrl_data == doneflag)
28288c2ecf20Sopenharmony_ci			return RDWR_STATUS_DONE;
28298c2ecf20Sopenharmony_ci		if (ctrl_data != reg->fw_dump_host_ready) {
28308c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, WARN,
28318c2ecf20Sopenharmony_ci				    "The ctrl reg was changed, re-try again!\n");
28328c2ecf20Sopenharmony_ci			ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
28338c2ecf20Sopenharmony_ci						reg->fw_dump_host_ready);
28348c2ecf20Sopenharmony_ci			if (ret) {
28358c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
28368c2ecf20Sopenharmony_ci					    "PCIE write err\n");
28378c2ecf20Sopenharmony_ci				return RDWR_STATUS_FAILURE;
28388c2ecf20Sopenharmony_ci			}
28398c2ecf20Sopenharmony_ci		}
28408c2ecf20Sopenharmony_ci		usleep_range(100, 200);
28418c2ecf20Sopenharmony_ci	}
28428c2ecf20Sopenharmony_ci
28438c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, ERROR, "Fail to pull ctrl_data\n");
28448c2ecf20Sopenharmony_ci	return RDWR_STATUS_FAILURE;
28458c2ecf20Sopenharmony_ci}
28468c2ecf20Sopenharmony_ci
28478c2ecf20Sopenharmony_ci/* This function dump firmware memory to file */
28488c2ecf20Sopenharmony_cistatic void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
28498c2ecf20Sopenharmony_ci{
28508c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
28518c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *creg = card->pcie.reg;
28528c2ecf20Sopenharmony_ci	unsigned int reg, reg_start, reg_end;
28538c2ecf20Sopenharmony_ci	u8 *dbg_ptr, *end_ptr, *tmp_ptr, fw_dump_num, dump_num;
28548c2ecf20Sopenharmony_ci	u8 idx, i, read_reg, doneflag = 0;
28558c2ecf20Sopenharmony_ci	enum rdwr_status stat;
28568c2ecf20Sopenharmony_ci	u32 memory_size;
28578c2ecf20Sopenharmony_ci	int ret;
28588c2ecf20Sopenharmony_ci
28598c2ecf20Sopenharmony_ci	if (!card->pcie.can_dump_fw)
28608c2ecf20Sopenharmony_ci		return;
28618c2ecf20Sopenharmony_ci
28628c2ecf20Sopenharmony_ci	for (idx = 0; idx < adapter->num_mem_types; idx++) {
28638c2ecf20Sopenharmony_ci		struct memory_type_mapping *entry =
28648c2ecf20Sopenharmony_ci				&adapter->mem_type_mapping_tbl[idx];
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci		if (entry->mem_ptr) {
28678c2ecf20Sopenharmony_ci			vfree(entry->mem_ptr);
28688c2ecf20Sopenharmony_ci			entry->mem_ptr = NULL;
28698c2ecf20Sopenharmony_ci		}
28708c2ecf20Sopenharmony_ci		entry->mem_size = 0;
28718c2ecf20Sopenharmony_ci	}
28728c2ecf20Sopenharmony_ci
28738c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n");
28748c2ecf20Sopenharmony_ci
28758c2ecf20Sopenharmony_ci	/* Read the number of the memories which will dump */
28768c2ecf20Sopenharmony_ci	stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
28778c2ecf20Sopenharmony_ci	if (stat == RDWR_STATUS_FAILURE)
28788c2ecf20Sopenharmony_ci		return;
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	reg = creg->fw_dump_start;
28818c2ecf20Sopenharmony_ci	mwifiex_read_reg_byte(adapter, reg, &fw_dump_num);
28828c2ecf20Sopenharmony_ci
28838c2ecf20Sopenharmony_ci	/* W8997 chipset firmware dump will be restore in single region*/
28848c2ecf20Sopenharmony_ci	if (fw_dump_num == 0)
28858c2ecf20Sopenharmony_ci		dump_num = 1;
28868c2ecf20Sopenharmony_ci	else
28878c2ecf20Sopenharmony_ci		dump_num = fw_dump_num;
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	/* Read the length of every memory which will dump */
28908c2ecf20Sopenharmony_ci	for (idx = 0; idx < dump_num; idx++) {
28918c2ecf20Sopenharmony_ci		struct memory_type_mapping *entry =
28928c2ecf20Sopenharmony_ci				&adapter->mem_type_mapping_tbl[idx];
28938c2ecf20Sopenharmony_ci		memory_size = 0;
28948c2ecf20Sopenharmony_ci		if (fw_dump_num != 0) {
28958c2ecf20Sopenharmony_ci			stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
28968c2ecf20Sopenharmony_ci			if (stat == RDWR_STATUS_FAILURE)
28978c2ecf20Sopenharmony_ci				return;
28988c2ecf20Sopenharmony_ci
28998c2ecf20Sopenharmony_ci			reg = creg->fw_dump_start;
29008c2ecf20Sopenharmony_ci			for (i = 0; i < 4; i++) {
29018c2ecf20Sopenharmony_ci				mwifiex_read_reg_byte(adapter, reg, &read_reg);
29028c2ecf20Sopenharmony_ci				memory_size |= (read_reg << (i * 8));
29038c2ecf20Sopenharmony_ci				reg++;
29048c2ecf20Sopenharmony_ci			}
29058c2ecf20Sopenharmony_ci		} else {
29068c2ecf20Sopenharmony_ci			memory_size = MWIFIEX_FW_DUMP_MAX_MEMSIZE;
29078c2ecf20Sopenharmony_ci		}
29088c2ecf20Sopenharmony_ci
29098c2ecf20Sopenharmony_ci		if (memory_size == 0) {
29108c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, MSG, "Firmware dump Finished!\n");
29118c2ecf20Sopenharmony_ci			ret = mwifiex_write_reg(adapter, creg->fw_dump_ctrl,
29128c2ecf20Sopenharmony_ci						creg->fw_dump_read_done);
29138c2ecf20Sopenharmony_ci			if (ret) {
29148c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR, "PCIE write err\n");
29158c2ecf20Sopenharmony_ci				return;
29168c2ecf20Sopenharmony_ci			}
29178c2ecf20Sopenharmony_ci			break;
29188c2ecf20Sopenharmony_ci		}
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, DUMP,
29218c2ecf20Sopenharmony_ci			    "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
29228c2ecf20Sopenharmony_ci		entry->mem_ptr = vmalloc(memory_size + 1);
29238c2ecf20Sopenharmony_ci		entry->mem_size = memory_size;
29248c2ecf20Sopenharmony_ci		if (!entry->mem_ptr) {
29258c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
29268c2ecf20Sopenharmony_ci				    "Vmalloc %s failed\n", entry->mem_name);
29278c2ecf20Sopenharmony_ci			return;
29288c2ecf20Sopenharmony_ci		}
29298c2ecf20Sopenharmony_ci		dbg_ptr = entry->mem_ptr;
29308c2ecf20Sopenharmony_ci		end_ptr = dbg_ptr + memory_size;
29318c2ecf20Sopenharmony_ci
29328c2ecf20Sopenharmony_ci		doneflag = entry->done_flag;
29338c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, DUMP, "Start %s output, please wait...\n",
29348c2ecf20Sopenharmony_ci			    entry->mem_name);
29358c2ecf20Sopenharmony_ci
29368c2ecf20Sopenharmony_ci		do {
29378c2ecf20Sopenharmony_ci			stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
29388c2ecf20Sopenharmony_ci			if (RDWR_STATUS_FAILURE == stat)
29398c2ecf20Sopenharmony_ci				return;
29408c2ecf20Sopenharmony_ci
29418c2ecf20Sopenharmony_ci			reg_start = creg->fw_dump_start;
29428c2ecf20Sopenharmony_ci			reg_end = creg->fw_dump_end;
29438c2ecf20Sopenharmony_ci			for (reg = reg_start; reg <= reg_end; reg++) {
29448c2ecf20Sopenharmony_ci				mwifiex_read_reg_byte(adapter, reg, dbg_ptr);
29458c2ecf20Sopenharmony_ci				if (dbg_ptr < end_ptr) {
29468c2ecf20Sopenharmony_ci					dbg_ptr++;
29478c2ecf20Sopenharmony_ci					continue;
29488c2ecf20Sopenharmony_ci				}
29498c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
29508c2ecf20Sopenharmony_ci					    "pre-allocated buf not enough\n");
29518c2ecf20Sopenharmony_ci				tmp_ptr =
29528c2ecf20Sopenharmony_ci					vzalloc(memory_size + MWIFIEX_SIZE_4K);
29538c2ecf20Sopenharmony_ci				if (!tmp_ptr)
29548c2ecf20Sopenharmony_ci					return;
29558c2ecf20Sopenharmony_ci				memcpy(tmp_ptr, entry->mem_ptr, memory_size);
29568c2ecf20Sopenharmony_ci				vfree(entry->mem_ptr);
29578c2ecf20Sopenharmony_ci				entry->mem_ptr = tmp_ptr;
29588c2ecf20Sopenharmony_ci				tmp_ptr = NULL;
29598c2ecf20Sopenharmony_ci				dbg_ptr = entry->mem_ptr + memory_size;
29608c2ecf20Sopenharmony_ci				memory_size += MWIFIEX_SIZE_4K;
29618c2ecf20Sopenharmony_ci				end_ptr = entry->mem_ptr + memory_size;
29628c2ecf20Sopenharmony_ci			}
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci			if (stat != RDWR_STATUS_DONE)
29658c2ecf20Sopenharmony_ci				continue;
29668c2ecf20Sopenharmony_ci
29678c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, DUMP,
29688c2ecf20Sopenharmony_ci				    "%s done: size=0x%tx\n",
29698c2ecf20Sopenharmony_ci				    entry->mem_name, dbg_ptr - entry->mem_ptr);
29708c2ecf20Sopenharmony_ci			break;
29718c2ecf20Sopenharmony_ci		} while (true);
29728c2ecf20Sopenharmony_ci	}
29738c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
29748c2ecf20Sopenharmony_ci}
29758c2ecf20Sopenharmony_ci
29768c2ecf20Sopenharmony_cistatic void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
29778c2ecf20Sopenharmony_ci{
29788c2ecf20Sopenharmony_ci	adapter->devdump_data = vzalloc(MWIFIEX_FW_DUMP_SIZE);
29798c2ecf20Sopenharmony_ci	if (!adapter->devdump_data) {
29808c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
29818c2ecf20Sopenharmony_ci			    "vzalloc devdump data failure!\n");
29828c2ecf20Sopenharmony_ci		return;
29838c2ecf20Sopenharmony_ci	}
29848c2ecf20Sopenharmony_ci
29858c2ecf20Sopenharmony_ci	mwifiex_drv_info_dump(adapter);
29868c2ecf20Sopenharmony_ci	mwifiex_pcie_fw_dump(adapter);
29878c2ecf20Sopenharmony_ci	mwifiex_prepare_fw_dump_info(adapter);
29888c2ecf20Sopenharmony_ci	mwifiex_upload_device_dump(adapter);
29898c2ecf20Sopenharmony_ci}
29908c2ecf20Sopenharmony_ci
29918c2ecf20Sopenharmony_cistatic void mwifiex_pcie_card_reset_work(struct mwifiex_adapter *adapter)
29928c2ecf20Sopenharmony_ci{
29938c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
29948c2ecf20Sopenharmony_ci
29958c2ecf20Sopenharmony_ci	/* We can't afford to wait here; remove() might be waiting on us. If we
29968c2ecf20Sopenharmony_ci	 * can't grab the device lock, maybe we'll get another chance later.
29978c2ecf20Sopenharmony_ci	 */
29988c2ecf20Sopenharmony_ci	pci_try_reset_function(card->dev);
29998c2ecf20Sopenharmony_ci}
30008c2ecf20Sopenharmony_ci
30018c2ecf20Sopenharmony_cistatic void mwifiex_pcie_work(struct work_struct *work)
30028c2ecf20Sopenharmony_ci{
30038c2ecf20Sopenharmony_ci	struct pcie_service_card *card =
30048c2ecf20Sopenharmony_ci		container_of(work, struct pcie_service_card, work);
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_ci	if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
30078c2ecf20Sopenharmony_ci			       &card->work_flags))
30088c2ecf20Sopenharmony_ci		mwifiex_pcie_device_dump_work(card->adapter);
30098c2ecf20Sopenharmony_ci	if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET,
30108c2ecf20Sopenharmony_ci			       &card->work_flags))
30118c2ecf20Sopenharmony_ci		mwifiex_pcie_card_reset_work(card->adapter);
30128c2ecf20Sopenharmony_ci}
30138c2ecf20Sopenharmony_ci
30148c2ecf20Sopenharmony_ci/* This function dumps FW information */
30158c2ecf20Sopenharmony_cistatic void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter)
30168c2ecf20Sopenharmony_ci{
30178c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
30188c2ecf20Sopenharmony_ci
30198c2ecf20Sopenharmony_ci	if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
30208c2ecf20Sopenharmony_ci			      &card->work_flags))
30218c2ecf20Sopenharmony_ci		schedule_work(&card->work);
30228c2ecf20Sopenharmony_ci}
30238c2ecf20Sopenharmony_ci
30248c2ecf20Sopenharmony_cistatic void mwifiex_pcie_card_reset(struct mwifiex_adapter *adapter)
30258c2ecf20Sopenharmony_ci{
30268c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
30278c2ecf20Sopenharmony_ci
30288c2ecf20Sopenharmony_ci	if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags))
30298c2ecf20Sopenharmony_ci		schedule_work(&card->work);
30308c2ecf20Sopenharmony_ci}
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_cistatic int mwifiex_pcie_alloc_buffers(struct mwifiex_adapter *adapter)
30338c2ecf20Sopenharmony_ci{
30348c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
30358c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
30368c2ecf20Sopenharmony_ci	int ret;
30378c2ecf20Sopenharmony_ci
30388c2ecf20Sopenharmony_ci	card->cmdrsp_buf = NULL;
30398c2ecf20Sopenharmony_ci	ret = mwifiex_pcie_create_txbd_ring(adapter);
30408c2ecf20Sopenharmony_ci	if (ret) {
30418c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n");
30428c2ecf20Sopenharmony_ci		goto err_cre_txbd;
30438c2ecf20Sopenharmony_ci	}
30448c2ecf20Sopenharmony_ci
30458c2ecf20Sopenharmony_ci	ret = mwifiex_pcie_create_rxbd_ring(adapter);
30468c2ecf20Sopenharmony_ci	if (ret) {
30478c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n");
30488c2ecf20Sopenharmony_ci		goto err_cre_rxbd;
30498c2ecf20Sopenharmony_ci	}
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci	ret = mwifiex_pcie_create_evtbd_ring(adapter);
30528c2ecf20Sopenharmony_ci	if (ret) {
30538c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n");
30548c2ecf20Sopenharmony_ci		goto err_cre_evtbd;
30558c2ecf20Sopenharmony_ci	}
30568c2ecf20Sopenharmony_ci
30578c2ecf20Sopenharmony_ci	ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
30588c2ecf20Sopenharmony_ci	if (ret) {
30598c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n");
30608c2ecf20Sopenharmony_ci		goto err_alloc_cmdbuf;
30618c2ecf20Sopenharmony_ci	}
30628c2ecf20Sopenharmony_ci
30638c2ecf20Sopenharmony_ci	if (reg->sleep_cookie) {
30648c2ecf20Sopenharmony_ci		ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
30658c2ecf20Sopenharmony_ci		if (ret) {
30668c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n");
30678c2ecf20Sopenharmony_ci			goto err_alloc_cookie;
30688c2ecf20Sopenharmony_ci		}
30698c2ecf20Sopenharmony_ci	} else {
30708c2ecf20Sopenharmony_ci		card->sleep_cookie_vbase = NULL;
30718c2ecf20Sopenharmony_ci	}
30728c2ecf20Sopenharmony_ci
30738c2ecf20Sopenharmony_ci	return 0;
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_cierr_alloc_cookie:
30768c2ecf20Sopenharmony_ci	mwifiex_pcie_delete_cmdrsp_buf(adapter);
30778c2ecf20Sopenharmony_cierr_alloc_cmdbuf:
30788c2ecf20Sopenharmony_ci	mwifiex_pcie_delete_evtbd_ring(adapter);
30798c2ecf20Sopenharmony_cierr_cre_evtbd:
30808c2ecf20Sopenharmony_ci	mwifiex_pcie_delete_rxbd_ring(adapter);
30818c2ecf20Sopenharmony_cierr_cre_rxbd:
30828c2ecf20Sopenharmony_ci	mwifiex_pcie_delete_txbd_ring(adapter);
30838c2ecf20Sopenharmony_cierr_cre_txbd:
30848c2ecf20Sopenharmony_ci	return ret;
30858c2ecf20Sopenharmony_ci}
30868c2ecf20Sopenharmony_ci
30878c2ecf20Sopenharmony_cistatic void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter)
30888c2ecf20Sopenharmony_ci{
30898c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
30908c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci	if (reg->sleep_cookie)
30938c2ecf20Sopenharmony_ci		mwifiex_pcie_delete_sleep_cookie_buf(adapter);
30948c2ecf20Sopenharmony_ci
30958c2ecf20Sopenharmony_ci	mwifiex_pcie_delete_cmdrsp_buf(adapter);
30968c2ecf20Sopenharmony_ci	mwifiex_pcie_delete_evtbd_ring(adapter);
30978c2ecf20Sopenharmony_ci	mwifiex_pcie_delete_rxbd_ring(adapter);
30988c2ecf20Sopenharmony_ci	mwifiex_pcie_delete_txbd_ring(adapter);
30998c2ecf20Sopenharmony_ci}
31008c2ecf20Sopenharmony_ci
31018c2ecf20Sopenharmony_ci/*
31028c2ecf20Sopenharmony_ci * This function initializes the PCI-E host memory space, WCB rings, etc.
31038c2ecf20Sopenharmony_ci */
31048c2ecf20Sopenharmony_cistatic int mwifiex_init_pcie(struct mwifiex_adapter *adapter)
31058c2ecf20Sopenharmony_ci{
31068c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
31078c2ecf20Sopenharmony_ci	int ret;
31088c2ecf20Sopenharmony_ci	struct pci_dev *pdev = card->dev;
31098c2ecf20Sopenharmony_ci
31108c2ecf20Sopenharmony_ci	pci_set_drvdata(pdev, card);
31118c2ecf20Sopenharmony_ci
31128c2ecf20Sopenharmony_ci	ret = pci_enable_device(pdev);
31138c2ecf20Sopenharmony_ci	if (ret)
31148c2ecf20Sopenharmony_ci		goto err_enable_dev;
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	pci_set_master(pdev);
31178c2ecf20Sopenharmony_ci
31188c2ecf20Sopenharmony_ci	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
31198c2ecf20Sopenharmony_ci	if (ret) {
31208c2ecf20Sopenharmony_ci		pr_err("dma_set_mask(32) failed: %d\n", ret);
31218c2ecf20Sopenharmony_ci		goto err_set_dma_mask;
31228c2ecf20Sopenharmony_ci	}
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	ret = pci_request_region(pdev, 0, DRV_NAME);
31258c2ecf20Sopenharmony_ci	if (ret) {
31268c2ecf20Sopenharmony_ci		pr_err("req_reg(0) error\n");
31278c2ecf20Sopenharmony_ci		goto err_req_region0;
31288c2ecf20Sopenharmony_ci	}
31298c2ecf20Sopenharmony_ci	card->pci_mmap = pci_iomap(pdev, 0, 0);
31308c2ecf20Sopenharmony_ci	if (!card->pci_mmap) {
31318c2ecf20Sopenharmony_ci		pr_err("iomap(0) error\n");
31328c2ecf20Sopenharmony_ci		ret = -EIO;
31338c2ecf20Sopenharmony_ci		goto err_iomap0;
31348c2ecf20Sopenharmony_ci	}
31358c2ecf20Sopenharmony_ci	ret = pci_request_region(pdev, 2, DRV_NAME);
31368c2ecf20Sopenharmony_ci	if (ret) {
31378c2ecf20Sopenharmony_ci		pr_err("req_reg(2) error\n");
31388c2ecf20Sopenharmony_ci		goto err_req_region2;
31398c2ecf20Sopenharmony_ci	}
31408c2ecf20Sopenharmony_ci	card->pci_mmap1 = pci_iomap(pdev, 2, 0);
31418c2ecf20Sopenharmony_ci	if (!card->pci_mmap1) {
31428c2ecf20Sopenharmony_ci		pr_err("iomap(2) error\n");
31438c2ecf20Sopenharmony_ci		ret = -EIO;
31448c2ecf20Sopenharmony_ci		goto err_iomap2;
31458c2ecf20Sopenharmony_ci	}
31468c2ecf20Sopenharmony_ci
31478c2ecf20Sopenharmony_ci	pr_notice("PCI memory map Virt0: %pK PCI memory map Virt2: %pK\n",
31488c2ecf20Sopenharmony_ci		  card->pci_mmap, card->pci_mmap1);
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_ci	ret = mwifiex_pcie_alloc_buffers(adapter);
31518c2ecf20Sopenharmony_ci	if (ret)
31528c2ecf20Sopenharmony_ci		goto err_alloc_buffers;
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	if (pdev->device == PCIE_DEVICE_ID_MARVELL_88W8897)
31558c2ecf20Sopenharmony_ci		adapter->ignore_btcoex_events = true;
31568c2ecf20Sopenharmony_ci
31578c2ecf20Sopenharmony_ci	return 0;
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_cierr_alloc_buffers:
31608c2ecf20Sopenharmony_ci	pci_iounmap(pdev, card->pci_mmap1);
31618c2ecf20Sopenharmony_cierr_iomap2:
31628c2ecf20Sopenharmony_ci	pci_release_region(pdev, 2);
31638c2ecf20Sopenharmony_cierr_req_region2:
31648c2ecf20Sopenharmony_ci	pci_iounmap(pdev, card->pci_mmap);
31658c2ecf20Sopenharmony_cierr_iomap0:
31668c2ecf20Sopenharmony_ci	pci_release_region(pdev, 0);
31678c2ecf20Sopenharmony_cierr_req_region0:
31688c2ecf20Sopenharmony_cierr_set_dma_mask:
31698c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
31708c2ecf20Sopenharmony_cierr_enable_dev:
31718c2ecf20Sopenharmony_ci	return ret;
31728c2ecf20Sopenharmony_ci}
31738c2ecf20Sopenharmony_ci
31748c2ecf20Sopenharmony_ci/*
31758c2ecf20Sopenharmony_ci * This function cleans up the allocated card buffers.
31768c2ecf20Sopenharmony_ci */
31778c2ecf20Sopenharmony_cistatic void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter)
31788c2ecf20Sopenharmony_ci{
31798c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
31808c2ecf20Sopenharmony_ci	struct pci_dev *pdev = card->dev;
31818c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
31828c2ecf20Sopenharmony_ci	int ret;
31838c2ecf20Sopenharmony_ci	u32 fw_status;
31848c2ecf20Sopenharmony_ci
31858c2ecf20Sopenharmony_ci	/* Perform the cancel_work_sync() only when we're not resetting
31868c2ecf20Sopenharmony_ci	 * the card. It's because that function never returns if we're
31878c2ecf20Sopenharmony_ci	 * in reset path. If we're here when resetting the card, it means
31888c2ecf20Sopenharmony_ci	 * that we failed to reset the card (reset failure path).
31898c2ecf20Sopenharmony_ci	 */
31908c2ecf20Sopenharmony_ci	if (!card->pci_reset_ongoing) {
31918c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, MSG, "performing cancel_work_sync()...\n");
31928c2ecf20Sopenharmony_ci		cancel_work_sync(&card->work);
31938c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, MSG, "cancel_work_sync() done\n");
31948c2ecf20Sopenharmony_ci	} else {
31958c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, MSG,
31968c2ecf20Sopenharmony_ci			    "skipped cancel_work_sync() because we're in card reset failure path\n");
31978c2ecf20Sopenharmony_ci	}
31988c2ecf20Sopenharmony_ci
31998c2ecf20Sopenharmony_ci	ret = mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
32008c2ecf20Sopenharmony_ci	if (fw_status == FIRMWARE_READY_PCIE) {
32018c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
32028c2ecf20Sopenharmony_ci			    "Clearing driver ready signature\n");
32038c2ecf20Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
32048c2ecf20Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
32058c2ecf20Sopenharmony_ci				    "Failed to write driver not-ready signature\n");
32068c2ecf20Sopenharmony_ci	}
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_ci	pci_disable_device(pdev);
32098c2ecf20Sopenharmony_ci
32108c2ecf20Sopenharmony_ci	pci_iounmap(pdev, card->pci_mmap);
32118c2ecf20Sopenharmony_ci	pci_iounmap(pdev, card->pci_mmap1);
32128c2ecf20Sopenharmony_ci	pci_release_region(pdev, 2);
32138c2ecf20Sopenharmony_ci	pci_release_region(pdev, 0);
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	mwifiex_pcie_free_buffers(adapter);
32168c2ecf20Sopenharmony_ci}
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_cistatic int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
32198c2ecf20Sopenharmony_ci{
32208c2ecf20Sopenharmony_ci	int ret, i, j;
32218c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
32228c2ecf20Sopenharmony_ci	struct pci_dev *pdev = card->dev;
32238c2ecf20Sopenharmony_ci
32248c2ecf20Sopenharmony_ci	if (card->pcie.reg->msix_support) {
32258c2ecf20Sopenharmony_ci		for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
32268c2ecf20Sopenharmony_ci			card->msix_entries[i].entry = i;
32278c2ecf20Sopenharmony_ci		ret = pci_enable_msix_exact(pdev, card->msix_entries,
32288c2ecf20Sopenharmony_ci					    MWIFIEX_NUM_MSIX_VECTORS);
32298c2ecf20Sopenharmony_ci		if (!ret) {
32308c2ecf20Sopenharmony_ci			for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) {
32318c2ecf20Sopenharmony_ci				card->msix_ctx[i].dev = pdev;
32328c2ecf20Sopenharmony_ci				card->msix_ctx[i].msg_id = i;
32338c2ecf20Sopenharmony_ci
32348c2ecf20Sopenharmony_ci				ret = request_irq(card->msix_entries[i].vector,
32358c2ecf20Sopenharmony_ci						  mwifiex_pcie_interrupt, 0,
32368c2ecf20Sopenharmony_ci						  "MWIFIEX_PCIE_MSIX",
32378c2ecf20Sopenharmony_ci						  &card->msix_ctx[i]);
32388c2ecf20Sopenharmony_ci				if (ret)
32398c2ecf20Sopenharmony_ci					break;
32408c2ecf20Sopenharmony_ci			}
32418c2ecf20Sopenharmony_ci
32428c2ecf20Sopenharmony_ci			if (ret) {
32438c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, INFO, "request_irq fail: %d\n",
32448c2ecf20Sopenharmony_ci					    ret);
32458c2ecf20Sopenharmony_ci				for (j = 0; j < i; j++)
32468c2ecf20Sopenharmony_ci					free_irq(card->msix_entries[j].vector,
32478c2ecf20Sopenharmony_ci						 &card->msix_ctx[i]);
32488c2ecf20Sopenharmony_ci				pci_disable_msix(pdev);
32498c2ecf20Sopenharmony_ci			} else {
32508c2ecf20Sopenharmony_ci				mwifiex_dbg(adapter, MSG, "MSIx enabled!");
32518c2ecf20Sopenharmony_ci				card->msix_enable = 1;
32528c2ecf20Sopenharmony_ci				return 0;
32538c2ecf20Sopenharmony_ci			}
32548c2ecf20Sopenharmony_ci		}
32558c2ecf20Sopenharmony_ci	}
32568c2ecf20Sopenharmony_ci
32578c2ecf20Sopenharmony_ci	if (pci_enable_msi(pdev) != 0)
32588c2ecf20Sopenharmony_ci		pci_disable_msi(pdev);
32598c2ecf20Sopenharmony_ci	else
32608c2ecf20Sopenharmony_ci		card->msi_enable = 1;
32618c2ecf20Sopenharmony_ci
32628c2ecf20Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "msi_enable = %d\n", card->msi_enable);
32638c2ecf20Sopenharmony_ci
32648c2ecf20Sopenharmony_ci	card->share_irq_ctx.dev = pdev;
32658c2ecf20Sopenharmony_ci	card->share_irq_ctx.msg_id = -1;
32668c2ecf20Sopenharmony_ci	ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
32678c2ecf20Sopenharmony_ci			  "MRVL_PCIE", &card->share_irq_ctx);
32688c2ecf20Sopenharmony_ci	if (ret) {
32698c2ecf20Sopenharmony_ci		pr_err("request_irq failed: ret=%d\n", ret);
32708c2ecf20Sopenharmony_ci		return -1;
32718c2ecf20Sopenharmony_ci	}
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	return 0;
32748c2ecf20Sopenharmony_ci}
32758c2ecf20Sopenharmony_ci
32768c2ecf20Sopenharmony_ci/*
32778c2ecf20Sopenharmony_ci * This function gets the firmware name for downloading by revision id
32788c2ecf20Sopenharmony_ci *
32798c2ecf20Sopenharmony_ci * Read revision id register to get revision id
32808c2ecf20Sopenharmony_ci */
32818c2ecf20Sopenharmony_cistatic void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter)
32828c2ecf20Sopenharmony_ci{
32838c2ecf20Sopenharmony_ci	int revision_id = 0;
32848c2ecf20Sopenharmony_ci	int version, magic;
32858c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
32868c2ecf20Sopenharmony_ci
32878c2ecf20Sopenharmony_ci	switch (card->dev->device) {
32888c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_MARVELL_88W8766P:
32898c2ecf20Sopenharmony_ci		strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME);
32908c2ecf20Sopenharmony_ci		break;
32918c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_MARVELL_88W8897:
32928c2ecf20Sopenharmony_ci		mwifiex_write_reg(adapter, 0x0c58, 0x80c00000);
32938c2ecf20Sopenharmony_ci		mwifiex_read_reg(adapter, 0x0c58, &revision_id);
32948c2ecf20Sopenharmony_ci		revision_id &= 0xff00;
32958c2ecf20Sopenharmony_ci		switch (revision_id) {
32968c2ecf20Sopenharmony_ci		case PCIE8897_A0:
32978c2ecf20Sopenharmony_ci			strcpy(adapter->fw_name, PCIE8897_A0_FW_NAME);
32988c2ecf20Sopenharmony_ci			break;
32998c2ecf20Sopenharmony_ci		case PCIE8897_B0:
33008c2ecf20Sopenharmony_ci			strcpy(adapter->fw_name, PCIE8897_B0_FW_NAME);
33018c2ecf20Sopenharmony_ci			break;
33028c2ecf20Sopenharmony_ci		default:
33038c2ecf20Sopenharmony_ci			strcpy(adapter->fw_name, PCIE8897_DEFAULT_FW_NAME);
33048c2ecf20Sopenharmony_ci
33058c2ecf20Sopenharmony_ci			break;
33068c2ecf20Sopenharmony_ci		}
33078c2ecf20Sopenharmony_ci		break;
33088c2ecf20Sopenharmony_ci	case PCIE_DEVICE_ID_MARVELL_88W8997:
33098c2ecf20Sopenharmony_ci		mwifiex_read_reg(adapter, 0x8, &revision_id);
33108c2ecf20Sopenharmony_ci		mwifiex_read_reg(adapter, 0x0cd0, &version);
33118c2ecf20Sopenharmony_ci		mwifiex_read_reg(adapter, 0x0cd4, &magic);
33128c2ecf20Sopenharmony_ci		revision_id &= 0xff;
33138c2ecf20Sopenharmony_ci		version &= 0x7;
33148c2ecf20Sopenharmony_ci		magic &= 0xff;
33158c2ecf20Sopenharmony_ci		if (revision_id == PCIE8997_A1 &&
33168c2ecf20Sopenharmony_ci		    magic == CHIP_MAGIC_VALUE &&
33178c2ecf20Sopenharmony_ci		    version == CHIP_VER_PCIEUART)
33188c2ecf20Sopenharmony_ci			strcpy(adapter->fw_name, PCIEUART8997_FW_NAME_V4);
33198c2ecf20Sopenharmony_ci		else
33208c2ecf20Sopenharmony_ci			strcpy(adapter->fw_name, PCIEUSB8997_FW_NAME_V4);
33218c2ecf20Sopenharmony_ci		break;
33228c2ecf20Sopenharmony_ci	default:
33238c2ecf20Sopenharmony_ci		break;
33248c2ecf20Sopenharmony_ci	}
33258c2ecf20Sopenharmony_ci}
33268c2ecf20Sopenharmony_ci
33278c2ecf20Sopenharmony_ci/*
33288c2ecf20Sopenharmony_ci * This function registers the PCIE device.
33298c2ecf20Sopenharmony_ci *
33308c2ecf20Sopenharmony_ci * PCIE IRQ is claimed, block size is set and driver data is initialized.
33318c2ecf20Sopenharmony_ci */
33328c2ecf20Sopenharmony_cistatic int mwifiex_register_dev(struct mwifiex_adapter *adapter)
33338c2ecf20Sopenharmony_ci{
33348c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
33358c2ecf20Sopenharmony_ci
33368c2ecf20Sopenharmony_ci	/* save adapter pointer in card */
33378c2ecf20Sopenharmony_ci	card->adapter = adapter;
33388c2ecf20Sopenharmony_ci
33398c2ecf20Sopenharmony_ci	if (mwifiex_pcie_request_irq(adapter))
33408c2ecf20Sopenharmony_ci		return -1;
33418c2ecf20Sopenharmony_ci
33428c2ecf20Sopenharmony_ci	adapter->tx_buf_size = card->pcie.tx_buf_size;
33438c2ecf20Sopenharmony_ci	adapter->mem_type_mapping_tbl = card->pcie.mem_type_mapping_tbl;
33448c2ecf20Sopenharmony_ci	adapter->num_mem_types = card->pcie.num_mem_types;
33458c2ecf20Sopenharmony_ci	adapter->ext_scan = card->pcie.can_ext_scan;
33468c2ecf20Sopenharmony_ci	mwifiex_pcie_get_fw_name(adapter);
33478c2ecf20Sopenharmony_ci
33488c2ecf20Sopenharmony_ci	return 0;
33498c2ecf20Sopenharmony_ci}
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci/*
33528c2ecf20Sopenharmony_ci * This function unregisters the PCIE device.
33538c2ecf20Sopenharmony_ci *
33548c2ecf20Sopenharmony_ci * The PCIE IRQ is released, the function is disabled and driver
33558c2ecf20Sopenharmony_ci * data is set to null.
33568c2ecf20Sopenharmony_ci */
33578c2ecf20Sopenharmony_cistatic void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
33588c2ecf20Sopenharmony_ci{
33598c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
33608c2ecf20Sopenharmony_ci	struct pci_dev *pdev = card->dev;
33618c2ecf20Sopenharmony_ci	int i;
33628c2ecf20Sopenharmony_ci
33638c2ecf20Sopenharmony_ci	if (card->msix_enable) {
33648c2ecf20Sopenharmony_ci		for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
33658c2ecf20Sopenharmony_ci			synchronize_irq(card->msix_entries[i].vector);
33668c2ecf20Sopenharmony_ci
33678c2ecf20Sopenharmony_ci		for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
33688c2ecf20Sopenharmony_ci			free_irq(card->msix_entries[i].vector,
33698c2ecf20Sopenharmony_ci				 &card->msix_ctx[i]);
33708c2ecf20Sopenharmony_ci
33718c2ecf20Sopenharmony_ci		card->msix_enable = 0;
33728c2ecf20Sopenharmony_ci		pci_disable_msix(pdev);
33738c2ecf20Sopenharmony_ci	} else {
33748c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
33758c2ecf20Sopenharmony_ci			    "%s(): calling free_irq()\n", __func__);
33768c2ecf20Sopenharmony_ci	       free_irq(card->dev->irq, &card->share_irq_ctx);
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci		if (card->msi_enable)
33798c2ecf20Sopenharmony_ci			pci_disable_msi(pdev);
33808c2ecf20Sopenharmony_ci	}
33818c2ecf20Sopenharmony_ci	card->adapter = NULL;
33828c2ecf20Sopenharmony_ci}
33838c2ecf20Sopenharmony_ci
33848c2ecf20Sopenharmony_ci/*
33858c2ecf20Sopenharmony_ci * This function initializes the PCI-E host memory space, WCB rings, etc.,
33868c2ecf20Sopenharmony_ci * similar to mwifiex_init_pcie(), but without resetting PCI-E state.
33878c2ecf20Sopenharmony_ci */
33888c2ecf20Sopenharmony_cistatic void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter)
33898c2ecf20Sopenharmony_ci{
33908c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
33918c2ecf20Sopenharmony_ci	struct pci_dev *pdev = card->dev;
33928c2ecf20Sopenharmony_ci
33938c2ecf20Sopenharmony_ci	/* tx_buf_size might be changed to 3584 by firmware during
33948c2ecf20Sopenharmony_ci	 * data transfer, we should reset it to default size.
33958c2ecf20Sopenharmony_ci	 */
33968c2ecf20Sopenharmony_ci	adapter->tx_buf_size = card->pcie.tx_buf_size;
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ci	mwifiex_pcie_alloc_buffers(adapter);
33998c2ecf20Sopenharmony_ci
34008c2ecf20Sopenharmony_ci	pci_set_master(pdev);
34018c2ecf20Sopenharmony_ci}
34028c2ecf20Sopenharmony_ci
34038c2ecf20Sopenharmony_ci/* This function cleans up the PCI-E host memory space. */
34048c2ecf20Sopenharmony_cistatic void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter)
34058c2ecf20Sopenharmony_ci{
34068c2ecf20Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
34078c2ecf20Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
34088c2ecf20Sopenharmony_ci	struct pci_dev *pdev = card->dev;
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
34118c2ecf20Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to write driver not-ready signature\n");
34128c2ecf20Sopenharmony_ci
34138c2ecf20Sopenharmony_ci	pci_clear_master(pdev);
34148c2ecf20Sopenharmony_ci
34158c2ecf20Sopenharmony_ci	adapter->seq_num = 0;
34168c2ecf20Sopenharmony_ci
34178c2ecf20Sopenharmony_ci	mwifiex_pcie_free_buffers(adapter);
34188c2ecf20Sopenharmony_ci}
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_cistatic struct mwifiex_if_ops pcie_ops = {
34218c2ecf20Sopenharmony_ci	.init_if =			mwifiex_init_pcie,
34228c2ecf20Sopenharmony_ci	.cleanup_if =			mwifiex_cleanup_pcie,
34238c2ecf20Sopenharmony_ci	.check_fw_status =		mwifiex_check_fw_status,
34248c2ecf20Sopenharmony_ci	.check_winner_status =          mwifiex_check_winner_status,
34258c2ecf20Sopenharmony_ci	.prog_fw =			mwifiex_prog_fw_w_helper,
34268c2ecf20Sopenharmony_ci	.register_dev =			mwifiex_register_dev,
34278c2ecf20Sopenharmony_ci	.unregister_dev =		mwifiex_unregister_dev,
34288c2ecf20Sopenharmony_ci	.enable_int =			mwifiex_pcie_enable_host_int,
34298c2ecf20Sopenharmony_ci	.disable_int =			mwifiex_pcie_disable_host_int_noerr,
34308c2ecf20Sopenharmony_ci	.process_int_status =		mwifiex_process_int_status,
34318c2ecf20Sopenharmony_ci	.host_to_card =			mwifiex_pcie_host_to_card,
34328c2ecf20Sopenharmony_ci	.wakeup =			mwifiex_pm_wakeup_card,
34338c2ecf20Sopenharmony_ci	.wakeup_complete =		mwifiex_pm_wakeup_card_complete,
34348c2ecf20Sopenharmony_ci
34358c2ecf20Sopenharmony_ci	/* PCIE specific */
34368c2ecf20Sopenharmony_ci	.cmdrsp_complete =		mwifiex_pcie_cmdrsp_complete,
34378c2ecf20Sopenharmony_ci	.event_complete =		mwifiex_pcie_event_complete,
34388c2ecf20Sopenharmony_ci	.update_mp_end_port =		NULL,
34398c2ecf20Sopenharmony_ci	.cleanup_mpa_buf =		NULL,
34408c2ecf20Sopenharmony_ci	.init_fw_port =			mwifiex_pcie_init_fw_port,
34418c2ecf20Sopenharmony_ci	.clean_pcie_ring =		mwifiex_clean_pcie_ring_buf,
34428c2ecf20Sopenharmony_ci	.card_reset =			mwifiex_pcie_card_reset,
34438c2ecf20Sopenharmony_ci	.reg_dump =			mwifiex_pcie_reg_dump,
34448c2ecf20Sopenharmony_ci	.device_dump =			mwifiex_pcie_device_dump,
34458c2ecf20Sopenharmony_ci	.down_dev =			mwifiex_pcie_down_dev,
34468c2ecf20Sopenharmony_ci	.up_dev =			mwifiex_pcie_up_dev,
34478c2ecf20Sopenharmony_ci};
34488c2ecf20Sopenharmony_ci
34498c2ecf20Sopenharmony_cimodule_pci_driver(mwifiex_pcie);
34508c2ecf20Sopenharmony_ci
34518c2ecf20Sopenharmony_ciMODULE_AUTHOR("Marvell International Ltd.");
34528c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
34538c2ecf20Sopenharmony_ciMODULE_VERSION(PCIE_VERSION);
34548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
3455