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