162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * NXP Wireless LAN device driver: PCIE specific handling
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2011-2020 NXP
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/iopoll.h>
962306a36Sopenharmony_ci#include <linux/firmware.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "decl.h"
1262306a36Sopenharmony_ci#include "ioctl.h"
1362306a36Sopenharmony_ci#include "util.h"
1462306a36Sopenharmony_ci#include "fw.h"
1562306a36Sopenharmony_ci#include "main.h"
1662306a36Sopenharmony_ci#include "wmm.h"
1762306a36Sopenharmony_ci#include "11n.h"
1862306a36Sopenharmony_ci#include "pcie.h"
1962306a36Sopenharmony_ci#include "pcie_quirks.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define PCIE_VERSION	"1.0"
2262306a36Sopenharmony_ci#define DRV_NAME        "Marvell mwifiex PCIe"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic struct mwifiex_if_ops pcie_ops;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
2762306a36Sopenharmony_ci	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
2862306a36Sopenharmony_ci	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
2962306a36Sopenharmony_ci	.cmd_size = PCIE_SCRATCH_2_REG,
3062306a36Sopenharmony_ci	.fw_status = PCIE_SCRATCH_3_REG,
3162306a36Sopenharmony_ci	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
3262306a36Sopenharmony_ci	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
3362306a36Sopenharmony_ci	.tx_rdptr = PCIE_SCRATCH_6_REG,
3462306a36Sopenharmony_ci	.tx_wrptr = PCIE_SCRATCH_7_REG,
3562306a36Sopenharmony_ci	.rx_rdptr = PCIE_SCRATCH_8_REG,
3662306a36Sopenharmony_ci	.rx_wrptr = PCIE_SCRATCH_9_REG,
3762306a36Sopenharmony_ci	.evt_rdptr = PCIE_SCRATCH_10_REG,
3862306a36Sopenharmony_ci	.evt_wrptr = PCIE_SCRATCH_11_REG,
3962306a36Sopenharmony_ci	.drv_rdy = PCIE_SCRATCH_12_REG,
4062306a36Sopenharmony_ci	.tx_start_ptr = 0,
4162306a36Sopenharmony_ci	.tx_mask = MWIFIEX_TXBD_MASK,
4262306a36Sopenharmony_ci	.tx_wrap_mask = 0,
4362306a36Sopenharmony_ci	.rx_mask = MWIFIEX_RXBD_MASK,
4462306a36Sopenharmony_ci	.rx_wrap_mask = 0,
4562306a36Sopenharmony_ci	.tx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
4662306a36Sopenharmony_ci	.rx_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
4762306a36Sopenharmony_ci	.evt_rollover_ind = MWIFIEX_BD_FLAG_ROLLOVER_IND,
4862306a36Sopenharmony_ci	.ring_flag_sop = 0,
4962306a36Sopenharmony_ci	.ring_flag_eop = 0,
5062306a36Sopenharmony_ci	.ring_flag_xs_sop = 0,
5162306a36Sopenharmony_ci	.ring_flag_xs_eop = 0,
5262306a36Sopenharmony_ci	.ring_tx_start_ptr = 0,
5362306a36Sopenharmony_ci	.pfu_enabled = 0,
5462306a36Sopenharmony_ci	.sleep_cookie = 1,
5562306a36Sopenharmony_ci	.msix_support = 0,
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
5962306a36Sopenharmony_ci	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
6062306a36Sopenharmony_ci	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
6162306a36Sopenharmony_ci	.cmd_size = PCIE_SCRATCH_2_REG,
6262306a36Sopenharmony_ci	.fw_status = PCIE_SCRATCH_3_REG,
6362306a36Sopenharmony_ci	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
6462306a36Sopenharmony_ci	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
6562306a36Sopenharmony_ci	.tx_rdptr = PCIE_RD_DATA_PTR_Q0_Q1,
6662306a36Sopenharmony_ci	.tx_wrptr = PCIE_WR_DATA_PTR_Q0_Q1,
6762306a36Sopenharmony_ci	.rx_rdptr = PCIE_WR_DATA_PTR_Q0_Q1,
6862306a36Sopenharmony_ci	.rx_wrptr = PCIE_RD_DATA_PTR_Q0_Q1,
6962306a36Sopenharmony_ci	.evt_rdptr = PCIE_SCRATCH_10_REG,
7062306a36Sopenharmony_ci	.evt_wrptr = PCIE_SCRATCH_11_REG,
7162306a36Sopenharmony_ci	.drv_rdy = PCIE_SCRATCH_12_REG,
7262306a36Sopenharmony_ci	.tx_start_ptr = 16,
7362306a36Sopenharmony_ci	.tx_mask = 0x03FF0000,
7462306a36Sopenharmony_ci	.tx_wrap_mask = 0x07FF0000,
7562306a36Sopenharmony_ci	.rx_mask = 0x000003FF,
7662306a36Sopenharmony_ci	.rx_wrap_mask = 0x000007FF,
7762306a36Sopenharmony_ci	.tx_rollover_ind = MWIFIEX_BD_FLAG_TX_ROLLOVER_IND,
7862306a36Sopenharmony_ci	.rx_rollover_ind = MWIFIEX_BD_FLAG_RX_ROLLOVER_IND,
7962306a36Sopenharmony_ci	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND,
8062306a36Sopenharmony_ci	.ring_flag_sop = MWIFIEX_BD_FLAG_SOP,
8162306a36Sopenharmony_ci	.ring_flag_eop = MWIFIEX_BD_FLAG_EOP,
8262306a36Sopenharmony_ci	.ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP,
8362306a36Sopenharmony_ci	.ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP,
8462306a36Sopenharmony_ci	.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
8562306a36Sopenharmony_ci	.pfu_enabled = 1,
8662306a36Sopenharmony_ci	.sleep_cookie = 0,
8762306a36Sopenharmony_ci	.fw_dump_ctrl = PCIE_SCRATCH_13_REG,
8862306a36Sopenharmony_ci	.fw_dump_start = PCIE_SCRATCH_14_REG,
8962306a36Sopenharmony_ci	.fw_dump_end = 0xcff,
9062306a36Sopenharmony_ci	.fw_dump_host_ready = 0xee,
9162306a36Sopenharmony_ci	.fw_dump_read_done = 0xfe,
9262306a36Sopenharmony_ci	.msix_support = 0,
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
9662306a36Sopenharmony_ci	.cmd_addr_lo = PCIE_SCRATCH_0_REG,
9762306a36Sopenharmony_ci	.cmd_addr_hi = PCIE_SCRATCH_1_REG,
9862306a36Sopenharmony_ci	.cmd_size = PCIE_SCRATCH_2_REG,
9962306a36Sopenharmony_ci	.fw_status = PCIE_SCRATCH_3_REG,
10062306a36Sopenharmony_ci	.cmdrsp_addr_lo = PCIE_SCRATCH_4_REG,
10162306a36Sopenharmony_ci	.cmdrsp_addr_hi = PCIE_SCRATCH_5_REG,
10262306a36Sopenharmony_ci	.tx_rdptr = 0xC1A4,
10362306a36Sopenharmony_ci	.tx_wrptr = 0xC174,
10462306a36Sopenharmony_ci	.rx_rdptr = 0xC174,
10562306a36Sopenharmony_ci	.rx_wrptr = 0xC1A4,
10662306a36Sopenharmony_ci	.evt_rdptr = PCIE_SCRATCH_10_REG,
10762306a36Sopenharmony_ci	.evt_wrptr = PCIE_SCRATCH_11_REG,
10862306a36Sopenharmony_ci	.drv_rdy = PCIE_SCRATCH_12_REG,
10962306a36Sopenharmony_ci	.tx_start_ptr = 16,
11062306a36Sopenharmony_ci	.tx_mask = 0x0FFF0000,
11162306a36Sopenharmony_ci	.tx_wrap_mask = 0x1FFF0000,
11262306a36Sopenharmony_ci	.rx_mask = 0x00000FFF,
11362306a36Sopenharmony_ci	.rx_wrap_mask = 0x00001FFF,
11462306a36Sopenharmony_ci	.tx_rollover_ind = BIT(28),
11562306a36Sopenharmony_ci	.rx_rollover_ind = BIT(12),
11662306a36Sopenharmony_ci	.evt_rollover_ind = MWIFIEX_BD_FLAG_EVT_ROLLOVER_IND,
11762306a36Sopenharmony_ci	.ring_flag_sop = MWIFIEX_BD_FLAG_SOP,
11862306a36Sopenharmony_ci	.ring_flag_eop = MWIFIEX_BD_FLAG_EOP,
11962306a36Sopenharmony_ci	.ring_flag_xs_sop = MWIFIEX_BD_FLAG_XS_SOP,
12062306a36Sopenharmony_ci	.ring_flag_xs_eop = MWIFIEX_BD_FLAG_XS_EOP,
12162306a36Sopenharmony_ci	.ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
12262306a36Sopenharmony_ci	.pfu_enabled = 1,
12362306a36Sopenharmony_ci	.sleep_cookie = 0,
12462306a36Sopenharmony_ci	.fw_dump_ctrl = PCIE_SCRATCH_13_REG,
12562306a36Sopenharmony_ci	.fw_dump_start = PCIE_SCRATCH_14_REG,
12662306a36Sopenharmony_ci	.fw_dump_end = 0xcff,
12762306a36Sopenharmony_ci	.fw_dump_host_ready = 0xcc,
12862306a36Sopenharmony_ci	.fw_dump_read_done = 0xdd,
12962306a36Sopenharmony_ci	.msix_support = 0,
13062306a36Sopenharmony_ci};
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic struct memory_type_mapping mem_type_mapping_tbl_w8897[] = {
13362306a36Sopenharmony_ci	{"ITCM", NULL, 0, 0xF0},
13462306a36Sopenharmony_ci	{"DTCM", NULL, 0, 0xF1},
13562306a36Sopenharmony_ci	{"SQRAM", NULL, 0, 0xF2},
13662306a36Sopenharmony_ci	{"IRAM", NULL, 0, 0xF3},
13762306a36Sopenharmony_ci	{"APU", NULL, 0, 0xF4},
13862306a36Sopenharmony_ci	{"CIU", NULL, 0, 0xF5},
13962306a36Sopenharmony_ci	{"ICU", NULL, 0, 0xF6},
14062306a36Sopenharmony_ci	{"MAC", NULL, 0, 0xF7},
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic struct memory_type_mapping mem_type_mapping_tbl_w8997[] = {
14462306a36Sopenharmony_ci	{"DUMP", NULL, 0, 0xDD},
14562306a36Sopenharmony_ci};
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic const struct mwifiex_pcie_device mwifiex_pcie8766 = {
14862306a36Sopenharmony_ci	.reg            = &mwifiex_reg_8766,
14962306a36Sopenharmony_ci	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
15062306a36Sopenharmony_ci	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
15162306a36Sopenharmony_ci	.can_dump_fw = false,
15262306a36Sopenharmony_ci	.can_ext_scan = true,
15362306a36Sopenharmony_ci};
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic const struct mwifiex_pcie_device mwifiex_pcie8897 = {
15662306a36Sopenharmony_ci	.reg            = &mwifiex_reg_8897,
15762306a36Sopenharmony_ci	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
15862306a36Sopenharmony_ci	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
15962306a36Sopenharmony_ci	.can_dump_fw = true,
16062306a36Sopenharmony_ci	.mem_type_mapping_tbl = mem_type_mapping_tbl_w8897,
16162306a36Sopenharmony_ci	.num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8897),
16262306a36Sopenharmony_ci	.can_ext_scan = true,
16362306a36Sopenharmony_ci};
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic const struct mwifiex_pcie_device mwifiex_pcie8997 = {
16662306a36Sopenharmony_ci	.reg            = &mwifiex_reg_8997,
16762306a36Sopenharmony_ci	.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
16862306a36Sopenharmony_ci	.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
16962306a36Sopenharmony_ci	.can_dump_fw = true,
17062306a36Sopenharmony_ci	.mem_type_mapping_tbl = mem_type_mapping_tbl_w8997,
17162306a36Sopenharmony_ci	.num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8997),
17262306a36Sopenharmony_ci	.can_ext_scan = true,
17362306a36Sopenharmony_ci};
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_cistatic const struct of_device_id mwifiex_pcie_of_match_table[] __maybe_unused = {
17662306a36Sopenharmony_ci	{ .compatible = "pci11ab,2b42" },
17762306a36Sopenharmony_ci	{ .compatible = "pci1b4b,2b42" },
17862306a36Sopenharmony_ci	{ }
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic int mwifiex_pcie_probe_of(struct device *dev)
18262306a36Sopenharmony_ci{
18362306a36Sopenharmony_ci	if (!of_match_node(mwifiex_pcie_of_match_table, dev->of_node)) {
18462306a36Sopenharmony_ci		dev_err(dev, "required compatible string missing\n");
18562306a36Sopenharmony_ci		return -EINVAL;
18662306a36Sopenharmony_ci	}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	return 0;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistatic void mwifiex_pcie_work(struct work_struct *work);
19262306a36Sopenharmony_cistatic int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter);
19362306a36Sopenharmony_cistatic int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic int
19662306a36Sopenharmony_cimwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
19762306a36Sopenharmony_ci		       size_t size, int flags)
19862306a36Sopenharmony_ci{
19962306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
20062306a36Sopenharmony_ci	struct mwifiex_dma_mapping mapping;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	mapping.addr = dma_map_single(&card->dev->dev, skb->data, size, flags);
20362306a36Sopenharmony_ci	if (dma_mapping_error(&card->dev->dev, mapping.addr)) {
20462306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "failed to map pci memory!\n");
20562306a36Sopenharmony_ci		return -1;
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci	mapping.len = size;
20862306a36Sopenharmony_ci	mwifiex_store_mapping(skb, &mapping);
20962306a36Sopenharmony_ci	return 0;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic void mwifiex_unmap_pci_memory(struct mwifiex_adapter *adapter,
21362306a36Sopenharmony_ci				     struct sk_buff *skb, int flags)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
21662306a36Sopenharmony_ci	struct mwifiex_dma_mapping mapping;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	mwifiex_get_mapping(skb, &mapping);
21962306a36Sopenharmony_ci	dma_unmap_single(&card->dev->dev, mapping.addr, mapping.len, flags);
22062306a36Sopenharmony_ci}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci/*
22362306a36Sopenharmony_ci * This function writes data into PCIE card register.
22462306a36Sopenharmony_ci */
22562306a36Sopenharmony_cistatic int mwifiex_write_reg(struct mwifiex_adapter *adapter, int reg, u32 data)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	iowrite32(data, card->pci_mmap1 + reg);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	return 0;
23262306a36Sopenharmony_ci}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci/* This function reads data from PCIE card register.
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_cistatic int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	*data = ioread32(card->pci_mmap1 + reg);
24162306a36Sopenharmony_ci	if (*data == 0xffffffff)
24262306a36Sopenharmony_ci		return 0xffffffff;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	return 0;
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/* This function reads u8 data from PCIE card register. */
24862306a36Sopenharmony_cistatic int mwifiex_read_reg_byte(struct mwifiex_adapter *adapter,
24962306a36Sopenharmony_ci				 int reg, u8 *data)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	*data = ioread8(card->pci_mmap1 + reg);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	return 0;
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci/*
25962306a36Sopenharmony_ci * This function reads sleep cookie and checks if FW is ready
26062306a36Sopenharmony_ci */
26162306a36Sopenharmony_cistatic bool mwifiex_pcie_ok_to_access_hw(struct mwifiex_adapter *adapter)
26262306a36Sopenharmony_ci{
26362306a36Sopenharmony_ci	u32 cookie_value;
26462306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
26562306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	if (!reg->sleep_cookie)
26862306a36Sopenharmony_ci		return true;
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	if (card->sleep_cookie_vbase) {
27162306a36Sopenharmony_ci		cookie_value = get_unaligned_le32(card->sleep_cookie_vbase);
27262306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
27362306a36Sopenharmony_ci			    "info: ACCESS_HW: sleep cookie=0x%x\n",
27462306a36Sopenharmony_ci			    cookie_value);
27562306a36Sopenharmony_ci		if (cookie_value == FW_AWAKE_COOKIE)
27662306a36Sopenharmony_ci			return true;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	return false;
28062306a36Sopenharmony_ci}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
28362306a36Sopenharmony_ci/*
28462306a36Sopenharmony_ci * Kernel needs to suspend all functions separately. Therefore all
28562306a36Sopenharmony_ci * registered functions must have drivers with suspend and resume
28662306a36Sopenharmony_ci * methods. Failing that the kernel simply removes the whole card.
28762306a36Sopenharmony_ci *
28862306a36Sopenharmony_ci * If already not suspended, this function allocates and sends a host
28962306a36Sopenharmony_ci * sleep activate request to the firmware and turns off the traffic.
29062306a36Sopenharmony_ci */
29162306a36Sopenharmony_cistatic int mwifiex_pcie_suspend(struct device *dev)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	struct mwifiex_adapter *adapter;
29462306a36Sopenharmony_ci	struct pcie_service_card *card = dev_get_drvdata(dev);
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	/* Might still be loading firmware */
29862306a36Sopenharmony_ci	wait_for_completion(&card->fw_done);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	adapter = card->adapter;
30162306a36Sopenharmony_ci	if (!adapter) {
30262306a36Sopenharmony_ci		dev_err(dev, "adapter is not valid\n");
30362306a36Sopenharmony_ci		return 0;
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	mwifiex_enable_wake(adapter);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	/* Enable the Host Sleep */
30962306a36Sopenharmony_ci	if (!mwifiex_enable_hs(adapter)) {
31062306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
31162306a36Sopenharmony_ci			    "cmd: failed to suspend\n");
31262306a36Sopenharmony_ci		clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);
31362306a36Sopenharmony_ci		mwifiex_disable_wake(adapter);
31462306a36Sopenharmony_ci		return -EFAULT;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	flush_workqueue(adapter->workqueue);
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* Indicate device suspended */
32062306a36Sopenharmony_ci	set_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags);
32162306a36Sopenharmony_ci	clear_bit(MWIFIEX_IS_HS_ENABLING, &adapter->work_flags);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	return 0;
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci/*
32762306a36Sopenharmony_ci * Kernel needs to suspend all functions separately. Therefore all
32862306a36Sopenharmony_ci * registered functions must have drivers with suspend and resume
32962306a36Sopenharmony_ci * methods. Failing that the kernel simply removes the whole card.
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci * If already not resumed, this function turns on the traffic and
33262306a36Sopenharmony_ci * sends a host sleep cancel request to the firmware.
33362306a36Sopenharmony_ci */
33462306a36Sopenharmony_cistatic int mwifiex_pcie_resume(struct device *dev)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct mwifiex_adapter *adapter;
33762306a36Sopenharmony_ci	struct pcie_service_card *card = dev_get_drvdata(dev);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (!card->adapter) {
34162306a36Sopenharmony_ci		dev_err(dev, "adapter structure is not valid\n");
34262306a36Sopenharmony_ci		return 0;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	adapter = card->adapter;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (!test_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags)) {
34862306a36Sopenharmony_ci		mwifiex_dbg(adapter, WARN,
34962306a36Sopenharmony_ci			    "Device already resumed\n");
35062306a36Sopenharmony_ci		return 0;
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	clear_bit(MWIFIEX_IS_SUSPENDED, &adapter->work_flags);
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
35662306a36Sopenharmony_ci			  MWIFIEX_ASYNC_CMD);
35762306a36Sopenharmony_ci	mwifiex_disable_wake(adapter);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return 0;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci#endif
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/*
36462306a36Sopenharmony_ci * This function probes an mwifiex device and registers it. It allocates
36562306a36Sopenharmony_ci * the card structure, enables PCIE function number and initiates the
36662306a36Sopenharmony_ci * device registration and initialization procedure by adding a logical
36762306a36Sopenharmony_ci * interface.
36862306a36Sopenharmony_ci */
36962306a36Sopenharmony_cistatic int mwifiex_pcie_probe(struct pci_dev *pdev,
37062306a36Sopenharmony_ci					const struct pci_device_id *ent)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct pcie_service_card *card;
37362306a36Sopenharmony_ci	int ret;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	pr_debug("info: vendor=0x%4.04X device=0x%4.04X rev=%d\n",
37662306a36Sopenharmony_ci		 pdev->vendor, pdev->device, pdev->revision);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	card = devm_kzalloc(&pdev->dev, sizeof(*card), GFP_KERNEL);
37962306a36Sopenharmony_ci	if (!card)
38062306a36Sopenharmony_ci		return -ENOMEM;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	init_completion(&card->fw_done);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	card->dev = pdev;
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	if (ent->driver_data) {
38762306a36Sopenharmony_ci		struct mwifiex_pcie_device *data = (void *)ent->driver_data;
38862306a36Sopenharmony_ci		card->pcie.reg = data->reg;
38962306a36Sopenharmony_ci		card->pcie.blksz_fw_dl = data->blksz_fw_dl;
39062306a36Sopenharmony_ci		card->pcie.tx_buf_size = data->tx_buf_size;
39162306a36Sopenharmony_ci		card->pcie.can_dump_fw = data->can_dump_fw;
39262306a36Sopenharmony_ci		card->pcie.mem_type_mapping_tbl = data->mem_type_mapping_tbl;
39362306a36Sopenharmony_ci		card->pcie.num_mem_types = data->num_mem_types;
39462306a36Sopenharmony_ci		card->pcie.can_ext_scan = data->can_ext_scan;
39562306a36Sopenharmony_ci		INIT_WORK(&card->work, mwifiex_pcie_work);
39662306a36Sopenharmony_ci	}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	/* device tree node parsing and platform specific configuration*/
39962306a36Sopenharmony_ci	if (pdev->dev.of_node) {
40062306a36Sopenharmony_ci		ret = mwifiex_pcie_probe_of(&pdev->dev);
40162306a36Sopenharmony_ci		if (ret)
40262306a36Sopenharmony_ci			return ret;
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	/* check quirks */
40662306a36Sopenharmony_ci	mwifiex_initialize_quirks(card);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	if (mwifiex_add_card(card, &card->fw_done, &pcie_ops,
40962306a36Sopenharmony_ci			     MWIFIEX_PCIE, &pdev->dev)) {
41062306a36Sopenharmony_ci		pr_err("%s failed\n", __func__);
41162306a36Sopenharmony_ci		return -1;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	return 0;
41562306a36Sopenharmony_ci}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci/*
41862306a36Sopenharmony_ci * This function removes the interface and frees up the card structure.
41962306a36Sopenharmony_ci */
42062306a36Sopenharmony_cistatic void mwifiex_pcie_remove(struct pci_dev *pdev)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	struct pcie_service_card *card;
42362306a36Sopenharmony_ci	struct mwifiex_adapter *adapter;
42462306a36Sopenharmony_ci	struct mwifiex_private *priv;
42562306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg;
42662306a36Sopenharmony_ci	u32 fw_status;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	card = pci_get_drvdata(pdev);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	wait_for_completion(&card->fw_done);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	adapter = card->adapter;
43362306a36Sopenharmony_ci	if (!adapter || !adapter->priv_num)
43462306a36Sopenharmony_ci		return;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	reg = card->pcie.reg;
43762306a36Sopenharmony_ci	if (reg)
43862306a36Sopenharmony_ci		mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
43962306a36Sopenharmony_ci	else
44062306a36Sopenharmony_ci		fw_status = -1;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	if (fw_status == FIRMWARE_READY_PCIE && !adapter->mfg_mode) {
44362306a36Sopenharmony_ci		mwifiex_deauthenticate_all(adapter);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci		mwifiex_disable_auto_ds(priv);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci		mwifiex_init_shutdown_fw(priv, MWIFIEX_FUNC_SHUTDOWN);
45062306a36Sopenharmony_ci	}
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_ci	mwifiex_remove_card(adapter);
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic void mwifiex_pcie_shutdown(struct pci_dev *pdev)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	mwifiex_pcie_remove(pdev);
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic void mwifiex_pcie_coredump(struct device *dev)
46362306a36Sopenharmony_ci{
46462306a36Sopenharmony_ci	struct pci_dev *pdev;
46562306a36Sopenharmony_ci	struct pcie_service_card *card;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	pdev = container_of(dev, struct pci_dev, dev);
46862306a36Sopenharmony_ci	card = pci_get_drvdata(pdev);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
47162306a36Sopenharmony_ci			      &card->work_flags))
47262306a36Sopenharmony_ci		schedule_work(&card->work);
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic const struct pci_device_id mwifiex_ids[] = {
47662306a36Sopenharmony_ci	{
47762306a36Sopenharmony_ci		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8766P,
47862306a36Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
47962306a36Sopenharmony_ci		.driver_data = (unsigned long)&mwifiex_pcie8766,
48062306a36Sopenharmony_ci	},
48162306a36Sopenharmony_ci	{
48262306a36Sopenharmony_ci		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8897,
48362306a36Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
48462306a36Sopenharmony_ci		.driver_data = (unsigned long)&mwifiex_pcie8897,
48562306a36Sopenharmony_ci	},
48662306a36Sopenharmony_ci	{
48762306a36Sopenharmony_ci		PCIE_VENDOR_ID_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8997,
48862306a36Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
48962306a36Sopenharmony_ci		.driver_data = (unsigned long)&mwifiex_pcie8997,
49062306a36Sopenharmony_ci	},
49162306a36Sopenharmony_ci	{
49262306a36Sopenharmony_ci		PCIE_VENDOR_ID_V2_MARVELL, PCIE_DEVICE_ID_MARVELL_88W8997,
49362306a36Sopenharmony_ci		PCI_ANY_ID, PCI_ANY_ID, 0, 0,
49462306a36Sopenharmony_ci		.driver_data = (unsigned long)&mwifiex_pcie8997,
49562306a36Sopenharmony_ci	},
49662306a36Sopenharmony_ci	{},
49762306a36Sopenharmony_ci};
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, mwifiex_ids);
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/*
50262306a36Sopenharmony_ci * Cleanup all software without cleaning anything related to PCIe and HW.
50362306a36Sopenharmony_ci */
50462306a36Sopenharmony_cistatic void mwifiex_pcie_reset_prepare(struct pci_dev *pdev)
50562306a36Sopenharmony_ci{
50662306a36Sopenharmony_ci	struct pcie_service_card *card = pci_get_drvdata(pdev);
50762306a36Sopenharmony_ci	struct mwifiex_adapter *adapter = card->adapter;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	if (!adapter) {
51062306a36Sopenharmony_ci		dev_err(&pdev->dev, "%s: adapter structure is not valid\n",
51162306a36Sopenharmony_ci			__func__);
51262306a36Sopenharmony_ci		return;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
51662306a36Sopenharmony_ci		    "%s: vendor=0x%4.04x device=0x%4.04x rev=%d Pre-FLR\n",
51762306a36Sopenharmony_ci		    __func__, pdev->vendor, pdev->device, pdev->revision);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	mwifiex_shutdown_sw(adapter);
52062306a36Sopenharmony_ci	clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP, &card->work_flags);
52162306a36Sopenharmony_ci	clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	/* On MS Surface gen4+ devices FLR isn't effective to recover from
52462306a36Sopenharmony_ci	 * hangups, so we power-cycle the card instead.
52562306a36Sopenharmony_ci	 */
52662306a36Sopenharmony_ci	if (card->quirks & QUIRK_FW_RST_D3COLD)
52762306a36Sopenharmony_ci		mwifiex_pcie_reset_d3cold_quirk(pdev);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	card->pci_reset_ongoing = true;
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci/*
53562306a36Sopenharmony_ci * Kernel stores and restores PCIe function context before and after performing
53662306a36Sopenharmony_ci * FLR respectively. Reconfigure the software and firmware including firmware
53762306a36Sopenharmony_ci * redownload.
53862306a36Sopenharmony_ci */
53962306a36Sopenharmony_cistatic void mwifiex_pcie_reset_done(struct pci_dev *pdev)
54062306a36Sopenharmony_ci{
54162306a36Sopenharmony_ci	struct pcie_service_card *card = pci_get_drvdata(pdev);
54262306a36Sopenharmony_ci	struct mwifiex_adapter *adapter = card->adapter;
54362306a36Sopenharmony_ci	int ret;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (!adapter) {
54662306a36Sopenharmony_ci		dev_err(&pdev->dev, "%s: adapter structure is not valid\n",
54762306a36Sopenharmony_ci			__func__);
54862306a36Sopenharmony_ci		return;
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
55262306a36Sopenharmony_ci		    "%s: vendor=0x%4.04x device=0x%4.04x rev=%d Post-FLR\n",
55362306a36Sopenharmony_ci		    __func__, pdev->vendor, pdev->device, pdev->revision);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	ret = mwifiex_reinit_sw(adapter);
55662306a36Sopenharmony_ci	if (ret)
55762306a36Sopenharmony_ci		dev_err(&pdev->dev, "reinit failed: %d\n", ret);
55862306a36Sopenharmony_ci	else
55962306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO, "%s, successful\n", __func__);
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	card->pci_reset_ongoing = false;
56262306a36Sopenharmony_ci}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_cistatic const struct pci_error_handlers mwifiex_pcie_err_handler = {
56562306a36Sopenharmony_ci	.reset_prepare		= mwifiex_pcie_reset_prepare,
56662306a36Sopenharmony_ci	.reset_done		= mwifiex_pcie_reset_done,
56762306a36Sopenharmony_ci};
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
57062306a36Sopenharmony_ci/* Power Management Hooks */
57162306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(mwifiex_pcie_pm_ops, mwifiex_pcie_suspend,
57262306a36Sopenharmony_ci				mwifiex_pcie_resume);
57362306a36Sopenharmony_ci#endif
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci/* PCI Device Driver */
57662306a36Sopenharmony_cistatic struct pci_driver mwifiex_pcie = {
57762306a36Sopenharmony_ci	.name     = "mwifiex_pcie",
57862306a36Sopenharmony_ci	.id_table = mwifiex_ids,
57962306a36Sopenharmony_ci	.probe    = mwifiex_pcie_probe,
58062306a36Sopenharmony_ci	.remove   = mwifiex_pcie_remove,
58162306a36Sopenharmony_ci	.driver   = {
58262306a36Sopenharmony_ci		.coredump = mwifiex_pcie_coredump,
58362306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
58462306a36Sopenharmony_ci		.pm = &mwifiex_pcie_pm_ops,
58562306a36Sopenharmony_ci#endif
58662306a36Sopenharmony_ci	},
58762306a36Sopenharmony_ci	.shutdown = mwifiex_pcie_shutdown,
58862306a36Sopenharmony_ci	.err_handler = &mwifiex_pcie_err_handler,
58962306a36Sopenharmony_ci};
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci/*
59262306a36Sopenharmony_ci * This function adds delay loop to ensure FW is awake before proceeding.
59362306a36Sopenharmony_ci */
59462306a36Sopenharmony_cistatic void mwifiex_pcie_dev_wakeup_delay(struct mwifiex_adapter *adapter)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	int i = 0;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	while (mwifiex_pcie_ok_to_access_hw(adapter)) {
59962306a36Sopenharmony_ci		i++;
60062306a36Sopenharmony_ci		usleep_range(10, 20);
60162306a36Sopenharmony_ci		/* 50ms max wait */
60262306a36Sopenharmony_ci		if (i == 5000)
60362306a36Sopenharmony_ci			break;
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic void mwifiex_delay_for_sleep_cookie(struct mwifiex_adapter *adapter,
61062306a36Sopenharmony_ci					   u32 max_delay_loop_cnt)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
61362306a36Sopenharmony_ci	u8 *buffer;
61462306a36Sopenharmony_ci	u32 sleep_cookie, count;
61562306a36Sopenharmony_ci	struct sk_buff *cmdrsp = card->cmdrsp_buf;
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_ci	for (count = 0; count < max_delay_loop_cnt; count++) {
61862306a36Sopenharmony_ci		dma_sync_single_for_cpu(&card->dev->dev,
61962306a36Sopenharmony_ci					MWIFIEX_SKB_DMA_ADDR(cmdrsp),
62062306a36Sopenharmony_ci					sizeof(sleep_cookie), DMA_FROM_DEVICE);
62162306a36Sopenharmony_ci		buffer = cmdrsp->data;
62262306a36Sopenharmony_ci		sleep_cookie = get_unaligned_le32(buffer);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci		if (sleep_cookie == MWIFIEX_DEF_SLEEP_COOKIE) {
62562306a36Sopenharmony_ci			mwifiex_dbg(adapter, INFO,
62662306a36Sopenharmony_ci				    "sleep cookie found at count %d\n", count);
62762306a36Sopenharmony_ci			break;
62862306a36Sopenharmony_ci		}
62962306a36Sopenharmony_ci		dma_sync_single_for_device(&card->dev->dev,
63062306a36Sopenharmony_ci					   MWIFIEX_SKB_DMA_ADDR(cmdrsp),
63162306a36Sopenharmony_ci					   sizeof(sleep_cookie),
63262306a36Sopenharmony_ci					   DMA_FROM_DEVICE);
63362306a36Sopenharmony_ci		usleep_range(20, 30);
63462306a36Sopenharmony_ci	}
63562306a36Sopenharmony_ci
63662306a36Sopenharmony_ci	if (count >= max_delay_loop_cnt)
63762306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
63862306a36Sopenharmony_ci			    "max count reached while accessing sleep cookie\n");
63962306a36Sopenharmony_ci}
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_ci#define N_WAKEUP_TRIES_SHORT_INTERVAL 15
64262306a36Sopenharmony_ci#define N_WAKEUP_TRIES_LONG_INTERVAL 35
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci/* This function wakes up the card by reading fw_status register. */
64562306a36Sopenharmony_cistatic int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
64662306a36Sopenharmony_ci{
64762306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
64862306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
64962306a36Sopenharmony_ci	int retval __maybe_unused;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
65262306a36Sopenharmony_ci		    "event: Wakeup device...\n");
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (reg->sleep_cookie)
65562306a36Sopenharmony_ci		mwifiex_pcie_dev_wakeup_delay(adapter);
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	/* The 88W8897 PCIe+USB firmware (latest version 15.68.19.p21) sometimes
65862306a36Sopenharmony_ci	 * appears to ignore or miss our wakeup request, so we continue trying
65962306a36Sopenharmony_ci	 * until we receive an interrupt from the card.
66062306a36Sopenharmony_ci	 */
66162306a36Sopenharmony_ci	if (read_poll_timeout(mwifiex_write_reg, retval,
66262306a36Sopenharmony_ci			      READ_ONCE(adapter->int_status) != 0,
66362306a36Sopenharmony_ci			      500, 500 * N_WAKEUP_TRIES_SHORT_INTERVAL,
66462306a36Sopenharmony_ci			      false,
66562306a36Sopenharmony_ci			      adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {
66662306a36Sopenharmony_ci		if (read_poll_timeout(mwifiex_write_reg, retval,
66762306a36Sopenharmony_ci				      READ_ONCE(adapter->int_status) != 0,
66862306a36Sopenharmony_ci				      10000, 10000 * N_WAKEUP_TRIES_LONG_INTERVAL,
66962306a36Sopenharmony_ci				      false,
67062306a36Sopenharmony_ci				      adapter, reg->fw_status, FIRMWARE_READY_PCIE)) {
67162306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
67262306a36Sopenharmony_ci				    "Firmware didn't wake up\n");
67362306a36Sopenharmony_ci			return -EIO;
67462306a36Sopenharmony_ci		}
67562306a36Sopenharmony_ci	}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci	if (reg->sleep_cookie) {
67862306a36Sopenharmony_ci		mwifiex_pcie_dev_wakeup_delay(adapter);
67962306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
68062306a36Sopenharmony_ci			    "PCIE wakeup: Setting PS_STATE_AWAKE\n");
68162306a36Sopenharmony_ci		adapter->ps_state = PS_STATE_AWAKE;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	return 0;
68562306a36Sopenharmony_ci}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci/*
68862306a36Sopenharmony_ci * This function is called after the card has woken up.
68962306a36Sopenharmony_ci *
69062306a36Sopenharmony_ci * The card configuration register is reset.
69162306a36Sopenharmony_ci */
69262306a36Sopenharmony_cistatic int mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	mwifiex_dbg(adapter, CMD,
69562306a36Sopenharmony_ci		    "cmd: Wakeup device completed\n");
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	return 0;
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci/*
70162306a36Sopenharmony_ci * This function disables the host interrupt.
70262306a36Sopenharmony_ci *
70362306a36Sopenharmony_ci * The host interrupt mask is read, the disable bit is reset and
70462306a36Sopenharmony_ci * written back to the card host interrupt mask register.
70562306a36Sopenharmony_ci */
70662306a36Sopenharmony_cistatic int mwifiex_pcie_disable_host_int(struct mwifiex_adapter *adapter)
70762306a36Sopenharmony_ci{
70862306a36Sopenharmony_ci	if (mwifiex_pcie_ok_to_access_hw(adapter)) {
70962306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
71062306a36Sopenharmony_ci				      0x00000000)) {
71162306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
71262306a36Sopenharmony_ci				    "Disable host interrupt failed\n");
71362306a36Sopenharmony_ci			return -1;
71462306a36Sopenharmony_ci		}
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	atomic_set(&adapter->tx_hw_pending, 0);
71862306a36Sopenharmony_ci	return 0;
71962306a36Sopenharmony_ci}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_cistatic void mwifiex_pcie_disable_host_int_noerr(struct mwifiex_adapter *adapter)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	WARN_ON(mwifiex_pcie_disable_host_int(adapter));
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci/*
72762306a36Sopenharmony_ci * This function enables the host interrupt.
72862306a36Sopenharmony_ci *
72962306a36Sopenharmony_ci * The host interrupt enable mask is written to the card
73062306a36Sopenharmony_ci * host interrupt mask register.
73162306a36Sopenharmony_ci */
73262306a36Sopenharmony_cistatic int mwifiex_pcie_enable_host_int(struct mwifiex_adapter *adapter)
73362306a36Sopenharmony_ci{
73462306a36Sopenharmony_ci	if (mwifiex_pcie_ok_to_access_hw(adapter)) {
73562306a36Sopenharmony_ci		/* Simply write the mask to the register */
73662306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_MASK,
73762306a36Sopenharmony_ci				      HOST_INTR_MASK)) {
73862306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
73962306a36Sopenharmony_ci				    "Enable host interrupt failed\n");
74062306a36Sopenharmony_ci			return -1;
74162306a36Sopenharmony_ci		}
74262306a36Sopenharmony_ci	}
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	return 0;
74562306a36Sopenharmony_ci}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci/*
74862306a36Sopenharmony_ci * This function initializes TX buffer ring descriptors
74962306a36Sopenharmony_ci */
75062306a36Sopenharmony_cistatic int mwifiex_init_txq_ring(struct mwifiex_adapter *adapter)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
75362306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
75462306a36Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
75562306a36Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
75662306a36Sopenharmony_ci	int i;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
75962306a36Sopenharmony_ci		card->tx_buf_list[i] = NULL;
76062306a36Sopenharmony_ci		if (reg->pfu_enabled) {
76162306a36Sopenharmony_ci			card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
76262306a36Sopenharmony_ci					     (sizeof(*desc2) * i);
76362306a36Sopenharmony_ci			desc2 = card->txbd_ring[i];
76462306a36Sopenharmony_ci			memset(desc2, 0, sizeof(*desc2));
76562306a36Sopenharmony_ci		} else {
76662306a36Sopenharmony_ci			card->txbd_ring[i] = (void *)card->txbd_ring_vbase +
76762306a36Sopenharmony_ci					     (sizeof(*desc) * i);
76862306a36Sopenharmony_ci			desc = card->txbd_ring[i];
76962306a36Sopenharmony_ci			memset(desc, 0, sizeof(*desc));
77062306a36Sopenharmony_ci		}
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	return 0;
77462306a36Sopenharmony_ci}
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci/* This function initializes RX buffer ring descriptors. Each SKB is allocated
77762306a36Sopenharmony_ci * here and after mapping PCI memory, its physical address is assigned to
77862306a36Sopenharmony_ci * PCIE Rx buffer descriptor's physical address.
77962306a36Sopenharmony_ci */
78062306a36Sopenharmony_cistatic int mwifiex_init_rxq_ring(struct mwifiex_adapter *adapter)
78162306a36Sopenharmony_ci{
78262306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
78362306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
78462306a36Sopenharmony_ci	struct sk_buff *skb;
78562306a36Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
78662306a36Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
78762306a36Sopenharmony_ci	dma_addr_t buf_pa;
78862306a36Sopenharmony_ci	int i;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
79162306a36Sopenharmony_ci		/* Allocate skb here so that firmware can DMA data from it */
79262306a36Sopenharmony_ci		skb = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
79362306a36Sopenharmony_ci						  GFP_KERNEL);
79462306a36Sopenharmony_ci		if (!skb) {
79562306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
79662306a36Sopenharmony_ci				    "Unable to allocate skb for RX ring.\n");
79762306a36Sopenharmony_ci			return -ENOMEM;
79862306a36Sopenharmony_ci		}
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb,
80162306a36Sopenharmony_ci					   MWIFIEX_RX_DATA_BUF_SIZE,
80262306a36Sopenharmony_ci					   DMA_FROM_DEVICE)) {
80362306a36Sopenharmony_ci			kfree_skb(skb);
80462306a36Sopenharmony_ci			return -ENOMEM;
80562306a36Sopenharmony_ci		}
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
81062306a36Sopenharmony_ci			    "info: RX ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
81162306a36Sopenharmony_ci			    skb, skb->len, skb->data, (u32)buf_pa,
81262306a36Sopenharmony_ci			    (u32)((u64)buf_pa >> 32));
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		card->rx_buf_list[i] = skb;
81562306a36Sopenharmony_ci		if (reg->pfu_enabled) {
81662306a36Sopenharmony_ci			card->rxbd_ring[i] = (void *)card->rxbd_ring_vbase +
81762306a36Sopenharmony_ci					     (sizeof(*desc2) * i);
81862306a36Sopenharmony_ci			desc2 = card->rxbd_ring[i];
81962306a36Sopenharmony_ci			desc2->paddr = buf_pa;
82062306a36Sopenharmony_ci			desc2->len = (u16)skb->len;
82162306a36Sopenharmony_ci			desc2->frag_len = (u16)skb->len;
82262306a36Sopenharmony_ci			desc2->flags = reg->ring_flag_eop | reg->ring_flag_sop;
82362306a36Sopenharmony_ci			desc2->offset = 0;
82462306a36Sopenharmony_ci		} else {
82562306a36Sopenharmony_ci			card->rxbd_ring[i] = (void *)(card->rxbd_ring_vbase +
82662306a36Sopenharmony_ci					     (sizeof(*desc) * i));
82762306a36Sopenharmony_ci			desc = card->rxbd_ring[i];
82862306a36Sopenharmony_ci			desc->paddr = buf_pa;
82962306a36Sopenharmony_ci			desc->len = (u16)skb->len;
83062306a36Sopenharmony_ci			desc->flags = 0;
83162306a36Sopenharmony_ci		}
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	return 0;
83562306a36Sopenharmony_ci}
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci/* This function initializes event buffer ring descriptors. Each SKB is
83862306a36Sopenharmony_ci * allocated here and after mapping PCI memory, its physical address is assigned
83962306a36Sopenharmony_ci * to PCIE Rx buffer descriptor's physical address
84062306a36Sopenharmony_ci */
84162306a36Sopenharmony_cistatic int mwifiex_pcie_init_evt_ring(struct mwifiex_adapter *adapter)
84262306a36Sopenharmony_ci{
84362306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
84462306a36Sopenharmony_ci	struct mwifiex_evt_buf_desc *desc;
84562306a36Sopenharmony_ci	struct sk_buff *skb;
84662306a36Sopenharmony_ci	dma_addr_t buf_pa;
84762306a36Sopenharmony_ci	int i;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
85062306a36Sopenharmony_ci		/* Allocate skb here so that firmware can DMA data from it */
85162306a36Sopenharmony_ci		skb = dev_alloc_skb(MAX_EVENT_SIZE);
85262306a36Sopenharmony_ci		if (!skb) {
85362306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
85462306a36Sopenharmony_ci				    "Unable to allocate skb for EVENT buf.\n");
85562306a36Sopenharmony_ci			return -ENOMEM;
85662306a36Sopenharmony_ci		}
85762306a36Sopenharmony_ci		skb_put(skb, MAX_EVENT_SIZE);
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb, MAX_EVENT_SIZE,
86062306a36Sopenharmony_ci					   DMA_FROM_DEVICE)) {
86162306a36Sopenharmony_ci			kfree_skb(skb);
86262306a36Sopenharmony_ci			return -ENOMEM;
86362306a36Sopenharmony_ci		}
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci		mwifiex_dbg(adapter, EVENT,
86862306a36Sopenharmony_ci			    "info: EVT ring: skb=%p len=%d data=%p buf_pa=%#x:%x\n",
86962306a36Sopenharmony_ci			    skb, skb->len, skb->data, (u32)buf_pa,
87062306a36Sopenharmony_ci			    (u32)((u64)buf_pa >> 32));
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_ci		card->evt_buf_list[i] = skb;
87362306a36Sopenharmony_ci		card->evtbd_ring[i] = (void *)(card->evtbd_ring_vbase +
87462306a36Sopenharmony_ci				      (sizeof(*desc) * i));
87562306a36Sopenharmony_ci		desc = card->evtbd_ring[i];
87662306a36Sopenharmony_ci		desc->paddr = buf_pa;
87762306a36Sopenharmony_ci		desc->len = (u16)skb->len;
87862306a36Sopenharmony_ci		desc->flags = 0;
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	return 0;
88262306a36Sopenharmony_ci}
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci/* This function cleans up TX buffer rings. If any of the buffer list has valid
88562306a36Sopenharmony_ci * SKB address, associated SKB is freed.
88662306a36Sopenharmony_ci */
88762306a36Sopenharmony_cistatic void mwifiex_cleanup_txq_ring(struct mwifiex_adapter *adapter)
88862306a36Sopenharmony_ci{
88962306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
89062306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
89162306a36Sopenharmony_ci	struct sk_buff *skb;
89262306a36Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
89362306a36Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
89462306a36Sopenharmony_ci	int i;
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
89762306a36Sopenharmony_ci		if (reg->pfu_enabled) {
89862306a36Sopenharmony_ci			desc2 = card->txbd_ring[i];
89962306a36Sopenharmony_ci			if (card->tx_buf_list[i]) {
90062306a36Sopenharmony_ci				skb = card->tx_buf_list[i];
90162306a36Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
90262306a36Sopenharmony_ci							 DMA_TO_DEVICE);
90362306a36Sopenharmony_ci				dev_kfree_skb_any(skb);
90462306a36Sopenharmony_ci			}
90562306a36Sopenharmony_ci			memset(desc2, 0, sizeof(*desc2));
90662306a36Sopenharmony_ci		} else {
90762306a36Sopenharmony_ci			desc = card->txbd_ring[i];
90862306a36Sopenharmony_ci			if (card->tx_buf_list[i]) {
90962306a36Sopenharmony_ci				skb = card->tx_buf_list[i];
91062306a36Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
91162306a36Sopenharmony_ci							 DMA_TO_DEVICE);
91262306a36Sopenharmony_ci				dev_kfree_skb_any(skb);
91362306a36Sopenharmony_ci			}
91462306a36Sopenharmony_ci			memset(desc, 0, sizeof(*desc));
91562306a36Sopenharmony_ci		}
91662306a36Sopenharmony_ci		card->tx_buf_list[i] = NULL;
91762306a36Sopenharmony_ci	}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	atomic_set(&adapter->tx_hw_pending, 0);
92062306a36Sopenharmony_ci	return;
92162306a36Sopenharmony_ci}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci/* This function cleans up RX buffer rings. If any of the buffer list has valid
92462306a36Sopenharmony_ci * SKB address, associated SKB is freed.
92562306a36Sopenharmony_ci */
92662306a36Sopenharmony_cistatic void mwifiex_cleanup_rxq_ring(struct mwifiex_adapter *adapter)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
92962306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
93062306a36Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
93162306a36Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
93262306a36Sopenharmony_ci	struct sk_buff *skb;
93362306a36Sopenharmony_ci	int i;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_TXRX_BD; i++) {
93662306a36Sopenharmony_ci		if (reg->pfu_enabled) {
93762306a36Sopenharmony_ci			desc2 = card->rxbd_ring[i];
93862306a36Sopenharmony_ci			if (card->rx_buf_list[i]) {
93962306a36Sopenharmony_ci				skb = card->rx_buf_list[i];
94062306a36Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
94162306a36Sopenharmony_ci							 DMA_FROM_DEVICE);
94262306a36Sopenharmony_ci				dev_kfree_skb_any(skb);
94362306a36Sopenharmony_ci			}
94462306a36Sopenharmony_ci			memset(desc2, 0, sizeof(*desc2));
94562306a36Sopenharmony_ci		} else {
94662306a36Sopenharmony_ci			desc = card->rxbd_ring[i];
94762306a36Sopenharmony_ci			if (card->rx_buf_list[i]) {
94862306a36Sopenharmony_ci				skb = card->rx_buf_list[i];
94962306a36Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
95062306a36Sopenharmony_ci							 DMA_FROM_DEVICE);
95162306a36Sopenharmony_ci				dev_kfree_skb_any(skb);
95262306a36Sopenharmony_ci			}
95362306a36Sopenharmony_ci			memset(desc, 0, sizeof(*desc));
95462306a36Sopenharmony_ci		}
95562306a36Sopenharmony_ci		card->rx_buf_list[i] = NULL;
95662306a36Sopenharmony_ci	}
95762306a36Sopenharmony_ci
95862306a36Sopenharmony_ci	return;
95962306a36Sopenharmony_ci}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci/* This function cleans up event buffer rings. If any of the buffer list has
96262306a36Sopenharmony_ci * valid SKB address, associated SKB is freed.
96362306a36Sopenharmony_ci */
96462306a36Sopenharmony_cistatic void mwifiex_cleanup_evt_ring(struct mwifiex_adapter *adapter)
96562306a36Sopenharmony_ci{
96662306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
96762306a36Sopenharmony_ci	struct mwifiex_evt_buf_desc *desc;
96862306a36Sopenharmony_ci	struct sk_buff *skb;
96962306a36Sopenharmony_ci	int i;
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ci	for (i = 0; i < MWIFIEX_MAX_EVT_BD; i++) {
97262306a36Sopenharmony_ci		desc = card->evtbd_ring[i];
97362306a36Sopenharmony_ci		if (card->evt_buf_list[i]) {
97462306a36Sopenharmony_ci			skb = card->evt_buf_list[i];
97562306a36Sopenharmony_ci			mwifiex_unmap_pci_memory(adapter, skb,
97662306a36Sopenharmony_ci						 DMA_FROM_DEVICE);
97762306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
97862306a36Sopenharmony_ci		}
97962306a36Sopenharmony_ci		card->evt_buf_list[i] = NULL;
98062306a36Sopenharmony_ci		memset(desc, 0, sizeof(*desc));
98162306a36Sopenharmony_ci	}
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	return;
98462306a36Sopenharmony_ci}
98562306a36Sopenharmony_ci
98662306a36Sopenharmony_ci/* This function creates buffer descriptor ring for TX
98762306a36Sopenharmony_ci */
98862306a36Sopenharmony_cistatic int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
99162306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	/*
99462306a36Sopenharmony_ci	 * driver maintaines the write pointer and firmware maintaines the read
99562306a36Sopenharmony_ci	 * pointer. The write pointer starts at 0 (zero) while the read pointer
99662306a36Sopenharmony_ci	 * starts at zero with rollover bit set
99762306a36Sopenharmony_ci	 */
99862306a36Sopenharmony_ci	card->txbd_wrptr = 0;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	if (reg->pfu_enabled)
100162306a36Sopenharmony_ci		card->txbd_rdptr = 0;
100262306a36Sopenharmony_ci	else
100362306a36Sopenharmony_ci		card->txbd_rdptr |= reg->tx_rollover_ind;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* allocate shared memory for the BD ring and divide the same in to
100662306a36Sopenharmony_ci	   several descriptors */
100762306a36Sopenharmony_ci	if (reg->pfu_enabled)
100862306a36Sopenharmony_ci		card->txbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
100962306a36Sopenharmony_ci				       MWIFIEX_MAX_TXRX_BD;
101062306a36Sopenharmony_ci	else
101162306a36Sopenharmony_ci		card->txbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
101262306a36Sopenharmony_ci				       MWIFIEX_MAX_TXRX_BD;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
101562306a36Sopenharmony_ci		    "info: txbd_ring: Allocating %d bytes\n",
101662306a36Sopenharmony_ci		    card->txbd_ring_size);
101762306a36Sopenharmony_ci	card->txbd_ring_vbase = dma_alloc_coherent(&card->dev->dev,
101862306a36Sopenharmony_ci						   card->txbd_ring_size,
101962306a36Sopenharmony_ci						   &card->txbd_ring_pbase,
102062306a36Sopenharmony_ci						   GFP_KERNEL);
102162306a36Sopenharmony_ci	if (!card->txbd_ring_vbase) {
102262306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
102362306a36Sopenharmony_ci			    "allocate coherent memory (%d bytes) failed!\n",
102462306a36Sopenharmony_ci			    card->txbd_ring_size);
102562306a36Sopenharmony_ci		return -ENOMEM;
102662306a36Sopenharmony_ci	}
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	mwifiex_dbg(adapter, DATA,
102962306a36Sopenharmony_ci		    "info: txbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
103062306a36Sopenharmony_ci		    card->txbd_ring_vbase, (u32)card->txbd_ring_pbase,
103162306a36Sopenharmony_ci		    (u32)((u64)card->txbd_ring_pbase >> 32),
103262306a36Sopenharmony_ci		    card->txbd_ring_size);
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_ci	return mwifiex_init_txq_ring(adapter);
103562306a36Sopenharmony_ci}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_cistatic int mwifiex_pcie_delete_txbd_ring(struct mwifiex_adapter *adapter)
103862306a36Sopenharmony_ci{
103962306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
104062306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
104162306a36Sopenharmony_ci
104262306a36Sopenharmony_ci	mwifiex_cleanup_txq_ring(adapter);
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	if (card->txbd_ring_vbase)
104562306a36Sopenharmony_ci		dma_free_coherent(&card->dev->dev, card->txbd_ring_size,
104662306a36Sopenharmony_ci				  card->txbd_ring_vbase,
104762306a36Sopenharmony_ci				  card->txbd_ring_pbase);
104862306a36Sopenharmony_ci	card->txbd_ring_size = 0;
104962306a36Sopenharmony_ci	card->txbd_wrptr = 0;
105062306a36Sopenharmony_ci	card->txbd_rdptr = 0 | reg->tx_rollover_ind;
105162306a36Sopenharmony_ci	card->txbd_ring_vbase = NULL;
105262306a36Sopenharmony_ci	card->txbd_ring_pbase = 0;
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_ci	return 0;
105562306a36Sopenharmony_ci}
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci/*
105862306a36Sopenharmony_ci * This function creates buffer descriptor ring for RX
105962306a36Sopenharmony_ci */
106062306a36Sopenharmony_cistatic int mwifiex_pcie_create_rxbd_ring(struct mwifiex_adapter *adapter)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	int ret;
106362306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
106462306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	/*
106762306a36Sopenharmony_ci	 * driver maintaines the read pointer and firmware maintaines the write
106862306a36Sopenharmony_ci	 * pointer. The write pointer starts at 0 (zero) while the read pointer
106962306a36Sopenharmony_ci	 * starts at zero with rollover bit set
107062306a36Sopenharmony_ci	 */
107162306a36Sopenharmony_ci	card->rxbd_wrptr = 0;
107262306a36Sopenharmony_ci	card->rxbd_rdptr = reg->rx_rollover_ind;
107362306a36Sopenharmony_ci
107462306a36Sopenharmony_ci	if (reg->pfu_enabled)
107562306a36Sopenharmony_ci		card->rxbd_ring_size = sizeof(struct mwifiex_pfu_buf_desc) *
107662306a36Sopenharmony_ci				       MWIFIEX_MAX_TXRX_BD;
107762306a36Sopenharmony_ci	else
107862306a36Sopenharmony_ci		card->rxbd_ring_size = sizeof(struct mwifiex_pcie_buf_desc) *
107962306a36Sopenharmony_ci				       MWIFIEX_MAX_TXRX_BD;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
108262306a36Sopenharmony_ci		    "info: rxbd_ring: Allocating %d bytes\n",
108362306a36Sopenharmony_ci		    card->rxbd_ring_size);
108462306a36Sopenharmony_ci	card->rxbd_ring_vbase = dma_alloc_coherent(&card->dev->dev,
108562306a36Sopenharmony_ci						   card->rxbd_ring_size,
108662306a36Sopenharmony_ci						   &card->rxbd_ring_pbase,
108762306a36Sopenharmony_ci						   GFP_KERNEL);
108862306a36Sopenharmony_ci	if (!card->rxbd_ring_vbase) {
108962306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
109062306a36Sopenharmony_ci			    "allocate coherent memory (%d bytes) failed!\n",
109162306a36Sopenharmony_ci			    card->rxbd_ring_size);
109262306a36Sopenharmony_ci		return -ENOMEM;
109362306a36Sopenharmony_ci	}
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci	mwifiex_dbg(adapter, DATA,
109662306a36Sopenharmony_ci		    "info: rxbd_ring - base: %p, pbase: %#x:%x, len: %#x\n",
109762306a36Sopenharmony_ci		    card->rxbd_ring_vbase, (u32)card->rxbd_ring_pbase,
109862306a36Sopenharmony_ci		    (u32)((u64)card->rxbd_ring_pbase >> 32),
109962306a36Sopenharmony_ci		    card->rxbd_ring_size);
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	ret = mwifiex_init_rxq_ring(adapter);
110262306a36Sopenharmony_ci	if (ret)
110362306a36Sopenharmony_ci		mwifiex_pcie_delete_rxbd_ring(adapter);
110462306a36Sopenharmony_ci	return ret;
110562306a36Sopenharmony_ci}
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci/*
110862306a36Sopenharmony_ci * This function deletes Buffer descriptor ring for RX
110962306a36Sopenharmony_ci */
111062306a36Sopenharmony_cistatic int mwifiex_pcie_delete_rxbd_ring(struct mwifiex_adapter *adapter)
111162306a36Sopenharmony_ci{
111262306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
111362306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	mwifiex_cleanup_rxq_ring(adapter);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	if (card->rxbd_ring_vbase)
111862306a36Sopenharmony_ci		dma_free_coherent(&card->dev->dev, card->rxbd_ring_size,
111962306a36Sopenharmony_ci				  card->rxbd_ring_vbase,
112062306a36Sopenharmony_ci				  card->rxbd_ring_pbase);
112162306a36Sopenharmony_ci	card->rxbd_ring_size = 0;
112262306a36Sopenharmony_ci	card->rxbd_wrptr = 0;
112362306a36Sopenharmony_ci	card->rxbd_rdptr = 0 | reg->rx_rollover_ind;
112462306a36Sopenharmony_ci	card->rxbd_ring_vbase = NULL;
112562306a36Sopenharmony_ci	card->rxbd_ring_pbase = 0;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci	return 0;
112862306a36Sopenharmony_ci}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci/*
113162306a36Sopenharmony_ci * This function creates buffer descriptor ring for Events
113262306a36Sopenharmony_ci */
113362306a36Sopenharmony_cistatic int mwifiex_pcie_create_evtbd_ring(struct mwifiex_adapter *adapter)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	int ret;
113662306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
113762306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	/*
114062306a36Sopenharmony_ci	 * driver maintaines the read pointer and firmware maintaines the write
114162306a36Sopenharmony_ci	 * pointer. The write pointer starts at 0 (zero) while the read pointer
114262306a36Sopenharmony_ci	 * starts at zero with rollover bit set
114362306a36Sopenharmony_ci	 */
114462306a36Sopenharmony_ci	card->evtbd_wrptr = 0;
114562306a36Sopenharmony_ci	card->evtbd_rdptr = reg->evt_rollover_ind;
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_ci	card->evtbd_ring_size = sizeof(struct mwifiex_evt_buf_desc) *
114862306a36Sopenharmony_ci				MWIFIEX_MAX_EVT_BD;
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
115162306a36Sopenharmony_ci		    "info: evtbd_ring: Allocating %d bytes\n",
115262306a36Sopenharmony_ci		    card->evtbd_ring_size);
115362306a36Sopenharmony_ci	card->evtbd_ring_vbase = dma_alloc_coherent(&card->dev->dev,
115462306a36Sopenharmony_ci						    card->evtbd_ring_size,
115562306a36Sopenharmony_ci						    &card->evtbd_ring_pbase,
115662306a36Sopenharmony_ci						    GFP_KERNEL);
115762306a36Sopenharmony_ci	if (!card->evtbd_ring_vbase) {
115862306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
115962306a36Sopenharmony_ci			    "allocate coherent memory (%d bytes) failed!\n",
116062306a36Sopenharmony_ci			    card->evtbd_ring_size);
116162306a36Sopenharmony_ci		return -ENOMEM;
116262306a36Sopenharmony_ci	}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
116562306a36Sopenharmony_ci		    "info: CMDRSP/EVT bd_ring - base: %p pbase: %#x:%x len: %#x\n",
116662306a36Sopenharmony_ci		    card->evtbd_ring_vbase, (u32)card->evtbd_ring_pbase,
116762306a36Sopenharmony_ci		    (u32)((u64)card->evtbd_ring_pbase >> 32),
116862306a36Sopenharmony_ci		    card->evtbd_ring_size);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	ret = mwifiex_pcie_init_evt_ring(adapter);
117162306a36Sopenharmony_ci	if (ret)
117262306a36Sopenharmony_ci		mwifiex_pcie_delete_evtbd_ring(adapter);
117362306a36Sopenharmony_ci	return ret;
117462306a36Sopenharmony_ci}
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci/*
117762306a36Sopenharmony_ci * This function deletes Buffer descriptor ring for Events
117862306a36Sopenharmony_ci */
117962306a36Sopenharmony_cistatic int mwifiex_pcie_delete_evtbd_ring(struct mwifiex_adapter *adapter)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
118262306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	mwifiex_cleanup_evt_ring(adapter);
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	if (card->evtbd_ring_vbase)
118762306a36Sopenharmony_ci		dma_free_coherent(&card->dev->dev, card->evtbd_ring_size,
118862306a36Sopenharmony_ci				  card->evtbd_ring_vbase,
118962306a36Sopenharmony_ci				  card->evtbd_ring_pbase);
119062306a36Sopenharmony_ci	card->evtbd_wrptr = 0;
119162306a36Sopenharmony_ci	card->evtbd_rdptr = 0 | reg->evt_rollover_ind;
119262306a36Sopenharmony_ci	card->evtbd_ring_size = 0;
119362306a36Sopenharmony_ci	card->evtbd_ring_vbase = NULL;
119462306a36Sopenharmony_ci	card->evtbd_ring_pbase = 0;
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	return 0;
119762306a36Sopenharmony_ci}
119862306a36Sopenharmony_ci
119962306a36Sopenharmony_ci/*
120062306a36Sopenharmony_ci * This function allocates a buffer for CMDRSP
120162306a36Sopenharmony_ci */
120262306a36Sopenharmony_cistatic int mwifiex_pcie_alloc_cmdrsp_buf(struct mwifiex_adapter *adapter)
120362306a36Sopenharmony_ci{
120462306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
120562306a36Sopenharmony_ci	struct sk_buff *skb;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	/* Allocate memory for receiving command response data */
120862306a36Sopenharmony_ci	skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
120962306a36Sopenharmony_ci	if (!skb) {
121062306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
121162306a36Sopenharmony_ci			    "Unable to allocate skb for command response data.\n");
121262306a36Sopenharmony_ci		return -ENOMEM;
121362306a36Sopenharmony_ci	}
121462306a36Sopenharmony_ci	skb_put(skb, MWIFIEX_UPLD_SIZE);
121562306a36Sopenharmony_ci	if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
121662306a36Sopenharmony_ci				   DMA_FROM_DEVICE)) {
121762306a36Sopenharmony_ci		kfree_skb(skb);
121862306a36Sopenharmony_ci		return -1;
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci	card->cmdrsp_buf = skb;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	return 0;
122462306a36Sopenharmony_ci}
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci/*
122762306a36Sopenharmony_ci * This function deletes a buffer for CMDRSP
122862306a36Sopenharmony_ci */
122962306a36Sopenharmony_cistatic int mwifiex_pcie_delete_cmdrsp_buf(struct mwifiex_adapter *adapter)
123062306a36Sopenharmony_ci{
123162306a36Sopenharmony_ci	struct pcie_service_card *card;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	if (!adapter)
123462306a36Sopenharmony_ci		return 0;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci	card = adapter->card;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (card && card->cmdrsp_buf) {
123962306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, card->cmdrsp_buf,
124062306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
124162306a36Sopenharmony_ci		dev_kfree_skb_any(card->cmdrsp_buf);
124262306a36Sopenharmony_ci		card->cmdrsp_buf = NULL;
124362306a36Sopenharmony_ci	}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci	if (card && card->cmd_buf) {
124662306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, card->cmd_buf,
124762306a36Sopenharmony_ci					 DMA_TO_DEVICE);
124862306a36Sopenharmony_ci		dev_kfree_skb_any(card->cmd_buf);
124962306a36Sopenharmony_ci		card->cmd_buf = NULL;
125062306a36Sopenharmony_ci	}
125162306a36Sopenharmony_ci	return 0;
125262306a36Sopenharmony_ci}
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci/*
125562306a36Sopenharmony_ci * This function allocates a buffer for sleep cookie
125662306a36Sopenharmony_ci */
125762306a36Sopenharmony_cistatic int mwifiex_pcie_alloc_sleep_cookie_buf(struct mwifiex_adapter *adapter)
125862306a36Sopenharmony_ci{
125962306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
126062306a36Sopenharmony_ci	u32 *cookie;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	card->sleep_cookie_vbase = dma_alloc_coherent(&card->dev->dev,
126362306a36Sopenharmony_ci						      sizeof(u32),
126462306a36Sopenharmony_ci						      &card->sleep_cookie_pbase,
126562306a36Sopenharmony_ci						      GFP_KERNEL);
126662306a36Sopenharmony_ci	if (!card->sleep_cookie_vbase) {
126762306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
126862306a36Sopenharmony_ci			    "dma_alloc_coherent failed!\n");
126962306a36Sopenharmony_ci		return -ENOMEM;
127062306a36Sopenharmony_ci	}
127162306a36Sopenharmony_ci	cookie = (u32 *)card->sleep_cookie_vbase;
127262306a36Sopenharmony_ci	/* Init val of Sleep Cookie */
127362306a36Sopenharmony_ci	*cookie = FW_AWAKE_COOKIE;
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "alloc_scook: sleep cookie=0x%x\n", *cookie);
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	return 0;
127862306a36Sopenharmony_ci}
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci/*
128162306a36Sopenharmony_ci * This function deletes buffer for sleep cookie
128262306a36Sopenharmony_ci */
128362306a36Sopenharmony_cistatic int mwifiex_pcie_delete_sleep_cookie_buf(struct mwifiex_adapter *adapter)
128462306a36Sopenharmony_ci{
128562306a36Sopenharmony_ci	struct pcie_service_card *card;
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	if (!adapter)
128862306a36Sopenharmony_ci		return 0;
128962306a36Sopenharmony_ci
129062306a36Sopenharmony_ci	card = adapter->card;
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	if (card && card->sleep_cookie_vbase) {
129362306a36Sopenharmony_ci		dma_free_coherent(&card->dev->dev, sizeof(u32),
129462306a36Sopenharmony_ci				  card->sleep_cookie_vbase,
129562306a36Sopenharmony_ci				  card->sleep_cookie_pbase);
129662306a36Sopenharmony_ci		card->sleep_cookie_vbase = NULL;
129762306a36Sopenharmony_ci	}
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	return 0;
130062306a36Sopenharmony_ci}
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci/* This function flushes the TX buffer descriptor ring
130362306a36Sopenharmony_ci * This function defined as handler is also called while cleaning TXRX
130462306a36Sopenharmony_ci * during disconnect/ bss stop.
130562306a36Sopenharmony_ci */
130662306a36Sopenharmony_cistatic int mwifiex_clean_pcie_ring_buf(struct mwifiex_adapter *adapter)
130762306a36Sopenharmony_ci{
130862306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
130962306a36Sopenharmony_ci
131062306a36Sopenharmony_ci	if (!mwifiex_pcie_txbd_empty(card, card->txbd_rdptr)) {
131162306a36Sopenharmony_ci		card->txbd_flush = 1;
131262306a36Sopenharmony_ci		/* write pointer already set at last send
131362306a36Sopenharmony_ci		 * send dnld-rdy intr again, wait for completion.
131462306a36Sopenharmony_ci		 */
131562306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
131662306a36Sopenharmony_ci				      CPU_INTR_DNLD_RDY)) {
131762306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
131862306a36Sopenharmony_ci				    "failed to assert dnld-rdy interrupt.\n");
131962306a36Sopenharmony_ci			return -1;
132062306a36Sopenharmony_ci		}
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci	return 0;
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_ci/*
132662306a36Sopenharmony_ci * This function unmaps and frees downloaded data buffer
132762306a36Sopenharmony_ci */
132862306a36Sopenharmony_cistatic int mwifiex_pcie_send_data_complete(struct mwifiex_adapter *adapter)
132962306a36Sopenharmony_ci{
133062306a36Sopenharmony_ci	struct sk_buff *skb;
133162306a36Sopenharmony_ci	u32 wrdoneidx, rdptr, num_tx_buffs, unmap_count = 0;
133262306a36Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
133362306a36Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
133462306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
133562306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
133862306a36Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_ci	/* Read the TX ring read pointer set by firmware */
134162306a36Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->tx_rdptr, &rdptr)) {
134262306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
134362306a36Sopenharmony_ci			    "SEND COMP: failed to read reg->tx_rdptr\n");
134462306a36Sopenharmony_ci		return -1;
134562306a36Sopenharmony_ci	}
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	mwifiex_dbg(adapter, DATA,
134862306a36Sopenharmony_ci		    "SEND COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
134962306a36Sopenharmony_ci		    card->txbd_rdptr, rdptr);
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci	num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
135262306a36Sopenharmony_ci	/* free from previous txbd_rdptr to current txbd_rdptr */
135362306a36Sopenharmony_ci	while (((card->txbd_rdptr & reg->tx_mask) !=
135462306a36Sopenharmony_ci		(rdptr & reg->tx_mask)) ||
135562306a36Sopenharmony_ci	       ((card->txbd_rdptr & reg->tx_rollover_ind) !=
135662306a36Sopenharmony_ci		(rdptr & reg->tx_rollover_ind))) {
135762306a36Sopenharmony_ci		wrdoneidx = (card->txbd_rdptr & reg->tx_mask) >>
135862306a36Sopenharmony_ci			    reg->tx_start_ptr;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci		skb = card->tx_buf_list[wrdoneidx];
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci		if (skb) {
136362306a36Sopenharmony_ci			mwifiex_dbg(adapter, DATA,
136462306a36Sopenharmony_ci				    "SEND COMP: Detach skb %p at txbd_rdidx=%d\n",
136562306a36Sopenharmony_ci				    skb, wrdoneidx);
136662306a36Sopenharmony_ci			mwifiex_unmap_pci_memory(adapter, skb,
136762306a36Sopenharmony_ci						 DMA_TO_DEVICE);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci			unmap_count++;
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci			if (card->txbd_flush)
137262306a36Sopenharmony_ci				mwifiex_write_data_complete(adapter, skb, 0,
137362306a36Sopenharmony_ci							    -1);
137462306a36Sopenharmony_ci			else
137562306a36Sopenharmony_ci				mwifiex_write_data_complete(adapter, skb, 0, 0);
137662306a36Sopenharmony_ci			atomic_dec(&adapter->tx_hw_pending);
137762306a36Sopenharmony_ci		}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci		card->tx_buf_list[wrdoneidx] = NULL;
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci		if (reg->pfu_enabled) {
138262306a36Sopenharmony_ci			desc2 = card->txbd_ring[wrdoneidx];
138362306a36Sopenharmony_ci			memset(desc2, 0, sizeof(*desc2));
138462306a36Sopenharmony_ci		} else {
138562306a36Sopenharmony_ci			desc = card->txbd_ring[wrdoneidx];
138662306a36Sopenharmony_ci			memset(desc, 0, sizeof(*desc));
138762306a36Sopenharmony_ci		}
138862306a36Sopenharmony_ci		switch (card->dev->device) {
138962306a36Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8766P:
139062306a36Sopenharmony_ci			card->txbd_rdptr++;
139162306a36Sopenharmony_ci			break;
139262306a36Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8897:
139362306a36Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8997:
139462306a36Sopenharmony_ci			card->txbd_rdptr += reg->ring_tx_start_ptr;
139562306a36Sopenharmony_ci			break;
139662306a36Sopenharmony_ci		}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci		if ((card->txbd_rdptr & reg->tx_mask) == num_tx_buffs)
140062306a36Sopenharmony_ci			card->txbd_rdptr = ((card->txbd_rdptr &
140162306a36Sopenharmony_ci					     reg->tx_rollover_ind) ^
140262306a36Sopenharmony_ci					     reg->tx_rollover_ind);
140362306a36Sopenharmony_ci	}
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	if (unmap_count)
140662306a36Sopenharmony_ci		adapter->data_sent = false;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	if (card->txbd_flush) {
140962306a36Sopenharmony_ci		if (mwifiex_pcie_txbd_empty(card, card->txbd_rdptr))
141062306a36Sopenharmony_ci			card->txbd_flush = 0;
141162306a36Sopenharmony_ci		else
141262306a36Sopenharmony_ci			mwifiex_clean_pcie_ring_buf(adapter);
141362306a36Sopenharmony_ci	}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	return 0;
141662306a36Sopenharmony_ci}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci/* This function sends data buffer to device. First 4 bytes of payload
141962306a36Sopenharmony_ci * are filled with payload length and payload type. Then this payload
142062306a36Sopenharmony_ci * is mapped to PCI device memory. Tx ring pointers are advanced accordingly.
142162306a36Sopenharmony_ci * Download ready interrupt to FW is deffered if Tx ring is not full and
142262306a36Sopenharmony_ci * additional payload can be accomodated.
142362306a36Sopenharmony_ci * Caller must ensure tx_param parameter to this function is not NULL.
142462306a36Sopenharmony_ci */
142562306a36Sopenharmony_cistatic int
142662306a36Sopenharmony_cimwifiex_pcie_send_data(struct mwifiex_adapter *adapter, struct sk_buff *skb,
142762306a36Sopenharmony_ci		       struct mwifiex_tx_param *tx_param)
142862306a36Sopenharmony_ci{
142962306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
143062306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
143162306a36Sopenharmony_ci	u32 wrindx, num_tx_buffs, rx_val;
143262306a36Sopenharmony_ci	int ret;
143362306a36Sopenharmony_ci	dma_addr_t buf_pa;
143462306a36Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc = NULL;
143562306a36Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2 = NULL;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	if (!(skb->data && skb->len)) {
143862306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
143962306a36Sopenharmony_ci			    "%s(): invalid parameter <%p, %#x>\n",
144062306a36Sopenharmony_ci			    __func__, skb->data, skb->len);
144162306a36Sopenharmony_ci		return -1;
144262306a36Sopenharmony_ci	}
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
144562306a36Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci	num_tx_buffs = MWIFIEX_MAX_TXRX_BD << reg->tx_start_ptr;
144862306a36Sopenharmony_ci	mwifiex_dbg(adapter, DATA,
144962306a36Sopenharmony_ci		    "info: SEND DATA: <Rd: %#x, Wr: %#x>\n",
145062306a36Sopenharmony_ci		card->txbd_rdptr, card->txbd_wrptr);
145162306a36Sopenharmony_ci	if (mwifiex_pcie_txbd_not_full(card)) {
145262306a36Sopenharmony_ci		u8 *payload;
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci		adapter->data_sent = true;
145562306a36Sopenharmony_ci		payload = skb->data;
145662306a36Sopenharmony_ci		put_unaligned_le16((u16)skb->len, payload + 0);
145762306a36Sopenharmony_ci		put_unaligned_le16(MWIFIEX_TYPE_DATA, payload + 2);
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb, skb->len,
146062306a36Sopenharmony_ci					   DMA_TO_DEVICE))
146162306a36Sopenharmony_ci			return -1;
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci		wrindx = (card->txbd_wrptr & reg->tx_mask) >> reg->tx_start_ptr;
146462306a36Sopenharmony_ci		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
146562306a36Sopenharmony_ci		card->tx_buf_list[wrindx] = skb;
146662306a36Sopenharmony_ci		atomic_inc(&adapter->tx_hw_pending);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci		if (reg->pfu_enabled) {
146962306a36Sopenharmony_ci			desc2 = card->txbd_ring[wrindx];
147062306a36Sopenharmony_ci			desc2->paddr = buf_pa;
147162306a36Sopenharmony_ci			desc2->len = (u16)skb->len;
147262306a36Sopenharmony_ci			desc2->frag_len = (u16)skb->len;
147362306a36Sopenharmony_ci			desc2->offset = 0;
147462306a36Sopenharmony_ci			desc2->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
147562306a36Sopenharmony_ci					 MWIFIEX_BD_FLAG_LAST_DESC;
147662306a36Sopenharmony_ci		} else {
147762306a36Sopenharmony_ci			desc = card->txbd_ring[wrindx];
147862306a36Sopenharmony_ci			desc->paddr = buf_pa;
147962306a36Sopenharmony_ci			desc->len = (u16)skb->len;
148062306a36Sopenharmony_ci			desc->flags = MWIFIEX_BD_FLAG_FIRST_DESC |
148162306a36Sopenharmony_ci				      MWIFIEX_BD_FLAG_LAST_DESC;
148262306a36Sopenharmony_ci		}
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci		switch (card->dev->device) {
148562306a36Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8766P:
148662306a36Sopenharmony_ci			card->txbd_wrptr++;
148762306a36Sopenharmony_ci			break;
148862306a36Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8897:
148962306a36Sopenharmony_ci		case PCIE_DEVICE_ID_MARVELL_88W8997:
149062306a36Sopenharmony_ci			card->txbd_wrptr += reg->ring_tx_start_ptr;
149162306a36Sopenharmony_ci			break;
149262306a36Sopenharmony_ci		}
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci		if ((card->txbd_wrptr & reg->tx_mask) == num_tx_buffs)
149562306a36Sopenharmony_ci			card->txbd_wrptr = ((card->txbd_wrptr &
149662306a36Sopenharmony_ci						reg->tx_rollover_ind) ^
149762306a36Sopenharmony_ci						reg->tx_rollover_ind);
149862306a36Sopenharmony_ci
149962306a36Sopenharmony_ci		rx_val = card->rxbd_rdptr & reg->rx_wrap_mask;
150062306a36Sopenharmony_ci		/* Write the TX ring write pointer in to reg->tx_wrptr */
150162306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->tx_wrptr,
150262306a36Sopenharmony_ci				      card->txbd_wrptr | rx_val)) {
150362306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
150462306a36Sopenharmony_ci				    "SEND DATA: failed to write reg->tx_wrptr\n");
150562306a36Sopenharmony_ci			ret = -1;
150662306a36Sopenharmony_ci			goto done_unmap;
150762306a36Sopenharmony_ci		}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci		/* The firmware (latest version 15.68.19.p21) of the 88W8897 PCIe+USB card
151062306a36Sopenharmony_ci		 * seems to crash randomly after setting the TX ring write pointer when
151162306a36Sopenharmony_ci		 * ASPM powersaving is enabled. A workaround seems to be keeping the bus
151262306a36Sopenharmony_ci		 * busy by reading a random register afterwards.
151362306a36Sopenharmony_ci		 */
151462306a36Sopenharmony_ci		mwifiex_read_reg(adapter, PCI_VENDOR_ID, &rx_val);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		if ((mwifiex_pcie_txbd_not_full(card)) &&
151762306a36Sopenharmony_ci		    tx_param->next_pkt_len) {
151862306a36Sopenharmony_ci			/* have more packets and TxBD still can hold more */
151962306a36Sopenharmony_ci			mwifiex_dbg(adapter, DATA,
152062306a36Sopenharmony_ci				    "SEND DATA: delay dnld-rdy interrupt.\n");
152162306a36Sopenharmony_ci			adapter->data_sent = false;
152262306a36Sopenharmony_ci		} else {
152362306a36Sopenharmony_ci			/* Send the TX ready interrupt */
152462306a36Sopenharmony_ci			if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
152562306a36Sopenharmony_ci					      CPU_INTR_DNLD_RDY)) {
152662306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
152762306a36Sopenharmony_ci					    "SEND DATA: failed to assert dnld-rdy interrupt.\n");
152862306a36Sopenharmony_ci				ret = -1;
152962306a36Sopenharmony_ci				goto done_unmap;
153062306a36Sopenharmony_ci			}
153162306a36Sopenharmony_ci		}
153262306a36Sopenharmony_ci		mwifiex_dbg(adapter, DATA,
153362306a36Sopenharmony_ci			    "info: SEND DATA: Updated <Rd: %#x, Wr:\t"
153462306a36Sopenharmony_ci			    "%#x> and sent packet to firmware successfully\n",
153562306a36Sopenharmony_ci			    card->txbd_rdptr, card->txbd_wrptr);
153662306a36Sopenharmony_ci	} else {
153762306a36Sopenharmony_ci		mwifiex_dbg(adapter, DATA,
153862306a36Sopenharmony_ci			    "info: TX Ring full, can't send packets to fw\n");
153962306a36Sopenharmony_ci		adapter->data_sent = true;
154062306a36Sopenharmony_ci		/* Send the TX ready interrupt */
154162306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
154262306a36Sopenharmony_ci				      CPU_INTR_DNLD_RDY))
154362306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
154462306a36Sopenharmony_ci				    "SEND DATA: failed to assert door-bell intr\n");
154562306a36Sopenharmony_ci		return -EBUSY;
154662306a36Sopenharmony_ci	}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	return -EINPROGRESS;
154962306a36Sopenharmony_cidone_unmap:
155062306a36Sopenharmony_ci	mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
155162306a36Sopenharmony_ci	card->tx_buf_list[wrindx] = NULL;
155262306a36Sopenharmony_ci	atomic_dec(&adapter->tx_hw_pending);
155362306a36Sopenharmony_ci	if (reg->pfu_enabled)
155462306a36Sopenharmony_ci		memset(desc2, 0, sizeof(*desc2));
155562306a36Sopenharmony_ci	else
155662306a36Sopenharmony_ci		memset(desc, 0, sizeof(*desc));
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	return ret;
155962306a36Sopenharmony_ci}
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci/*
156262306a36Sopenharmony_ci * This function handles received buffer ring and
156362306a36Sopenharmony_ci * dispatches packets to upper
156462306a36Sopenharmony_ci */
156562306a36Sopenharmony_cistatic int mwifiex_pcie_process_recv_data(struct mwifiex_adapter *adapter)
156662306a36Sopenharmony_ci{
156762306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
156862306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
156962306a36Sopenharmony_ci	u32 wrptr, rd_index, tx_val;
157062306a36Sopenharmony_ci	dma_addr_t buf_pa;
157162306a36Sopenharmony_ci	int ret = 0;
157262306a36Sopenharmony_ci	struct sk_buff *skb_tmp = NULL;
157362306a36Sopenharmony_ci	struct mwifiex_pcie_buf_desc *desc;
157462306a36Sopenharmony_ci	struct mwifiex_pfu_buf_desc *desc2;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
157762306a36Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	/* Read the RX ring Write pointer set by firmware */
158062306a36Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
158162306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
158262306a36Sopenharmony_ci			    "RECV DATA: failed to read reg->rx_wrptr\n");
158362306a36Sopenharmony_ci		ret = -1;
158462306a36Sopenharmony_ci		goto done;
158562306a36Sopenharmony_ci	}
158662306a36Sopenharmony_ci	card->rxbd_wrptr = wrptr;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	while (((wrptr & reg->rx_mask) !=
158962306a36Sopenharmony_ci		(card->rxbd_rdptr & reg->rx_mask)) ||
159062306a36Sopenharmony_ci	       ((wrptr & reg->rx_rollover_ind) ==
159162306a36Sopenharmony_ci		(card->rxbd_rdptr & reg->rx_rollover_ind))) {
159262306a36Sopenharmony_ci		struct sk_buff *skb_data;
159362306a36Sopenharmony_ci		u16 rx_len;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci		rd_index = card->rxbd_rdptr & reg->rx_mask;
159662306a36Sopenharmony_ci		skb_data = card->rx_buf_list[rd_index];
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci		/* If skb allocation was failed earlier for Rx packet,
159962306a36Sopenharmony_ci		 * rx_buf_list[rd_index] would have been left with a NULL.
160062306a36Sopenharmony_ci		 */
160162306a36Sopenharmony_ci		if (!skb_data)
160262306a36Sopenharmony_ci			return -ENOMEM;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb_data, DMA_FROM_DEVICE);
160562306a36Sopenharmony_ci		card->rx_buf_list[rd_index] = NULL;
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_ci		/* Get data length from interface header -
160862306a36Sopenharmony_ci		 * first 2 bytes for len, next 2 bytes is for type
160962306a36Sopenharmony_ci		 */
161062306a36Sopenharmony_ci		rx_len = get_unaligned_le16(skb_data->data);
161162306a36Sopenharmony_ci		if (WARN_ON(rx_len <= adapter->intf_hdr_len ||
161262306a36Sopenharmony_ci			    rx_len > MWIFIEX_RX_DATA_BUF_SIZE)) {
161362306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
161462306a36Sopenharmony_ci				    "Invalid RX len %d, Rd=%#x, Wr=%#x\n",
161562306a36Sopenharmony_ci				    rx_len, card->rxbd_rdptr, wrptr);
161662306a36Sopenharmony_ci			dev_kfree_skb_any(skb_data);
161762306a36Sopenharmony_ci		} else {
161862306a36Sopenharmony_ci			skb_put(skb_data, rx_len);
161962306a36Sopenharmony_ci			mwifiex_dbg(adapter, DATA,
162062306a36Sopenharmony_ci				    "info: RECV DATA: Rd=%#x, Wr=%#x, Len=%d\n",
162162306a36Sopenharmony_ci				    card->rxbd_rdptr, wrptr, rx_len);
162262306a36Sopenharmony_ci			skb_pull(skb_data, adapter->intf_hdr_len);
162362306a36Sopenharmony_ci			if (adapter->rx_work_enabled) {
162462306a36Sopenharmony_ci				skb_queue_tail(&adapter->rx_data_q, skb_data);
162562306a36Sopenharmony_ci				adapter->data_received = true;
162662306a36Sopenharmony_ci				atomic_inc(&adapter->rx_pending);
162762306a36Sopenharmony_ci			} else {
162862306a36Sopenharmony_ci				mwifiex_handle_rx_packet(adapter, skb_data);
162962306a36Sopenharmony_ci			}
163062306a36Sopenharmony_ci		}
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci		skb_tmp = mwifiex_alloc_dma_align_buf(MWIFIEX_RX_DATA_BUF_SIZE,
163362306a36Sopenharmony_ci						      GFP_KERNEL);
163462306a36Sopenharmony_ci		if (!skb_tmp) {
163562306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
163662306a36Sopenharmony_ci				    "Unable to allocate skb.\n");
163762306a36Sopenharmony_ci			return -ENOMEM;
163862306a36Sopenharmony_ci		}
163962306a36Sopenharmony_ci
164062306a36Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb_tmp,
164162306a36Sopenharmony_ci					   MWIFIEX_RX_DATA_BUF_SIZE,
164262306a36Sopenharmony_ci					   DMA_FROM_DEVICE))
164362306a36Sopenharmony_ci			return -1;
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_ci		buf_pa = MWIFIEX_SKB_DMA_ADDR(skb_tmp);
164662306a36Sopenharmony_ci
164762306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
164862306a36Sopenharmony_ci			    "RECV DATA: Attach new sk_buff %p at rxbd_rdidx=%d\n",
164962306a36Sopenharmony_ci			    skb_tmp, rd_index);
165062306a36Sopenharmony_ci		card->rx_buf_list[rd_index] = skb_tmp;
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci		if (reg->pfu_enabled) {
165362306a36Sopenharmony_ci			desc2 = card->rxbd_ring[rd_index];
165462306a36Sopenharmony_ci			desc2->paddr = buf_pa;
165562306a36Sopenharmony_ci			desc2->len = skb_tmp->len;
165662306a36Sopenharmony_ci			desc2->frag_len = skb_tmp->len;
165762306a36Sopenharmony_ci			desc2->offset = 0;
165862306a36Sopenharmony_ci			desc2->flags = reg->ring_flag_sop | reg->ring_flag_eop;
165962306a36Sopenharmony_ci		} else {
166062306a36Sopenharmony_ci			desc = card->rxbd_ring[rd_index];
166162306a36Sopenharmony_ci			desc->paddr = buf_pa;
166262306a36Sopenharmony_ci			desc->len = skb_tmp->len;
166362306a36Sopenharmony_ci			desc->flags = 0;
166462306a36Sopenharmony_ci		}
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci		if ((++card->rxbd_rdptr & reg->rx_mask) ==
166762306a36Sopenharmony_ci							MWIFIEX_MAX_TXRX_BD) {
166862306a36Sopenharmony_ci			card->rxbd_rdptr = ((card->rxbd_rdptr &
166962306a36Sopenharmony_ci					     reg->rx_rollover_ind) ^
167062306a36Sopenharmony_ci					     reg->rx_rollover_ind);
167162306a36Sopenharmony_ci		}
167262306a36Sopenharmony_ci		mwifiex_dbg(adapter, DATA,
167362306a36Sopenharmony_ci			    "info: RECV DATA: <Rd: %#x, Wr: %#x>\n",
167462306a36Sopenharmony_ci			    card->rxbd_rdptr, wrptr);
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci		tx_val = card->txbd_wrptr & reg->tx_wrap_mask;
167762306a36Sopenharmony_ci		/* Write the RX ring read pointer in to reg->rx_rdptr */
167862306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->rx_rdptr,
167962306a36Sopenharmony_ci				      card->rxbd_rdptr | tx_val)) {
168062306a36Sopenharmony_ci			mwifiex_dbg(adapter, DATA,
168162306a36Sopenharmony_ci				    "RECV DATA: failed to write reg->rx_rdptr\n");
168262306a36Sopenharmony_ci			ret = -1;
168362306a36Sopenharmony_ci			goto done;
168462306a36Sopenharmony_ci		}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci		/* Read the RX ring Write pointer set by firmware */
168762306a36Sopenharmony_ci		if (mwifiex_read_reg(adapter, reg->rx_wrptr, &wrptr)) {
168862306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
168962306a36Sopenharmony_ci				    "RECV DATA: failed to read reg->rx_wrptr\n");
169062306a36Sopenharmony_ci			ret = -1;
169162306a36Sopenharmony_ci			goto done;
169262306a36Sopenharmony_ci		}
169362306a36Sopenharmony_ci		mwifiex_dbg(adapter, DATA,
169462306a36Sopenharmony_ci			    "info: RECV DATA: Rcvd packet from fw successfully\n");
169562306a36Sopenharmony_ci		card->rxbd_wrptr = wrptr;
169662306a36Sopenharmony_ci	}
169762306a36Sopenharmony_ci
169862306a36Sopenharmony_cidone:
169962306a36Sopenharmony_ci	return ret;
170062306a36Sopenharmony_ci}
170162306a36Sopenharmony_ci
170262306a36Sopenharmony_ci/*
170362306a36Sopenharmony_ci * This function downloads the boot command to device
170462306a36Sopenharmony_ci */
170562306a36Sopenharmony_cistatic int
170662306a36Sopenharmony_cimwifiex_pcie_send_boot_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
170762306a36Sopenharmony_ci{
170862306a36Sopenharmony_ci	dma_addr_t buf_pa;
170962306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
171062306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	if (!(skb->data && skb->len)) {
171362306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
171462306a36Sopenharmony_ci			    "Invalid parameter in %s <%p. len %d>\n",
171562306a36Sopenharmony_ci			    __func__, skb->data, skb->len);
171662306a36Sopenharmony_ci		return -1;
171762306a36Sopenharmony_ci	}
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	if (mwifiex_map_pci_memory(adapter, skb, skb->len, DMA_TO_DEVICE))
172062306a36Sopenharmony_ci		return -1;
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_ci	buf_pa = MWIFIEX_SKB_DMA_ADDR(skb);
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	/* Write the lower 32bits of the physical address to low command
172562306a36Sopenharmony_ci	 * address scratch register
172662306a36Sopenharmony_ci	 */
172762306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_addr_lo, (u32)buf_pa)) {
172862306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
172962306a36Sopenharmony_ci			    "%s: failed to write download command to boot code.\n",
173062306a36Sopenharmony_ci			    __func__);
173162306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
173262306a36Sopenharmony_ci		return -1;
173362306a36Sopenharmony_ci	}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_ci	/* Write the upper 32bits of the physical address to high command
173662306a36Sopenharmony_ci	 * address scratch register
173762306a36Sopenharmony_ci	 */
173862306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
173962306a36Sopenharmony_ci			      (u32)((u64)buf_pa >> 32))) {
174062306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
174162306a36Sopenharmony_ci			    "%s: failed to write download command to boot code.\n",
174262306a36Sopenharmony_ci			    __func__);
174362306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
174462306a36Sopenharmony_ci		return -1;
174562306a36Sopenharmony_ci	}
174662306a36Sopenharmony_ci
174762306a36Sopenharmony_ci	/* Write the command length to cmd_size scratch register */
174862306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_size, skb->len)) {
174962306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
175062306a36Sopenharmony_ci			    "%s: failed to write command len to cmd_size scratch reg\n",
175162306a36Sopenharmony_ci			    __func__);
175262306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
175362306a36Sopenharmony_ci		return -1;
175462306a36Sopenharmony_ci	}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	/* Ring the door bell */
175762306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
175862306a36Sopenharmony_ci			      CPU_INTR_DOOR_BELL)) {
175962306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
176062306a36Sopenharmony_ci			    "%s: failed to assert door-bell intr\n", __func__);
176162306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
176262306a36Sopenharmony_ci		return -1;
176362306a36Sopenharmony_ci	}
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci	return 0;
176662306a36Sopenharmony_ci}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ci/* This function init rx port in firmware which in turn enables to receive data
176962306a36Sopenharmony_ci * from device before transmitting any packet.
177062306a36Sopenharmony_ci */
177162306a36Sopenharmony_cistatic int mwifiex_pcie_init_fw_port(struct mwifiex_adapter *adapter)
177262306a36Sopenharmony_ci{
177362306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
177462306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
177562306a36Sopenharmony_ci	int tx_wrap = card->txbd_wrptr & reg->tx_wrap_mask;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	/* Write the RX ring read pointer in to reg->rx_rdptr */
177862306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->rx_rdptr, card->rxbd_rdptr |
177962306a36Sopenharmony_ci			      tx_wrap)) {
178062306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
178162306a36Sopenharmony_ci			    "RECV DATA: failed to write reg->rx_rdptr\n");
178262306a36Sopenharmony_ci		return -1;
178362306a36Sopenharmony_ci	}
178462306a36Sopenharmony_ci	return 0;
178562306a36Sopenharmony_ci}
178662306a36Sopenharmony_ci
178762306a36Sopenharmony_ci/* This function downloads commands to the device
178862306a36Sopenharmony_ci */
178962306a36Sopenharmony_cistatic int
179062306a36Sopenharmony_cimwifiex_pcie_send_cmd(struct mwifiex_adapter *adapter, struct sk_buff *skb)
179162306a36Sopenharmony_ci{
179262306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
179362306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
179462306a36Sopenharmony_ci	int ret = 0;
179562306a36Sopenharmony_ci	dma_addr_t cmd_buf_pa, cmdrsp_buf_pa;
179662306a36Sopenharmony_ci	u8 *payload = (u8 *)skb->data;
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	if (!(skb->data && skb->len)) {
179962306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
180062306a36Sopenharmony_ci			    "Invalid parameter in %s <%p, %#x>\n",
180162306a36Sopenharmony_ci			    __func__, skb->data, skb->len);
180262306a36Sopenharmony_ci		return -1;
180362306a36Sopenharmony_ci	}
180462306a36Sopenharmony_ci
180562306a36Sopenharmony_ci	/* Make sure a command response buffer is available */
180662306a36Sopenharmony_ci	if (!card->cmdrsp_buf) {
180762306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
180862306a36Sopenharmony_ci			    "No response buffer available, send command failed\n");
180962306a36Sopenharmony_ci		return -EBUSY;
181062306a36Sopenharmony_ci	}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
181362306a36Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	adapter->cmd_sent = true;
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	put_unaligned_le16((u16)skb->len, &payload[0]);
181862306a36Sopenharmony_ci	put_unaligned_le16(MWIFIEX_TYPE_CMD, &payload[2]);
181962306a36Sopenharmony_ci
182062306a36Sopenharmony_ci	if (mwifiex_map_pci_memory(adapter, skb, skb->len, DMA_TO_DEVICE))
182162306a36Sopenharmony_ci		return -1;
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_ci	card->cmd_buf = skb;
182462306a36Sopenharmony_ci	/*
182562306a36Sopenharmony_ci	 * Need to keep a reference, since core driver might free up this
182662306a36Sopenharmony_ci	 * buffer before we've unmapped it.
182762306a36Sopenharmony_ci	 */
182862306a36Sopenharmony_ci	skb_get(skb);
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	/* To send a command, the driver will:
183162306a36Sopenharmony_ci		1. Write the 64bit physical address of the data buffer to
183262306a36Sopenharmony_ci		   cmd response address low  + cmd response address high
183362306a36Sopenharmony_ci		2. Ring the door bell (i.e. set the door bell interrupt)
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci		In response to door bell interrupt, the firmware will perform
183662306a36Sopenharmony_ci		the DMA of the command packet (first header to obtain the total
183762306a36Sopenharmony_ci		length and then rest of the command).
183862306a36Sopenharmony_ci	*/
183962306a36Sopenharmony_ci
184062306a36Sopenharmony_ci	if (card->cmdrsp_buf) {
184162306a36Sopenharmony_ci		cmdrsp_buf_pa = MWIFIEX_SKB_DMA_ADDR(card->cmdrsp_buf);
184262306a36Sopenharmony_ci		/* Write the lower 32bits of the cmdrsp buffer physical
184362306a36Sopenharmony_ci		   address */
184462306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo,
184562306a36Sopenharmony_ci				      (u32)cmdrsp_buf_pa)) {
184662306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
184762306a36Sopenharmony_ci				    "Failed to write download cmd to boot code.\n");
184862306a36Sopenharmony_ci			ret = -1;
184962306a36Sopenharmony_ci			goto done;
185062306a36Sopenharmony_ci		}
185162306a36Sopenharmony_ci		/* Write the upper 32bits of the cmdrsp buffer physical
185262306a36Sopenharmony_ci		   address */
185362306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi,
185462306a36Sopenharmony_ci				      (u32)((u64)cmdrsp_buf_pa >> 32))) {
185562306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
185662306a36Sopenharmony_ci				    "Failed to write download cmd to boot code.\n");
185762306a36Sopenharmony_ci			ret = -1;
185862306a36Sopenharmony_ci			goto done;
185962306a36Sopenharmony_ci		}
186062306a36Sopenharmony_ci	}
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	cmd_buf_pa = MWIFIEX_SKB_DMA_ADDR(card->cmd_buf);
186362306a36Sopenharmony_ci	/* Write the lower 32bits of the physical address to reg->cmd_addr_lo */
186462306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_addr_lo,
186562306a36Sopenharmony_ci			      (u32)cmd_buf_pa)) {
186662306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
186762306a36Sopenharmony_ci			    "Failed to write download cmd to boot code.\n");
186862306a36Sopenharmony_ci		ret = -1;
186962306a36Sopenharmony_ci		goto done;
187062306a36Sopenharmony_ci	}
187162306a36Sopenharmony_ci	/* Write the upper 32bits of the physical address to reg->cmd_addr_hi */
187262306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_addr_hi,
187362306a36Sopenharmony_ci			      (u32)((u64)cmd_buf_pa >> 32))) {
187462306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
187562306a36Sopenharmony_ci			    "Failed to write download cmd to boot code.\n");
187662306a36Sopenharmony_ci		ret = -1;
187762306a36Sopenharmony_ci		goto done;
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	/* Write the command length to reg->cmd_size */
188162306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->cmd_size,
188262306a36Sopenharmony_ci			      card->cmd_buf->len)) {
188362306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
188462306a36Sopenharmony_ci			    "Failed to write cmd len to reg->cmd_size\n");
188562306a36Sopenharmony_ci		ret = -1;
188662306a36Sopenharmony_ci		goto done;
188762306a36Sopenharmony_ci	}
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	/* Ring the door bell */
189062306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
189162306a36Sopenharmony_ci			      CPU_INTR_DOOR_BELL)) {
189262306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
189362306a36Sopenharmony_ci			    "Failed to assert door-bell intr\n");
189462306a36Sopenharmony_ci		ret = -1;
189562306a36Sopenharmony_ci		goto done;
189662306a36Sopenharmony_ci	}
189762306a36Sopenharmony_ci
189862306a36Sopenharmony_cidone:
189962306a36Sopenharmony_ci	if (ret)
190062306a36Sopenharmony_ci		adapter->cmd_sent = false;
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci	return 0;
190362306a36Sopenharmony_ci}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci/*
190662306a36Sopenharmony_ci * This function handles command complete interrupt
190762306a36Sopenharmony_ci */
190862306a36Sopenharmony_cistatic int mwifiex_pcie_process_cmd_complete(struct mwifiex_adapter *adapter)
190962306a36Sopenharmony_ci{
191062306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
191162306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
191262306a36Sopenharmony_ci	struct sk_buff *skb = card->cmdrsp_buf;
191362306a36Sopenharmony_ci	int count = 0;
191462306a36Sopenharmony_ci	u16 rx_len;
191562306a36Sopenharmony_ci
191662306a36Sopenharmony_ci	mwifiex_dbg(adapter, CMD,
191762306a36Sopenharmony_ci		    "info: Rx CMD Response\n");
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	if (adapter->curr_cmd)
192062306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_FROM_DEVICE);
192162306a36Sopenharmony_ci	else
192262306a36Sopenharmony_ci		dma_sync_single_for_cpu(&card->dev->dev,
192362306a36Sopenharmony_ci					MWIFIEX_SKB_DMA_ADDR(skb),
192462306a36Sopenharmony_ci					MWIFIEX_UPLD_SIZE, DMA_FROM_DEVICE);
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	/* Unmap the command as a response has been received. */
192762306a36Sopenharmony_ci	if (card->cmd_buf) {
192862306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, card->cmd_buf,
192962306a36Sopenharmony_ci					 DMA_TO_DEVICE);
193062306a36Sopenharmony_ci		dev_kfree_skb_any(card->cmd_buf);
193162306a36Sopenharmony_ci		card->cmd_buf = NULL;
193262306a36Sopenharmony_ci	}
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	rx_len = get_unaligned_le16(skb->data);
193562306a36Sopenharmony_ci	skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
193662306a36Sopenharmony_ci	skb_trim(skb, rx_len);
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	if (!adapter->curr_cmd) {
193962306a36Sopenharmony_ci		if (adapter->ps_state == PS_STATE_SLEEP_CFM) {
194062306a36Sopenharmony_ci			dma_sync_single_for_device(&card->dev->dev,
194162306a36Sopenharmony_ci						   MWIFIEX_SKB_DMA_ADDR(skb),
194262306a36Sopenharmony_ci						   MWIFIEX_SLEEP_COOKIE_SIZE,
194362306a36Sopenharmony_ci						   DMA_FROM_DEVICE);
194462306a36Sopenharmony_ci			if (mwifiex_write_reg(adapter,
194562306a36Sopenharmony_ci					      PCIE_CPU_INT_EVENT,
194662306a36Sopenharmony_ci					      CPU_INTR_SLEEP_CFM_DONE)) {
194762306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
194862306a36Sopenharmony_ci					    "Write register failed\n");
194962306a36Sopenharmony_ci				return -1;
195062306a36Sopenharmony_ci			}
195162306a36Sopenharmony_ci			mwifiex_delay_for_sleep_cookie(adapter,
195262306a36Sopenharmony_ci						       MWIFIEX_MAX_DELAY_COUNT);
195362306a36Sopenharmony_ci			mwifiex_unmap_pci_memory(adapter, skb,
195462306a36Sopenharmony_ci						 DMA_FROM_DEVICE);
195562306a36Sopenharmony_ci			skb_pull(skb, adapter->intf_hdr_len);
195662306a36Sopenharmony_ci			while (reg->sleep_cookie && (count++ < 10) &&
195762306a36Sopenharmony_ci			       mwifiex_pcie_ok_to_access_hw(adapter))
195862306a36Sopenharmony_ci				usleep_range(50, 60);
195962306a36Sopenharmony_ci			mwifiex_pcie_enable_host_int(adapter);
196062306a36Sopenharmony_ci			mwifiex_process_sleep_confirm_resp(adapter, skb->data,
196162306a36Sopenharmony_ci							   skb->len);
196262306a36Sopenharmony_ci		} else {
196362306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
196462306a36Sopenharmony_ci				    "There is no command but got cmdrsp\n");
196562306a36Sopenharmony_ci		}
196662306a36Sopenharmony_ci		memcpy(adapter->upld_buf, skb->data,
196762306a36Sopenharmony_ci		       min_t(u32, MWIFIEX_SIZE_OF_CMD_BUFFER, skb->len));
196862306a36Sopenharmony_ci		skb_push(skb, adapter->intf_hdr_len);
196962306a36Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
197062306a36Sopenharmony_ci					   DMA_FROM_DEVICE))
197162306a36Sopenharmony_ci			return -1;
197262306a36Sopenharmony_ci	} else if (mwifiex_pcie_ok_to_access_hw(adapter)) {
197362306a36Sopenharmony_ci		skb_pull(skb, adapter->intf_hdr_len);
197462306a36Sopenharmony_ci		adapter->curr_cmd->resp_skb = skb;
197562306a36Sopenharmony_ci		adapter->cmd_resp_received = true;
197662306a36Sopenharmony_ci		/* Take the pointer and set it to CMD node and will
197762306a36Sopenharmony_ci		   return in the response complete callback */
197862306a36Sopenharmony_ci		card->cmdrsp_buf = NULL;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci		/* Clear the cmd-rsp buffer address in scratch registers. This
198162306a36Sopenharmony_ci		   will prevent firmware from writing to the same response
198262306a36Sopenharmony_ci		   buffer again. */
198362306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_lo, 0)) {
198462306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
198562306a36Sopenharmony_ci				    "cmd_done: failed to clear cmd_rsp_addr_lo\n");
198662306a36Sopenharmony_ci			return -1;
198762306a36Sopenharmony_ci		}
198862306a36Sopenharmony_ci		/* Write the upper 32bits of the cmdrsp buffer physical
198962306a36Sopenharmony_ci		   address */
199062306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->cmdrsp_addr_hi, 0)) {
199162306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
199262306a36Sopenharmony_ci				    "cmd_done: failed to clear cmd_rsp_addr_hi\n");
199362306a36Sopenharmony_ci			return -1;
199462306a36Sopenharmony_ci		}
199562306a36Sopenharmony_ci	}
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci	return 0;
199862306a36Sopenharmony_ci}
199962306a36Sopenharmony_ci
200062306a36Sopenharmony_ci/*
200162306a36Sopenharmony_ci * Command Response processing complete handler
200262306a36Sopenharmony_ci */
200362306a36Sopenharmony_cistatic int mwifiex_pcie_cmdrsp_complete(struct mwifiex_adapter *adapter,
200462306a36Sopenharmony_ci					struct sk_buff *skb)
200562306a36Sopenharmony_ci{
200662306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
200762306a36Sopenharmony_ci
200862306a36Sopenharmony_ci	if (skb) {
200962306a36Sopenharmony_ci		card->cmdrsp_buf = skb;
201062306a36Sopenharmony_ci		skb_push(card->cmdrsp_buf, adapter->intf_hdr_len);
201162306a36Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb, MWIFIEX_UPLD_SIZE,
201262306a36Sopenharmony_ci					   DMA_FROM_DEVICE))
201362306a36Sopenharmony_ci			return -1;
201462306a36Sopenharmony_ci	}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_ci	return 0;
201762306a36Sopenharmony_ci}
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci/*
202062306a36Sopenharmony_ci * This function handles firmware event ready interrupt
202162306a36Sopenharmony_ci */
202262306a36Sopenharmony_cistatic int mwifiex_pcie_process_event_ready(struct mwifiex_adapter *adapter)
202362306a36Sopenharmony_ci{
202462306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
202562306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
202662306a36Sopenharmony_ci	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
202762306a36Sopenharmony_ci	u32 wrptr, event;
202862306a36Sopenharmony_ci	struct mwifiex_evt_buf_desc *desc;
202962306a36Sopenharmony_ci
203062306a36Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
203162306a36Sopenharmony_ci		mwifiex_pm_wakeup_card(adapter);
203262306a36Sopenharmony_ci
203362306a36Sopenharmony_ci	if (adapter->event_received) {
203462306a36Sopenharmony_ci		mwifiex_dbg(adapter, EVENT,
203562306a36Sopenharmony_ci			    "info: Event being processed,\t"
203662306a36Sopenharmony_ci			    "do not process this interrupt just yet\n");
203762306a36Sopenharmony_ci		return 0;
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci
204062306a36Sopenharmony_ci	if (rdptr >= MWIFIEX_MAX_EVT_BD) {
204162306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
204262306a36Sopenharmony_ci			    "info: Invalid read pointer...\n");
204362306a36Sopenharmony_ci		return -1;
204462306a36Sopenharmony_ci	}
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci	/* Read the event ring write pointer set by firmware */
204762306a36Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
204862306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
204962306a36Sopenharmony_ci			    "EventReady: failed to read reg->evt_wrptr\n");
205062306a36Sopenharmony_ci		return -1;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
205462306a36Sopenharmony_ci		    "info: EventReady: Initial <Rd: 0x%x, Wr: 0x%x>",
205562306a36Sopenharmony_ci		    card->evtbd_rdptr, wrptr);
205662306a36Sopenharmony_ci	if (((wrptr & MWIFIEX_EVTBD_MASK) != (card->evtbd_rdptr
205762306a36Sopenharmony_ci					      & MWIFIEX_EVTBD_MASK)) ||
205862306a36Sopenharmony_ci	    ((wrptr & reg->evt_rollover_ind) ==
205962306a36Sopenharmony_ci	     (card->evtbd_rdptr & reg->evt_rollover_ind))) {
206062306a36Sopenharmony_ci		struct sk_buff *skb_cmd;
206162306a36Sopenharmony_ci		__le16 data_len = 0;
206262306a36Sopenharmony_ci		u16 evt_len;
206362306a36Sopenharmony_ci
206462306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
206562306a36Sopenharmony_ci			    "info: Read Index: %d\n", rdptr);
206662306a36Sopenharmony_ci		skb_cmd = card->evt_buf_list[rdptr];
206762306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb_cmd, DMA_FROM_DEVICE);
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci		/* Take the pointer and set it to event pointer in adapter
207062306a36Sopenharmony_ci		   and will return back after event handling callback */
207162306a36Sopenharmony_ci		card->evt_buf_list[rdptr] = NULL;
207262306a36Sopenharmony_ci		desc = card->evtbd_ring[rdptr];
207362306a36Sopenharmony_ci		memset(desc, 0, sizeof(*desc));
207462306a36Sopenharmony_ci
207562306a36Sopenharmony_ci		event = get_unaligned_le32(
207662306a36Sopenharmony_ci			&skb_cmd->data[adapter->intf_hdr_len]);
207762306a36Sopenharmony_ci		adapter->event_cause = event;
207862306a36Sopenharmony_ci		/* The first 4bytes will be the event transfer header
207962306a36Sopenharmony_ci		   len is 2 bytes followed by type which is 2 bytes */
208062306a36Sopenharmony_ci		memcpy(&data_len, skb_cmd->data, sizeof(__le16));
208162306a36Sopenharmony_ci		evt_len = le16_to_cpu(data_len);
208262306a36Sopenharmony_ci		skb_trim(skb_cmd, evt_len);
208362306a36Sopenharmony_ci		skb_pull(skb_cmd, adapter->intf_hdr_len);
208462306a36Sopenharmony_ci		mwifiex_dbg(adapter, EVENT,
208562306a36Sopenharmony_ci			    "info: Event length: %d\n", evt_len);
208662306a36Sopenharmony_ci
208762306a36Sopenharmony_ci		if (evt_len > MWIFIEX_EVENT_HEADER_LEN &&
208862306a36Sopenharmony_ci		    evt_len < MAX_EVENT_SIZE)
208962306a36Sopenharmony_ci			memcpy(adapter->event_body, skb_cmd->data +
209062306a36Sopenharmony_ci			       MWIFIEX_EVENT_HEADER_LEN, evt_len -
209162306a36Sopenharmony_ci			       MWIFIEX_EVENT_HEADER_LEN);
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci		adapter->event_received = true;
209462306a36Sopenharmony_ci		adapter->event_skb = skb_cmd;
209562306a36Sopenharmony_ci
209662306a36Sopenharmony_ci		/* Do not update the event read pointer here, wait till the
209762306a36Sopenharmony_ci		   buffer is released. This is just to make things simpler,
209862306a36Sopenharmony_ci		   we need to find a better method of managing these buffers.
209962306a36Sopenharmony_ci		*/
210062306a36Sopenharmony_ci	} else {
210162306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT,
210262306a36Sopenharmony_ci				      CPU_INTR_EVENT_DONE)) {
210362306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
210462306a36Sopenharmony_ci				    "Write register failed\n");
210562306a36Sopenharmony_ci			return -1;
210662306a36Sopenharmony_ci		}
210762306a36Sopenharmony_ci	}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci	return 0;
211062306a36Sopenharmony_ci}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci/*
211362306a36Sopenharmony_ci * Event processing complete handler
211462306a36Sopenharmony_ci */
211562306a36Sopenharmony_cistatic int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
211662306a36Sopenharmony_ci				       struct sk_buff *skb)
211762306a36Sopenharmony_ci{
211862306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
211962306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
212062306a36Sopenharmony_ci	int ret = 0;
212162306a36Sopenharmony_ci	u32 rdptr = card->evtbd_rdptr & MWIFIEX_EVTBD_MASK;
212262306a36Sopenharmony_ci	u32 wrptr;
212362306a36Sopenharmony_ci	struct mwifiex_evt_buf_desc *desc;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	if (!skb)
212662306a36Sopenharmony_ci		return 0;
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	if (rdptr >= MWIFIEX_MAX_EVT_BD) {
212962306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
213062306a36Sopenharmony_ci			    "event_complete: Invalid rdptr 0x%x\n",
213162306a36Sopenharmony_ci			    rdptr);
213262306a36Sopenharmony_ci		return -EINVAL;
213362306a36Sopenharmony_ci	}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_ci	/* Read the event ring write pointer set by firmware */
213662306a36Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->evt_wrptr, &wrptr)) {
213762306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
213862306a36Sopenharmony_ci			    "event_complete: failed to read reg->evt_wrptr\n");
213962306a36Sopenharmony_ci		return -1;
214062306a36Sopenharmony_ci	}
214162306a36Sopenharmony_ci
214262306a36Sopenharmony_ci	if (!card->evt_buf_list[rdptr]) {
214362306a36Sopenharmony_ci		skb_push(skb, adapter->intf_hdr_len);
214462306a36Sopenharmony_ci		skb_put(skb, MAX_EVENT_SIZE - skb->len);
214562306a36Sopenharmony_ci		if (mwifiex_map_pci_memory(adapter, skb,
214662306a36Sopenharmony_ci					   MAX_EVENT_SIZE,
214762306a36Sopenharmony_ci					   DMA_FROM_DEVICE))
214862306a36Sopenharmony_ci			return -1;
214962306a36Sopenharmony_ci		card->evt_buf_list[rdptr] = skb;
215062306a36Sopenharmony_ci		desc = card->evtbd_ring[rdptr];
215162306a36Sopenharmony_ci		desc->paddr = MWIFIEX_SKB_DMA_ADDR(skb);
215262306a36Sopenharmony_ci		desc->len = (u16)skb->len;
215362306a36Sopenharmony_ci		desc->flags = 0;
215462306a36Sopenharmony_ci		skb = NULL;
215562306a36Sopenharmony_ci	} else {
215662306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
215762306a36Sopenharmony_ci			    "info: ERROR: buf still valid at index %d, <%p, %p>\n",
215862306a36Sopenharmony_ci			    rdptr, card->evt_buf_list[rdptr], skb);
215962306a36Sopenharmony_ci	}
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci	if ((++card->evtbd_rdptr & MWIFIEX_EVTBD_MASK) == MWIFIEX_MAX_EVT_BD) {
216262306a36Sopenharmony_ci		card->evtbd_rdptr = ((card->evtbd_rdptr &
216362306a36Sopenharmony_ci					reg->evt_rollover_ind) ^
216462306a36Sopenharmony_ci					reg->evt_rollover_ind);
216562306a36Sopenharmony_ci	}
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
216862306a36Sopenharmony_ci		    "info: Updated <Rd: 0x%x, Wr: 0x%x>",
216962306a36Sopenharmony_ci		    card->evtbd_rdptr, wrptr);
217062306a36Sopenharmony_ci
217162306a36Sopenharmony_ci	/* Write the event ring read pointer in to reg->evt_rdptr */
217262306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->evt_rdptr,
217362306a36Sopenharmony_ci			      card->evtbd_rdptr)) {
217462306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
217562306a36Sopenharmony_ci			    "event_complete: failed to read reg->evt_rdptr\n");
217662306a36Sopenharmony_ci		return -1;
217762306a36Sopenharmony_ci	}
217862306a36Sopenharmony_ci
217962306a36Sopenharmony_ci	mwifiex_dbg(adapter, EVENT,
218062306a36Sopenharmony_ci		    "info: Check Events Again\n");
218162306a36Sopenharmony_ci	ret = mwifiex_pcie_process_event_ready(adapter);
218262306a36Sopenharmony_ci
218362306a36Sopenharmony_ci	return ret;
218462306a36Sopenharmony_ci}
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci/* Combo firmware image is a combination of
218762306a36Sopenharmony_ci * (1) combo crc heaer, start with CMD5
218862306a36Sopenharmony_ci * (2) bluetooth image, start with CMD7, end with CMD6, data wrapped in CMD1.
218962306a36Sopenharmony_ci * (3) wifi image.
219062306a36Sopenharmony_ci *
219162306a36Sopenharmony_ci * This function bypass the header and bluetooth part, return
219262306a36Sopenharmony_ci * the offset of tail wifi-only part. If the image is already wifi-only,
219362306a36Sopenharmony_ci * that is start with CMD1, return 0.
219462306a36Sopenharmony_ci */
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_cistatic int mwifiex_extract_wifi_fw(struct mwifiex_adapter *adapter,
219762306a36Sopenharmony_ci				   const void *firmware, u32 firmware_len) {
219862306a36Sopenharmony_ci	const struct mwifiex_fw_data *fwdata;
219962306a36Sopenharmony_ci	u32 offset = 0, data_len, dnld_cmd;
220062306a36Sopenharmony_ci	int ret = 0;
220162306a36Sopenharmony_ci	bool cmd7_before = false, first_cmd = false;
220262306a36Sopenharmony_ci
220362306a36Sopenharmony_ci	while (1) {
220462306a36Sopenharmony_ci		/* Check for integer and buffer overflow */
220562306a36Sopenharmony_ci		if (offset + sizeof(fwdata->header) < sizeof(fwdata->header) ||
220662306a36Sopenharmony_ci		    offset + sizeof(fwdata->header) >= firmware_len) {
220762306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
220862306a36Sopenharmony_ci				    "extract wifi-only fw failure!\n");
220962306a36Sopenharmony_ci			ret = -1;
221062306a36Sopenharmony_ci			goto done;
221162306a36Sopenharmony_ci		}
221262306a36Sopenharmony_ci
221362306a36Sopenharmony_ci		fwdata = firmware + offset;
221462306a36Sopenharmony_ci		dnld_cmd = le32_to_cpu(fwdata->header.dnld_cmd);
221562306a36Sopenharmony_ci		data_len = le32_to_cpu(fwdata->header.data_length);
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci		/* Skip past header */
221862306a36Sopenharmony_ci		offset += sizeof(fwdata->header);
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_ci		switch (dnld_cmd) {
222162306a36Sopenharmony_ci		case MWIFIEX_FW_DNLD_CMD_1:
222262306a36Sopenharmony_ci			if (offset + data_len < data_len) {
222362306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
222462306a36Sopenharmony_ci				ret = -1;
222562306a36Sopenharmony_ci				goto done;
222662306a36Sopenharmony_ci			}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci			/* Image start with cmd1, already wifi-only firmware */
222962306a36Sopenharmony_ci			if (!first_cmd) {
223062306a36Sopenharmony_ci				mwifiex_dbg(adapter, MSG,
223162306a36Sopenharmony_ci					    "input wifi-only firmware\n");
223262306a36Sopenharmony_ci				return 0;
223362306a36Sopenharmony_ci			}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci			if (!cmd7_before) {
223662306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
223762306a36Sopenharmony_ci					    "no cmd7 before cmd1!\n");
223862306a36Sopenharmony_ci				ret = -1;
223962306a36Sopenharmony_ci				goto done;
224062306a36Sopenharmony_ci			}
224162306a36Sopenharmony_ci			offset += data_len;
224262306a36Sopenharmony_ci			break;
224362306a36Sopenharmony_ci		case MWIFIEX_FW_DNLD_CMD_5:
224462306a36Sopenharmony_ci			first_cmd = true;
224562306a36Sopenharmony_ci			/* Check for integer overflow */
224662306a36Sopenharmony_ci			if (offset + data_len < data_len) {
224762306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
224862306a36Sopenharmony_ci				ret = -1;
224962306a36Sopenharmony_ci				goto done;
225062306a36Sopenharmony_ci			}
225162306a36Sopenharmony_ci			offset += data_len;
225262306a36Sopenharmony_ci			break;
225362306a36Sopenharmony_ci		case MWIFIEX_FW_DNLD_CMD_6:
225462306a36Sopenharmony_ci			first_cmd = true;
225562306a36Sopenharmony_ci			/* Check for integer overflow */
225662306a36Sopenharmony_ci			if (offset + data_len < data_len) {
225762306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR, "bad FW parse\n");
225862306a36Sopenharmony_ci				ret = -1;
225962306a36Sopenharmony_ci				goto done;
226062306a36Sopenharmony_ci			}
226162306a36Sopenharmony_ci			offset += data_len;
226262306a36Sopenharmony_ci			if (offset >= firmware_len) {
226362306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
226462306a36Sopenharmony_ci					    "extract wifi-only fw failure!\n");
226562306a36Sopenharmony_ci				ret = -1;
226662306a36Sopenharmony_ci			} else {
226762306a36Sopenharmony_ci				ret = offset;
226862306a36Sopenharmony_ci			}
226962306a36Sopenharmony_ci			goto done;
227062306a36Sopenharmony_ci		case MWIFIEX_FW_DNLD_CMD_7:
227162306a36Sopenharmony_ci			first_cmd = true;
227262306a36Sopenharmony_ci			cmd7_before = true;
227362306a36Sopenharmony_ci			break;
227462306a36Sopenharmony_ci		default:
227562306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "unknown dnld_cmd %d\n",
227662306a36Sopenharmony_ci				    dnld_cmd);
227762306a36Sopenharmony_ci			ret = -1;
227862306a36Sopenharmony_ci			goto done;
227962306a36Sopenharmony_ci		}
228062306a36Sopenharmony_ci	}
228162306a36Sopenharmony_ci
228262306a36Sopenharmony_cidone:
228362306a36Sopenharmony_ci	return ret;
228462306a36Sopenharmony_ci}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci/*
228762306a36Sopenharmony_ci * This function downloads the firmware to the card.
228862306a36Sopenharmony_ci *
228962306a36Sopenharmony_ci * Firmware is downloaded to the card in blocks. Every block download
229062306a36Sopenharmony_ci * is tested for CRC errors, and retried a number of times before
229162306a36Sopenharmony_ci * returning failure.
229262306a36Sopenharmony_ci */
229362306a36Sopenharmony_cistatic int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
229462306a36Sopenharmony_ci				    struct mwifiex_fw_image *fw)
229562306a36Sopenharmony_ci{
229662306a36Sopenharmony_ci	int ret;
229762306a36Sopenharmony_ci	u8 *firmware = fw->fw_buf;
229862306a36Sopenharmony_ci	u32 firmware_len = fw->fw_len;
229962306a36Sopenharmony_ci	u32 offset = 0;
230062306a36Sopenharmony_ci	struct sk_buff *skb;
230162306a36Sopenharmony_ci	u32 txlen, tx_blocks = 0, tries, len, val;
230262306a36Sopenharmony_ci	u32 block_retry_cnt = 0;
230362306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
230462306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	if (!firmware || !firmware_len) {
230762306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
230862306a36Sopenharmony_ci			    "No firmware image found! Terminating download\n");
230962306a36Sopenharmony_ci		return -1;
231062306a36Sopenharmony_ci	}
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
231362306a36Sopenharmony_ci		    "info: Downloading FW image (%d bytes)\n",
231462306a36Sopenharmony_ci		    firmware_len);
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	if (mwifiex_pcie_disable_host_int(adapter)) {
231762306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
231862306a36Sopenharmony_ci			    "%s: Disabling interrupts failed.\n", __func__);
231962306a36Sopenharmony_ci		return -1;
232062306a36Sopenharmony_ci	}
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	skb = dev_alloc_skb(MWIFIEX_UPLD_SIZE);
232362306a36Sopenharmony_ci	if (!skb) {
232462306a36Sopenharmony_ci		ret = -ENOMEM;
232562306a36Sopenharmony_ci		goto done;
232662306a36Sopenharmony_ci	}
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci	ret = mwifiex_read_reg(adapter, PCIE_SCRATCH_13_REG, &val);
232962306a36Sopenharmony_ci	if (ret) {
233062306a36Sopenharmony_ci		mwifiex_dbg(adapter, FATAL, "Failed to read scratch register 13\n");
233162306a36Sopenharmony_ci		goto done;
233262306a36Sopenharmony_ci	}
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci	/* PCIE FLR case: extract wifi part from combo firmware*/
233562306a36Sopenharmony_ci	if (val == MWIFIEX_PCIE_FLR_HAPPENS) {
233662306a36Sopenharmony_ci		ret = mwifiex_extract_wifi_fw(adapter, firmware, firmware_len);
233762306a36Sopenharmony_ci		if (ret < 0) {
233862306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "Failed to extract wifi fw\n");
233962306a36Sopenharmony_ci			goto done;
234062306a36Sopenharmony_ci		}
234162306a36Sopenharmony_ci		offset = ret;
234262306a36Sopenharmony_ci		mwifiex_dbg(adapter, MSG,
234362306a36Sopenharmony_ci			    "info: dnld wifi firmware from %d bytes\n", offset);
234462306a36Sopenharmony_ci	}
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	/* Perform firmware data transfer */
234762306a36Sopenharmony_ci	do {
234862306a36Sopenharmony_ci		u32 ireg_intr = 0;
234962306a36Sopenharmony_ci
235062306a36Sopenharmony_ci		/* More data? */
235162306a36Sopenharmony_ci		if (offset >= firmware_len)
235262306a36Sopenharmony_ci			break;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
235562306a36Sopenharmony_ci			ret = mwifiex_read_reg(adapter, reg->cmd_size,
235662306a36Sopenharmony_ci					       &len);
235762306a36Sopenharmony_ci			if (ret) {
235862306a36Sopenharmony_ci				mwifiex_dbg(adapter, FATAL,
235962306a36Sopenharmony_ci					    "Failed reading len from boot code\n");
236062306a36Sopenharmony_ci				goto done;
236162306a36Sopenharmony_ci			}
236262306a36Sopenharmony_ci			if (len)
236362306a36Sopenharmony_ci				break;
236462306a36Sopenharmony_ci			usleep_range(10, 20);
236562306a36Sopenharmony_ci		}
236662306a36Sopenharmony_ci
236762306a36Sopenharmony_ci		if (!len) {
236862306a36Sopenharmony_ci			break;
236962306a36Sopenharmony_ci		} else if (len > MWIFIEX_UPLD_SIZE) {
237062306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
237162306a36Sopenharmony_ci				    "FW download failure @ %d, invalid length %d\n",
237262306a36Sopenharmony_ci				    offset, len);
237362306a36Sopenharmony_ci			ret = -1;
237462306a36Sopenharmony_ci			goto done;
237562306a36Sopenharmony_ci		}
237662306a36Sopenharmony_ci
237762306a36Sopenharmony_ci		txlen = len;
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci		if (len & BIT(0)) {
238062306a36Sopenharmony_ci			block_retry_cnt++;
238162306a36Sopenharmony_ci			if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
238262306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
238362306a36Sopenharmony_ci					    "FW download failure @ %d, over max\t"
238462306a36Sopenharmony_ci					    "retry count\n", offset);
238562306a36Sopenharmony_ci				ret = -1;
238662306a36Sopenharmony_ci				goto done;
238762306a36Sopenharmony_ci			}
238862306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
238962306a36Sopenharmony_ci				    "FW CRC error indicated by the\t"
239062306a36Sopenharmony_ci				    "helper: len = 0x%04X, txlen = %d\n",
239162306a36Sopenharmony_ci				    len, txlen);
239262306a36Sopenharmony_ci			len &= ~BIT(0);
239362306a36Sopenharmony_ci			/* Setting this to 0 to resend from same offset */
239462306a36Sopenharmony_ci			txlen = 0;
239562306a36Sopenharmony_ci		} else {
239662306a36Sopenharmony_ci			block_retry_cnt = 0;
239762306a36Sopenharmony_ci			/* Set blocksize to transfer - checking for
239862306a36Sopenharmony_ci			   last block */
239962306a36Sopenharmony_ci			if (firmware_len - offset < txlen)
240062306a36Sopenharmony_ci				txlen = firmware_len - offset;
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci			tx_blocks = (txlen + card->pcie.blksz_fw_dl - 1) /
240362306a36Sopenharmony_ci				    card->pcie.blksz_fw_dl;
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci			/* Copy payload to buffer */
240662306a36Sopenharmony_ci			memmove(skb->data, &firmware[offset], txlen);
240762306a36Sopenharmony_ci		}
240862306a36Sopenharmony_ci
240962306a36Sopenharmony_ci		skb_put(skb, MWIFIEX_UPLD_SIZE - skb->len);
241062306a36Sopenharmony_ci		skb_trim(skb, tx_blocks * card->pcie.blksz_fw_dl);
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci		/* Send the boot command to device */
241362306a36Sopenharmony_ci		if (mwifiex_pcie_send_boot_cmd(adapter, skb)) {
241462306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
241562306a36Sopenharmony_ci				    "Failed to send firmware download command\n");
241662306a36Sopenharmony_ci			ret = -1;
241762306a36Sopenharmony_ci			goto done;
241862306a36Sopenharmony_ci		}
241962306a36Sopenharmony_ci
242062306a36Sopenharmony_ci		/* Wait for the command done interrupt */
242162306a36Sopenharmony_ci		for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
242262306a36Sopenharmony_ci			if (mwifiex_read_reg(adapter, PCIE_CPU_INT_STATUS,
242362306a36Sopenharmony_ci					     &ireg_intr)) {
242462306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
242562306a36Sopenharmony_ci					    "%s: Failed to read\t"
242662306a36Sopenharmony_ci					    "interrupt status during fw dnld.\n",
242762306a36Sopenharmony_ci					    __func__);
242862306a36Sopenharmony_ci				mwifiex_unmap_pci_memory(adapter, skb,
242962306a36Sopenharmony_ci							 DMA_TO_DEVICE);
243062306a36Sopenharmony_ci				ret = -1;
243162306a36Sopenharmony_ci				goto done;
243262306a36Sopenharmony_ci			}
243362306a36Sopenharmony_ci			if (!(ireg_intr & CPU_INTR_DOOR_BELL))
243462306a36Sopenharmony_ci				break;
243562306a36Sopenharmony_ci			usleep_range(10, 20);
243662306a36Sopenharmony_ci		}
243762306a36Sopenharmony_ci		if (ireg_intr & CPU_INTR_DOOR_BELL) {
243862306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "%s: Card failed to ACK download\n",
243962306a36Sopenharmony_ci				    __func__);
244062306a36Sopenharmony_ci			mwifiex_unmap_pci_memory(adapter, skb,
244162306a36Sopenharmony_ci						 DMA_TO_DEVICE);
244262306a36Sopenharmony_ci			ret = -1;
244362306a36Sopenharmony_ci			goto done;
244462306a36Sopenharmony_ci		}
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_ci		mwifiex_unmap_pci_memory(adapter, skb, DMA_TO_DEVICE);
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci		offset += txlen;
244962306a36Sopenharmony_ci	} while (true);
245062306a36Sopenharmony_ci
245162306a36Sopenharmony_ci	mwifiex_dbg(adapter, MSG,
245262306a36Sopenharmony_ci		    "info: FW download over, size %d bytes\n", offset);
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	ret = 0;
245562306a36Sopenharmony_ci
245662306a36Sopenharmony_cidone:
245762306a36Sopenharmony_ci	dev_kfree_skb_any(skb);
245862306a36Sopenharmony_ci	return ret;
245962306a36Sopenharmony_ci}
246062306a36Sopenharmony_ci
246162306a36Sopenharmony_ci/*
246262306a36Sopenharmony_ci * This function checks the firmware status in card.
246362306a36Sopenharmony_ci */
246462306a36Sopenharmony_cistatic int
246562306a36Sopenharmony_cimwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
246662306a36Sopenharmony_ci{
246762306a36Sopenharmony_ci	int ret = 0;
246862306a36Sopenharmony_ci	u32 firmware_stat;
246962306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
247062306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
247162306a36Sopenharmony_ci	u32 tries;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	/* Mask spurios interrupts */
247462306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS_MASK,
247562306a36Sopenharmony_ci			      HOST_INTR_MASK)) {
247662306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
247762306a36Sopenharmony_ci			    "Write register failed\n");
247862306a36Sopenharmony_ci		return -1;
247962306a36Sopenharmony_ci	}
248062306a36Sopenharmony_ci
248162306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO,
248262306a36Sopenharmony_ci		    "Setting driver ready signature\n");
248362306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->drv_rdy,
248462306a36Sopenharmony_ci			      FIRMWARE_READY_PCIE)) {
248562306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
248662306a36Sopenharmony_ci			    "Failed to write driver ready signature\n");
248762306a36Sopenharmony_ci		return -1;
248862306a36Sopenharmony_ci	}
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci	/* Wait for firmware initialization event */
249162306a36Sopenharmony_ci	for (tries = 0; tries < poll_num; tries++) {
249262306a36Sopenharmony_ci		if (mwifiex_read_reg(adapter, reg->fw_status,
249362306a36Sopenharmony_ci				     &firmware_stat))
249462306a36Sopenharmony_ci			ret = -1;
249562306a36Sopenharmony_ci		else
249662306a36Sopenharmony_ci			ret = 0;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO, "Try %d if FW is ready <%d,%#x>",
249962306a36Sopenharmony_ci			    tries, ret, firmware_stat);
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci		if (ret)
250262306a36Sopenharmony_ci			continue;
250362306a36Sopenharmony_ci		if (firmware_stat == FIRMWARE_READY_PCIE) {
250462306a36Sopenharmony_ci			ret = 0;
250562306a36Sopenharmony_ci			break;
250662306a36Sopenharmony_ci		} else {
250762306a36Sopenharmony_ci			msleep(100);
250862306a36Sopenharmony_ci			ret = -1;
250962306a36Sopenharmony_ci		}
251062306a36Sopenharmony_ci	}
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci	return ret;
251362306a36Sopenharmony_ci}
251462306a36Sopenharmony_ci
251562306a36Sopenharmony_ci/* This function checks if WLAN is the winner.
251662306a36Sopenharmony_ci */
251762306a36Sopenharmony_cistatic int
251862306a36Sopenharmony_cimwifiex_check_winner_status(struct mwifiex_adapter *adapter)
251962306a36Sopenharmony_ci{
252062306a36Sopenharmony_ci	u32 winner = 0;
252162306a36Sopenharmony_ci	int ret = 0;
252262306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
252362306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
252462306a36Sopenharmony_ci
252562306a36Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->fw_status, &winner)) {
252662306a36Sopenharmony_ci		ret = -1;
252762306a36Sopenharmony_ci	} else if (!winner) {
252862306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO, "PCI-E is the winner\n");
252962306a36Sopenharmony_ci		adapter->winner = 1;
253062306a36Sopenharmony_ci	} else {
253162306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
253262306a36Sopenharmony_ci			    "PCI-E is not the winner <%#x>", winner);
253362306a36Sopenharmony_ci	}
253462306a36Sopenharmony_ci
253562306a36Sopenharmony_ci	return ret;
253662306a36Sopenharmony_ci}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci/*
253962306a36Sopenharmony_ci * This function reads the interrupt status from card.
254062306a36Sopenharmony_ci */
254162306a36Sopenharmony_cistatic void mwifiex_interrupt_status(struct mwifiex_adapter *adapter,
254262306a36Sopenharmony_ci				     int msg_id)
254362306a36Sopenharmony_ci{
254462306a36Sopenharmony_ci	u32 pcie_ireg;
254562306a36Sopenharmony_ci	unsigned long flags;
254662306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
254762306a36Sopenharmony_ci
254862306a36Sopenharmony_ci	if (card->msi_enable) {
254962306a36Sopenharmony_ci		spin_lock_irqsave(&adapter->int_lock, flags);
255062306a36Sopenharmony_ci		adapter->int_status = 1;
255162306a36Sopenharmony_ci		spin_unlock_irqrestore(&adapter->int_lock, flags);
255262306a36Sopenharmony_ci		return;
255362306a36Sopenharmony_ci	}
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	if (!mwifiex_pcie_ok_to_access_hw(adapter))
255662306a36Sopenharmony_ci		return;
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	if (card->msix_enable && msg_id >= 0) {
255962306a36Sopenharmony_ci		pcie_ireg = BIT(msg_id);
256062306a36Sopenharmony_ci	} else {
256162306a36Sopenharmony_ci		if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
256262306a36Sopenharmony_ci				     &pcie_ireg)) {
256362306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "Read register failed\n");
256462306a36Sopenharmony_ci			return;
256562306a36Sopenharmony_ci		}
256662306a36Sopenharmony_ci
256762306a36Sopenharmony_ci		if ((pcie_ireg == 0xFFFFFFFF) || !pcie_ireg)
256862306a36Sopenharmony_ci			return;
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci
257162306a36Sopenharmony_ci		mwifiex_pcie_disable_host_int(adapter);
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci		/* Clear the pending interrupts */
257462306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, PCIE_HOST_INT_STATUS,
257562306a36Sopenharmony_ci				      ~pcie_ireg)) {
257662306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
257762306a36Sopenharmony_ci				    "Write register failed\n");
257862306a36Sopenharmony_ci			return;
257962306a36Sopenharmony_ci		}
258062306a36Sopenharmony_ci	}
258162306a36Sopenharmony_ci
258262306a36Sopenharmony_ci	if (!adapter->pps_uapsd_mode &&
258362306a36Sopenharmony_ci	    adapter->ps_state == PS_STATE_SLEEP &&
258462306a36Sopenharmony_ci	    mwifiex_pcie_ok_to_access_hw(adapter)) {
258562306a36Sopenharmony_ci		/* Potentially for PCIe we could get other
258662306a36Sopenharmony_ci		 * interrupts like shared. Don't change power
258762306a36Sopenharmony_ci		 * state until cookie is set
258862306a36Sopenharmony_ci		 */
258962306a36Sopenharmony_ci		adapter->ps_state = PS_STATE_AWAKE;
259062306a36Sopenharmony_ci		adapter->pm_wakeup_fw_try = false;
259162306a36Sopenharmony_ci		del_timer(&adapter->wakeup_timer);
259262306a36Sopenharmony_ci	}
259362306a36Sopenharmony_ci
259462306a36Sopenharmony_ci	spin_lock_irqsave(&adapter->int_lock, flags);
259562306a36Sopenharmony_ci	adapter->int_status |= pcie_ireg;
259662306a36Sopenharmony_ci	spin_unlock_irqrestore(&adapter->int_lock, flags);
259762306a36Sopenharmony_ci	mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg);
259862306a36Sopenharmony_ci}
259962306a36Sopenharmony_ci
260062306a36Sopenharmony_ci/*
260162306a36Sopenharmony_ci * Interrupt handler for PCIe root port
260262306a36Sopenharmony_ci *
260362306a36Sopenharmony_ci * This function reads the interrupt status from firmware and assigns
260462306a36Sopenharmony_ci * the main process in workqueue which will handle the interrupt.
260562306a36Sopenharmony_ci */
260662306a36Sopenharmony_cistatic irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
260762306a36Sopenharmony_ci{
260862306a36Sopenharmony_ci	struct mwifiex_msix_context *ctx = context;
260962306a36Sopenharmony_ci	struct pci_dev *pdev = ctx->dev;
261062306a36Sopenharmony_ci	struct pcie_service_card *card;
261162306a36Sopenharmony_ci	struct mwifiex_adapter *adapter;
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	card = pci_get_drvdata(pdev);
261462306a36Sopenharmony_ci
261562306a36Sopenharmony_ci	if (!card->adapter) {
261662306a36Sopenharmony_ci		pr_err("info: %s: card=%p adapter=%p\n", __func__, card,
261762306a36Sopenharmony_ci		       card ? card->adapter : NULL);
261862306a36Sopenharmony_ci		goto exit;
261962306a36Sopenharmony_ci	}
262062306a36Sopenharmony_ci	adapter = card->adapter;
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	if (test_bit(MWIFIEX_SURPRISE_REMOVED, &adapter->work_flags))
262362306a36Sopenharmony_ci		goto exit;
262462306a36Sopenharmony_ci
262562306a36Sopenharmony_ci	if (card->msix_enable)
262662306a36Sopenharmony_ci		mwifiex_interrupt_status(adapter, ctx->msg_id);
262762306a36Sopenharmony_ci	else
262862306a36Sopenharmony_ci		mwifiex_interrupt_status(adapter, -1);
262962306a36Sopenharmony_ci
263062306a36Sopenharmony_ci	mwifiex_queue_main_work(adapter);
263162306a36Sopenharmony_ci
263262306a36Sopenharmony_ciexit:
263362306a36Sopenharmony_ci	return IRQ_HANDLED;
263462306a36Sopenharmony_ci}
263562306a36Sopenharmony_ci
263662306a36Sopenharmony_ci/*
263762306a36Sopenharmony_ci * This function checks the current interrupt status.
263862306a36Sopenharmony_ci *
263962306a36Sopenharmony_ci * The following interrupts are checked and handled by this function -
264062306a36Sopenharmony_ci *      - Data sent
264162306a36Sopenharmony_ci *      - Command sent
264262306a36Sopenharmony_ci *      - Command received
264362306a36Sopenharmony_ci *      - Packets received
264462306a36Sopenharmony_ci *      - Events received
264562306a36Sopenharmony_ci *
264662306a36Sopenharmony_ci * In case of Rx packets received, the packets are uploaded from card to
264762306a36Sopenharmony_ci * host and processed accordingly.
264862306a36Sopenharmony_ci */
264962306a36Sopenharmony_cistatic int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
265062306a36Sopenharmony_ci{
265162306a36Sopenharmony_ci	int ret;
265262306a36Sopenharmony_ci	u32 pcie_ireg = 0;
265362306a36Sopenharmony_ci	unsigned long flags;
265462306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	spin_lock_irqsave(&adapter->int_lock, flags);
265762306a36Sopenharmony_ci	if (!card->msi_enable) {
265862306a36Sopenharmony_ci		/* Clear out unused interrupts */
265962306a36Sopenharmony_ci		pcie_ireg = adapter->int_status;
266062306a36Sopenharmony_ci	}
266162306a36Sopenharmony_ci	adapter->int_status = 0;
266262306a36Sopenharmony_ci	spin_unlock_irqrestore(&adapter->int_lock, flags);
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	if (card->msi_enable) {
266562306a36Sopenharmony_ci		if (mwifiex_pcie_ok_to_access_hw(adapter)) {
266662306a36Sopenharmony_ci			if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
266762306a36Sopenharmony_ci					     &pcie_ireg)) {
266862306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
266962306a36Sopenharmony_ci					    "Read register failed\n");
267062306a36Sopenharmony_ci				return -1;
267162306a36Sopenharmony_ci			}
267262306a36Sopenharmony_ci
267362306a36Sopenharmony_ci			if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
267462306a36Sopenharmony_ci				if (mwifiex_write_reg(adapter,
267562306a36Sopenharmony_ci						      PCIE_HOST_INT_STATUS,
267662306a36Sopenharmony_ci						      ~pcie_ireg)) {
267762306a36Sopenharmony_ci					mwifiex_dbg(adapter, ERROR,
267862306a36Sopenharmony_ci						    "Write register failed\n");
267962306a36Sopenharmony_ci					return -1;
268062306a36Sopenharmony_ci				}
268162306a36Sopenharmony_ci				if (!adapter->pps_uapsd_mode &&
268262306a36Sopenharmony_ci				    adapter->ps_state == PS_STATE_SLEEP) {
268362306a36Sopenharmony_ci					adapter->ps_state = PS_STATE_AWAKE;
268462306a36Sopenharmony_ci					adapter->pm_wakeup_fw_try = false;
268562306a36Sopenharmony_ci					del_timer(&adapter->wakeup_timer);
268662306a36Sopenharmony_ci				}
268762306a36Sopenharmony_ci			}
268862306a36Sopenharmony_ci		}
268962306a36Sopenharmony_ci	}
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci	if (pcie_ireg & HOST_INTR_DNLD_DONE) {
269262306a36Sopenharmony_ci		mwifiex_dbg(adapter, INTR, "info: TX DNLD Done\n");
269362306a36Sopenharmony_ci		ret = mwifiex_pcie_send_data_complete(adapter);
269462306a36Sopenharmony_ci		if (ret)
269562306a36Sopenharmony_ci			return ret;
269662306a36Sopenharmony_ci	}
269762306a36Sopenharmony_ci	if (pcie_ireg & HOST_INTR_UPLD_RDY) {
269862306a36Sopenharmony_ci		mwifiex_dbg(adapter, INTR, "info: Rx DATA\n");
269962306a36Sopenharmony_ci		ret = mwifiex_pcie_process_recv_data(adapter);
270062306a36Sopenharmony_ci		if (ret)
270162306a36Sopenharmony_ci			return ret;
270262306a36Sopenharmony_ci	}
270362306a36Sopenharmony_ci	if (pcie_ireg & HOST_INTR_EVENT_RDY) {
270462306a36Sopenharmony_ci		mwifiex_dbg(adapter, INTR, "info: Rx EVENT\n");
270562306a36Sopenharmony_ci		ret = mwifiex_pcie_process_event_ready(adapter);
270662306a36Sopenharmony_ci		if (ret)
270762306a36Sopenharmony_ci			return ret;
270862306a36Sopenharmony_ci	}
270962306a36Sopenharmony_ci	if (pcie_ireg & HOST_INTR_CMD_DONE) {
271062306a36Sopenharmony_ci		if (adapter->cmd_sent) {
271162306a36Sopenharmony_ci			mwifiex_dbg(adapter, INTR,
271262306a36Sopenharmony_ci				    "info: CMD sent Interrupt\n");
271362306a36Sopenharmony_ci			adapter->cmd_sent = false;
271462306a36Sopenharmony_ci		}
271562306a36Sopenharmony_ci		/* Handle command response */
271662306a36Sopenharmony_ci		ret = mwifiex_pcie_process_cmd_complete(adapter);
271762306a36Sopenharmony_ci		if (ret)
271862306a36Sopenharmony_ci			return ret;
271962306a36Sopenharmony_ci	}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	mwifiex_dbg(adapter, INTR,
272262306a36Sopenharmony_ci		    "info: cmd_sent=%d data_sent=%d\n",
272362306a36Sopenharmony_ci		    adapter->cmd_sent, adapter->data_sent);
272462306a36Sopenharmony_ci	if (!card->msi_enable && !card->msix_enable &&
272562306a36Sopenharmony_ci				 adapter->ps_state != PS_STATE_SLEEP)
272662306a36Sopenharmony_ci		mwifiex_pcie_enable_host_int(adapter);
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	return 0;
272962306a36Sopenharmony_ci}
273062306a36Sopenharmony_ci
273162306a36Sopenharmony_ci/*
273262306a36Sopenharmony_ci * This function downloads data from driver to card.
273362306a36Sopenharmony_ci *
273462306a36Sopenharmony_ci * Both commands and data packets are transferred to the card by this
273562306a36Sopenharmony_ci * function.
273662306a36Sopenharmony_ci *
273762306a36Sopenharmony_ci * This function adds the PCIE specific header to the front of the buffer
273862306a36Sopenharmony_ci * before transferring. The header contains the length of the packet and
273962306a36Sopenharmony_ci * the type. The firmware handles the packets based upon this set type.
274062306a36Sopenharmony_ci */
274162306a36Sopenharmony_cistatic int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
274262306a36Sopenharmony_ci				     struct sk_buff *skb,
274362306a36Sopenharmony_ci				     struct mwifiex_tx_param *tx_param)
274462306a36Sopenharmony_ci{
274562306a36Sopenharmony_ci	if (!skb) {
274662306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
274762306a36Sopenharmony_ci			    "Passed NULL skb to %s\n", __func__);
274862306a36Sopenharmony_ci		return -1;
274962306a36Sopenharmony_ci	}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	if (type == MWIFIEX_TYPE_DATA)
275262306a36Sopenharmony_ci		return mwifiex_pcie_send_data(adapter, skb, tx_param);
275362306a36Sopenharmony_ci	else if (type == MWIFIEX_TYPE_CMD)
275462306a36Sopenharmony_ci		return mwifiex_pcie_send_cmd(adapter, skb);
275562306a36Sopenharmony_ci
275662306a36Sopenharmony_ci	return 0;
275762306a36Sopenharmony_ci}
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci/* Function to dump PCIE scratch registers in case of FW crash
276062306a36Sopenharmony_ci */
276162306a36Sopenharmony_cistatic int
276262306a36Sopenharmony_cimwifiex_pcie_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf)
276362306a36Sopenharmony_ci{
276462306a36Sopenharmony_ci	char *p = drv_buf;
276562306a36Sopenharmony_ci	char buf[256], *ptr;
276662306a36Sopenharmony_ci	int i;
276762306a36Sopenharmony_ci	u32 value;
276862306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
276962306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
277062306a36Sopenharmony_ci	int pcie_scratch_reg[] = {PCIE_SCRATCH_12_REG,
277162306a36Sopenharmony_ci				  PCIE_SCRATCH_14_REG,
277262306a36Sopenharmony_ci				  PCIE_SCRATCH_15_REG};
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	if (!p)
277562306a36Sopenharmony_ci		return 0;
277662306a36Sopenharmony_ci
277762306a36Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "PCIE register dump start\n");
277862306a36Sopenharmony_ci
277962306a36Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->fw_status, &value)) {
278062306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "failed to read firmware status");
278162306a36Sopenharmony_ci		return 0;
278262306a36Sopenharmony_ci	}
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci	ptr = buf;
278562306a36Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "pcie scratch register:");
278662306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(pcie_scratch_reg); i++) {
278762306a36Sopenharmony_ci		mwifiex_read_reg(adapter, pcie_scratch_reg[i], &value);
278862306a36Sopenharmony_ci		ptr += sprintf(ptr, "reg:0x%x, value=0x%x\n",
278962306a36Sopenharmony_ci			       pcie_scratch_reg[i], value);
279062306a36Sopenharmony_ci	}
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "%s\n", buf);
279362306a36Sopenharmony_ci	p += sprintf(p, "%s\n", buf);
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "PCIE register dump end\n");
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_ci	return p - drv_buf;
279862306a36Sopenharmony_ci}
279962306a36Sopenharmony_ci
280062306a36Sopenharmony_ci/* This function read/write firmware */
280162306a36Sopenharmony_cistatic enum rdwr_status
280262306a36Sopenharmony_cimwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
280362306a36Sopenharmony_ci{
280462306a36Sopenharmony_ci	int ret, tries;
280562306a36Sopenharmony_ci	u8 ctrl_data;
280662306a36Sopenharmony_ci	u32 fw_status;
280762306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
280862306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
280962306a36Sopenharmony_ci
281062306a36Sopenharmony_ci	if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status))
281162306a36Sopenharmony_ci		return RDWR_STATUS_FAILURE;
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
281462306a36Sopenharmony_ci				reg->fw_dump_host_ready);
281562306a36Sopenharmony_ci	if (ret) {
281662306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
281762306a36Sopenharmony_ci			    "PCIE write err\n");
281862306a36Sopenharmony_ci		return RDWR_STATUS_FAILURE;
281962306a36Sopenharmony_ci	}
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
282262306a36Sopenharmony_ci		mwifiex_read_reg_byte(adapter, reg->fw_dump_ctrl, &ctrl_data);
282362306a36Sopenharmony_ci		if (ctrl_data == FW_DUMP_DONE)
282462306a36Sopenharmony_ci			return RDWR_STATUS_SUCCESS;
282562306a36Sopenharmony_ci		if (doneflag && ctrl_data == doneflag)
282662306a36Sopenharmony_ci			return RDWR_STATUS_DONE;
282762306a36Sopenharmony_ci		if (ctrl_data != reg->fw_dump_host_ready) {
282862306a36Sopenharmony_ci			mwifiex_dbg(adapter, WARN,
282962306a36Sopenharmony_ci				    "The ctrl reg was changed, re-try again!\n");
283062306a36Sopenharmony_ci			ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
283162306a36Sopenharmony_ci						reg->fw_dump_host_ready);
283262306a36Sopenharmony_ci			if (ret) {
283362306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
283462306a36Sopenharmony_ci					    "PCIE write err\n");
283562306a36Sopenharmony_ci				return RDWR_STATUS_FAILURE;
283662306a36Sopenharmony_ci			}
283762306a36Sopenharmony_ci		}
283862306a36Sopenharmony_ci		usleep_range(100, 200);
283962306a36Sopenharmony_ci	}
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	mwifiex_dbg(adapter, ERROR, "Fail to pull ctrl_data\n");
284262306a36Sopenharmony_ci	return RDWR_STATUS_FAILURE;
284362306a36Sopenharmony_ci}
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci/* This function dump firmware memory to file */
284662306a36Sopenharmony_cistatic void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
284762306a36Sopenharmony_ci{
284862306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
284962306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *creg = card->pcie.reg;
285062306a36Sopenharmony_ci	unsigned int reg, reg_start, reg_end;
285162306a36Sopenharmony_ci	u8 *dbg_ptr, *end_ptr, *tmp_ptr, fw_dump_num, dump_num;
285262306a36Sopenharmony_ci	u8 idx, i, read_reg, doneflag = 0;
285362306a36Sopenharmony_ci	enum rdwr_status stat;
285462306a36Sopenharmony_ci	u32 memory_size;
285562306a36Sopenharmony_ci	int ret;
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_ci	if (!card->pcie.can_dump_fw)
285862306a36Sopenharmony_ci		return;
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	for (idx = 0; idx < adapter->num_mem_types; idx++) {
286162306a36Sopenharmony_ci		struct memory_type_mapping *entry =
286262306a36Sopenharmony_ci				&adapter->mem_type_mapping_tbl[idx];
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci		if (entry->mem_ptr) {
286562306a36Sopenharmony_ci			vfree(entry->mem_ptr);
286662306a36Sopenharmony_ci			entry->mem_ptr = NULL;
286762306a36Sopenharmony_ci		}
286862306a36Sopenharmony_ci		entry->mem_size = 0;
286962306a36Sopenharmony_ci	}
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n");
287262306a36Sopenharmony_ci
287362306a36Sopenharmony_ci	/* Read the number of the memories which will dump */
287462306a36Sopenharmony_ci	stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
287562306a36Sopenharmony_ci	if (stat == RDWR_STATUS_FAILURE)
287662306a36Sopenharmony_ci		return;
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci	reg = creg->fw_dump_start;
287962306a36Sopenharmony_ci	mwifiex_read_reg_byte(adapter, reg, &fw_dump_num);
288062306a36Sopenharmony_ci
288162306a36Sopenharmony_ci	/* W8997 chipset firmware dump will be restore in single region*/
288262306a36Sopenharmony_ci	if (fw_dump_num == 0)
288362306a36Sopenharmony_ci		dump_num = 1;
288462306a36Sopenharmony_ci	else
288562306a36Sopenharmony_ci		dump_num = fw_dump_num;
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	/* Read the length of every memory which will dump */
288862306a36Sopenharmony_ci	for (idx = 0; idx < dump_num; idx++) {
288962306a36Sopenharmony_ci		struct memory_type_mapping *entry =
289062306a36Sopenharmony_ci				&adapter->mem_type_mapping_tbl[idx];
289162306a36Sopenharmony_ci		memory_size = 0;
289262306a36Sopenharmony_ci		if (fw_dump_num != 0) {
289362306a36Sopenharmony_ci			stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
289462306a36Sopenharmony_ci			if (stat == RDWR_STATUS_FAILURE)
289562306a36Sopenharmony_ci				return;
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci			reg = creg->fw_dump_start;
289862306a36Sopenharmony_ci			for (i = 0; i < 4; i++) {
289962306a36Sopenharmony_ci				mwifiex_read_reg_byte(adapter, reg, &read_reg);
290062306a36Sopenharmony_ci				memory_size |= (read_reg << (i * 8));
290162306a36Sopenharmony_ci				reg++;
290262306a36Sopenharmony_ci			}
290362306a36Sopenharmony_ci		} else {
290462306a36Sopenharmony_ci			memory_size = MWIFIEX_FW_DUMP_MAX_MEMSIZE;
290562306a36Sopenharmony_ci		}
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci		if (memory_size == 0) {
290862306a36Sopenharmony_ci			mwifiex_dbg(adapter, MSG, "Firmware dump Finished!\n");
290962306a36Sopenharmony_ci			ret = mwifiex_write_reg(adapter, creg->fw_dump_ctrl,
291062306a36Sopenharmony_ci						creg->fw_dump_read_done);
291162306a36Sopenharmony_ci			if (ret) {
291262306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR, "PCIE write err\n");
291362306a36Sopenharmony_ci				return;
291462306a36Sopenharmony_ci			}
291562306a36Sopenharmony_ci			break;
291662306a36Sopenharmony_ci		}
291762306a36Sopenharmony_ci
291862306a36Sopenharmony_ci		mwifiex_dbg(adapter, DUMP,
291962306a36Sopenharmony_ci			    "%s_SIZE=0x%x\n", entry->mem_name, memory_size);
292062306a36Sopenharmony_ci		entry->mem_ptr = vmalloc(memory_size + 1);
292162306a36Sopenharmony_ci		entry->mem_size = memory_size;
292262306a36Sopenharmony_ci		if (!entry->mem_ptr) {
292362306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
292462306a36Sopenharmony_ci				    "Vmalloc %s failed\n", entry->mem_name);
292562306a36Sopenharmony_ci			return;
292662306a36Sopenharmony_ci		}
292762306a36Sopenharmony_ci		dbg_ptr = entry->mem_ptr;
292862306a36Sopenharmony_ci		end_ptr = dbg_ptr + memory_size;
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci		doneflag = entry->done_flag;
293162306a36Sopenharmony_ci		mwifiex_dbg(adapter, DUMP, "Start %s output, please wait...\n",
293262306a36Sopenharmony_ci			    entry->mem_name);
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci		do {
293562306a36Sopenharmony_ci			stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
293662306a36Sopenharmony_ci			if (RDWR_STATUS_FAILURE == stat)
293762306a36Sopenharmony_ci				return;
293862306a36Sopenharmony_ci
293962306a36Sopenharmony_ci			reg_start = creg->fw_dump_start;
294062306a36Sopenharmony_ci			reg_end = creg->fw_dump_end;
294162306a36Sopenharmony_ci			for (reg = reg_start; reg <= reg_end; reg++) {
294262306a36Sopenharmony_ci				mwifiex_read_reg_byte(adapter, reg, dbg_ptr);
294362306a36Sopenharmony_ci				if (dbg_ptr < end_ptr) {
294462306a36Sopenharmony_ci					dbg_ptr++;
294562306a36Sopenharmony_ci					continue;
294662306a36Sopenharmony_ci				}
294762306a36Sopenharmony_ci				mwifiex_dbg(adapter, ERROR,
294862306a36Sopenharmony_ci					    "pre-allocated buf not enough\n");
294962306a36Sopenharmony_ci				tmp_ptr =
295062306a36Sopenharmony_ci					vzalloc(memory_size + MWIFIEX_SIZE_4K);
295162306a36Sopenharmony_ci				if (!tmp_ptr)
295262306a36Sopenharmony_ci					return;
295362306a36Sopenharmony_ci				memcpy(tmp_ptr, entry->mem_ptr, memory_size);
295462306a36Sopenharmony_ci				vfree(entry->mem_ptr);
295562306a36Sopenharmony_ci				entry->mem_ptr = tmp_ptr;
295662306a36Sopenharmony_ci				tmp_ptr = NULL;
295762306a36Sopenharmony_ci				dbg_ptr = entry->mem_ptr + memory_size;
295862306a36Sopenharmony_ci				memory_size += MWIFIEX_SIZE_4K;
295962306a36Sopenharmony_ci				end_ptr = entry->mem_ptr + memory_size;
296062306a36Sopenharmony_ci			}
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci			if (stat != RDWR_STATUS_DONE)
296362306a36Sopenharmony_ci				continue;
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci			mwifiex_dbg(adapter, DUMP,
296662306a36Sopenharmony_ci				    "%s done: size=0x%tx\n",
296762306a36Sopenharmony_ci				    entry->mem_name, dbg_ptr - entry->mem_ptr);
296862306a36Sopenharmony_ci			break;
296962306a36Sopenharmony_ci		} while (true);
297062306a36Sopenharmony_ci	}
297162306a36Sopenharmony_ci	mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
297262306a36Sopenharmony_ci}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_cistatic void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
297562306a36Sopenharmony_ci{
297662306a36Sopenharmony_ci	adapter->devdump_data = vzalloc(MWIFIEX_FW_DUMP_SIZE);
297762306a36Sopenharmony_ci	if (!adapter->devdump_data) {
297862306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR,
297962306a36Sopenharmony_ci			    "vzalloc devdump data failure!\n");
298062306a36Sopenharmony_ci		return;
298162306a36Sopenharmony_ci	}
298262306a36Sopenharmony_ci
298362306a36Sopenharmony_ci	mwifiex_drv_info_dump(adapter);
298462306a36Sopenharmony_ci	mwifiex_pcie_fw_dump(adapter);
298562306a36Sopenharmony_ci	mwifiex_prepare_fw_dump_info(adapter);
298662306a36Sopenharmony_ci	mwifiex_upload_device_dump(adapter);
298762306a36Sopenharmony_ci}
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_cistatic void mwifiex_pcie_card_reset_work(struct mwifiex_adapter *adapter)
299062306a36Sopenharmony_ci{
299162306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	/* We can't afford to wait here; remove() might be waiting on us. If we
299462306a36Sopenharmony_ci	 * can't grab the device lock, maybe we'll get another chance later.
299562306a36Sopenharmony_ci	 */
299662306a36Sopenharmony_ci	pci_try_reset_function(card->dev);
299762306a36Sopenharmony_ci}
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_cistatic void mwifiex_pcie_work(struct work_struct *work)
300062306a36Sopenharmony_ci{
300162306a36Sopenharmony_ci	struct pcie_service_card *card =
300262306a36Sopenharmony_ci		container_of(work, struct pcie_service_card, work);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	if (test_and_clear_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
300562306a36Sopenharmony_ci			       &card->work_flags))
300662306a36Sopenharmony_ci		mwifiex_pcie_device_dump_work(card->adapter);
300762306a36Sopenharmony_ci	if (test_and_clear_bit(MWIFIEX_IFACE_WORK_CARD_RESET,
300862306a36Sopenharmony_ci			       &card->work_flags))
300962306a36Sopenharmony_ci		mwifiex_pcie_card_reset_work(card->adapter);
301062306a36Sopenharmony_ci}
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci/* This function dumps FW information */
301362306a36Sopenharmony_cistatic void mwifiex_pcie_device_dump(struct mwifiex_adapter *adapter)
301462306a36Sopenharmony_ci{
301562306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_ci	if (!test_and_set_bit(MWIFIEX_IFACE_WORK_DEVICE_DUMP,
301862306a36Sopenharmony_ci			      &card->work_flags))
301962306a36Sopenharmony_ci		schedule_work(&card->work);
302062306a36Sopenharmony_ci}
302162306a36Sopenharmony_ci
302262306a36Sopenharmony_cistatic void mwifiex_pcie_card_reset(struct mwifiex_adapter *adapter)
302362306a36Sopenharmony_ci{
302462306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci	if (!test_and_set_bit(MWIFIEX_IFACE_WORK_CARD_RESET, &card->work_flags))
302762306a36Sopenharmony_ci		schedule_work(&card->work);
302862306a36Sopenharmony_ci}
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_cistatic int mwifiex_pcie_alloc_buffers(struct mwifiex_adapter *adapter)
303162306a36Sopenharmony_ci{
303262306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
303362306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
303462306a36Sopenharmony_ci	int ret;
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	card->cmdrsp_buf = NULL;
303762306a36Sopenharmony_ci	ret = mwifiex_pcie_create_txbd_ring(adapter);
303862306a36Sopenharmony_ci	if (ret) {
303962306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to create txbd ring\n");
304062306a36Sopenharmony_ci		goto err_cre_txbd;
304162306a36Sopenharmony_ci	}
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	ret = mwifiex_pcie_create_rxbd_ring(adapter);
304462306a36Sopenharmony_ci	if (ret) {
304562306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to create rxbd ring\n");
304662306a36Sopenharmony_ci		goto err_cre_rxbd;
304762306a36Sopenharmony_ci	}
304862306a36Sopenharmony_ci
304962306a36Sopenharmony_ci	ret = mwifiex_pcie_create_evtbd_ring(adapter);
305062306a36Sopenharmony_ci	if (ret) {
305162306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to create evtbd ring\n");
305262306a36Sopenharmony_ci		goto err_cre_evtbd;
305362306a36Sopenharmony_ci	}
305462306a36Sopenharmony_ci
305562306a36Sopenharmony_ci	ret = mwifiex_pcie_alloc_cmdrsp_buf(adapter);
305662306a36Sopenharmony_ci	if (ret) {
305762306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to allocate cmdbuf buffer\n");
305862306a36Sopenharmony_ci		goto err_alloc_cmdbuf;
305962306a36Sopenharmony_ci	}
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci	if (reg->sleep_cookie) {
306262306a36Sopenharmony_ci		ret = mwifiex_pcie_alloc_sleep_cookie_buf(adapter);
306362306a36Sopenharmony_ci		if (ret) {
306462306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR, "Failed to allocate sleep_cookie buffer\n");
306562306a36Sopenharmony_ci			goto err_alloc_cookie;
306662306a36Sopenharmony_ci		}
306762306a36Sopenharmony_ci	} else {
306862306a36Sopenharmony_ci		card->sleep_cookie_vbase = NULL;
306962306a36Sopenharmony_ci	}
307062306a36Sopenharmony_ci
307162306a36Sopenharmony_ci	return 0;
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_cierr_alloc_cookie:
307462306a36Sopenharmony_ci	mwifiex_pcie_delete_cmdrsp_buf(adapter);
307562306a36Sopenharmony_cierr_alloc_cmdbuf:
307662306a36Sopenharmony_ci	mwifiex_pcie_delete_evtbd_ring(adapter);
307762306a36Sopenharmony_cierr_cre_evtbd:
307862306a36Sopenharmony_ci	mwifiex_pcie_delete_rxbd_ring(adapter);
307962306a36Sopenharmony_cierr_cre_rxbd:
308062306a36Sopenharmony_ci	mwifiex_pcie_delete_txbd_ring(adapter);
308162306a36Sopenharmony_cierr_cre_txbd:
308262306a36Sopenharmony_ci	return ret;
308362306a36Sopenharmony_ci}
308462306a36Sopenharmony_ci
308562306a36Sopenharmony_cistatic void mwifiex_pcie_free_buffers(struct mwifiex_adapter *adapter)
308662306a36Sopenharmony_ci{
308762306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
308862306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	if (reg->sleep_cookie)
309162306a36Sopenharmony_ci		mwifiex_pcie_delete_sleep_cookie_buf(adapter);
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	mwifiex_pcie_delete_cmdrsp_buf(adapter);
309462306a36Sopenharmony_ci	mwifiex_pcie_delete_evtbd_ring(adapter);
309562306a36Sopenharmony_ci	mwifiex_pcie_delete_rxbd_ring(adapter);
309662306a36Sopenharmony_ci	mwifiex_pcie_delete_txbd_ring(adapter);
309762306a36Sopenharmony_ci}
309862306a36Sopenharmony_ci
309962306a36Sopenharmony_ci/*
310062306a36Sopenharmony_ci * This function initializes the PCI-E host memory space, WCB rings, etc.
310162306a36Sopenharmony_ci */
310262306a36Sopenharmony_cistatic int mwifiex_init_pcie(struct mwifiex_adapter *adapter)
310362306a36Sopenharmony_ci{
310462306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
310562306a36Sopenharmony_ci	int ret;
310662306a36Sopenharmony_ci	struct pci_dev *pdev = card->dev;
310762306a36Sopenharmony_ci
310862306a36Sopenharmony_ci	pci_set_drvdata(pdev, card);
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci	ret = pci_enable_device(pdev);
311162306a36Sopenharmony_ci	if (ret)
311262306a36Sopenharmony_ci		goto err_enable_dev;
311362306a36Sopenharmony_ci
311462306a36Sopenharmony_ci	pci_set_master(pdev);
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_ci	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
311762306a36Sopenharmony_ci	if (ret) {
311862306a36Sopenharmony_ci		pr_err("dma_set_mask(32) failed: %d\n", ret);
311962306a36Sopenharmony_ci		goto err_set_dma_mask;
312062306a36Sopenharmony_ci	}
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	ret = pci_request_region(pdev, 0, DRV_NAME);
312362306a36Sopenharmony_ci	if (ret) {
312462306a36Sopenharmony_ci		pr_err("req_reg(0) error\n");
312562306a36Sopenharmony_ci		goto err_req_region0;
312662306a36Sopenharmony_ci	}
312762306a36Sopenharmony_ci	card->pci_mmap = pci_iomap(pdev, 0, 0);
312862306a36Sopenharmony_ci	if (!card->pci_mmap) {
312962306a36Sopenharmony_ci		pr_err("iomap(0) error\n");
313062306a36Sopenharmony_ci		ret = -EIO;
313162306a36Sopenharmony_ci		goto err_iomap0;
313262306a36Sopenharmony_ci	}
313362306a36Sopenharmony_ci	ret = pci_request_region(pdev, 2, DRV_NAME);
313462306a36Sopenharmony_ci	if (ret) {
313562306a36Sopenharmony_ci		pr_err("req_reg(2) error\n");
313662306a36Sopenharmony_ci		goto err_req_region2;
313762306a36Sopenharmony_ci	}
313862306a36Sopenharmony_ci	card->pci_mmap1 = pci_iomap(pdev, 2, 0);
313962306a36Sopenharmony_ci	if (!card->pci_mmap1) {
314062306a36Sopenharmony_ci		pr_err("iomap(2) error\n");
314162306a36Sopenharmony_ci		ret = -EIO;
314262306a36Sopenharmony_ci		goto err_iomap2;
314362306a36Sopenharmony_ci	}
314462306a36Sopenharmony_ci
314562306a36Sopenharmony_ci	pr_notice("PCI memory map Virt0: %pK PCI memory map Virt2: %pK\n",
314662306a36Sopenharmony_ci		  card->pci_mmap, card->pci_mmap1);
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci	ret = mwifiex_pcie_alloc_buffers(adapter);
314962306a36Sopenharmony_ci	if (ret)
315062306a36Sopenharmony_ci		goto err_alloc_buffers;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci	if (pdev->device == PCIE_DEVICE_ID_MARVELL_88W8897)
315362306a36Sopenharmony_ci		adapter->ignore_btcoex_events = true;
315462306a36Sopenharmony_ci
315562306a36Sopenharmony_ci	return 0;
315662306a36Sopenharmony_ci
315762306a36Sopenharmony_cierr_alloc_buffers:
315862306a36Sopenharmony_ci	pci_iounmap(pdev, card->pci_mmap1);
315962306a36Sopenharmony_cierr_iomap2:
316062306a36Sopenharmony_ci	pci_release_region(pdev, 2);
316162306a36Sopenharmony_cierr_req_region2:
316262306a36Sopenharmony_ci	pci_iounmap(pdev, card->pci_mmap);
316362306a36Sopenharmony_cierr_iomap0:
316462306a36Sopenharmony_ci	pci_release_region(pdev, 0);
316562306a36Sopenharmony_cierr_req_region0:
316662306a36Sopenharmony_cierr_set_dma_mask:
316762306a36Sopenharmony_ci	pci_disable_device(pdev);
316862306a36Sopenharmony_cierr_enable_dev:
316962306a36Sopenharmony_ci	return ret;
317062306a36Sopenharmony_ci}
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci/*
317362306a36Sopenharmony_ci * This function cleans up the allocated card buffers.
317462306a36Sopenharmony_ci */
317562306a36Sopenharmony_cistatic void mwifiex_cleanup_pcie(struct mwifiex_adapter *adapter)
317662306a36Sopenharmony_ci{
317762306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
317862306a36Sopenharmony_ci	struct pci_dev *pdev = card->dev;
317962306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
318062306a36Sopenharmony_ci	u32 fw_status;
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	/* Perform the cancel_work_sync() only when we're not resetting
318362306a36Sopenharmony_ci	 * the card. It's because that function never returns if we're
318462306a36Sopenharmony_ci	 * in reset path. If we're here when resetting the card, it means
318562306a36Sopenharmony_ci	 * that we failed to reset the card (reset failure path).
318662306a36Sopenharmony_ci	 */
318762306a36Sopenharmony_ci	if (!card->pci_reset_ongoing) {
318862306a36Sopenharmony_ci		mwifiex_dbg(adapter, MSG, "performing cancel_work_sync()...\n");
318962306a36Sopenharmony_ci		cancel_work_sync(&card->work);
319062306a36Sopenharmony_ci		mwifiex_dbg(adapter, MSG, "cancel_work_sync() done\n");
319162306a36Sopenharmony_ci	} else {
319262306a36Sopenharmony_ci		mwifiex_dbg(adapter, MSG,
319362306a36Sopenharmony_ci			    "skipped cancel_work_sync() because we're in card reset failure path\n");
319462306a36Sopenharmony_ci	}
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci	mwifiex_read_reg(adapter, reg->fw_status, &fw_status);
319762306a36Sopenharmony_ci	if (fw_status == FIRMWARE_READY_PCIE) {
319862306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
319962306a36Sopenharmony_ci			    "Clearing driver ready signature\n");
320062306a36Sopenharmony_ci		if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
320162306a36Sopenharmony_ci			mwifiex_dbg(adapter, ERROR,
320262306a36Sopenharmony_ci				    "Failed to write driver not-ready signature\n");
320362306a36Sopenharmony_ci	}
320462306a36Sopenharmony_ci
320562306a36Sopenharmony_ci	pci_disable_device(pdev);
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	pci_iounmap(pdev, card->pci_mmap);
320862306a36Sopenharmony_ci	pci_iounmap(pdev, card->pci_mmap1);
320962306a36Sopenharmony_ci	pci_release_region(pdev, 2);
321062306a36Sopenharmony_ci	pci_release_region(pdev, 0);
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci	mwifiex_pcie_free_buffers(adapter);
321362306a36Sopenharmony_ci}
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_cistatic int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
321662306a36Sopenharmony_ci{
321762306a36Sopenharmony_ci	int ret, i, j;
321862306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
321962306a36Sopenharmony_ci	struct pci_dev *pdev = card->dev;
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci	if (card->pcie.reg->msix_support) {
322262306a36Sopenharmony_ci		for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
322362306a36Sopenharmony_ci			card->msix_entries[i].entry = i;
322462306a36Sopenharmony_ci		ret = pci_enable_msix_exact(pdev, card->msix_entries,
322562306a36Sopenharmony_ci					    MWIFIEX_NUM_MSIX_VECTORS);
322662306a36Sopenharmony_ci		if (!ret) {
322762306a36Sopenharmony_ci			for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) {
322862306a36Sopenharmony_ci				card->msix_ctx[i].dev = pdev;
322962306a36Sopenharmony_ci				card->msix_ctx[i].msg_id = i;
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci				ret = request_irq(card->msix_entries[i].vector,
323262306a36Sopenharmony_ci						  mwifiex_pcie_interrupt, 0,
323362306a36Sopenharmony_ci						  "MWIFIEX_PCIE_MSIX",
323462306a36Sopenharmony_ci						  &card->msix_ctx[i]);
323562306a36Sopenharmony_ci				if (ret)
323662306a36Sopenharmony_ci					break;
323762306a36Sopenharmony_ci			}
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_ci			if (ret) {
324062306a36Sopenharmony_ci				mwifiex_dbg(adapter, INFO, "request_irq fail: %d\n",
324162306a36Sopenharmony_ci					    ret);
324262306a36Sopenharmony_ci				for (j = 0; j < i; j++)
324362306a36Sopenharmony_ci					free_irq(card->msix_entries[j].vector,
324462306a36Sopenharmony_ci						 &card->msix_ctx[i]);
324562306a36Sopenharmony_ci				pci_disable_msix(pdev);
324662306a36Sopenharmony_ci			} else {
324762306a36Sopenharmony_ci				mwifiex_dbg(adapter, MSG, "MSIx enabled!");
324862306a36Sopenharmony_ci				card->msix_enable = 1;
324962306a36Sopenharmony_ci				return 0;
325062306a36Sopenharmony_ci			}
325162306a36Sopenharmony_ci		}
325262306a36Sopenharmony_ci	}
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	if (pci_enable_msi(pdev) != 0)
325562306a36Sopenharmony_ci		pci_disable_msi(pdev);
325662306a36Sopenharmony_ci	else
325762306a36Sopenharmony_ci		card->msi_enable = 1;
325862306a36Sopenharmony_ci
325962306a36Sopenharmony_ci	mwifiex_dbg(adapter, INFO, "msi_enable = %d\n", card->msi_enable);
326062306a36Sopenharmony_ci
326162306a36Sopenharmony_ci	card->share_irq_ctx.dev = pdev;
326262306a36Sopenharmony_ci	card->share_irq_ctx.msg_id = -1;
326362306a36Sopenharmony_ci	ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
326462306a36Sopenharmony_ci			  "MRVL_PCIE", &card->share_irq_ctx);
326562306a36Sopenharmony_ci	if (ret) {
326662306a36Sopenharmony_ci		pr_err("request_irq failed: ret=%d\n", ret);
326762306a36Sopenharmony_ci		return -1;
326862306a36Sopenharmony_ci	}
326962306a36Sopenharmony_ci
327062306a36Sopenharmony_ci	return 0;
327162306a36Sopenharmony_ci}
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci/*
327462306a36Sopenharmony_ci * This function gets the firmware name for downloading by revision id
327562306a36Sopenharmony_ci *
327662306a36Sopenharmony_ci * Read revision id register to get revision id
327762306a36Sopenharmony_ci */
327862306a36Sopenharmony_cistatic void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter)
327962306a36Sopenharmony_ci{
328062306a36Sopenharmony_ci	int revision_id = 0;
328162306a36Sopenharmony_ci	int version, magic;
328262306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	switch (card->dev->device) {
328562306a36Sopenharmony_ci	case PCIE_DEVICE_ID_MARVELL_88W8766P:
328662306a36Sopenharmony_ci		strcpy(adapter->fw_name, PCIE8766_DEFAULT_FW_NAME);
328762306a36Sopenharmony_ci		break;
328862306a36Sopenharmony_ci	case PCIE_DEVICE_ID_MARVELL_88W8897:
328962306a36Sopenharmony_ci		mwifiex_write_reg(adapter, 0x0c58, 0x80c00000);
329062306a36Sopenharmony_ci		mwifiex_read_reg(adapter, 0x0c58, &revision_id);
329162306a36Sopenharmony_ci		revision_id &= 0xff00;
329262306a36Sopenharmony_ci		switch (revision_id) {
329362306a36Sopenharmony_ci		case PCIE8897_A0:
329462306a36Sopenharmony_ci			strcpy(adapter->fw_name, PCIE8897_A0_FW_NAME);
329562306a36Sopenharmony_ci			break;
329662306a36Sopenharmony_ci		case PCIE8897_B0:
329762306a36Sopenharmony_ci			strcpy(adapter->fw_name, PCIE8897_B0_FW_NAME);
329862306a36Sopenharmony_ci			break;
329962306a36Sopenharmony_ci		default:
330062306a36Sopenharmony_ci			strcpy(adapter->fw_name, PCIE8897_DEFAULT_FW_NAME);
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_ci			break;
330362306a36Sopenharmony_ci		}
330462306a36Sopenharmony_ci		break;
330562306a36Sopenharmony_ci	case PCIE_DEVICE_ID_MARVELL_88W8997:
330662306a36Sopenharmony_ci		mwifiex_read_reg(adapter, 0x8, &revision_id);
330762306a36Sopenharmony_ci		mwifiex_read_reg(adapter, 0x0cd0, &version);
330862306a36Sopenharmony_ci		mwifiex_read_reg(adapter, 0x0cd4, &magic);
330962306a36Sopenharmony_ci		revision_id &= 0xff;
331062306a36Sopenharmony_ci		version &= 0x7;
331162306a36Sopenharmony_ci		magic &= 0xff;
331262306a36Sopenharmony_ci		if (revision_id == PCIE8997_A1 &&
331362306a36Sopenharmony_ci		    magic == CHIP_MAGIC_VALUE &&
331462306a36Sopenharmony_ci		    version == CHIP_VER_PCIEUART)
331562306a36Sopenharmony_ci			strcpy(adapter->fw_name, PCIEUART8997_FW_NAME_V4);
331662306a36Sopenharmony_ci		else
331762306a36Sopenharmony_ci			strcpy(adapter->fw_name, PCIEUSB8997_FW_NAME_V4);
331862306a36Sopenharmony_ci		break;
331962306a36Sopenharmony_ci	default:
332062306a36Sopenharmony_ci		break;
332162306a36Sopenharmony_ci	}
332262306a36Sopenharmony_ci}
332362306a36Sopenharmony_ci
332462306a36Sopenharmony_ci/*
332562306a36Sopenharmony_ci * This function registers the PCIE device.
332662306a36Sopenharmony_ci *
332762306a36Sopenharmony_ci * PCIE IRQ is claimed, block size is set and driver data is initialized.
332862306a36Sopenharmony_ci */
332962306a36Sopenharmony_cistatic int mwifiex_register_dev(struct mwifiex_adapter *adapter)
333062306a36Sopenharmony_ci{
333162306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	/* save adapter pointer in card */
333462306a36Sopenharmony_ci	card->adapter = adapter;
333562306a36Sopenharmony_ci
333662306a36Sopenharmony_ci	if (mwifiex_pcie_request_irq(adapter))
333762306a36Sopenharmony_ci		return -1;
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	adapter->tx_buf_size = card->pcie.tx_buf_size;
334062306a36Sopenharmony_ci	adapter->mem_type_mapping_tbl = card->pcie.mem_type_mapping_tbl;
334162306a36Sopenharmony_ci	adapter->num_mem_types = card->pcie.num_mem_types;
334262306a36Sopenharmony_ci	adapter->ext_scan = card->pcie.can_ext_scan;
334362306a36Sopenharmony_ci	mwifiex_pcie_get_fw_name(adapter);
334462306a36Sopenharmony_ci
334562306a36Sopenharmony_ci	return 0;
334662306a36Sopenharmony_ci}
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci/*
334962306a36Sopenharmony_ci * This function unregisters the PCIE device.
335062306a36Sopenharmony_ci *
335162306a36Sopenharmony_ci * The PCIE IRQ is released, the function is disabled and driver
335262306a36Sopenharmony_ci * data is set to null.
335362306a36Sopenharmony_ci */
335462306a36Sopenharmony_cistatic void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
335562306a36Sopenharmony_ci{
335662306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
335762306a36Sopenharmony_ci	struct pci_dev *pdev = card->dev;
335862306a36Sopenharmony_ci	int i;
335962306a36Sopenharmony_ci
336062306a36Sopenharmony_ci	if (card->msix_enable) {
336162306a36Sopenharmony_ci		for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
336262306a36Sopenharmony_ci			synchronize_irq(card->msix_entries[i].vector);
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci		for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
336562306a36Sopenharmony_ci			free_irq(card->msix_entries[i].vector,
336662306a36Sopenharmony_ci				 &card->msix_ctx[i]);
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci		card->msix_enable = 0;
336962306a36Sopenharmony_ci		pci_disable_msix(pdev);
337062306a36Sopenharmony_ci	} else {
337162306a36Sopenharmony_ci		mwifiex_dbg(adapter, INFO,
337262306a36Sopenharmony_ci			    "%s(): calling free_irq()\n", __func__);
337362306a36Sopenharmony_ci		free_irq(card->dev->irq, &card->share_irq_ctx);
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci		if (card->msi_enable)
337662306a36Sopenharmony_ci			pci_disable_msi(pdev);
337762306a36Sopenharmony_ci	}
337862306a36Sopenharmony_ci	card->adapter = NULL;
337962306a36Sopenharmony_ci}
338062306a36Sopenharmony_ci
338162306a36Sopenharmony_ci/*
338262306a36Sopenharmony_ci * This function initializes the PCI-E host memory space, WCB rings, etc.,
338362306a36Sopenharmony_ci * similar to mwifiex_init_pcie(), but without resetting PCI-E state.
338462306a36Sopenharmony_ci */
338562306a36Sopenharmony_cistatic void mwifiex_pcie_up_dev(struct mwifiex_adapter *adapter)
338662306a36Sopenharmony_ci{
338762306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
338862306a36Sopenharmony_ci	struct pci_dev *pdev = card->dev;
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci	/* tx_buf_size might be changed to 3584 by firmware during
339162306a36Sopenharmony_ci	 * data transfer, we should reset it to default size.
339262306a36Sopenharmony_ci	 */
339362306a36Sopenharmony_ci	adapter->tx_buf_size = card->pcie.tx_buf_size;
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ci	mwifiex_pcie_alloc_buffers(adapter);
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	pci_set_master(pdev);
339862306a36Sopenharmony_ci}
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci/* This function cleans up the PCI-E host memory space. */
340162306a36Sopenharmony_cistatic void mwifiex_pcie_down_dev(struct mwifiex_adapter *adapter)
340262306a36Sopenharmony_ci{
340362306a36Sopenharmony_ci	struct pcie_service_card *card = adapter->card;
340462306a36Sopenharmony_ci	const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
340562306a36Sopenharmony_ci	struct pci_dev *pdev = card->dev;
340662306a36Sopenharmony_ci
340762306a36Sopenharmony_ci	if (mwifiex_write_reg(adapter, reg->drv_rdy, 0x00000000))
340862306a36Sopenharmony_ci		mwifiex_dbg(adapter, ERROR, "Failed to write driver not-ready signature\n");
340962306a36Sopenharmony_ci
341062306a36Sopenharmony_ci	pci_clear_master(pdev);
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_ci	adapter->seq_num = 0;
341362306a36Sopenharmony_ci
341462306a36Sopenharmony_ci	mwifiex_pcie_free_buffers(adapter);
341562306a36Sopenharmony_ci}
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_cistatic struct mwifiex_if_ops pcie_ops = {
341862306a36Sopenharmony_ci	.init_if =			mwifiex_init_pcie,
341962306a36Sopenharmony_ci	.cleanup_if =			mwifiex_cleanup_pcie,
342062306a36Sopenharmony_ci	.check_fw_status =		mwifiex_check_fw_status,
342162306a36Sopenharmony_ci	.check_winner_status =          mwifiex_check_winner_status,
342262306a36Sopenharmony_ci	.prog_fw =			mwifiex_prog_fw_w_helper,
342362306a36Sopenharmony_ci	.register_dev =			mwifiex_register_dev,
342462306a36Sopenharmony_ci	.unregister_dev =		mwifiex_unregister_dev,
342562306a36Sopenharmony_ci	.enable_int =			mwifiex_pcie_enable_host_int,
342662306a36Sopenharmony_ci	.disable_int =			mwifiex_pcie_disable_host_int_noerr,
342762306a36Sopenharmony_ci	.process_int_status =		mwifiex_process_int_status,
342862306a36Sopenharmony_ci	.host_to_card =			mwifiex_pcie_host_to_card,
342962306a36Sopenharmony_ci	.wakeup =			mwifiex_pm_wakeup_card,
343062306a36Sopenharmony_ci	.wakeup_complete =		mwifiex_pm_wakeup_card_complete,
343162306a36Sopenharmony_ci
343262306a36Sopenharmony_ci	/* PCIE specific */
343362306a36Sopenharmony_ci	.cmdrsp_complete =		mwifiex_pcie_cmdrsp_complete,
343462306a36Sopenharmony_ci	.event_complete =		mwifiex_pcie_event_complete,
343562306a36Sopenharmony_ci	.update_mp_end_port =		NULL,
343662306a36Sopenharmony_ci	.cleanup_mpa_buf =		NULL,
343762306a36Sopenharmony_ci	.init_fw_port =			mwifiex_pcie_init_fw_port,
343862306a36Sopenharmony_ci	.clean_pcie_ring =		mwifiex_clean_pcie_ring_buf,
343962306a36Sopenharmony_ci	.card_reset =			mwifiex_pcie_card_reset,
344062306a36Sopenharmony_ci	.reg_dump =			mwifiex_pcie_reg_dump,
344162306a36Sopenharmony_ci	.device_dump =			mwifiex_pcie_device_dump,
344262306a36Sopenharmony_ci	.down_dev =			mwifiex_pcie_down_dev,
344362306a36Sopenharmony_ci	.up_dev =			mwifiex_pcie_up_dev,
344462306a36Sopenharmony_ci};
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_cimodule_pci_driver(mwifiex_pcie);
344762306a36Sopenharmony_ci
344862306a36Sopenharmony_ciMODULE_AUTHOR("Marvell International Ltd.");
344962306a36Sopenharmony_ciMODULE_DESCRIPTION("Marvell WiFi-Ex PCI-Express Driver version " PCIE_VERSION);
345062306a36Sopenharmony_ciMODULE_VERSION(PCIE_VERSION);
345162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
3452