mirror of
https://github.com/nxp-imx/mwifiex.git
synced 2024-11-15 11:35:35 +00:00
5a38226a47
Driver Bug Fixes: ----------------- 1. WSW-19892: Driver compilation errors on older kernel version 2. WSW-19638: Enable RF Test Mode support for 9098 PCIE and SDIO 3. WCSWREL-370: oob irq request fail on i.MX93 9x9 qsb board 4. WSW-21756: WLAN Driver hang observed during WiFi connect/disconnect 5. WCSWREL-362: merge the L6.0.0 build errors fix patches 6. WSW-22054: STA CSA event is not propagated to cfg80211 7. WSW-21873: STA does not send probes after switching from DFS channel 8. WSW-21530: UDP Tx not able to send ARP when high bandwidth is used 9. WSW-21541: WFA Pre-Cert Channel switch test is failing 10. WSW-21072: AP stops sending CTS-to-Self in mcast Tx after issue mc_aggr_cfg Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
4527 lines
132 KiB
C
4527 lines
132 KiB
C
/** @file mlan_pcie.c
|
|
*
|
|
* @brief This file contains PCI-E specific code
|
|
*
|
|
*
|
|
* Copyright 2008-2021 NXP
|
|
*
|
|
* This software file (the File) is distributed by NXP
|
|
* under the terms of the GNU General Public License Version 2, June 1991
|
|
* (the License). You may use, redistribute and/or modify the File in
|
|
* accordance with the terms and conditions of the License, a copy of which
|
|
* is available by writing to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
|
|
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
|
|
*
|
|
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
|
|
* this warranty disclaimer.
|
|
*
|
|
*/
|
|
|
|
/********************************************************
|
|
Change log:
|
|
02/01/2012: initial version
|
|
********************************************************/
|
|
|
|
#include "mlan.h"
|
|
#ifdef STA_SUPPORT
|
|
#include "mlan_join.h"
|
|
#endif
|
|
#include "mlan_util.h"
|
|
#include "mlan_fw.h"
|
|
#include "mlan_main.h"
|
|
#include "mlan_init.h"
|
|
#include "mlan_wmm.h"
|
|
#include "mlan_11n.h"
|
|
#include "mlan_pcie.h"
|
|
|
|
/********************************************************
|
|
Local Variables
|
|
********************************************************/
|
|
#ifdef PCIE8897
|
|
static const struct _mlan_pcie_card_reg mlan_reg_pcie8897 = {
|
|
.reg_txbd_rdptr = PCIE8897_RD_DATA_PTR_Q0_Q1,
|
|
.reg_txbd_wrptr = PCIE8897_WR_DATA_PTR_Q0_Q1,
|
|
.reg_rxbd_rdptr = PCIE8897_RD_DATA_PTR_Q0_Q1,
|
|
.reg_rxbd_wrptr = PCIE8897_WR_DATA_PTR_Q0_Q1,
|
|
.reg_evtbd_rdptr = REG_EVTBD_RDPTR,
|
|
.reg_evtbd_wrptr = REG_EVTBD_WRPTR,
|
|
.reg_host_int_mask = PCIE_HOST_INT_MASK,
|
|
.reg_host_int_status_mask = PCIE_HOST_INT_STATUS_MASK,
|
|
.reg_host_int_status = PCIE_HOST_INT_STATUS,
|
|
.reg_cpu_int_event = PCIE_CPU_INT_EVENT,
|
|
.reg_ip_rev = PCIE_IP_REV_REG,
|
|
.reg_drv_ready = REG_DRV_READY,
|
|
.reg_cpu_int_status = PCIE_CPU_INT_STATUS,
|
|
.reg_scratch_0 = PCIE_SCRATCH_0_REG,
|
|
.reg_scratch_1 = PCIE_SCRATCH_1_REG,
|
|
.reg_scratch_2 = PCIE_SCRATCH_2_REG,
|
|
.reg_scratch_3 = PCIE_SCRATCH_3_REG,
|
|
.host_intr_mask = HOST_INTR_MASK,
|
|
.host_intr_dnld_done = HOST_INTR_DNLD_DONE,
|
|
.host_intr_upld_rdy = HOST_INTR_UPLD_RDY,
|
|
.host_intr_cmd_done = HOST_INTR_CMD_DONE,
|
|
.host_intr_event_rdy = HOST_INTR_EVENT_RDY,
|
|
.txrx_rw_ptr_mask = 0x000003FF,
|
|
.txrx_rw_ptr_wrap_mask = 0x000007FF,
|
|
.txrx_rw_ptr_rollover_ind = MBIT(10),
|
|
.use_adma = MFALSE,
|
|
.msi_int_wr_clr = MTRUE,
|
|
};
|
|
|
|
static const struct _mlan_card_info mlan_card_info_pcie8897 = {
|
|
.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
|
|
.v16_fw_api = 0,
|
|
.supp_ps_handshake = 0,
|
|
.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
|
|
};
|
|
#endif
|
|
|
|
#ifdef PCIE8997
|
|
static const struct _mlan_pcie_card_reg mlan_reg_pcie8997 = {
|
|
.reg_txbd_rdptr = PCIE8997_RD_DATA_PTR_Q0_Q1,
|
|
.reg_txbd_wrptr = PCIE8997_WR_DATA_PTR_Q0_Q1,
|
|
.reg_rxbd_rdptr = PCIE8997_RD_DATA_PTR_Q0_Q1,
|
|
.reg_rxbd_wrptr = PCIE8997_WR_DATA_PTR_Q0_Q1,
|
|
.reg_evtbd_rdptr = REG_EVTBD_RDPTR,
|
|
.reg_evtbd_wrptr = REG_EVTBD_WRPTR,
|
|
.reg_host_int_mask = PCIE_HOST_INT_MASK,
|
|
.reg_host_int_status_mask = PCIE_HOST_INT_STATUS_MASK,
|
|
.reg_host_int_status = PCIE_HOST_INT_STATUS,
|
|
.reg_cpu_int_event = PCIE_CPU_INT_EVENT,
|
|
.reg_ip_rev = PCIE_IP_REV_REG,
|
|
.reg_drv_ready = REG_DRV_READY,
|
|
.reg_cpu_int_status = PCIE_CPU_INT_STATUS,
|
|
.reg_scratch_0 = PCIE_SCRATCH_0_REG,
|
|
.reg_scratch_1 = PCIE_SCRATCH_1_REG,
|
|
.reg_scratch_2 = PCIE_SCRATCH_2_REG,
|
|
.reg_scratch_3 = PCIE_SCRATCH_3_REG,
|
|
.host_intr_mask = HOST_INTR_MASK,
|
|
.host_intr_dnld_done = HOST_INTR_DNLD_DONE,
|
|
.host_intr_upld_rdy = HOST_INTR_UPLD_RDY,
|
|
.host_intr_cmd_done = HOST_INTR_CMD_DONE,
|
|
.host_intr_event_rdy = HOST_INTR_EVENT_RDY,
|
|
.txrx_rw_ptr_mask = 0x00000FFF,
|
|
.txrx_rw_ptr_wrap_mask = 0x00001FFF,
|
|
.txrx_rw_ptr_rollover_ind = MBIT(12),
|
|
.use_adma = MFALSE,
|
|
.msi_int_wr_clr = MTRUE,
|
|
};
|
|
|
|
static const struct _mlan_card_info mlan_card_info_pcie8997 = {
|
|
.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
|
|
.v16_fw_api = 1,
|
|
.supp_ps_handshake = 0,
|
|
.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
|
|
};
|
|
#endif
|
|
|
|
#if defined(PCIE9097) || defined(PCIENW62X)
|
|
static const struct _mlan_pcie_card_reg mlan_reg_pcie9097_b0 = {
|
|
.reg_txbd_rdptr = PCIE9098_TXBD_RDPTR,
|
|
.reg_txbd_wrptr = PCIE9098_TXBD_WRPTR,
|
|
.reg_rxbd_rdptr = PCIE9098_RXBD_RDPTR,
|
|
.reg_rxbd_wrptr = PCIE9098_RXBD_WRPTR,
|
|
.reg_evtbd_rdptr = PCIE9098_EVTBD_RDPTR,
|
|
.reg_evtbd_wrptr = PCIE9098_EVTBD_WRPTR,
|
|
.reg_host_int_mask = PCIE9097_B0_HOST_INT_MASK,
|
|
.reg_host_int_status_mask = PCIE9097_B0_HOST_INT_STATUS_MASK,
|
|
.reg_host_int_status = PCIE9097_B0_HOST_INT_STATUS,
|
|
.reg_host_int_clr_sel = PCIE9097_B0_HOST_INT_CLR_SEL,
|
|
.reg_cpu_int_event = PCIE9098_CPU_INT_EVENT,
|
|
.reg_ip_rev = PCIE9098_DEV_ID_REG,
|
|
.reg_drv_ready = PCIE9098_DRV_READY,
|
|
.reg_cpu_int_status = PCIE9098_CPU_INT_STATUS,
|
|
.reg_rev_id = PCIE9098_REV_ID_REG,
|
|
.reg_scratch_0 = PCIE9098_SCRATCH_0_REG,
|
|
.reg_scratch_1 = PCIE9098_SCRATCH_1_REG,
|
|
.reg_scratch_2 = PCIE9098_SCRATCH_2_REG,
|
|
.reg_scratch_3 = PCIE9098_SCRATCH_3_REG,
|
|
.reg_scratch_6 = PCIE9098_SCRATCH_6_REG,
|
|
.reg_scratch_7 = PCIE9098_SCRATCH_7_REG,
|
|
.host_intr_mask = PCIE9098_HOST_INTR_MASK,
|
|
.host_intr_dnld_done = PCIE9098_HOST_INTR_DNLD_DONE,
|
|
.host_intr_upld_rdy = PCIE9098_HOST_INTR_UPLD_RDY,
|
|
.host_intr_cmd_done = PCIE9098_HOST_INTR_CMD_DONE,
|
|
.host_intr_event_rdy = PCIE9098_HOST_INTR_EVENT_RDY,
|
|
.host_intr_cmd_dnld = PCIE9098_HOST_INTR_CMD_DNLD,
|
|
.use_adma = MTRUE,
|
|
.msi_int_wr_clr = MTRUE,
|
|
};
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
static const struct _mlan_pcie_card_reg mlan_reg_pcie9098 = {
|
|
.reg_txbd_rdptr = PCIE9098_TXBD_RDPTR,
|
|
.reg_txbd_wrptr = PCIE9098_TXBD_WRPTR,
|
|
.reg_rxbd_rdptr = PCIE9098_RXBD_RDPTR,
|
|
.reg_rxbd_wrptr = PCIE9098_RXBD_WRPTR,
|
|
.reg_evtbd_rdptr = PCIE9098_EVTBD_RDPTR,
|
|
.reg_evtbd_wrptr = PCIE9098_EVTBD_WRPTR,
|
|
.reg_host_int_mask = PCIE9098_HOST_INT_MASK,
|
|
.reg_host_int_status_mask = PCIE9098_HOST_INT_STATUS_MASK,
|
|
.reg_host_int_status = PCIE9098_HOST_INT_STATUS,
|
|
.reg_host_int_clr_sel = PCIE9098_HOST_INT_CLR_SEL,
|
|
.reg_cpu_int_event = PCIE9098_CPU_INT_EVENT,
|
|
.reg_ip_rev = PCIE9098_DEV_ID_REG,
|
|
.reg_drv_ready = PCIE9098_DRV_READY,
|
|
.reg_cpu_int_status = PCIE9098_CPU_INT_STATUS,
|
|
.reg_rev_id = PCIE9098_REV_ID_REG,
|
|
.reg_scratch_0 = PCIE9098_SCRATCH_0_REG,
|
|
.reg_scratch_1 = PCIE9098_SCRATCH_1_REG,
|
|
.reg_scratch_2 = PCIE9098_SCRATCH_2_REG,
|
|
.reg_scratch_3 = PCIE9098_SCRATCH_3_REG,
|
|
.reg_scratch_6 = PCIE9098_SCRATCH_6_REG,
|
|
.reg_scratch_7 = PCIE9098_SCRATCH_7_REG,
|
|
.host_intr_mask = PCIE9098_HOST_INTR_MASK,
|
|
.host_intr_dnld_done = PCIE9098_HOST_INTR_DNLD_DONE,
|
|
.host_intr_upld_rdy = PCIE9098_HOST_INTR_UPLD_RDY,
|
|
.host_intr_cmd_done = PCIE9098_HOST_INTR_CMD_DONE,
|
|
.host_intr_event_rdy = PCIE9098_HOST_INTR_EVENT_RDY,
|
|
.host_intr_cmd_dnld = PCIE9098_HOST_INTR_CMD_DNLD,
|
|
.use_adma = MTRUE,
|
|
.msi_int_wr_clr = MTRUE,
|
|
};
|
|
|
|
static const struct _mlan_card_info mlan_card_info_pcie9098 = {
|
|
.max_tx_buf_size = MLAN_TX_DATA_BUF_SIZE_4K,
|
|
.v16_fw_api = 1,
|
|
.v17_fw_api = 1,
|
|
.supp_ps_handshake = 0,
|
|
.default_11n_tx_bf_cap = DEFAULT_11N_TX_BF_CAP_2X2,
|
|
};
|
|
#endif
|
|
/********************************************************
|
|
Global Variables
|
|
********************************************************/
|
|
|
|
/********************************************************
|
|
Local Functions
|
|
********************************************************/
|
|
|
|
static mlan_status wlan_pcie_delete_evtbd_ring(pmlan_adapter pmadapter);
|
|
static mlan_status wlan_pcie_delete_rxbd_ring(pmlan_adapter pmadapter);
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
/**
|
|
* @brief This function init the adma setting
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param adma_type TX/RX data, event, cmd/cmdresp
|
|
* @param pbase physical address
|
|
* @param size desc num/dma_size
|
|
* @param init init flag
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_init_adma(mlan_adapter *pmadapter, t_u8 type,
|
|
t_u64 pbase, t_u16 size, t_u8 init)
|
|
{
|
|
t_u32 dma_cfg, dma_cfg2, dma_cfg3, int_mapping;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u32 q_addr = 0;
|
|
t_u8 direction = 0;
|
|
t_u8 dma_mode = 0;
|
|
t_u32 msix_data;
|
|
t_u32 msix_vector;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
ENTER();
|
|
if (init)
|
|
PRINTM(MCMND, "Init ADMA: type=%d, size=%d init=%d\n", type,
|
|
size, init);
|
|
switch (type) {
|
|
case ADMA_TX_DATA:
|
|
q_addr = ADMA_CHAN0_Q0;
|
|
direction = ADMA_HOST_TO_DEVICE;
|
|
dma_mode = DMA_MODE_DUAL_DESC;
|
|
msix_vector = ADMA_VECTOR_CHAN0_Q0;
|
|
break;
|
|
case ADMA_RX_DATA:
|
|
q_addr = ADMA_CHAN1_Q0;
|
|
direction = ADMA_DEVICE_TO_HOST;
|
|
dma_mode = DMA_MODE_DUAL_DESC;
|
|
msix_vector = AMDA_VECTOR_CHAN1_Q0;
|
|
break;
|
|
case ADMA_EVENT:
|
|
q_addr = ADMA_CHAN1_Q1;
|
|
direction = ADMA_DEVICE_TO_HOST;
|
|
dma_mode = DMA_MODE_DUAL_DESC;
|
|
msix_vector = AMDA_VECTOR_CHAN1_Q1;
|
|
break;
|
|
case ADMA_CMD:
|
|
q_addr = ADMA_CHAN2_Q0;
|
|
direction = ADMA_HOST_TO_DEVICE;
|
|
dma_mode = DMA_MODE_DIRECT;
|
|
msix_vector = AMDA_VECTOR_CHAN2_Q0;
|
|
break;
|
|
case ADMA_CMDRESP:
|
|
q_addr = ADMA_CHAN2_Q1;
|
|
direction = ADMA_DEVICE_TO_HOST;
|
|
dma_mode = DMA_MODE_DIRECT;
|
|
msix_vector = AMDA_VECTOR_CHAN2_Q1;
|
|
break;
|
|
default:
|
|
PRINTM(MERROR, "unknow adma type\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
if (ret)
|
|
goto done;
|
|
if (init) {
|
|
if (dma_mode == DMA_MODE_DUAL_DESC) {
|
|
if (direction == ADMA_HOST_TO_DEVICE)
|
|
int_mapping = DEST_INT_TO_DEVICE;
|
|
else
|
|
int_mapping = DEST_INT_TO_HOST;
|
|
} else {
|
|
int_mapping = 0;
|
|
}
|
|
/* set INT_MAPPING register */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_INT_MAPPING,
|
|
(t_u32)int_mapping)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write ADMA_INT_MAPPING register.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Read the dma_cfg2 register */
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_DMA_CFG2, &dma_cfg2)) {
|
|
PRINTM(MERROR, "Fail to read DMA CFG2 register\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
dma_cfg2 &= ~(ADMA_SRC_DMA_DONE_INT_BYPASS_EN |
|
|
ADMA_DST_DMA_DONE_INT_BYPASS_EN |
|
|
ADMA_MSI_LEGACY_SRC_DMA_DONE_INT_BYPASS_EN |
|
|
ADMA_MSI_LEGACY_DST_DMA_DONE_INT_BYPASS_EN |
|
|
ADMA_MSI_LEGACY_ENABLE | ADMA_MSIX_ENABLE |
|
|
ADMA_MSIX_INT_SRC_DST_SEL);
|
|
|
|
if (dma_mode == DMA_MODE_DUAL_DESC) {
|
|
if (direction == ADMA_HOST_TO_DEVICE) {
|
|
dma_cfg2 |= ADMA_SRC_DMA_DONE_INT_BYPASS_EN;
|
|
if (pmadapter->pcard_pcie->pcie_int_mode !=
|
|
PCIE_INT_MODE_MSIX)
|
|
dma_cfg2 |=
|
|
ADMA_MSI_LEGACY_SRC_DMA_DONE_INT_BYPASS_EN;
|
|
} else {
|
|
/* Read the dma_cfg3 register */
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_DMA_CFG3,
|
|
&dma_cfg3)) {
|
|
PRINTM(MERROR,
|
|
"Fail to read DMA CFG3 register\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
dma_cfg3 |= ADMA_Q_PTR_CLR;
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_DMA_CFG3,
|
|
(t_u32)dma_cfg3)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write ADMA_DMA_CFG3.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
dma_cfg2 |= ADMA_DST_DMA_DONE_INT_BYPASS_EN;
|
|
if (pmadapter->pcard_pcie->pcie_int_mode !=
|
|
PCIE_INT_MODE_MSIX)
|
|
dma_cfg2 |=
|
|
ADMA_MSI_LEGACY_DST_DMA_DONE_INT_BYPASS_EN;
|
|
}
|
|
} else {
|
|
if (direction == ADMA_HOST_TO_DEVICE)
|
|
dma_cfg2 |= ADMA_SRC_ADDR_IS_HOST;
|
|
else
|
|
dma_cfg2 |= ADMA_DST_ADDR_IS_HOST;
|
|
}
|
|
|
|
if (pmadapter->pcard_pcie->pcie_int_mode ==
|
|
PCIE_INT_MODE_MSIX) {
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_MSIX_DOORBELL_DATA,
|
|
&msix_data)) {
|
|
PRINTM(MERROR,
|
|
"Fail to read DMA MSIX data register\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
msix_data &= ~ADMA_MSIX_VECTOR_MASK;
|
|
msix_data &= ~ADMA_MSIX_PF_MASK;
|
|
msix_data |= msix_vector;
|
|
msix_data |= pmadapter->pcard_pcie->func_num
|
|
<< ADMA_MSIX_PF_BIT;
|
|
PRINTM(MCMND, "msix_data=0x%x\n", msix_data);
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr +
|
|
ADMA_MSIX_DOORBELL_DATA,
|
|
(t_u32)msix_data)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write DMA DOORBELL_DATA.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
dma_cfg2 |= ADMA_MSIX_ENABLE;
|
|
} else
|
|
dma_cfg2 |= ADMA_MSI_LEGACY_ENABLE;
|
|
PRINTM(MCMND, "dma_cfg2=0x%x\n", dma_cfg2);
|
|
|
|
/* enable INT_BYPASS_EN in the dma_cfg2 register */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_DMA_CFG2,
|
|
(t_u32)dma_cfg2)) {
|
|
PRINTM(MERROR, "Failed to write DMA CFG2.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
/* Read the TX ring read pointer set by firmware */
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle, q_addr + ADMA_DMA_CFG,
|
|
&dma_cfg)) {
|
|
PRINTM(MERROR, "Fail to read DMA CFG register\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if (direction == ADMA_HOST_TO_DEVICE) {
|
|
/* Write the lower 32bits of the physical address to
|
|
* ADMA_SRC_LOW */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_SRC_LOW, (t_u32)pbase)) {
|
|
PRINTM(MERROR, "Failed to write ADMA_SRC_LOW.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
/* Write the upper 32bits of the physical address to
|
|
* ADMA_SRC_HIGH */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_SRC_HIGH,
|
|
(t_u32)((t_u64)pbase >> 32))) {
|
|
PRINTM(MERROR, "Failed to write ADMA_SRC_HIGH.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if (init) {
|
|
/** Enable DMA done interrupt */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
q_addr + ADMA_SRC_INT_STATUS_MASK,
|
|
DEF_ADMA_INT_MASK)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write ADMA_SRC_INT_STATUS_MASK.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_SRC_INT_MASK,
|
|
DEF_ADMA_INT_MASK)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write ADMA_SRC_INT_MASK.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
if (dma_mode == DMA_MODE_DUAL_DESC) {
|
|
dma_cfg &= ~(DESC_MODE_MASK | DMA_MODE_MASK |
|
|
SRC_NUM_DESC_MASK | DMA_SIZE_MASK);
|
|
dma_cfg |= (t_u32)size << SRC_NUM_DESC_BIT;
|
|
dma_cfg |= DESC_MODE_RING << 2;
|
|
} else {
|
|
dma_cfg &= ~(DESC_MODE_MASK | DMA_MODE_MASK |
|
|
SRC_NUM_DESC_MASK | DST_NUM_DESC_MASK |
|
|
DMA_SIZE_MASK);
|
|
dma_cfg |= (t_u32)size << DMA_SIZE_BIT;
|
|
}
|
|
} else {
|
|
/* Write the lower 32bits of the physical address to
|
|
* ADMA_DST_LOW */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_DST_LOW, (t_u32)pbase)) {
|
|
PRINTM(MERROR, "Failed to write ADMA_DST_LOW.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
/* Write the upper 32bits of the physical address to
|
|
* ADMA_DST_HIGH */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_DST_HIGH,
|
|
(t_u32)((t_u64)pbase >> 32))) {
|
|
PRINTM(MERROR, "Failed to write ADMA_DST_HIGH.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if (init && (dma_mode == DMA_MODE_DUAL_DESC)) {
|
|
/** Enable DMA done interrupt */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
q_addr + ADMA_DST_INT_STATUS_MASK,
|
|
DEF_ADMA_INT_MASK)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write ADMA_SRC_INT_STATUS_MASK.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_DST_INT_MASK,
|
|
DEF_ADMA_INT_MASK)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write ADMA_SRC_INT_MASK.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
if (dma_mode == DMA_MODE_DUAL_DESC) {
|
|
dma_cfg &= ~(DESC_MODE_MASK | DMA_MODE_MASK |
|
|
DST_NUM_DESC_MASK | DMA_SIZE_MASK);
|
|
dma_cfg |= (t_u32)size << DST_NUM_DESC_BIT;
|
|
dma_cfg |= DESC_MODE_RING << 2;
|
|
} else {
|
|
dma_cfg &= ~(DESC_MODE_MASK | DMA_MODE_MASK |
|
|
SRC_NUM_DESC_MASK | DST_NUM_DESC_MASK);
|
|
}
|
|
}
|
|
dma_cfg |= (t_u32)dma_mode;
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle, q_addr + ADMA_DMA_CFG,
|
|
dma_cfg)) {
|
|
PRINTM(MERROR, "Fail to set DMA CFG register\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
if (type == ADMA_CMD && !init) {
|
|
/* Write 1 to src_wr_ptr to trigger direct dma */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
q_addr + ADMA_SRC_RW_PTR, 1)) {
|
|
PRINTM(MERROR, "Failed to write ADMA_SRC_HIGH.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function init the adma ring size from user input
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return N/A
|
|
*/
|
|
static void wlan_pcie_init_adma_ring_size(mlan_adapter *pmadapter)
|
|
{
|
|
t_u16 num_desc = 0;
|
|
t_u16 ring_size = 0;
|
|
|
|
ring_size = pmadapter->init_para.ring_size;
|
|
if (!ring_size)
|
|
return;
|
|
if (ring_size < MAX_TXRX_BD)
|
|
ring_size = MAX_TXRX_BD;
|
|
else if (ring_size > ADMA_MAX_TXRX_BD)
|
|
ring_size = ADMA_MAX_TXRX_BD;
|
|
if (ring_size != pmadapter->pcard_pcie->txrx_bd_size) {
|
|
ring_size = ring_size >> 1;
|
|
while (ring_size > 0) {
|
|
ring_size = ring_size >> 1;
|
|
num_desc++;
|
|
}
|
|
pmadapter->pcard_pcie->txrx_bd_size = 1 << num_desc;
|
|
pmadapter->pcard_pcie->txrx_num_desc = num_desc;
|
|
}
|
|
PRINTM(MMSG, "ring_size =%d num_desc=%d\n",
|
|
pmadapter->pcard_pcie->txrx_bd_size,
|
|
pmadapter->pcard_pcie->txrx_num_desc);
|
|
return;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
/**
|
|
* @brief This function set the host interrupt select mask
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param enable 0-disable 1-enable
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_set_host_int_select_mask(mlan_adapter *pmadapter,
|
|
t_u8 enable)
|
|
{
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 int_sel_mask = 0;
|
|
t_u32 int_clr_mask = 0;
|
|
ENTER();
|
|
|
|
if (enable) {
|
|
int_sel_mask = PCIE9098_HOST_INTR_SEL_MASK;
|
|
int_clr_mask = pmadapter->pcard_pcie->reg->host_intr_mask;
|
|
}
|
|
|
|
/* Simply write the mask to the register */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle, PCIE9098_HOST_INT_SEL,
|
|
int_sel_mask)) {
|
|
PRINTM(MWARN, "Set host interrupt select register failed\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSI) {
|
|
if (!pmadapter->pcard_pcie->reg->msi_int_wr_clr) {
|
|
/** enable read to clear interrupt */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_host_int_clr_sel,
|
|
int_clr_mask)) {
|
|
PRINTM(MWARN,
|
|
"enable read to clear interrupt failed\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
/**
|
|
* @brief This function handles command response completion
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pmbuf A pointer to mlan_buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_send_vdll_complete(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_buffer *pcmdbuf;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
ENTER();
|
|
/*unmap the cmd pmbuf, so the cpu can not access the memory in the
|
|
* command node*/
|
|
pcmdbuf = pmadapter->pcard_pcie->vdll_cmd_buf;
|
|
if (pcmdbuf) {
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
pcmdbuf->pbuf + pcmdbuf->data_offset,
|
|
pcmdbuf->buf_pa, pcmdbuf->data_len,
|
|
PCI_DMA_TODEVICE);
|
|
pmadapter->pcard_pcie->vdll_cmd_buf = MNULL;
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function downloads VDLL image to the card.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pmbuf A pointer to mlan_buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_send_vdll(mlan_adapter *pmadapter,
|
|
mlan_buffer *pmbuf)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_PENDING;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u16 *tmp;
|
|
t_u8 *payload;
|
|
|
|
ENTER();
|
|
pmadapter->cmd_sent = MTRUE;
|
|
payload = pmbuf->pbuf + pmbuf->data_offset;
|
|
|
|
tmp = (t_u16 *)&payload[0];
|
|
*tmp = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
tmp = (t_u16 *)&payload[2];
|
|
*tmp = wlan_cpu_to_le16(MLAN_TYPE_VDLL);
|
|
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_map_memory(
|
|
pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
|
|
&pmbuf->buf_pa, pmbuf->data_len, PCI_DMA_TODEVICE)) {
|
|
PRINTM(MERROR,
|
|
"PCIE - Download VDLL block: moal_map_memory failed\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
pmadapter->pcard_pcie->vdll_cmd_buf = pmbuf;
|
|
/* issue the DMA */
|
|
/* send the VDLL block down to the firmware */
|
|
wlan_init_adma(pmadapter, ADMA_CMD, pmbuf->buf_pa, pmbuf->data_len,
|
|
MFALSE);
|
|
|
|
PRINTM(MINFO, "PCIE - Download VDLL Block: successful.\n");
|
|
done:
|
|
if (ret == MLAN_STATUS_FAILURE)
|
|
pmadapter->cmd_sent = MFALSE;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief This function disables the host interrupt
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_disable_host_int_mask(mlan_adapter *pmadapter)
|
|
{
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_host_int_mask,
|
|
0x00000000)) {
|
|
PRINTM(MWARN, "Disable host interrupt failed\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function enables the host interrupt
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_enable_host_int_mask(mlan_adapter *pmadapter)
|
|
{
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
ENTER();
|
|
/* Simply write the mask to the register */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_host_int_mask,
|
|
pmadapter->pcard_pcie->reg->host_intr_mask)) {
|
|
PRINTM(MWARN, "Enable host interrupt failed\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function enables the host interrupts.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param enable 0-disable 1-enable
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status
|
|
wlan_pcie_enable_host_int_status_mask(mlan_adapter *pmadapter, t_u8 enable)
|
|
{
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 host_int_status_mask = 0;
|
|
ENTER();
|
|
if (enable)
|
|
host_int_status_mask =
|
|
pmadapter->pcard_pcie->reg->host_intr_mask;
|
|
/* Enable host int status mask */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_host_int_status_mask,
|
|
host_int_status_mask)) {
|
|
PRINTM(MWARN, "Enable host interrupt status mask failed\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function disables the host interrupts.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_disable_pcie_host_int(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret;
|
|
|
|
ENTER();
|
|
ret = wlan_pcie_enable_host_int_status_mask(pmadapter, MFALSE);
|
|
if (ret) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if ((pmadapter->card_type == CARD_TYPE_PCIE9098) ||
|
|
(pmadapter->card_type == CARD_TYPE_PCIENW62X) ||
|
|
(pmadapter->card_type == CARD_TYPE_PCIE9097)) {
|
|
ret = wlan_pcie_set_host_int_select_mask(pmadapter, MFALSE);
|
|
if (ret) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
}
|
|
#endif
|
|
ret = wlan_pcie_disable_host_int_mask(pmadapter);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function checks the interrupt status and
|
|
* handle it accordingly.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_clear_pending_int_status(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u32 pcie_ireg = 0;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
|
|
if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSIX)
|
|
goto done;
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_host_int_status,
|
|
&pcie_ireg)) {
|
|
PRINTM(MERROR, "Read host int status register failed\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
|
|
PRINTM(MMSG, "pcie_ireg=0x%x\n", pcie_ireg);
|
|
if (pmadapter->pcard_pcie->reg->msi_int_wr_clr) {
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_host_int_status,
|
|
~pcie_ireg)) {
|
|
PRINTM(MERROR,
|
|
"Write host int status register failed\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function enables the host interrupts.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_enable_pcie_host_int(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret;
|
|
|
|
ENTER();
|
|
wlan_clear_pending_int_status(pmadapter);
|
|
ret = wlan_pcie_enable_host_int_status_mask(pmadapter, MTRUE);
|
|
if (ret) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if ((pmadapter->card_type == CARD_TYPE_PCIE9098) ||
|
|
(pmadapter->card_type == CARD_TYPE_PCIENW62X) ||
|
|
(pmadapter->card_type == CARD_TYPE_PCIE9097)) {
|
|
ret = wlan_pcie_set_host_int_select_mask(pmadapter, MTRUE);
|
|
if (ret) {
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
}
|
|
#endif
|
|
ret = wlan_pcie_enable_host_int_mask(pmadapter);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function creates buffer descriptor ring for TX
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_create_txbd_ring(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 i;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
pmlan_pcie_data_buf ptx_bd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
padma_dual_desc_buf padma_bd_buf;
|
|
#endif
|
|
|
|
ENTER();
|
|
/*
|
|
* driver maintaines the write pointer and firmware maintaines the read
|
|
* pointer.
|
|
*/
|
|
pmadapter->pcard_pcie->txbd_wrptr = 0;
|
|
pmadapter->pcard_pcie->txbd_pending = 0;
|
|
pmadapter->pcard_pcie->txbd_rdptr = 0;
|
|
|
|
/* allocate shared memory for the BD ring and divide the same in to
|
|
several descriptors */
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma)
|
|
pmadapter->pcard_pcie->txbd_ring_size =
|
|
sizeof(mlan_pcie_data_buf) *
|
|
pmadapter->pcard_pcie->txrx_bd_size;
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma)
|
|
pmadapter->pcard_pcie->txbd_ring_size =
|
|
sizeof(adma_dual_desc_buf) *
|
|
pmadapter->pcard_pcie->txrx_bd_size;
|
|
#endif
|
|
PRINTM(MINFO, "TX ring: allocating %d bytes\n",
|
|
pmadapter->pcard_pcie->txbd_ring_size);
|
|
|
|
ret = pcb->moal_malloc_consistent(
|
|
pmadapter->pmoal_handle, pmadapter->pcard_pcie->txbd_ring_size,
|
|
&pmadapter->pcard_pcie->txbd_ring_vbase,
|
|
&pmadapter->pcard_pcie->txbd_ring_pbase);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
|
|
__FUNCTION__);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
PRINTM(MINFO,
|
|
"TX ring: - base: %p, pbase: %#x:%x,"
|
|
"len: %x\n",
|
|
pmadapter->pcard_pcie->txbd_ring_vbase,
|
|
(t_u32)((t_u64)pmadapter->pcard_pcie->txbd_ring_pbase >> 32),
|
|
(t_u32)pmadapter->pcard_pcie->txbd_ring_pbase,
|
|
pmadapter->pcard_pcie->txbd_ring_size);
|
|
|
|
for (i = 0; i < pmadapter->pcard_pcie->txrx_bd_size; i++) {
|
|
pmadapter->pcard_pcie->tx_buf_list[i] = MNULL;
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf
|
|
*)(pmadapter->pcard_pcie
|
|
->txbd_ring_vbase +
|
|
(sizeof(adma_dual_desc_buf) * i));
|
|
pmadapter->pcard_pcie->txbd_ring[i] =
|
|
(t_void *)padma_bd_buf;
|
|
padma_bd_buf->paddr = 0;
|
|
padma_bd_buf->len = 0;
|
|
padma_bd_buf->flags = wlan_cpu_to_le16(
|
|
ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_SRC_HOST |
|
|
ADMA_BD_FLAG_SOP | ADMA_BD_FLAG_EOP);
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
ptx_bd_buf =
|
|
(mlan_pcie_data_buf
|
|
*)(pmadapter->pcard_pcie
|
|
->txbd_ring_vbase +
|
|
(sizeof(mlan_pcie_data_buf) * i));
|
|
pmadapter->pcard_pcie->txbd_ring[i] =
|
|
(t_void *)ptx_bd_buf;
|
|
ptx_bd_buf->paddr = 0;
|
|
ptx_bd_buf->len = 0;
|
|
ptx_bd_buf->flags = 0;
|
|
ptx_bd_buf->frag_len = 0;
|
|
ptx_bd_buf->offset = 0;
|
|
}
|
|
#endif
|
|
}
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function frees TX buffer descriptor ring
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_delete_txbd_ring(mlan_adapter *pmadapter)
|
|
{
|
|
t_u32 i;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
mlan_pcie_data_buf *ptx_bd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
#endif
|
|
|
|
ENTER();
|
|
|
|
for (i = 0; i < pmadapter->pcard_pcie->txrx_bd_size; i++) {
|
|
if (pmadapter->pcard_pcie->tx_buf_list[i]) {
|
|
pmbuf = pmadapter->pcard_pcie->tx_buf_list[i];
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa,
|
|
MLAN_RX_DATA_BUF_SIZE,
|
|
PCI_DMA_TODEVICE);
|
|
wlan_write_data_complete(pmadapter, pmbuf,
|
|
MLAN_STATUS_FAILURE);
|
|
}
|
|
pmadapter->pcard_pcie->tx_buf_list[i] = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
ptx_bd_buf =
|
|
(mlan_pcie_data_buf *)
|
|
pmadapter->pcard_pcie->txbd_ring[i];
|
|
|
|
if (ptx_bd_buf) {
|
|
ptx_bd_buf->paddr = 0;
|
|
ptx_bd_buf->len = 0;
|
|
ptx_bd_buf->flags = 0;
|
|
ptx_bd_buf->frag_len = 0;
|
|
ptx_bd_buf->offset = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf *)
|
|
pmadapter->pcard_pcie->txbd_ring[i];
|
|
|
|
if (padma_bd_buf) {
|
|
padma_bd_buf->paddr = 0;
|
|
padma_bd_buf->len = 0;
|
|
padma_bd_buf->flags = 0;
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
}
|
|
}
|
|
#endif
|
|
pmadapter->pcard_pcie->txbd_ring[i] = MNULL;
|
|
}
|
|
|
|
if (pmadapter->pcard_pcie->txbd_ring_vbase) {
|
|
pmadapter->callbacks.moal_mfree_consistent(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->txbd_ring_size,
|
|
pmadapter->pcard_pcie->txbd_ring_vbase,
|
|
pmadapter->pcard_pcie->txbd_ring_pbase);
|
|
}
|
|
pmadapter->pcard_pcie->txbd_pending = 0;
|
|
pmadapter->pcard_pcie->txbd_ring_size = 0;
|
|
pmadapter->pcard_pcie->txbd_wrptr = 0;
|
|
pmadapter->pcard_pcie->txbd_rdptr = 0;
|
|
pmadapter->pcard_pcie->txbd_ring_vbase = MNULL;
|
|
pmadapter->pcard_pcie->txbd_ring_pbase = 0;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function creates buffer descriptor ring for RX
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_create_rxbd_ring(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
t_u32 i;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
mlan_pcie_data_buf *prxbd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
#endif
|
|
|
|
ENTER();
|
|
|
|
pmadapter->pcard_pcie->rxbd_rdptr = 0;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
/*
|
|
* driver maintaines the write pointer and firmware maintaines the read
|
|
* pointer. The read pointer starts at 0 (zero) while the write pointer
|
|
* starts at zero with rollover bit set
|
|
*/
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
pmadapter->pcard_pcie->rxbd_wrptr =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
/* allocate shared memory for the BD ring and divide the same in
|
|
to several descriptors */
|
|
pmadapter->pcard_pcie->rxbd_ring_size =
|
|
sizeof(mlan_pcie_data_buf) *
|
|
pmadapter->pcard_pcie->txrx_bd_size;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
/*
|
|
* driver maintaines the write pointer and firmware maintaines the read
|
|
* pointer. The read pointer starts at 0 (zero) while the write pointer
|
|
* starts at pmadapter->pcard_pcie->txrx_bd_size;
|
|
*/
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
pmadapter->pcard_pcie->rxbd_wrptr =
|
|
pmadapter->pcard_pcie->txrx_bd_size;
|
|
pmadapter->pcard_pcie->rxbd_ring_size =
|
|
sizeof(adma_dual_desc_buf) *
|
|
pmadapter->pcard_pcie->txrx_bd_size;
|
|
}
|
|
#endif
|
|
|
|
PRINTM(MINFO, "RX ring: allocating %d bytes\n",
|
|
pmadapter->pcard_pcie->rxbd_ring_size);
|
|
|
|
ret = pcb->moal_malloc_consistent(
|
|
pmadapter->pmoal_handle, pmadapter->pcard_pcie->rxbd_ring_size,
|
|
&pmadapter->pcard_pcie->rxbd_ring_vbase,
|
|
&pmadapter->pcard_pcie->rxbd_ring_pbase);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
|
|
__FUNCTION__);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
PRINTM(MINFO,
|
|
"RX ring: - base: %p, pbase: %#x:%x,"
|
|
"len: %#x\n",
|
|
pmadapter->pcard_pcie->rxbd_ring_vbase,
|
|
(t_u32)((t_u64)pmadapter->pcard_pcie->rxbd_ring_pbase >> 32),
|
|
(t_u32)pmadapter->pcard_pcie->rxbd_ring_pbase,
|
|
pmadapter->pcard_pcie->rxbd_ring_size);
|
|
|
|
for (i = 0; i < pmadapter->pcard_pcie->txrx_bd_size; i++) {
|
|
/* Allocate buffer here so that firmware can DMA data on it */
|
|
pmbuf = wlan_alloc_mlan_buffer(pmadapter, MLAN_RX_DATA_BUF_SIZE,
|
|
MLAN_RX_HEADER_LEN,
|
|
MOAL_ALLOC_MLAN_BUFFER);
|
|
if (!pmbuf) {
|
|
PRINTM(MERROR,
|
|
"RX ring create : Unable to allocate mlan_buffer\n");
|
|
wlan_pcie_delete_rxbd_ring(pmadapter);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
pmadapter->pcard_pcie->rx_buf_list[i] = pmbuf;
|
|
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_map_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
&pmbuf->buf_pa, MLAN_RX_DATA_BUF_SIZE,
|
|
PCI_DMA_FROMDEVICE)) {
|
|
PRINTM(MERROR,
|
|
"Rx ring create : moal_map_memory failed\n");
|
|
wlan_pcie_delete_rxbd_ring(pmadapter);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
PRINTM(MINFO,
|
|
"RX ring: add new mlan_buffer base: %p, "
|
|
"buf_base: %p, buf_pbase: %#x:%x, "
|
|
"buf_len: %#x\n",
|
|
pmbuf, pmbuf->pbuf, (t_u32)((t_u64)pmbuf->buf_pa >> 32),
|
|
(t_u32)pmbuf->buf_pa, pmbuf->data_len);
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
prxbd_buf =
|
|
(mlan_pcie_data_buf
|
|
*)(pmadapter->pcard_pcie
|
|
->rxbd_ring_vbase +
|
|
(sizeof(mlan_pcie_data_buf) * i));
|
|
pmadapter->pcard_pcie->rxbd_ring[i] =
|
|
(t_void *)prxbd_buf;
|
|
prxbd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
prxbd_buf->len =
|
|
wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
prxbd_buf->flags = wlan_cpu_to_le16(MLAN_BD_FLAG_SOP |
|
|
MLAN_BD_FLAG_EOP);
|
|
prxbd_buf->offset = 0;
|
|
prxbd_buf->frag_len =
|
|
wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf
|
|
*)(pmadapter->pcard_pcie
|
|
->rxbd_ring_vbase +
|
|
(sizeof(adma_dual_desc_buf) * i));
|
|
pmadapter->pcard_pcie->rxbd_ring[i] =
|
|
(t_void *)padma_bd_buf;
|
|
padma_bd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
padma_bd_buf->len = wlan_cpu_to_le16(
|
|
ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE));
|
|
padma_bd_buf->flags = wlan_cpu_to_le16(
|
|
ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_DST_HOST);
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function frees RX buffer descriptor ring
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_delete_rxbd_ring(mlan_adapter *pmadapter)
|
|
{
|
|
t_u32 i;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
mlan_pcie_data_buf *prxbd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
#endif
|
|
|
|
ENTER();
|
|
for (i = 0; i < pmadapter->pcard_pcie->txrx_bd_size; i++) {
|
|
if (pmadapter->pcard_pcie->rx_buf_list[i]) {
|
|
pmbuf = pmadapter->pcard_pcie->rx_buf_list[i];
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa,
|
|
MLAN_RX_DATA_BUF_SIZE,
|
|
PCI_DMA_FROMDEVICE);
|
|
wlan_free_mlan_buffer(
|
|
pmadapter,
|
|
pmadapter->pcard_pcie->rx_buf_list[i]);
|
|
}
|
|
pmadapter->pcard_pcie->rx_buf_list[i] = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
prxbd_buf = (mlan_pcie_data_buf *)
|
|
pmadapter->pcard_pcie->rxbd_ring[i];
|
|
|
|
if (prxbd_buf) {
|
|
prxbd_buf->paddr = 0;
|
|
prxbd_buf->offset = 0;
|
|
prxbd_buf->frag_len = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf *)
|
|
pmadapter->pcard_pcie->rxbd_ring[i];
|
|
|
|
if (padma_bd_buf) {
|
|
padma_bd_buf->paddr = 0;
|
|
padma_bd_buf->flags = 0;
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
padma_bd_buf->len = 0;
|
|
}
|
|
}
|
|
#endif
|
|
pmadapter->pcard_pcie->rxbd_ring[i] = MNULL;
|
|
}
|
|
|
|
if (pmadapter->pcard_pcie->rxbd_ring_vbase)
|
|
pmadapter->callbacks.moal_mfree_consistent(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->rxbd_ring_size,
|
|
pmadapter->pcard_pcie->rxbd_ring_vbase,
|
|
pmadapter->pcard_pcie->rxbd_ring_pbase);
|
|
pmadapter->pcard_pcie->rxbd_ring_size = 0;
|
|
pmadapter->pcard_pcie->rxbd_rdptr = 0;
|
|
pmadapter->pcard_pcie->rxbd_wrptr = 0;
|
|
pmadapter->pcard_pcie->rxbd_ring_vbase = MNULL;
|
|
pmadapter->pcard_pcie->rxbd_ring_pbase = 0;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function creates buffer descriptor ring for Events
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_create_evtbd_ring(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
t_u32 i;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
pmlan_pcie_evt_buf pevtbd_buf;
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
#endif
|
|
|
|
ENTER();
|
|
/*
|
|
* driver maintaines the write pointer and firmware maintaines the read
|
|
* pointer. The read pointer starts at 0 (zero) while the write pointer
|
|
* starts at zero with rollover bit set
|
|
*/
|
|
pmadapter->pcard_pcie->evtbd_rdptr = 0;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
pmadapter->pcard_pcie->evtbd_wrptr = EVT_RW_PTR_ROLLOVER_IND;
|
|
pmadapter->pcard_pcie->evtbd_ring_size =
|
|
sizeof(mlan_pcie_evt_buf) * MLAN_MAX_EVT_BD;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
pmadapter->pcard_pcie->evtbd_wrptr = MLAN_MAX_EVT_BD;
|
|
pmadapter->pcard_pcie->evtbd_ring_size =
|
|
sizeof(adma_dual_desc_buf) * MLAN_MAX_EVT_BD;
|
|
}
|
|
#endif
|
|
PRINTM(MINFO, "Evt ring: allocating %d bytes\n",
|
|
pmadapter->pcard_pcie->evtbd_ring_size);
|
|
|
|
ret = pcb->moal_malloc_consistent(
|
|
pmadapter->pmoal_handle, pmadapter->pcard_pcie->evtbd_ring_size,
|
|
&pmadapter->pcard_pcie->evtbd_ring_vbase,
|
|
&pmadapter->pcard_pcie->evtbd_ring_pbase);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
|
|
__FUNCTION__);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
PRINTM(MINFO,
|
|
"Evt ring: - base: %p, pbase: %#x:%x,"
|
|
"len: %#x\n",
|
|
pmadapter->pcard_pcie->evtbd_ring_vbase,
|
|
(t_u32)((t_u64)pmadapter->pcard_pcie->evtbd_ring_pbase >> 32),
|
|
(t_u32)pmadapter->pcard_pcie->evtbd_ring_pbase,
|
|
pmadapter->pcard_pcie->evtbd_ring_size);
|
|
|
|
for (i = 0; i < MLAN_MAX_EVT_BD; i++) {
|
|
/* Allocate buffer here so that firmware can DMA data on it */
|
|
pmbuf = wlan_alloc_mlan_buffer(pmadapter, MAX_EVENT_SIZE,
|
|
MLAN_RX_HEADER_LEN,
|
|
MOAL_ALLOC_MLAN_BUFFER);
|
|
if (!pmbuf) {
|
|
PRINTM(MERROR,
|
|
"Event ring create : Unable to allocate mlan_buffer\n");
|
|
wlan_pcie_delete_evtbd_ring(pmadapter);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
pmadapter->pcard_pcie->evt_buf_list[i] = pmbuf;
|
|
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_map_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
&pmbuf->buf_pa, MAX_EVENT_SIZE,
|
|
PCI_DMA_FROMDEVICE)) {
|
|
PRINTM(MERROR,
|
|
"Event ring create : moal_map_memory failed\n");
|
|
wlan_pcie_delete_evtbd_ring(pmadapter);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
pevtbd_buf =
|
|
(mlan_pcie_evt_buf
|
|
*)(pmadapter->pcard_pcie
|
|
->evtbd_ring_vbase +
|
|
(sizeof(mlan_pcie_evt_buf) * i));
|
|
pmadapter->pcard_pcie->evtbd_ring[i] =
|
|
(t_void *)pevtbd_buf;
|
|
pevtbd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
pevtbd_buf->len =
|
|
wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
pevtbd_buf->flags = 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf
|
|
*)(pmadapter->pcard_pcie
|
|
->evtbd_ring_vbase +
|
|
(sizeof(adma_dual_desc_buf) * i));
|
|
pmadapter->pcard_pcie->evtbd_ring[i] =
|
|
(t_void *)padma_bd_buf;
|
|
padma_bd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
padma_bd_buf->len = wlan_cpu_to_le16(
|
|
ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE));
|
|
padma_bd_buf->flags = wlan_cpu_to_le16(
|
|
ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_DST_HOST);
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function frees event buffer descriptor ring
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_delete_evtbd_ring(mlan_adapter *pmadapter)
|
|
{
|
|
t_u32 i;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
mlan_pcie_evt_buf *pevtbd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
#endif
|
|
|
|
ENTER();
|
|
for (i = 0; i < MLAN_MAX_EVT_BD; i++) {
|
|
if (pmadapter->pcard_pcie->evt_buf_list[i]) {
|
|
pmbuf = pmadapter->pcard_pcie->evt_buf_list[i];
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa, MAX_EVENT_SIZE,
|
|
PCI_DMA_FROMDEVICE);
|
|
wlan_free_mlan_buffer(pmadapter, pmbuf);
|
|
}
|
|
|
|
pmadapter->pcard_pcie->evt_buf_list[i] = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
pevtbd_buf =
|
|
(mlan_pcie_evt_buf *)
|
|
pmadapter->pcard_pcie->evtbd_ring[i];
|
|
|
|
if (pevtbd_buf) {
|
|
pevtbd_buf->paddr = 0;
|
|
pevtbd_buf->len = 0;
|
|
pevtbd_buf->flags = 0;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf *)
|
|
pmadapter->pcard_pcie->evtbd_ring[i];
|
|
|
|
if (padma_bd_buf) {
|
|
padma_bd_buf->paddr = 0;
|
|
padma_bd_buf->len = 0;
|
|
padma_bd_buf->flags = 0;
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
}
|
|
}
|
|
#endif
|
|
pmadapter->pcard_pcie->evtbd_ring[i] = MNULL;
|
|
}
|
|
|
|
if (pmadapter->pcard_pcie->evtbd_ring_vbase)
|
|
pmadapter->callbacks.moal_mfree_consistent(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->evtbd_ring_size,
|
|
pmadapter->pcard_pcie->evtbd_ring_vbase,
|
|
pmadapter->pcard_pcie->evtbd_ring_pbase);
|
|
|
|
pmadapter->pcard_pcie->evtbd_rdptr = 0;
|
|
pmadapter->pcard_pcie->evtbd_wrptr = 0;
|
|
pmadapter->pcard_pcie->evtbd_ring_size = 0;
|
|
pmadapter->pcard_pcie->evtbd_ring_vbase = MNULL;
|
|
pmadapter->pcard_pcie->evtbd_ring_pbase = 0;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function allocates buffer for CMD and CMDRSP
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_alloc_cmdrsp_buf(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_buffer *pmbuf = MNULL;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
/** Virtual base address of command response */
|
|
t_u8 *cmdrsp_vbase;
|
|
/** Physical base address of command response */
|
|
t_u64 cmdrsp_pbase = 0;
|
|
|
|
ENTER();
|
|
|
|
/* Allocate memory for receiving command response data */
|
|
pmbuf = wlan_alloc_mlan_buffer(pmadapter, 0, 0, MOAL_MALLOC_BUFFER);
|
|
if (!pmbuf) {
|
|
PRINTM(MERROR,
|
|
"Command resp buffer create : Unable to allocate mlan_buffer\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
ret = pcb->moal_malloc_consistent(pmadapter->pmoal_handle,
|
|
MRVDRV_SIZE_OF_CMD_BUFFER,
|
|
&cmdrsp_vbase, &cmdrsp_pbase);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
|
|
__FUNCTION__);
|
|
/* free pmbuf */
|
|
wlan_free_mlan_buffer(pmadapter, pmbuf);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
pmbuf->buf_pa = cmdrsp_pbase;
|
|
pmbuf->pbuf = cmdrsp_vbase;
|
|
pmbuf->data_offset = 0;
|
|
pmbuf->data_len = MRVDRV_SIZE_OF_CMD_BUFFER;
|
|
pmbuf->total_pcie_buf_len = MRVDRV_SIZE_OF_CMD_BUFFER;
|
|
pmadapter->pcard_pcie->cmdrsp_buf = pmbuf;
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function frees CMD and CMDRSP buffer
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_delete_cmdrsp_buf(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_buffer *pmbuf = MNULL;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u8 *cmdrsp_vbase;
|
|
t_u64 cmdrsp_pbase;
|
|
ENTER();
|
|
|
|
if (!pmadapter) {
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (pmadapter->pcard_pcie->cmdrsp_buf) {
|
|
pmbuf = pmadapter->pcard_pcie->cmdrsp_buf;
|
|
cmdrsp_vbase = pmbuf->pbuf;
|
|
cmdrsp_pbase = pmbuf->buf_pa;
|
|
if (cmdrsp_vbase)
|
|
pmadapter->callbacks.moal_mfree_consistent(
|
|
pmadapter->pmoal_handle,
|
|
pmbuf->total_pcie_buf_len, cmdrsp_vbase,
|
|
cmdrsp_pbase);
|
|
wlan_free_mlan_buffer(pmadapter, pmbuf);
|
|
pmadapter->pcard_pcie->cmdrsp_buf = MNULL;
|
|
}
|
|
if (pmadapter->pcard_pcie->cmd_buf) {
|
|
pmbuf = pmadapter->pcard_pcie->cmd_buf;
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa, MRVDRV_SIZE_OF_CMD_BUFFER,
|
|
PCI_DMA_TODEVICE);
|
|
}
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
#define PCIE_TXBD_EMPTY(wrptr, rdptr, mask, rollover_ind) \
|
|
(((wrptr & mask) == (rdptr & mask)) && \
|
|
((wrptr & rollover_ind) == (rdptr & rollover_ind)))
|
|
|
|
/**
|
|
* @brief This function flushes the TX buffer descriptor ring
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_flush_txbd_ring(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
|
|
t_u32 txrx_rw_ptr_rollover_ind =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
|
|
ENTER();
|
|
|
|
if (!PCIE_TXBD_EMPTY(pmadapter->pcard_pcie->txbd_wrptr,
|
|
pmadapter->pcard_pcie->txbd_rdptr,
|
|
txrx_rw_ptr_mask, txrx_rw_ptr_rollover_ind)) {
|
|
pmadapter->pcard_pcie->txbd_flush = MTRUE;
|
|
/* write pointer already set at last send */
|
|
/* send dnld-rdy intr again, wait for completion */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_cpu_int_event,
|
|
CPU_INTR_DNLD_RDY)) {
|
|
PRINTM(MERROR,
|
|
"SEND DATA (FLUSH): failed to assert dnld-rdy interrupt.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief This function check the tx pending buffer
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param rdptr tx rdptr
|
|
*
|
|
* @return MTRUE/MFALSE;
|
|
*/
|
|
static t_u8 wlan_check_tx_pending_buffer(mlan_adapter *pmadapter, t_u32 rdptr)
|
|
{
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
|
|
t_u32 txrx_rw_ptr_rollover_ind =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
if (((pmadapter->pcard_pcie->txbd_rdptr & txrx_rw_ptr_mask) !=
|
|
(rdptr & txrx_rw_ptr_mask)) ||
|
|
((pmadapter->pcard_pcie->txbd_rdptr &
|
|
txrx_rw_ptr_rollover_ind) !=
|
|
(rdptr & txrx_rw_ptr_rollover_ind)))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
if ((pmadapter->pcard_pcie->txbd_rdptr &
|
|
ADMA_RW_PTR_WRAP_MASK) != (rdptr & ADMA_RW_PTR_WRAP_MASK))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
return MFALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief This function unmaps and frees downloaded data buffer
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_send_data_complete(mlan_adapter *pmadapter)
|
|
{
|
|
const t_u32 num_tx_buffs = pmadapter->pcard_pcie->txrx_bd_size;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_buffer *pmbuf;
|
|
t_u32 wrdoneidx;
|
|
t_u32 rdptr;
|
|
t_u32 unmap_count = 0;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
|
|
t_u32 txrx_rw_ptr_rollover_ind =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
mlan_pcie_data_buf *ptx_bd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
t_u32 wrptr;
|
|
#endif
|
|
|
|
ENTER();
|
|
|
|
/* Read the TX ring read pointer set by firmware */
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_txbd_rdptr,
|
|
&rdptr)) {
|
|
PRINTM(MERROR,
|
|
"SEND DATA COMP: failed to read REG_TXBD_RDPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
PRINTM(MINFO, "SEND DATA COMP: rdptr_prev=0x%x, rdptr=0x%x\n",
|
|
pmadapter->pcard_pcie->txbd_rdptr, rdptr);
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma)
|
|
rdptr = rdptr >> TXBD_RW_PTR_START;
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
wrptr = rdptr & 0xffff;
|
|
rdptr = rdptr >> ADMA_RPTR_START;
|
|
if (wrptr != pmadapter->pcard_pcie->txbd_wrptr)
|
|
PRINTM(MERROR, "wlan: Unexpected wrptr 0x%x 0x%x\n",
|
|
wrptr, pmadapter->pcard_pcie->txbd_wrptr);
|
|
}
|
|
#endif
|
|
|
|
/* free from previous txbd_rdptr to current txbd_rdptr */
|
|
while (wlan_check_tx_pending_buffer(pmadapter, rdptr)) {
|
|
wrdoneidx =
|
|
pmadapter->pcard_pcie->txbd_rdptr & (num_tx_buffs - 1);
|
|
pmbuf = pmadapter->pcard_pcie->tx_buf_list[wrdoneidx];
|
|
if (pmbuf) {
|
|
PRINTM(MDAT_D,
|
|
"SEND DATA COMP: Detach pmbuf %p at tx_ring[%d], pmadapter->txbd_rdptr=0x%x\n",
|
|
pmbuf, wrdoneidx,
|
|
pmadapter->pcard_pcie->txbd_rdptr);
|
|
ret = pcb->moal_unmap_memory(
|
|
pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset, pmbuf->buf_pa,
|
|
pmbuf->data_len, PCI_DMA_TODEVICE);
|
|
if (ret == MLAN_STATUS_FAILURE) {
|
|
PRINTM(MERROR, "%s: moal_unmap_memory failed\n",
|
|
__FUNCTION__);
|
|
break;
|
|
}
|
|
unmap_count++;
|
|
pmadapter->pcard_pcie->txbd_pending--;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (pmadapter->pcard_pcie->txbd_flush)
|
|
wlan_write_data_complete(pmadapter, pmbuf,
|
|
MLAN_STATUS_FAILURE);
|
|
else
|
|
#endif
|
|
wlan_write_data_complete(pmadapter, pmbuf,
|
|
MLAN_STATUS_SUCCESS);
|
|
}
|
|
|
|
pmadapter->pcard_pcie->tx_buf_list[wrdoneidx] = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
ptx_bd_buf = (mlan_pcie_data_buf *)pmadapter->pcard_pcie
|
|
->txbd_ring[wrdoneidx];
|
|
ptx_bd_buf->paddr = 0;
|
|
ptx_bd_buf->len = 0;
|
|
ptx_bd_buf->flags = 0;
|
|
ptx_bd_buf->frag_len = 0;
|
|
ptx_bd_buf->offset = 0;
|
|
pmadapter->pcard_pcie->txbd_rdptr++;
|
|
if ((pmadapter->pcard_pcie->txbd_rdptr &
|
|
txrx_rw_ptr_mask) == num_tx_buffs)
|
|
pmadapter->pcard_pcie->txbd_rdptr =
|
|
((pmadapter->pcard_pcie->txbd_rdptr &
|
|
txrx_rw_ptr_rollover_ind) ^
|
|
txrx_rw_ptr_rollover_ind);
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf *)pmadapter->pcard_pcie
|
|
->txbd_ring[wrdoneidx];
|
|
padma_bd_buf->paddr = 0;
|
|
padma_bd_buf->len = 0;
|
|
padma_bd_buf->flags = 0;
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
pmadapter->pcard_pcie->txbd_rdptr++;
|
|
pmadapter->pcard_pcie->txbd_rdptr &=
|
|
ADMA_RW_PTR_WRAP_MASK;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if (unmap_count)
|
|
pmadapter->data_sent = MFALSE;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (pmadapter->pcard_pcie->txbd_flush) {
|
|
if (PCIE_TXBD_EMPTY(pmadapter->pcard_pcie->txbd_wrptr,
|
|
pmadapter->pcard_pcie->txbd_rdptr,
|
|
txrx_rw_ptr_mask, txrx_rw_ptr_rollover_ind))
|
|
pmadapter->pcard_pcie->txbd_flush = MFALSE;
|
|
else
|
|
wlan_pcie_flush_txbd_ring(pmadapter);
|
|
}
|
|
#endif
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
#define PCIE_TXBD_NOT_FULL(wrptr, rdptr, mask, rollover_ind) \
|
|
(((wrptr & mask) != (rdptr & mask)) || \
|
|
((wrptr & rollover_ind) == (rdptr & rollover_ind)))
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
#define ADMA_TXBD_IS_FULL(wrptr, rdptr, mask, rollover_ind) \
|
|
(((wrptr & mask) == (rdptr & mask)) && \
|
|
((wrptr & rollover_ind) != (rdptr & rollover_ind)))
|
|
#endif
|
|
|
|
static t_u8 wlan_check_txbd_not_full(mlan_adapter *pmadapter)
|
|
{
|
|
t_u32 txrx_rw_ptr_mask;
|
|
t_u32 txrx_rw_ptr_rollover_ind;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
|
|
txrx_rw_ptr_rollover_ind =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
if (PCIE_TXBD_NOT_FULL(pmadapter->pcard_pcie->txbd_wrptr,
|
|
pmadapter->pcard_pcie->txbd_rdptr,
|
|
txrx_rw_ptr_mask,
|
|
txrx_rw_ptr_rollover_ind))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
txrx_rw_ptr_mask = pmadapter->pcard_pcie->txrx_bd_size - 1;
|
|
txrx_rw_ptr_rollover_ind = pmadapter->pcard_pcie->txrx_bd_size;
|
|
if (!ADMA_TXBD_IS_FULL(pmadapter->pcard_pcie->txbd_wrptr,
|
|
pmadapter->pcard_pcie->txbd_rdptr,
|
|
txrx_rw_ptr_mask,
|
|
txrx_rw_ptr_rollover_ind))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
return MFALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief This function downloads data to the card.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param type packet type
|
|
* @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
|
|
* PCIE header)
|
|
* @param tx_param A pointer to mlan_tx_param
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_send_data(mlan_adapter *pmadapter, t_u8 type,
|
|
mlan_buffer *pmbuf,
|
|
mlan_tx_param *tx_param)
|
|
{
|
|
t_u32 reg_txbd_wrptr = pmadapter->pcard_pcie->reg->reg_txbd_wrptr;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
|
|
t_u32 txrx_rw_ptr_rollover_ind =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
mlan_pcie_data_buf *ptx_bd_buf = MNULL;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf = MNULL;
|
|
#endif
|
|
const t_u32 num_tx_buffs = pmadapter->pcard_pcie->txrx_bd_size;
|
|
mlan_status ret = MLAN_STATUS_PENDING;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 rxbd_val = 0;
|
|
t_u32 wrindx;
|
|
t_u16 *tmp;
|
|
t_u8 *payload;
|
|
t_u32 wr_ptr_start = 0;
|
|
|
|
ENTER();
|
|
|
|
if (!pmbuf) {
|
|
PRINTM(MERROR, "%s() has no buffer", __FUNCTION__);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if (!(pmbuf->pbuf && pmbuf->data_len)) {
|
|
PRINTM(MERROR, "Invalid parameter <%p, %#x>\n", pmbuf->pbuf,
|
|
pmbuf->data_len);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
PRINTM(MINFO, "SEND DATA: <Rd: %#x, Wr: %#x>\n",
|
|
pmadapter->pcard_pcie->txbd_rdptr,
|
|
pmadapter->pcard_pcie->txbd_wrptr);
|
|
|
|
if (wlan_check_txbd_not_full(pmadapter)) {
|
|
pmadapter->data_sent = MTRUE;
|
|
|
|
payload = pmbuf->pbuf + pmbuf->data_offset;
|
|
tmp = (t_u16 *)&payload[0];
|
|
*tmp = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
tmp = (t_u16 *)&payload[2];
|
|
*tmp = wlan_cpu_to_le16(type);
|
|
|
|
/* Map pmbuf, and attach to tx ring */
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_map_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
&pmbuf->buf_pa, pmbuf->data_len,
|
|
PCI_DMA_TODEVICE)) {
|
|
PRINTM(MERROR,
|
|
"SEND DATA: failed to moal_map_memory\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
wrindx = pmadapter->pcard_pcie->txbd_wrptr & (num_tx_buffs - 1);
|
|
PRINTM(MDAT_D,
|
|
"SEND DATA: Attach pmbuf %p at tx_ring[%d], txbd_wrptr=0x%x\n",
|
|
pmbuf, wrindx, pmadapter->pcard_pcie->txbd_wrptr);
|
|
pmadapter->pcard_pcie->tx_buf_list[wrindx] = pmbuf;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
wr_ptr_start = TXBD_RW_PTR_START;
|
|
ptx_bd_buf = (mlan_pcie_data_buf *)pmadapter->pcard_pcie
|
|
->txbd_ring[wrindx];
|
|
ptx_bd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
ptx_bd_buf->len =
|
|
wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
ptx_bd_buf->flags = wlan_cpu_to_le16(MLAN_BD_FLAG_SOP |
|
|
MLAN_BD_FLAG_EOP);
|
|
ptx_bd_buf->frag_len =
|
|
wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
ptx_bd_buf->offset = 0;
|
|
pmadapter->pcard_pcie->last_tx_pkt_size[wrindx] =
|
|
pmbuf->data_len;
|
|
pmadapter->pcard_pcie->txbd_wrptr++;
|
|
if ((pmadapter->pcard_pcie->txbd_wrptr &
|
|
txrx_rw_ptr_mask) == num_tx_buffs)
|
|
pmadapter->pcard_pcie->txbd_wrptr =
|
|
((pmadapter->pcard_pcie->txbd_wrptr &
|
|
txrx_rw_ptr_rollover_ind) ^
|
|
txrx_rw_ptr_rollover_ind);
|
|
rxbd_val = pmadapter->pcard_pcie->rxbd_wrptr &
|
|
pmadapter->pcard_pcie->reg
|
|
->txrx_rw_ptr_wrap_mask;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
wr_ptr_start = ADMA_WPTR_START;
|
|
padma_bd_buf = (adma_dual_desc_buf *)pmadapter
|
|
->pcard_pcie->txbd_ring[wrindx];
|
|
padma_bd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
padma_bd_buf->len =
|
|
ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE);
|
|
padma_bd_buf->flags = wlan_cpu_to_le16(
|
|
ADMA_BD_FLAG_SOP | ADMA_BD_FLAG_EOP |
|
|
ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_SRC_HOST);
|
|
if (padma_bd_buf->len < ADMA_MIN_PKT_SIZE)
|
|
padma_bd_buf->len = ADMA_MIN_PKT_SIZE;
|
|
padma_bd_buf->len = wlan_cpu_to_le16(padma_bd_buf->len);
|
|
padma_bd_buf->pkt_size = padma_bd_buf->len;
|
|
pmadapter->pcard_pcie->last_tx_pkt_size[wrindx] =
|
|
pmbuf->data_len;
|
|
pmadapter->pcard_pcie->txbd_wrptr++;
|
|
pmadapter->pcard_pcie->txbd_wrptr &=
|
|
ADMA_RW_PTR_WRAP_MASK;
|
|
}
|
|
#endif
|
|
pmadapter->pcard_pcie->txbd_pending++;
|
|
PRINTM(MINFO, "REG_TXBD_WRPT(0x%x) = 0x%x\n", reg_txbd_wrptr,
|
|
((pmadapter->pcard_pcie->txbd_wrptr << wr_ptr_start) |
|
|
rxbd_val));
|
|
/* Write the TX ring write pointer in to REG_TXBD_WRPTR */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle, reg_txbd_wrptr,
|
|
(pmadapter->pcard_pcie->txbd_wrptr
|
|
<< wr_ptr_start) |
|
|
rxbd_val)) {
|
|
PRINTM(MERROR,
|
|
"SEND DATA: failed to write REG_TXBD_WRPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done_unmap;
|
|
}
|
|
PRINTM(MINFO, "SEND DATA: Updated <Rd: %#x, Wr: %#x>\n",
|
|
pmadapter->pcard_pcie->txbd_rdptr,
|
|
pmadapter->pcard_pcie->txbd_wrptr);
|
|
|
|
if (wlan_check_txbd_not_full(pmadapter))
|
|
pmadapter->data_sent = MFALSE;
|
|
else
|
|
wlan_pcie_send_data_complete(pmadapter);
|
|
if (pmadapter->data_sent)
|
|
pmadapter->data_sent_cnt++;
|
|
|
|
PRINTM(MINFO, "Sent packet to firmware successfully\n");
|
|
} else {
|
|
PRINTM(MERROR,
|
|
"TX Ring full, can't send anymore packets to firmware\n");
|
|
PRINTM(MINFO, "SEND DATA (FULL!): <Rd: %#x, Wr: %#x>\n",
|
|
pmadapter->pcard_pcie->txbd_rdptr,
|
|
pmadapter->pcard_pcie->txbd_wrptr);
|
|
pmadapter->data_sent = MTRUE;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
/* Send the TX ready interrupt */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_cpu_int_event,
|
|
CPU_INTR_DNLD_RDY))
|
|
PRINTM(MERROR,
|
|
"SEND DATA (FULL): failed to assert dnld-rdy interrupt\n");
|
|
}
|
|
#endif
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
|
|
done_unmap:
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_unmap_memory(
|
|
pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa, pmbuf->data_len, PCI_DMA_TODEVICE)) {
|
|
PRINTM(MERROR, "SEND DATA: failed to moal_unmap_memory\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
pmadapter->pcard_pcie->txbd_pending--;
|
|
pmadapter->pcard_pcie->tx_buf_list[wrindx] = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma && ptx_bd_buf) {
|
|
ptx_bd_buf->paddr = 0;
|
|
ptx_bd_buf->len = 0;
|
|
ptx_bd_buf->flags = 0;
|
|
ptx_bd_buf->frag_len = 0;
|
|
ptx_bd_buf->offset = 0;
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma && padma_bd_buf) {
|
|
padma_bd_buf->paddr = 0;
|
|
padma_bd_buf->len = 0;
|
|
padma_bd_buf->flags = 0;
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
}
|
|
#endif
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function check the rx pending buffer
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param rdptr rx rdptr
|
|
*
|
|
* @return MTRUE/MFALSE;
|
|
*/
|
|
static t_u8 wlan_check_rx_pending_buffer(mlan_adapter *pmadapter, t_u32 rdptr)
|
|
{
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
|
|
t_u32 txrx_rw_ptr_rollover_ind =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
if (((rdptr & txrx_rw_ptr_mask) !=
|
|
(pmadapter->pcard_pcie->rxbd_rdptr & txrx_rw_ptr_mask)) ||
|
|
((rdptr & txrx_rw_ptr_rollover_ind) !=
|
|
(pmadapter->pcard_pcie->rxbd_rdptr &
|
|
txrx_rw_ptr_rollover_ind)))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
if ((pmadapter->pcard_pcie->rxbd_rdptr &
|
|
ADMA_RW_PTR_WRAP_MASK) != (rdptr & ADMA_RW_PTR_WRAP_MASK))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
return MFALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief This function check if the rx pending buffer is full
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param rdptr rx rdptr
|
|
* @param rxbd_rdptr rxbd_rdptr
|
|
*
|
|
* @return MTRUE/MFALSE;
|
|
*/
|
|
static t_u8 wlan_is_rx_pending_full(mlan_adapter *pmadapter, t_u32 rdptr)
|
|
{
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
|
|
t_u32 txrx_rw_ptr_rollover_ind =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
PRINTM(MDATA,
|
|
"local wrptr: 0x%x(0x%x) -> reg rdptr: 0x%x(0x%x)\n",
|
|
(pmadapter->pcard_pcie->rxbd_wrptr & txrx_rw_ptr_mask),
|
|
(pmadapter->pcard_pcie->rxbd_wrptr &
|
|
txrx_rw_ptr_rollover_ind),
|
|
(rdptr & txrx_rw_ptr_mask),
|
|
(rdptr & txrx_rw_ptr_rollover_ind));
|
|
if (((rdptr & txrx_rw_ptr_mask) ==
|
|
(pmadapter->pcard_pcie->rxbd_wrptr & txrx_rw_ptr_mask)) &&
|
|
((rdptr & txrx_rw_ptr_rollover_ind) ==
|
|
(pmadapter->pcard_pcie->rxbd_wrptr &
|
|
txrx_rw_ptr_rollover_ind)))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
PRINTM(MDATA, "local wrptr: 0x%x -> reg rdptr: 0x%x\n",
|
|
(pmadapter->pcard_pcie->rxbd_wrptr &
|
|
ADMA_RW_PTR_WRAP_MASK),
|
|
(rdptr & ADMA_RW_PTR_WRAP_MASK));
|
|
if ((rdptr & ADMA_RW_PTR_WRAP_MASK) ==
|
|
(pmadapter->pcard_pcie->rxbd_wrptr & ADMA_RW_PTR_WRAP_MASK))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
return MFALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles received buffer ring and
|
|
* dispatches packets to upper
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_process_recv_data(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 rdptr, rd_index;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
t_u32 txbd_val = 0;
|
|
t_u16 rx_len, rx_type;
|
|
const t_u32 num_rx_buffs = pmadapter->pcard_pcie->txrx_bd_size;
|
|
t_u32 reg_rxbd_rdptr = pmadapter->pcard_pcie->reg->reg_rxbd_rdptr;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
t_u32 txrx_rw_ptr_mask = pmadapter->pcard_pcie->reg->txrx_rw_ptr_mask;
|
|
t_u32 txrx_rw_ptr_rollover_ind =
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_rollover_ind;
|
|
mlan_pcie_data_buf *prxbd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
#endif
|
|
t_u32 in_ts_sec, in_ts_usec;
|
|
|
|
ENTER();
|
|
|
|
/* Read the RX ring Read pointer set by firmware */
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle, reg_rxbd_rdptr,
|
|
&rdptr)) {
|
|
PRINTM(MERROR, "RECV DATA: failed to read REG_RXBD_RDPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma)
|
|
rdptr = rdptr >> ADMA_RPTR_START;
|
|
#endif
|
|
|
|
if (pmadapter->tp_state_on &&
|
|
wlan_is_rx_pending_full(pmadapter, rdptr)) {
|
|
PRINTM(MDATA, "RX FULL!\n");
|
|
pmadapter->callbacks.moal_tp_accounting_rx_param(
|
|
pmadapter->pmoal_handle, 6, 0);
|
|
}
|
|
while (wlan_check_rx_pending_buffer(pmadapter, rdptr)) {
|
|
/* detach pmbuf (with data) from Rx Ring */
|
|
rd_index =
|
|
pmadapter->pcard_pcie->rxbd_rdptr & (num_rx_buffs - 1);
|
|
if (rd_index >
|
|
(t_u32)(pmadapter->pcard_pcie->txrx_bd_size - 1)) {
|
|
PRINTM(MERROR, "RECV DATA: Invalid Rx buffer index.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
pmbuf = pmadapter->pcard_pcie->rx_buf_list[rd_index];
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa, MLAN_RX_DATA_BUF_SIZE,
|
|
PCI_DMA_FROMDEVICE)) {
|
|
PRINTM(MERROR,
|
|
"RECV DATA: moal_unmap_memory failed.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
pmadapter->pcard_pcie->rx_buf_list[rd_index] = MNULL;
|
|
PRINTM(MDAT_D,
|
|
"RECV DATA: Detach pmbuf %p at rx_ring[%d], pmadapter->rxbd_rdptr=0x%x\n",
|
|
pmbuf, rd_index, pmadapter->pcard_pcie->rxbd_rdptr);
|
|
|
|
/* Get data length from interface header -
|
|
first 2 bytes are len, second 2 bytes are type */
|
|
rx_len = *((t_u16 *)(pmbuf->pbuf + pmbuf->data_offset));
|
|
rx_len = wlan_le16_to_cpu(rx_len);
|
|
rx_type = *((t_u16 *)(pmbuf->pbuf + pmbuf->data_offset + 2));
|
|
rx_type = wlan_le16_to_cpu(rx_type);
|
|
|
|
PRINTM(MINFO,
|
|
"RECV DATA: <Wr: %#x, Rd: %#x>, Len=%d rx_type=%d\n",
|
|
pmadapter->pcard_pcie->rxbd_wrptr, rdptr, rx_len,
|
|
rx_type);
|
|
|
|
if (rx_len <= MLAN_RX_DATA_BUF_SIZE) {
|
|
/* send buffer to host (which will free it) */
|
|
pmbuf->data_len = rx_len - PCIE_INTF_HEADER_LEN;
|
|
pmbuf->data_offset += PCIE_INTF_HEADER_LEN;
|
|
// rx_trace 5
|
|
if (pmadapter->tp_state_on) {
|
|
pmadapter->callbacks.moal_tp_accounting(
|
|
pmadapter->pmoal_handle, pmbuf,
|
|
5 /*RX_DROP_P1*/);
|
|
pcb->moal_get_system_time(
|
|
pmadapter->pmoal_handle, &in_ts_sec,
|
|
&in_ts_usec);
|
|
pmbuf->in_ts_sec = in_ts_sec;
|
|
pmbuf->in_ts_usec = in_ts_usec;
|
|
}
|
|
if (pmadapter->tp_state_drop_point ==
|
|
5 /*RX_DROP_P1*/) {
|
|
pmadapter->ops.data_complete(pmadapter, pmbuf,
|
|
ret);
|
|
} else {
|
|
PRINTM(MINFO,
|
|
"RECV DATA: Received packet from FW successfully\n");
|
|
pmadapter->callbacks.moal_spin_lock(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->rx_data_queue.plock);
|
|
util_enqueue_list_tail(
|
|
pmadapter->pmoal_handle,
|
|
&pmadapter->rx_data_queue,
|
|
(pmlan_linked_list)pmbuf, MNULL, MNULL);
|
|
pmadapter->rx_pkts_queued++;
|
|
if (pmadapter->tp_state_on)
|
|
pmadapter->callbacks
|
|
.moal_tp_accounting_rx_param(
|
|
pmadapter->pmoal_handle,
|
|
1,
|
|
pmadapter
|
|
->rx_pkts_queued);
|
|
pmadapter->callbacks.moal_spin_unlock(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->rx_data_queue.plock);
|
|
|
|
pmadapter->data_received = MTRUE;
|
|
}
|
|
/* Create new buffer and attach it to Rx Ring */
|
|
pmbuf = wlan_alloc_mlan_buffer(pmadapter,
|
|
MLAN_RX_DATA_BUF_SIZE,
|
|
MLAN_RX_HEADER_LEN,
|
|
MOAL_ALLOC_MLAN_BUFFER);
|
|
if (!pmbuf) {
|
|
PRINTM(MERROR,
|
|
"RECV DATA: Unable to allocate mlan_buffer\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
} else {
|
|
/* Queue the mlan_buffer again */
|
|
PRINTM(MERROR, "PCIE: Drop invalid packet, length=%d",
|
|
rx_len);
|
|
}
|
|
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_map_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
&pmbuf->buf_pa, MLAN_RX_DATA_BUF_SIZE,
|
|
PCI_DMA_FROMDEVICE)) {
|
|
PRINTM(MERROR, "RECV DATA: moal_map_memory failed\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
PRINTM(MDAT_D,
|
|
"RECV DATA: Attach new pmbuf %p at rx_ring[%d]\n", pmbuf,
|
|
rd_index);
|
|
pmadapter->pcard_pcie->rx_buf_list[rd_index] = pmbuf;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
prxbd_buf = (mlan_pcie_data_buf *)pmadapter->pcard_pcie
|
|
->rxbd_ring[rd_index];
|
|
prxbd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
prxbd_buf->len =
|
|
wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
prxbd_buf->flags = wlan_cpu_to_le16(MLAN_BD_FLAG_SOP |
|
|
MLAN_BD_FLAG_EOP);
|
|
prxbd_buf->offset = 0;
|
|
prxbd_buf->frag_len =
|
|
wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
|
|
/* update rxbd's rdptrs */
|
|
if ((++pmadapter->pcard_pcie->rxbd_rdptr &
|
|
txrx_rw_ptr_mask) ==
|
|
pmadapter->pcard_pcie->txrx_bd_size) {
|
|
pmadapter->pcard_pcie->rxbd_rdptr =
|
|
((pmadapter->pcard_pcie->rxbd_rdptr &
|
|
txrx_rw_ptr_rollover_ind) ^
|
|
txrx_rw_ptr_rollover_ind);
|
|
}
|
|
|
|
/* update rxbd's wrptrs */
|
|
if ((++pmadapter->pcard_pcie->rxbd_wrptr &
|
|
txrx_rw_ptr_mask) ==
|
|
pmadapter->pcard_pcie->txrx_bd_size) {
|
|
pmadapter->pcard_pcie->rxbd_wrptr =
|
|
((pmadapter->pcard_pcie->rxbd_wrptr &
|
|
txrx_rw_ptr_rollover_ind) ^
|
|
txrx_rw_ptr_rollover_ind);
|
|
}
|
|
txbd_val = pmadapter->pcard_pcie->txbd_wrptr &
|
|
pmadapter->pcard_pcie->reg
|
|
->txrx_rw_ptr_wrap_mask;
|
|
txbd_val = txbd_val << TXBD_RW_PTR_START;
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf *)pmadapter->pcard_pcie
|
|
->rxbd_ring[rd_index];
|
|
padma_bd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
padma_bd_buf->len = wlan_cpu_to_le16(
|
|
ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE));
|
|
padma_bd_buf->flags = wlan_cpu_to_le16(
|
|
ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_DST_HOST);
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
pmadapter->pcard_pcie->rxbd_rdptr++;
|
|
pmadapter->pcard_pcie->rxbd_wrptr++;
|
|
pmadapter->pcard_pcie->rxbd_rdptr &=
|
|
ADMA_RW_PTR_WRAP_MASK;
|
|
pmadapter->pcard_pcie->rxbd_wrptr &=
|
|
ADMA_RW_PTR_WRAP_MASK;
|
|
}
|
|
#endif
|
|
PRINTM(MINFO, "RECV DATA: Updated <Wr: %#x, Rd: %#x>\n",
|
|
pmadapter->pcard_pcie->rxbd_wrptr, rdptr);
|
|
|
|
/* Write the RX ring write pointer in to REG_RXBD_WRPTR */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_rxbd_wrptr,
|
|
pmadapter->pcard_pcie->rxbd_wrptr | txbd_val)) {
|
|
PRINTM(MERROR,
|
|
"RECV DATA: failed to write REG_RXBD_WRPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Read the RX ring read pointer set by firmware */
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle, reg_rxbd_rdptr,
|
|
&rdptr)) {
|
|
PRINTM(MERROR,
|
|
"RECV DATA: failed to read REG_RXBD_RDPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma)
|
|
rdptr = rdptr >> ADMA_RPTR_START;
|
|
#endif
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function downloads command to the card.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
|
|
* PCIE header)
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_send_cmd(mlan_adapter *pmadapter,
|
|
mlan_buffer *pmbuf)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_PENDING;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u8 *payload = MNULL;
|
|
|
|
ENTER();
|
|
if (!(pmadapter && pmbuf)) {
|
|
PRINTM(MERROR, "%s() has no buffer", __FUNCTION__);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
if (!(pmbuf->pbuf && pmbuf->data_len)) {
|
|
PRINTM(MERROR, "Invalid parameter <%p, %#x>\n", pmbuf->pbuf,
|
|
pmbuf->data_len);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Make sure a command response buffer is available */
|
|
if (!pmadapter->pcard_pcie->cmdrsp_buf) {
|
|
PRINTM(MERROR,
|
|
"No response buffer available, send command failed\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
pmadapter->cmd_sent = MTRUE;
|
|
payload = pmbuf->pbuf + pmbuf->data_offset;
|
|
*(t_u16 *)&payload[0] = wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
*(t_u16 *)&payload[2] = wlan_cpu_to_le16(MLAN_TYPE_CMD);
|
|
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_map_memory(
|
|
pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
|
|
&pmbuf->buf_pa, MLAN_RX_CMD_BUF_SIZE, PCI_DMA_TODEVICE)) {
|
|
PRINTM(MERROR, "Command buffer : moal_map_memory failed\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
pmadapter->pcard_pcie->cmd_buf = pmbuf;
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
/* To send a command, the driver will:
|
|
1. Write the 64bit physical address of the data buffer to
|
|
SCRATCH1 + SCRATCH0
|
|
2. Ring the door bell (i.e. set the door bell interrupt)
|
|
|
|
In response to door bell interrupt, the firmware will
|
|
perform the DMA of the command packet (first header to obtain
|
|
the total length and then rest of the command).
|
|
*/
|
|
|
|
if (pmadapter->pcard_pcie->cmdrsp_buf) {
|
|
/* Write the lower 32bits of the cmdrsp buffer physical
|
|
address */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
REG_CMDRSP_ADDR_LO,
|
|
(t_u32)pmadapter->pcard_pcie
|
|
->cmdrsp_buf->buf_pa)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write download command to boot code.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
/* Write the upper 32bits of the cmdrsp buffer physical
|
|
address */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle, REG_CMDRSP_ADDR_HI,
|
|
(t_u32)((t_u64)pmadapter->pcard_pcie
|
|
->cmdrsp_buf->buf_pa >>
|
|
32))) {
|
|
PRINTM(MERROR,
|
|
"Failed to write download command to boot code.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
/* Write the lower 32bits of the physical address to
|
|
* REG_CMD_ADDR_LO */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle, REG_CMD_ADDR_LO,
|
|
(t_u32)pmadapter->pcard_pcie->cmd_buf->buf_pa)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write download command to boot code.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
/* Write the upper 32bits of the physical address to
|
|
* REG_CMD_ADDR_HI */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
REG_CMD_ADDR_HI,
|
|
(t_u32)((t_u64)pmadapter->pcard_pcie
|
|
->cmd_buf->buf_pa >>
|
|
32))) {
|
|
PRINTM(MERROR,
|
|
"Failed to write download command to boot code.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Write the command length to REG_CMD_SIZE */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle, REG_CMD_SIZE,
|
|
pmadapter->pcard_pcie->cmd_buf->data_len)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write command length to REG_CMD_SIZE\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Ring the door bell */
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_cpu_int_event,
|
|
CPU_INTR_DOOR_BELL)) {
|
|
PRINTM(MERROR,
|
|
"Failed to assert door-bell interrupt.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
/* To send a command, the driver will:
|
|
1. driver prepare the cmdrep buffer for adma
|
|
2. driver programs dma_mode field to direct programming mode
|
|
and programs dma_size field to define DMA data transfer size.
|
|
3. driver programs src_base_addr register to define source
|
|
location of DMA data
|
|
4. driver sets src_wptr to 1 to initiate DMA operation
|
|
*/
|
|
wlan_init_adma(pmadapter, ADMA_CMDRESP,
|
|
pmadapter->pcard_pcie->cmdrsp_buf->buf_pa,
|
|
MRVDRV_SIZE_OF_CMD_BUFFER, MFALSE);
|
|
wlan_init_adma(pmadapter, ADMA_CMD,
|
|
pmadapter->pcard_pcie->cmd_buf->buf_pa,
|
|
pmadapter->pcard_pcie->cmd_buf->data_len,
|
|
MFALSE);
|
|
}
|
|
#endif
|
|
done:
|
|
if ((ret == MLAN_STATUS_FAILURE) && pmadapter)
|
|
pmadapter->cmd_sent = MFALSE;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
#define MLAN_SLEEP_COOKIE_DEF 0xBEEFBEEF
|
|
#define MAX_DELAY_LOOP_COUNT 100
|
|
|
|
static void mlan_delay_for_sleep_cookie(mlan_adapter *pmadapter,
|
|
t_u32 max_delay_loop_cnt)
|
|
{
|
|
t_u8 *buffer;
|
|
t_u32 sleep_cookie = 0;
|
|
t_u32 count = 0;
|
|
pmlan_buffer pmbuf = pmadapter->pcard_pcie->cmdrsp_buf;
|
|
|
|
for (count = 0; count < max_delay_loop_cnt; count++) {
|
|
buffer = pmbuf->pbuf;
|
|
sleep_cookie = *(t_u32 *)buffer;
|
|
|
|
if (sleep_cookie == MLAN_SLEEP_COOKIE_DEF) {
|
|
PRINTM(MINFO, "sleep cookie FOUND at count = %d!!\n",
|
|
count);
|
|
break;
|
|
}
|
|
wlan_udelay(pmadapter, 20);
|
|
}
|
|
|
|
if (count >= max_delay_loop_cnt)
|
|
PRINTM(MINFO, "sleep cookie not found!!\n");
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief This function handles command complete interrupt
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_process_cmd_resp(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
pmlan_buffer pmbuf = pmadapter->pcard_pcie->cmdrsp_buf;
|
|
pmlan_buffer cmd_buf = MNULL;
|
|
t_u16 resp_len = 0;
|
|
|
|
ENTER();
|
|
|
|
PRINTM(MINFO, "Rx CMD Response\n");
|
|
|
|
if (pmbuf == MNULL) {
|
|
PRINTM(MMSG, "Rx CMD response pmbuf is null\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
/* Get data length from interface header -
|
|
first 2 bytes are len, second 2 bytes are type */
|
|
resp_len = *((t_u16 *)(pmbuf->pbuf + pmbuf->data_offset));
|
|
|
|
pmadapter->upld_len = wlan_le16_to_cpu(resp_len);
|
|
pmadapter->upld_len -= PCIE_INTF_HEADER_LEN;
|
|
cmd_buf = pmadapter->pcard_pcie->cmd_buf;
|
|
if (cmd_buf) {
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
cmd_buf->pbuf + cmd_buf->data_offset,
|
|
cmd_buf->buf_pa, WLAN_UPLD_SIZE,
|
|
PCI_DMA_TODEVICE);
|
|
pmadapter->pcard_pcie->cmd_buf = MNULL;
|
|
}
|
|
if (!pmadapter->curr_cmd) {
|
|
if (pmadapter->ps_state == PS_STATE_SLEEP_CFM) {
|
|
wlan_process_sleep_confirm_resp(
|
|
pmadapter,
|
|
pmbuf->pbuf + pmbuf->data_offset +
|
|
PCIE_INTF_HEADER_LEN,
|
|
pmadapter->upld_len);
|
|
/* We are sending sleep confirm done interrupt in the
|
|
* middle of sleep handshake. There is a corner case
|
|
* when Tx done interrupt is received from firmware
|
|
* during sleep handshake due to which host and firmware
|
|
* power states go out of sync causing Tx data timeout
|
|
* problem. Hence sleep confirm done interrupt is sent
|
|
* at the end of sleep handshake to fix the problem
|
|
*
|
|
* Host could be reading the interrupt during polling
|
|
* (while loop) or to address a FW interrupt. In either
|
|
* case, after clearing the interrupt driver needs to
|
|
* send a sleep confirm event at the end of processing
|
|
* command response right here. This marks the end of
|
|
* the sleep handshake with firmware.
|
|
*/
|
|
wlan_pcie_enable_host_int_mask(pmadapter);
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_cpu_int_event,
|
|
CPU_INTR_SLEEP_CFM_DONE)) {
|
|
PRINTM(MERROR, "Write register failed\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
mlan_delay_for_sleep_cookie(pmadapter,
|
|
MAX_DELAY_LOOP_COUNT);
|
|
#endif
|
|
}
|
|
memcpy_ext(pmadapter, pmadapter->upld_buf,
|
|
pmbuf->pbuf + pmbuf->data_offset +
|
|
PCIE_INTF_HEADER_LEN,
|
|
pmadapter->upld_len, MRVDRV_SIZE_OF_CMD_BUFFER);
|
|
|
|
} else {
|
|
pmadapter->cmd_resp_received = MTRUE;
|
|
pmbuf->data_len = pmadapter->upld_len;
|
|
pmbuf->data_offset += PCIE_INTF_HEADER_LEN;
|
|
pmadapter->curr_cmd->respbuf = pmbuf;
|
|
|
|
/* Take the pointer and set it to CMD node and will
|
|
return in the response complete callback */
|
|
pmadapter->pcard_pcie->cmdrsp_buf = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
/* Clear the cmd-rsp buffer address in scratch
|
|
registers. This will prevent firmware from writing to
|
|
the same response buffer again. */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
REG_CMDRSP_ADDR_LO, 0)) {
|
|
PRINTM(MERROR,
|
|
"Rx CMD: failed to clear cmd_rsp address.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
/* Write the upper 32bits of the cmdrsp buffer physical
|
|
address */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
REG_CMDRSP_ADDR_HI, 0)) {
|
|
PRINTM(MERROR,
|
|
"Rx CMD: failed to clear cmd_rsp address.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
/* Clear the cmd-rsp buffer address in adma registers.
|
|
This will prevent firmware from writing to the same
|
|
response buffer again. */
|
|
if (wlan_init_adma(pmadapter, ADMA_CMDRESP, 0, 0,
|
|
MFALSE)) {
|
|
PRINTM(MERROR,
|
|
"Rx CMD: failed to clear cmd_rsp address.\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles command response completion
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pmbuf A pointer to mlan_buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_cmdrsp_complete(mlan_adapter *pmadapter,
|
|
mlan_buffer *pmbuf,
|
|
mlan_status status)
|
|
{
|
|
ENTER();
|
|
|
|
/*return the cmd response pmbuf*/
|
|
if (pmbuf) {
|
|
pmbuf->data_len = MRVDRV_SIZE_OF_CMD_BUFFER;
|
|
pmbuf->data_offset -= PCIE_INTF_HEADER_LEN;
|
|
pmadapter->pcard_pcie->cmdrsp_buf = pmbuf;
|
|
}
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function check pending evt buffer
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param rdptr evt rdptr
|
|
*
|
|
* @return MTRUE/MFALSE;
|
|
*/
|
|
static t_u8 wlan_check_evt_buffer(mlan_adapter *pmadapter, t_u32 rdptr)
|
|
{
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
if (((rdptr & EVT_RW_PTR_MASK) !=
|
|
(pmadapter->pcard_pcie->evtbd_rdptr & EVT_RW_PTR_MASK)) ||
|
|
((rdptr & EVT_RW_PTR_ROLLOVER_IND) !=
|
|
(pmadapter->pcard_pcie->evtbd_rdptr &
|
|
EVT_RW_PTR_ROLLOVER_IND)))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
if ((pmadapter->pcard_pcie->evtbd_rdptr &
|
|
ADMA_RW_PTR_WRAP_MASK) != (rdptr & ADMA_RW_PTR_WRAP_MASK))
|
|
return MTRUE;
|
|
else
|
|
return MFALSE;
|
|
}
|
|
#endif
|
|
return MFALSE;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles FW event ready interrupt
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_process_event_ready(mlan_adapter *pmadapter)
|
|
{
|
|
t_u32 rd_index =
|
|
pmadapter->pcard_pcie->evtbd_rdptr & (MLAN_MAX_EVT_BD - 1);
|
|
t_u32 rdptr, event;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
mlan_pcie_evt_buf *pevtbd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
#endif
|
|
ENTER();
|
|
|
|
if (pmadapter->event_received) {
|
|
PRINTM(MINFO, "Event being processed, do not "
|
|
"process this interrupt just yet\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
if (rd_index >= MLAN_MAX_EVT_BD) {
|
|
PRINTM(MINFO, "Invalid rd_index...\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
/* Read the event ring read pointer set by firmware */
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_evtbd_rdptr,
|
|
&rdptr)) {
|
|
PRINTM(MERROR, "EvtRdy: failed to read REG_EVTBD_RDPTR\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma)
|
|
rdptr = rdptr >> ADMA_RPTR_START;
|
|
#endif
|
|
PRINTM(MINFO, "EvtRdy: Initial <Wr: 0x%x, Rd: 0x%x>\n",
|
|
pmadapter->pcard_pcie->evtbd_wrptr, rdptr);
|
|
if (wlan_check_evt_buffer(pmadapter, rdptr)) {
|
|
mlan_buffer *pmbuf_evt;
|
|
t_u16 evt_len;
|
|
|
|
PRINTM(MINFO, "EvtRdy: Read Index: %d\n", rd_index);
|
|
pmbuf_evt = pmadapter->pcard_pcie->evt_buf_list[rd_index];
|
|
|
|
/*unmap the pmbuf for CPU Access*/
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
pmbuf_evt->pbuf + pmbuf_evt->data_offset,
|
|
pmbuf_evt->buf_pa, MAX_EVENT_SIZE,
|
|
PCI_DMA_FROMDEVICE);
|
|
|
|
/* Take the pointer and set it to event pointer in adapter
|
|
and will return back after event handling callback */
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
pevtbd_buf = (mlan_pcie_evt_buf *)pmadapter->pcard_pcie
|
|
->evtbd_ring[rd_index];
|
|
pevtbd_buf->paddr = 0;
|
|
pevtbd_buf->len = 0;
|
|
pevtbd_buf->flags = 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf =
|
|
(adma_dual_desc_buf *)pmadapter->pcard_pcie
|
|
->evtbd_ring[rd_index];
|
|
padma_bd_buf->paddr = 0;
|
|
padma_bd_buf->len = 0;
|
|
padma_bd_buf->flags = 0;
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
}
|
|
#endif
|
|
pmadapter->pcard_pcie->evt_buf_list[rd_index] = MNULL;
|
|
|
|
event = *((t_u32 *)&pmbuf_evt->pbuf[pmbuf_evt->data_offset +
|
|
PCIE_INTF_HEADER_LEN]);
|
|
pmadapter->event_cause = wlan_le32_to_cpu(event);
|
|
/* The first 4bytes will be the event transfer header
|
|
len is 2 bytes followed by type which is 2 bytes */
|
|
evt_len = *((t_u16 *)&pmbuf_evt->pbuf[pmbuf_evt->data_offset]);
|
|
evt_len = wlan_le16_to_cpu(evt_len);
|
|
|
|
if ((evt_len > 0) && (evt_len > MLAN_EVENT_HEADER_LEN) &&
|
|
(evt_len - MLAN_EVENT_HEADER_LEN < MAX_EVENT_SIZE))
|
|
memcpy_ext(pmadapter, pmadapter->event_body,
|
|
pmbuf_evt->pbuf + pmbuf_evt->data_offset +
|
|
MLAN_EVENT_HEADER_LEN,
|
|
evt_len - MLAN_EVENT_HEADER_LEN,
|
|
sizeof(pmadapter->event_body));
|
|
|
|
pmbuf_evt->data_offset += PCIE_INTF_HEADER_LEN;
|
|
pmbuf_evt->data_len = evt_len - PCIE_INTF_HEADER_LEN;
|
|
PRINTM(MINFO, "Event length: %d\n", pmbuf_evt->data_len);
|
|
|
|
pmadapter->event_received = MTRUE;
|
|
pmadapter->pmlan_buffer_event = pmbuf_evt;
|
|
pmadapter->pcard_pcie->evtbd_rdptr++;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
if ((pmadapter->pcard_pcie->evtbd_rdptr &
|
|
EVT_RW_PTR_MASK) == MLAN_MAX_EVT_BD) {
|
|
pmadapter->pcard_pcie->evtbd_rdptr =
|
|
((pmadapter->pcard_pcie->evtbd_rdptr &
|
|
EVT_RW_PTR_ROLLOVER_IND) ^
|
|
EVT_RW_PTR_ROLLOVER_IND);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma)
|
|
pmadapter->pcard_pcie->evtbd_rdptr &=
|
|
ADMA_RW_PTR_WRAP_MASK;
|
|
#endif
|
|
|
|
/* Do not update the event write pointer here, wait till the
|
|
buffer is released. This is just to make things simpler,
|
|
we need to find a better method of managing these buffers.
|
|
*/
|
|
} else {
|
|
PRINTM(MINTR, "------>EVENT DONE\n");
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_cpu_int_event,
|
|
CPU_INTR_EVENT_DONE)) {
|
|
PRINTM(MERROR,
|
|
"Failed to asset event done interrupt\n");
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handles event completion
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pmbuf A pointer to mlan_buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_event_complete(mlan_adapter *pmadapter,
|
|
mlan_buffer *pmbuf,
|
|
mlan_status status)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 wrptr =
|
|
pmadapter->pcard_pcie->evtbd_wrptr & (MLAN_MAX_EVT_BD - 1);
|
|
t_u32 rdptr;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
mlan_pcie_evt_buf *pevtbd_buf;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
adma_dual_desc_buf *padma_bd_buf;
|
|
#endif
|
|
|
|
ENTER();
|
|
if (!pmbuf) {
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (wrptr >= MLAN_MAX_EVT_BD) {
|
|
PRINTM(MERROR, "EvtCom: Invalid wrptr 0x%x\n", wrptr);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Read the event ring read pointer set by firmware */
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_evtbd_rdptr,
|
|
&rdptr)) {
|
|
PRINTM(MERROR, "EvtCom: failed to read REG_EVTBD_RDPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma)
|
|
rdptr = rdptr >> ADMA_RPTR_START;
|
|
#endif
|
|
|
|
if (!pmadapter->pcard_pcie->evt_buf_list[wrptr]) {
|
|
pmbuf->data_len = MAX_EVENT_SIZE;
|
|
pmbuf->data_offset -= PCIE_INTF_HEADER_LEN;
|
|
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_map_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
&pmbuf->buf_pa, MAX_EVENT_SIZE,
|
|
PCI_DMA_FROMDEVICE)) {
|
|
PRINTM(MERROR, "EvtCom: failed to moal_map_memory\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
pmadapter->pcard_pcie->evt_buf_list[wrptr] = pmbuf;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
pevtbd_buf = (mlan_pcie_evt_buf *)pmadapter->pcard_pcie
|
|
->evtbd_ring[wrptr];
|
|
pevtbd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
pevtbd_buf->len =
|
|
wlan_cpu_to_le16((t_u16)pmbuf->data_len);
|
|
pevtbd_buf->flags = 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
padma_bd_buf = (adma_dual_desc_buf *)pmadapter
|
|
->pcard_pcie->evtbd_ring[wrptr];
|
|
padma_bd_buf->paddr = wlan_cpu_to_le64(pmbuf->buf_pa);
|
|
padma_bd_buf->len = wlan_cpu_to_le16(
|
|
ALIGN_SZ(pmbuf->data_len, ADMA_ALIGN_SIZE));
|
|
padma_bd_buf->flags = 0;
|
|
padma_bd_buf->flags = wlan_cpu_to_le16(
|
|
ADMA_BD_FLAG_INT_EN | ADMA_BD_FLAG_DST_HOST);
|
|
padma_bd_buf->pkt_size = 0;
|
|
padma_bd_buf->reserved = 0;
|
|
}
|
|
#endif
|
|
pmbuf = MNULL;
|
|
} else {
|
|
PRINTM(MINFO,
|
|
"EvtCom: ERROR: Buffer is still valid at "
|
|
"index %d, <%p, %p>\n",
|
|
wrptr, pmadapter->pcard_pcie->evt_buf_list[wrptr],
|
|
pmbuf);
|
|
}
|
|
|
|
pmadapter->pcard_pcie->evtbd_wrptr++;
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
if ((pmadapter->pcard_pcie->evtbd_wrptr & EVT_RW_PTR_MASK) ==
|
|
MLAN_MAX_EVT_BD) {
|
|
pmadapter->pcard_pcie->evtbd_wrptr =
|
|
((pmadapter->pcard_pcie->evtbd_wrptr &
|
|
EVT_RW_PTR_ROLLOVER_IND) ^
|
|
EVT_RW_PTR_ROLLOVER_IND);
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma)
|
|
pmadapter->pcard_pcie->evtbd_wrptr &= ADMA_RW_PTR_WRAP_MASK;
|
|
#endif
|
|
PRINTM(MINFO, "EvtCom: Updated <Wr: 0x%x, Rd: 0x%x>\n",
|
|
pmadapter->pcard_pcie->evtbd_wrptr, rdptr);
|
|
|
|
/* Write the event ring write pointer in to REG_EVTBD_WRPTR */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_evtbd_wrptr,
|
|
pmadapter->pcard_pcie->evtbd_wrptr)) {
|
|
PRINTM(MERROR, "EvtCom: failed to write REG_EVTBD_WRPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
done:
|
|
/* Free the buffer for failure case */
|
|
if (ret && pmbuf)
|
|
wlan_free_mlan_buffer(pmadapter, pmbuf);
|
|
|
|
PRINTM(MINFO, "EvtCom: Check Events Again\n");
|
|
ret = wlan_pcie_process_event_ready(pmadapter);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function downloads boot command to the card.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pmbuf A pointer to mlan_buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_send_boot_cmd(mlan_adapter *pmadapter,
|
|
mlan_buffer *pmbuf)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
|
|
if (!pmadapter || !pmbuf) {
|
|
PRINTM(MERROR, "NULL Pointer\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_map_memory(
|
|
pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
|
|
&pmbuf->buf_pa, WLAN_UPLD_SIZE, PCI_DMA_TODEVICE)) {
|
|
PRINTM(MERROR, "BootCmd: failed to moal_map_memory\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (!(pmbuf->pbuf && pmbuf->data_len && pmbuf->buf_pa)) {
|
|
PRINTM(MERROR, "%s: Invalid buffer <%p, %#x:%x, len=%d>\n",
|
|
__func__, pmbuf->pbuf,
|
|
(t_u32)((t_u64)pmbuf->buf_pa >> 32),
|
|
(t_u32)pmbuf->buf_pa, pmbuf->data_len);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Write the lower 32bits of the physical address to scratch
|
|
* register 0 */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_scratch_0,
|
|
(t_u32)pmbuf->buf_pa)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write download command to boot code\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Write the upper 32bits of the physical address to scratch
|
|
* register 1 */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_scratch_1,
|
|
(t_u32)((t_u64)pmbuf->buf_pa >> 32))) {
|
|
PRINTM(MERROR,
|
|
"Failed to write download command to boot code\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Write the command length to scratch register 2 */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_scratch_2,
|
|
pmbuf->data_len)) {
|
|
PRINTM(MERROR,
|
|
"Failed to write command length to scratch register 2\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
/* Ring the door bell */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_cpu_int_event,
|
|
CPU_INTR_DOOR_BELL)) {
|
|
PRINTM(MERROR, "Failed to assert door-bell interrupt\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
|
|
done:
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_unmap_memory(
|
|
pmadapter->pmoal_handle, pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa, WLAN_UPLD_SIZE, PCI_DMA_TODEVICE))
|
|
PRINTM(MERROR, "BootCmd: failed to moal_unmap_memory\n");
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function init rx port in firmware
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_pcie_init_fw(pmlan_adapter pmadapter)
|
|
{
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 txbd_val = 0;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
txbd_val = pmadapter->pcard_pcie->txbd_wrptr &
|
|
pmadapter->pcard_pcie->reg->txrx_rw_ptr_wrap_mask;
|
|
txbd_val = txbd_val << TXBD_RW_PTR_START;
|
|
}
|
|
#endif
|
|
/* Write the RX ring write pointer in to REG_RXBD_WRPTR */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_rxbd_wrptr,
|
|
pmadapter->pcard_pcie->rxbd_wrptr | txbd_val)) {
|
|
PRINTM(MERROR, "Init FW: failed to write REG_RXBD_WRPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
/* Write the event ring write pointer in to REG_EVTBD_WRPTR */
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_evtbd_wrptr,
|
|
pmadapter->pcard_pcie->evtbd_wrptr)) {
|
|
PRINTM(MERROR, "Init FW: failed to write REG_EVTBD_WRPTR\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
done:
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function downloads FW blocks to device
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter
|
|
* @param fw A pointer to firmware image
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_prog_fw_w_helper(mlan_adapter *pmadapter,
|
|
mlan_fw_image *fw)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_FAILURE;
|
|
t_u8 *firmware = fw->pfw_buf;
|
|
t_u32 firmware_len = fw->fw_len;
|
|
t_u32 offset = 0;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
t_u32 txlen, tries, len;
|
|
t_u32 block_retry_cnt = 0;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
#if defined(PCIE9098)
|
|
t_u32 rev_id_reg = 0;
|
|
t_u32 revision_id = 0;
|
|
#endif
|
|
t_u8 check_fw_status = MFALSE;
|
|
t_u32 fw_dnld_status = 0;
|
|
t_u32 fw_dnld_offset = 0;
|
|
t_u8 mic_retry = 0;
|
|
|
|
ENTER();
|
|
if (!pmadapter) {
|
|
PRINTM(MERROR, "adapter structure is not valid\n");
|
|
goto done;
|
|
}
|
|
|
|
if (!firmware || !firmware_len) {
|
|
PRINTM(MERROR,
|
|
"No firmware image found! Terminating download\n");
|
|
goto done;
|
|
}
|
|
|
|
PRINTM(MINFO, "Downloading FW image (%d bytes)\n", firmware_len);
|
|
|
|
if (wlan_disable_pcie_host_int(pmadapter)) {
|
|
PRINTM(MERROR, "prog_fw: Disabling interrupts failed\n");
|
|
goto done;
|
|
}
|
|
|
|
pmbuf = wlan_alloc_mlan_buffer(pmadapter, WLAN_UPLD_SIZE, 0,
|
|
MOAL_ALLOC_MLAN_BUFFER);
|
|
if (!pmbuf) {
|
|
PRINTM(MERROR, "prog_fw: Unable to allocate mlan_buffer\n");
|
|
goto done;
|
|
}
|
|
#if defined(PCIE9098)
|
|
if (IS_PCIE9098(pmadapter->card_type)) {
|
|
rev_id_reg = pmadapter->pcard_pcie->reg->reg_rev_id;
|
|
ret = pcb->moal_read_reg(pmadapter->pmoal_handle, rev_id_reg,
|
|
&revision_id);
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR,
|
|
"Failed to read PCIe revision id register\n");
|
|
goto done;
|
|
}
|
|
/* Skyhawk A0, need to check both CRC and MIC error */
|
|
if (revision_id >= CHIP_9098_REV_A0)
|
|
check_fw_status = MTRUE;
|
|
}
|
|
#endif
|
|
/* For PCIE9097, need check both CRC and MIC error */
|
|
#if defined(PCIE9097)
|
|
if (IS_PCIE9097(pmadapter->card_type))
|
|
check_fw_status = MTRUE;
|
|
#endif
|
|
#if defined(PCIENW62X)
|
|
if (IS_PCIENW62X(pmadapter->card_type))
|
|
check_fw_status = MTRUE;
|
|
#endif
|
|
|
|
/* Perform firmware data transfer */
|
|
do {
|
|
t_u32 ireg_intr = 0;
|
|
t_u32 read_retry_cnt = 0;
|
|
|
|
/* More data? */
|
|
if (offset >= firmware_len)
|
|
break;
|
|
|
|
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
|
|
ret = pcb->moal_read_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_scratch_2,
|
|
&len);
|
|
if (ret) {
|
|
PRINTM(MWARN,
|
|
"Failed reading length from boot code\n");
|
|
goto done;
|
|
}
|
|
if (len || offset)
|
|
break;
|
|
wlan_udelay(pmadapter, 10);
|
|
}
|
|
|
|
if (!len) {
|
|
break;
|
|
} else if (len > WLAN_UPLD_SIZE) {
|
|
PRINTM(MERROR,
|
|
"FW download failure @ %d, invalid length %d\n",
|
|
offset, len);
|
|
goto done;
|
|
}
|
|
|
|
txlen = len;
|
|
|
|
if (len & MBIT(0)) {
|
|
if (check_fw_status) {
|
|
/* Get offset from fw dnld offset Register */
|
|
ret = pcb->moal_read_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_scratch_6,
|
|
&fw_dnld_offset);
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR,
|
|
"FW download failure @ %d, reading fw dnld offset failed\n",
|
|
offset);
|
|
goto done;
|
|
}
|
|
/* Get CRC MIC error from fw dnld status
|
|
* Register */
|
|
ret = pcb->moal_read_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_scratch_7,
|
|
&fw_dnld_status);
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR,
|
|
"FW download failure @ %d, reading fw dnld status failed\n",
|
|
offset);
|
|
goto done;
|
|
}
|
|
PRINTM(MERROR,
|
|
"FW download error: status=0x%x offset = 0x%x fw offset = 0x%x\n",
|
|
fw_dnld_status, offset, fw_dnld_offset);
|
|
}
|
|
block_retry_cnt++;
|
|
if (block_retry_cnt > MAX_WRITE_IOMEM_RETRY) {
|
|
PRINTM(MERROR,
|
|
"FW download failure @ %d, over max "
|
|
"retry count\n",
|
|
offset);
|
|
goto done;
|
|
}
|
|
PRINTM(MERROR,
|
|
"FW CRC error indicated by the "
|
|
"helper: len = 0x%04X, txlen = %d\n",
|
|
len, txlen);
|
|
len &= ~MBIT(0);
|
|
/* Setting this to 0 to resend from same offset */
|
|
txlen = 0;
|
|
if (fw_dnld_status & (MBIT(6) | MBIT(7))) {
|
|
offset = 0;
|
|
mic_retry++;
|
|
if (mic_retry > MAX_FW_RETRY) {
|
|
PRINTM(MERROR,
|
|
"FW download failure @ %d, over max "
|
|
"mic retry count\n",
|
|
offset);
|
|
goto done;
|
|
}
|
|
}
|
|
} else {
|
|
block_retry_cnt = 0;
|
|
/* Set blocksize to transfer - checking for last block
|
|
*/
|
|
if (firmware_len - offset < txlen)
|
|
txlen = firmware_len - offset;
|
|
|
|
PRINTM(MINFO, ".");
|
|
|
|
/* Copy payload to buffer */
|
|
memmove(pmadapter, pmbuf->pbuf + pmbuf->data_offset,
|
|
&firmware[offset], txlen);
|
|
pmbuf->data_len = txlen;
|
|
}
|
|
|
|
/* Send the boot command to device */
|
|
if (wlan_pcie_send_boot_cmd(pmadapter, pmbuf)) {
|
|
PRINTM(MERROR,
|
|
"Failed to send firmware download command\n");
|
|
goto done;
|
|
}
|
|
/* Wait for the command done interrupt */
|
|
do {
|
|
if (read_retry_cnt > MAX_READ_REG_RETRY) {
|
|
PRINTM(MERROR,
|
|
"prog_fw: Failed to get command done interrupt "
|
|
"retry count = %d\n",
|
|
read_retry_cnt);
|
|
goto done;
|
|
}
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_cpu_int_status,
|
|
&ireg_intr)) {
|
|
PRINTM(MERROR,
|
|
"prog_fw: Failed to read "
|
|
"interrupt status during fw dnld\n");
|
|
/* buffer was mapped in send_boot_cmd, unmap
|
|
* first */
|
|
pcb->moal_unmap_memory(
|
|
pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa, WLAN_UPLD_SIZE,
|
|
PCI_DMA_TODEVICE);
|
|
goto done;
|
|
}
|
|
read_retry_cnt++;
|
|
pcb->moal_usleep_range(pmadapter->pmoal_handle, 10, 20);
|
|
} while ((ireg_intr & CPU_INTR_DOOR_BELL) ==
|
|
CPU_INTR_DOOR_BELL);
|
|
/* got interrupt - can unmap buffer now */
|
|
if (MLAN_STATUS_FAILURE ==
|
|
pcb->moal_unmap_memory(pmadapter->pmoal_handle,
|
|
pmbuf->pbuf + pmbuf->data_offset,
|
|
pmbuf->buf_pa, WLAN_UPLD_SIZE,
|
|
PCI_DMA_TODEVICE)) {
|
|
PRINTM(MERROR,
|
|
"prog_fw: failed to moal_unmap_memory\n");
|
|
goto done;
|
|
}
|
|
offset += txlen;
|
|
} while (MTRUE);
|
|
|
|
PRINTM(MMSG, "FW download over, size %d bytes\n", offset);
|
|
|
|
ret = MLAN_STATUS_SUCCESS;
|
|
done:
|
|
if (pmbuf)
|
|
wlan_free_mlan_buffer(pmadapter, pmbuf);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/********************************************************
|
|
Global Functions
|
|
********************************************************/
|
|
/**
|
|
* @brief This function get pcie device from card type
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_get_pcie_device(pmlan_adapter pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u16 card_type = pmadapter->card_type;
|
|
|
|
ENTER();
|
|
|
|
ret = pmadapter->callbacks.moal_malloc(pmadapter->pmoal_handle,
|
|
sizeof(mlan_pcie_card),
|
|
MLAN_MEM_DEF,
|
|
(t_u8 **)&pmadapter->pcard_pcie);
|
|
if (ret != MLAN_STATUS_SUCCESS || !pmadapter->pcard_pcie) {
|
|
PRINTM(MERROR, "Failed to allocate pcard_pcie\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
switch (card_type) {
|
|
#ifdef PCIE8897
|
|
case CARD_TYPE_PCIE8897:
|
|
pmadapter->pcard_pcie->reg = &mlan_reg_pcie8897;
|
|
pmadapter->pcard_info = &mlan_card_info_pcie8897;
|
|
pmadapter->pcard_pcie->txrx_bd_size = MAX_TXRX_BD;
|
|
break;
|
|
#endif
|
|
#ifdef PCIE8997
|
|
case CARD_TYPE_PCIE8997:
|
|
pmadapter->pcard_pcie->reg = &mlan_reg_pcie8997;
|
|
pmadapter->pcard_info = &mlan_card_info_pcie8997;
|
|
pmadapter->pcard_pcie->txrx_bd_size = MAX_TXRX_BD;
|
|
break;
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
case CARD_TYPE_PCIE9097:
|
|
case CARD_TYPE_PCIE9098:
|
|
case CARD_TYPE_PCIENW62X:
|
|
pmadapter->pcard_pcie->reg = &mlan_reg_pcie9098;
|
|
pmadapter->pcard_info = &mlan_card_info_pcie9098;
|
|
pmadapter->pcard_pcie->txrx_bd_size = ADMA_DEF_TXRX_BD;
|
|
pmadapter->pcard_pcie->txrx_num_desc = TXRX_DEF_NUM_DESC;
|
|
#if defined(PCIE9097) || defined(PCIENW62X)
|
|
if ((card_type == CARD_TYPE_PCIE9097 &&
|
|
pmadapter->card_rev == CHIP_9097_REV_B0) ||
|
|
(card_type == CARD_TYPE_PCIENW62X))
|
|
pmadapter->pcard_pcie->reg = &mlan_reg_pcie9097_b0;
|
|
#endif
|
|
|
|
break;
|
|
#endif
|
|
default:
|
|
PRINTM(MERROR, "can't get right pcie card type \n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief PCIE wakeup handler
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_pcie_wakeup(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u32 data = 0;
|
|
ENTER();
|
|
/* Enable interrupts or any chip access will wakeup device */
|
|
ret = pmadapter->callbacks.moal_read_reg(
|
|
pmadapter->pmoal_handle, pmadapter->pcard_pcie->reg->reg_ip_rev,
|
|
&data);
|
|
|
|
if (ret == MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MINFO,
|
|
"PCIE wakeup: Read PCI register to wakeup device ...\n");
|
|
} else {
|
|
PRINTM(MINFO, "PCIE wakeup: Failed to wakeup device ...\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function gets interrupt status.
|
|
*
|
|
*/
|
|
/**
|
|
* @param msg_id A message id
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @return MLAN_STATUS_FAILURE -- if the intererupt is not for us
|
|
*/
|
|
static mlan_status wlan_pcie_interrupt(t_u16 msg_id, pmlan_adapter pmadapter)
|
|
{
|
|
t_u32 pcie_ireg;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_void *pmoal_handle = pmadapter->pmoal_handle;
|
|
t_void *pint_lock = pmadapter->pint_lock;
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
|
|
if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSI) {
|
|
pcb->moal_spin_lock(pmoal_handle, pint_lock);
|
|
pmadapter->ireg = 1;
|
|
pcb->moal_spin_unlock(pmoal_handle, pint_lock);
|
|
} else if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSIX) {
|
|
pcie_ireg = (1 << msg_id) &
|
|
pmadapter->pcard_pcie->reg->host_intr_mask;
|
|
if (pcie_ireg) {
|
|
if (!pmadapter->pps_uapsd_mode &&
|
|
(pmadapter->ps_state == PS_STATE_SLEEP)) {
|
|
pmadapter->pm_wakeup_fw_try = MFALSE;
|
|
pmadapter->ps_state = PS_STATE_AWAKE;
|
|
pmadapter->pm_wakeup_card_req = MFALSE;
|
|
}
|
|
}
|
|
pcb->moal_spin_lock(pmoal_handle, pint_lock);
|
|
pmadapter->ireg |= pcie_ireg;
|
|
pcb->moal_spin_unlock(pmoal_handle, pint_lock);
|
|
|
|
PRINTM(MINTR, "ireg: 0x%08x\n", pcie_ireg);
|
|
} else {
|
|
wlan_pcie_disable_host_int_mask(pmadapter);
|
|
if (pcb->moal_read_reg(
|
|
pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_host_int_status,
|
|
&pcie_ireg)) {
|
|
PRINTM(MERROR, "Read func%d register failed\n",
|
|
pmadapter->pcard_pcie->func_num);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
|
|
PRINTM(MINTR, "func%d: pcie_ireg=0x%x\n",
|
|
pmadapter->pcard_pcie->func_num, pcie_ireg);
|
|
if (!pmadapter->pps_uapsd_mode &&
|
|
(pmadapter->ps_state == PS_STATE_SLEEP)) {
|
|
/* Potentially for PCIe we could get other
|
|
* interrupts like shared. */
|
|
pmadapter->pm_wakeup_fw_try = MFALSE;
|
|
pmadapter->ps_state = PS_STATE_AWAKE;
|
|
pmadapter->pm_wakeup_card_req = MFALSE;
|
|
}
|
|
pcb->moal_spin_lock(pmoal_handle, pint_lock);
|
|
pmadapter->ireg |= pcie_ireg;
|
|
pcb->moal_spin_unlock(pmoal_handle, pint_lock);
|
|
|
|
/* Clear the pending interrupts */
|
|
if (pcb->moal_write_reg(pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_host_int_status,
|
|
~pcie_ireg)) {
|
|
PRINTM(MWARN, "Write register failed\n");
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
} else {
|
|
wlan_pcie_enable_host_int_mask(pmadapter);
|
|
PRINTM(MINFO, "This is not our interrupt\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function checks the msix interrupt status and
|
|
* handle it accordingly.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_process_msix_int(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u32 pcie_ireg = 0;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
|
|
pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
|
|
pcie_ireg =
|
|
pmadapter->ireg & pmadapter->pcard_pcie->reg->host_intr_mask;
|
|
pmadapter->ireg = 0;
|
|
pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
|
|
|
|
if (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_dnld_done) {
|
|
PRINTM(MINFO, "<--- DATA sent Interrupt --->\n");
|
|
ret = wlan_pcie_send_data_complete(pmadapter);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
if (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_upld_rdy) {
|
|
PRINTM(MINFO, "Rx DATA\n");
|
|
ret = wlan_pcie_process_recv_data(pmadapter);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
if (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_event_rdy) {
|
|
PRINTM(MINFO, "Rx EVENT\n");
|
|
ret = wlan_pcie_process_event_ready(pmadapter);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
if (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_cmd_done) {
|
|
if (pmadapter->cmd_sent) {
|
|
PRINTM(MINFO, "<--- CMD sent Interrupt --->\n");
|
|
pmadapter->cmd_sent = MFALSE;
|
|
}
|
|
ret = wlan_pcie_process_cmd_resp(pmadapter);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->host_intr_cmd_dnld &&
|
|
(pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_cmd_dnld)) {
|
|
if (pmadapter->cmd_sent)
|
|
pmadapter->cmd_sent = MFALSE;
|
|
if (pmadapter->pcard_pcie->vdll_cmd_buf)
|
|
wlan_pcie_send_vdll_complete(pmadapter);
|
|
PRINTM(MINFO, "<--- CMD DNLD DONE Interrupt --->\n");
|
|
}
|
|
#endif
|
|
PRINTM(MINFO, "cmd_sent=%d data_sent=%d\n", pmadapter->cmd_sent,
|
|
pmadapter->data_sent);
|
|
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function checks the interrupt status and
|
|
* handle it accordingly.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_process_pcie_int_status(mlan_adapter *pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u32 pcie_ireg = 0;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
|
|
if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSIX) {
|
|
wlan_process_msix_int(pmadapter);
|
|
goto done;
|
|
}
|
|
pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->pint_lock);
|
|
if (pmadapter->pcard_pcie->pcie_int_mode != PCIE_INT_MODE_MSI)
|
|
pcie_ireg = pmadapter->ireg;
|
|
pmadapter->ireg = 0;
|
|
pcb->moal_spin_unlock(pmadapter->pmoal_handle, pmadapter->pint_lock);
|
|
if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSI) {
|
|
if (pcb->moal_read_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_host_int_status,
|
|
&pcie_ireg)) {
|
|
PRINTM(MERROR, "Read func%d register failed\n",
|
|
pmadapter->pcard_pcie->func_num);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
|
|
PRINTM(MINTR, "func%d: pcie_ireg=0x%x\n",
|
|
pmadapter->pcard_pcie->func_num, pcie_ireg);
|
|
if (pmadapter->pcard_pcie->reg->msi_int_wr_clr) {
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_host_int_status,
|
|
~pcie_ireg)) {
|
|
PRINTM(MERROR,
|
|
"Write register failed\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
}
|
|
if (!pmadapter->pps_uapsd_mode &&
|
|
(pmadapter->ps_state == PS_STATE_SLEEP)) {
|
|
/* Potentially for PCIe we could get other
|
|
* interrupts like shared. */
|
|
pmadapter->pm_wakeup_fw_try = MFALSE;
|
|
pmadapter->ps_state = PS_STATE_AWAKE;
|
|
pmadapter->pm_wakeup_card_req = MFALSE;
|
|
}
|
|
}
|
|
}
|
|
while (pcie_ireg & pmadapter->pcard_pcie->reg->host_intr_mask) {
|
|
if (pcie_ireg &
|
|
pmadapter->pcard_pcie->reg->host_intr_dnld_done) {
|
|
pcie_ireg &=
|
|
~pmadapter->pcard_pcie->reg->host_intr_dnld_done;
|
|
PRINTM(MINFO, "<--- DATA sent Interrupt --->\n");
|
|
pmadapter->callbacks.moal_tp_accounting_rx_param(
|
|
pmadapter->pmoal_handle, 3, 0);
|
|
|
|
ret = wlan_pcie_send_data_complete(pmadapter);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
if (pcie_ireg &
|
|
pmadapter->pcard_pcie->reg->host_intr_upld_rdy) {
|
|
pcie_ireg &=
|
|
~pmadapter->pcard_pcie->reg->host_intr_upld_rdy;
|
|
PRINTM(MINFO, "Rx DATA\n");
|
|
pmadapter->callbacks.moal_tp_accounting_rx_param(
|
|
pmadapter->pmoal_handle, 0, 0);
|
|
ret = wlan_pcie_process_recv_data(pmadapter);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
if (pcie_ireg &
|
|
pmadapter->pcard_pcie->reg->host_intr_event_rdy) {
|
|
pcie_ireg &=
|
|
~pmadapter->pcard_pcie->reg->host_intr_event_rdy;
|
|
PRINTM(MINFO, "Rx EVENT\n");
|
|
ret = wlan_pcie_process_event_ready(pmadapter);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
if (pcie_ireg &
|
|
pmadapter->pcard_pcie->reg->host_intr_cmd_done) {
|
|
pcie_ireg &=
|
|
~pmadapter->pcard_pcie->reg->host_intr_cmd_done;
|
|
if (pmadapter->cmd_sent) {
|
|
PRINTM(MINFO, "<--- CMD sent Interrupt --->\n");
|
|
pmadapter->cmd_sent = MFALSE;
|
|
}
|
|
ret = wlan_pcie_process_cmd_resp(pmadapter);
|
|
if (ret)
|
|
goto done;
|
|
}
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->host_intr_cmd_dnld &&
|
|
(pcie_ireg &
|
|
pmadapter->pcard_pcie->reg->host_intr_cmd_dnld)) {
|
|
pcie_ireg &=
|
|
~pmadapter->pcard_pcie->reg->host_intr_cmd_dnld;
|
|
if (pmadapter->cmd_sent)
|
|
pmadapter->cmd_sent = MFALSE;
|
|
if (pmadapter->pcard_pcie->vdll_cmd_buf)
|
|
wlan_pcie_send_vdll_complete(pmadapter);
|
|
PRINTM(MINFO, "<--- CMD DNLD DONE Interrupt --->\n");
|
|
}
|
|
#endif
|
|
if (pmadapter->pcard_pcie->pcie_int_mode == PCIE_INT_MODE_MSI) {
|
|
pcb->moal_spin_lock(pmadapter->pmoal_handle,
|
|
pmadapter->pint_lock);
|
|
pmadapter->ireg = 0;
|
|
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
|
|
pmadapter->pint_lock);
|
|
}
|
|
if (pcb->moal_read_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_host_int_status,
|
|
&pcie_ireg)) {
|
|
PRINTM(MERROR, "Read func%d register failed\n",
|
|
pmadapter->pcard_pcie->func_num);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
goto done;
|
|
}
|
|
|
|
if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
|
|
PRINTM(MINTR, "func%d: Poll pcie_ireg=0x%x\n",
|
|
pmadapter->pcard_pcie->func_num, pcie_ireg);
|
|
if ((pmadapter->pcard_pcie->pcie_int_mode ==
|
|
PCIE_INT_MODE_LEGACY) ||
|
|
pmadapter->pcard_pcie->reg->msi_int_wr_clr) {
|
|
if (pcb->moal_write_reg(
|
|
pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg
|
|
->reg_host_int_status,
|
|
~pcie_ireg)) {
|
|
PRINTM(MWARN,
|
|
"Write register failed\n");
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
if (pmadapter->pcard_pcie->pcie_int_mode !=
|
|
PCIE_INT_MODE_MSI) {
|
|
pcb->moal_spin_lock(pmadapter->pmoal_handle,
|
|
pmadapter->pint_lock);
|
|
pcie_ireg |= pmadapter->ireg;
|
|
pmadapter->ireg = 0;
|
|
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
|
|
pmadapter->pint_lock);
|
|
}
|
|
/* Don't update the pmadapter->pcie_ireg,
|
|
* serving the status right now */
|
|
}
|
|
}
|
|
PRINTM(MINFO, "cmd_sent=%d data_sent=%d\n", pmadapter->cmd_sent,
|
|
pmadapter->data_sent);
|
|
if (pmadapter->pcard_pcie->pcie_int_mode != PCIE_INT_MODE_MSI) {
|
|
if (pmadapter->ps_state != PS_STATE_SLEEP ||
|
|
pmadapter->pcard_info->supp_ps_handshake)
|
|
wlan_pcie_enable_host_int_mask(pmadapter);
|
|
}
|
|
done:
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function sets DRV_READY register
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param val Value
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*
|
|
*/
|
|
mlan_status wlan_set_drv_ready_reg(mlan_adapter *pmadapter, t_u32 val)
|
|
{
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
|
|
if (pcb->moal_write_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_drv_ready,
|
|
val)) {
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function checks if the interface is ready to download
|
|
* or not while other download interface is present
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param val Winner status (0: winner)
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*
|
|
*/
|
|
static mlan_status wlan_pcie_check_winner_status(mlan_adapter *pmadapter,
|
|
t_u32 *val)
|
|
{
|
|
t_u32 winner = 0;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
|
|
ENTER();
|
|
|
|
if (MLAN_STATUS_SUCCESS !=
|
|
pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_scratch_3,
|
|
&winner)) {
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
*val = winner;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function checks if the firmware is ready to accept
|
|
* command or not.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pollnum Maximum polling number
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_check_fw_status(mlan_adapter *pmadapter,
|
|
t_u32 pollnum)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
t_u32 firmware_stat;
|
|
t_u32 tries;
|
|
|
|
ENTER();
|
|
|
|
/* Wait for firmware initialization event */
|
|
for (tries = 0; tries < pollnum; tries++) {
|
|
if (pcb->moal_read_reg(pmadapter->pmoal_handle,
|
|
pmadapter->pcard_pcie->reg->reg_scratch_3,
|
|
&firmware_stat))
|
|
ret = MLAN_STATUS_FAILURE;
|
|
else
|
|
ret = MLAN_STATUS_SUCCESS;
|
|
if (ret)
|
|
continue;
|
|
if (firmware_stat == PCIE_FIRMWARE_READY) {
|
|
ret = MLAN_STATUS_SUCCESS;
|
|
break;
|
|
} else {
|
|
wlan_mdelay(pmadapter, 10);
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function init the pcie interface
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_pcie_init(mlan_adapter *pmadapter)
|
|
{
|
|
ENTER();
|
|
|
|
PRINTM(MINFO, "Setting driver ready signature\n");
|
|
if (wlan_set_drv_ready_reg(pmadapter, PCIE_FIRMWARE_READY)) {
|
|
PRINTM(MERROR, "Failed to write driver ready signature\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function downloads firmware to card
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter
|
|
* @param pmfw A pointer to firmware image
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pcie_dnld_fw(pmlan_adapter pmadapter,
|
|
pmlan_fw_image pmfw)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u32 poll_num = 1;
|
|
t_u32 winner = 0;
|
|
|
|
ENTER();
|
|
|
|
ret = wlan_pcie_init(pmadapter);
|
|
if (ret == MLAN_STATUS_FAILURE) {
|
|
PRINTM(MERROR, "WLAN PCIE init failed\n", ret);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
/* Check if firmware is already running */
|
|
ret = wlan_pcie_check_fw_status(pmadapter, poll_num);
|
|
if (ret == MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MMSG, "WLAN FW already running! Skip FW download\n");
|
|
goto done;
|
|
}
|
|
poll_num = MAX_FIRMWARE_POLL_TRIES;
|
|
|
|
/* Check if other interface is downloading */
|
|
ret = wlan_pcie_check_winner_status(pmadapter, &winner);
|
|
if (ret == MLAN_STATUS_FAILURE) {
|
|
PRINTM(MFATAL, "WLAN read winner status failed!\n");
|
|
goto done;
|
|
}
|
|
if (winner) {
|
|
PRINTM(MMSG,
|
|
"WLAN is not the winner (0x%x). Skip FW download\n",
|
|
winner);
|
|
poll_num = MAX_MULTI_INTERFACE_POLL_TRIES;
|
|
goto poll_fw;
|
|
}
|
|
|
|
/* Download the firmware image via helper */
|
|
ret = wlan_pcie_prog_fw_w_helper(pmadapter, pmfw);
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR, "prog_fw failed ret=%#x\n", ret);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
poll_fw:
|
|
/* Check if the firmware is downloaded successfully or not */
|
|
ret = wlan_pcie_check_fw_status(pmadapter, poll_num);
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MFATAL, "FW failed to be active in time!\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
done:
|
|
|
|
/* re-enable host interrupt for mlan after fw dnld is successful */
|
|
wlan_enable_pcie_host_int(pmadapter);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function downloads data from driver to card.
|
|
*
|
|
* Both commands and data packets are transferred to the card
|
|
* by this function. This function adds the PCIE specific header
|
|
* to the front of the buffer before transferring. The header
|
|
* contains the length of the packet and the type. The firmware
|
|
* handles the packets based upon this set type.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param type data or command
|
|
* @param pmbuf A pointer to mlan_buffer (pmbuf->data_len should include
|
|
* PCIE header)
|
|
* @param tx_param A pointer to mlan_tx_param (can be MNULL if type is
|
|
* command)
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_pcie_host_to_card(pmlan_private pmpriv, t_u8 type,
|
|
mlan_buffer *pmbuf, mlan_tx_param *tx_param)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_adapter pmadapter = pmpriv->adapter;
|
|
|
|
ENTER();
|
|
|
|
if (!pmbuf) {
|
|
PRINTM(MERROR, "Passed NULL pmbuf to %s\n", __FUNCTION__);
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (type == MLAN_TYPE_DATA)
|
|
ret = wlan_pcie_send_data(pmadapter, type, pmbuf, tx_param);
|
|
else if (type == MLAN_TYPE_CMD)
|
|
ret = wlan_pcie_send_cmd(pmadapter, pmbuf);
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
else if (type == MLAN_TYPE_VDLL)
|
|
ret = wlan_pcie_send_vdll(pmadapter, pmbuf);
|
|
#endif
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function allocates the PCIE buffer for SSU
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_alloc_ssu_pcie_buf(pmlan_adapter pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
/** Virtual base address of ssu buffer */
|
|
t_u8 *ssu_vbase;
|
|
/** Physical base address of ssu buffer */
|
|
t_u64 ssu_pbase = 0;
|
|
|
|
ENTER();
|
|
|
|
if (pmadapter->ssu_buf) {
|
|
PRINTM(MCMND, "ssu buffer already allocated\n");
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
/* Allocate buffer here so that firmware can DMA data on it */
|
|
pmbuf = wlan_alloc_mlan_buffer(pmadapter, 0, 0, MOAL_MALLOC_BUFFER);
|
|
if (!pmbuf) {
|
|
PRINTM(MERROR,
|
|
"SSU buffer create : Unable to allocate mlan_buffer\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
ret = pcb->moal_malloc_consistent(pmadapter->pmoal_handle,
|
|
MLAN_SSU_BUF_SIZE, &ssu_vbase,
|
|
&ssu_pbase);
|
|
|
|
if (ret != MLAN_STATUS_SUCCESS) {
|
|
PRINTM(MERROR, "%s: No free moal_malloc_consistent\n",
|
|
__FUNCTION__);
|
|
/* free pmbuf */
|
|
wlan_free_mlan_buffer(pmadapter, pmbuf);
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
pmbuf->buf_pa = ssu_pbase;
|
|
pmbuf->pbuf = ssu_vbase;
|
|
pmbuf->data_offset = 0;
|
|
pmbuf->data_len = MLAN_SSU_BUF_SIZE;
|
|
pmbuf->total_pcie_buf_len = MLAN_SSU_BUF_SIZE;
|
|
|
|
PRINTM(MCMND,
|
|
"SSU buffer: add new mlan_buffer base: %p, "
|
|
"buf_base: %p, data_offset: %x, buf_pbase: %#x:%x, "
|
|
"buf_len: %#x\n",
|
|
pmbuf, pmbuf->pbuf, pmbuf->data_offset,
|
|
(t_u32)((t_u64)pmbuf->buf_pa >> 32), (t_u32)pmbuf->buf_pa,
|
|
pmbuf->data_len);
|
|
|
|
pmadapter->ssu_buf = pmbuf;
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function frees the allocated ssu buffer.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_free_ssu_pcie_buf(pmlan_adapter pmadapter)
|
|
{
|
|
pmlan_callbacks pcb = &pmadapter->callbacks;
|
|
mlan_buffer *pmbuf = MNULL;
|
|
t_u8 *ssu_vbase;
|
|
t_u64 ssu_pbase;
|
|
|
|
ENTER();
|
|
if (!pmadapter) {
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
|
|
if (pmadapter->ssu_buf) {
|
|
pmbuf = pmadapter->ssu_buf;
|
|
ssu_vbase = pmbuf->pbuf;
|
|
ssu_pbase = pmbuf->buf_pa;
|
|
if (ssu_vbase)
|
|
pcb->moal_mfree_consistent(pmadapter->pmoal_handle,
|
|
pmbuf->total_pcie_buf_len,
|
|
ssu_vbase, ssu_pbase);
|
|
wlan_free_mlan_buffer(pmadapter, pmbuf);
|
|
}
|
|
pmadapter->ssu_buf = MNULL;
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function allocates the PCIE ring buffers
|
|
*
|
|
* The following initializations steps are followed -
|
|
* - Allocate TXBD ring buffers
|
|
* - Allocate RXBD ring buffers
|
|
* - Allocate event BD ring buffers
|
|
* - Allocate command and command response buffer
|
|
* - Allocate sleep cookie buffer
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_alloc_pcie_ring_buf(pmlan_adapter pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if ((pmadapter->card_type == CARD_TYPE_PCIE9098) ||
|
|
(pmadapter->card_type == CARD_TYPE_PCIENW62X) ||
|
|
(pmadapter->card_type == CARD_TYPE_PCIE9097)) {
|
|
wlan_pcie_init_adma_ring_size(pmadapter);
|
|
}
|
|
#endif
|
|
pmadapter->pcard_pcie->cmdrsp_buf = MNULL;
|
|
ret = wlan_pcie_create_txbd_ring(pmadapter);
|
|
if (ret)
|
|
goto err_cre_txbd;
|
|
ret = wlan_pcie_create_rxbd_ring(pmadapter);
|
|
if (ret)
|
|
goto err_cre_rxbd;
|
|
ret = wlan_pcie_create_evtbd_ring(pmadapter);
|
|
if (ret)
|
|
goto err_cre_evtbd;
|
|
ret = wlan_pcie_alloc_cmdrsp_buf(pmadapter);
|
|
if (ret)
|
|
goto err_alloc_cmdbuf;
|
|
return ret;
|
|
err_alloc_cmdbuf:
|
|
wlan_pcie_delete_evtbd_ring(pmadapter);
|
|
err_cre_evtbd:
|
|
wlan_pcie_delete_rxbd_ring(pmadapter);
|
|
err_cre_rxbd:
|
|
wlan_pcie_delete_txbd_ring(pmadapter);
|
|
err_cre_txbd:
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function frees the allocated ring buffers.
|
|
*
|
|
* The following are freed by this function -
|
|
* - TXBD ring buffers
|
|
* - RXBD ring buffers
|
|
* - Event BD ring buffers
|
|
* - Command and command response buffer
|
|
* - Sleep cookie buffer
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_free_pcie_ring_buf(pmlan_adapter pmadapter)
|
|
{
|
|
ENTER();
|
|
|
|
wlan_pcie_delete_cmdrsp_buf(pmadapter);
|
|
wlan_pcie_delete_evtbd_ring(pmadapter);
|
|
wlan_pcie_delete_rxbd_ring(pmadapter);
|
|
wlan_pcie_delete_txbd_ring(pmadapter);
|
|
pmadapter->pcard_pcie->cmdrsp_buf = MNULL;
|
|
#ifdef RPTR_MEM_COP
|
|
if ((pmadapter->card_type == CARD_TYPE_PCIE9098) ||
|
|
(pmadapter->card_type ==
|
|
CARD_TYPE_PCIENW62X)(pmadapter->card_type == CARD_TYPE_PCIE9097))
|
|
wlan_pcie_free_rdptrs(pmadapter);
|
|
#endif
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function cleans up packets in the ring buffers.
|
|
*
|
|
* The following are cleaned by this function -
|
|
* - TXBD ring buffers
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_clean_pcie_ring_buf(pmlan_adapter pmadapter)
|
|
{
|
|
ENTER();
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma)
|
|
wlan_pcie_flush_txbd_ring(pmadapter);
|
|
#endif
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief This function prepares command to set PCI-Express
|
|
* host buffer configuration
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
mlan_status wlan_set_pcie_buf_config(mlan_private *pmpriv)
|
|
{
|
|
pmlan_adapter pmadapter = MNULL;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
HostCmd_DS_PCIE_HOST_BUF_DETAILS host_spec;
|
|
#endif
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
|
|
ENTER();
|
|
if (!pmpriv) {
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
pmadapter = pmpriv->adapter;
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
if (!pmadapter->pcard_pcie->reg->use_adma) {
|
|
memset(pmadapter, &host_spec, 0,
|
|
sizeof(HostCmd_DS_PCIE_HOST_BUF_DETAILS));
|
|
|
|
/* Send the ring base addresses and count to firmware */
|
|
host_spec.txbd_addr_lo = wlan_cpu_to_le32(
|
|
(t_u32)(pmadapter->pcard_pcie->txbd_ring_pbase));
|
|
host_spec.txbd_addr_hi = wlan_cpu_to_le32((t_u32)(
|
|
((t_u64)pmadapter->pcard_pcie->txbd_ring_pbase) >> 32));
|
|
host_spec.txbd_count =
|
|
wlan_cpu_to_le32(pmadapter->pcard_pcie->txrx_bd_size);
|
|
host_spec.rxbd_addr_lo = wlan_cpu_to_le32(
|
|
(t_u32)(pmadapter->pcard_pcie->rxbd_ring_pbase));
|
|
host_spec.rxbd_addr_hi = wlan_cpu_to_le32((t_u32)(
|
|
((t_u64)pmadapter->pcard_pcie->rxbd_ring_pbase) >> 32));
|
|
host_spec.rxbd_count =
|
|
wlan_cpu_to_le32(pmadapter->pcard_pcie->txrx_bd_size);
|
|
host_spec.evtbd_addr_lo = wlan_cpu_to_le32(
|
|
(t_u32)(pmadapter->pcard_pcie->evtbd_ring_pbase));
|
|
host_spec.evtbd_addr_hi = wlan_cpu_to_le32((t_u32)(
|
|
((t_u64)pmadapter->pcard_pcie->evtbd_ring_pbase) >>
|
|
32));
|
|
host_spec.evtbd_count = wlan_cpu_to_le32(MLAN_MAX_EVT_BD);
|
|
|
|
ret = wlan_prepare_cmd(pmpriv,
|
|
HostCmd_CMD_PCIE_HOST_BUF_DETAILS,
|
|
HostCmd_ACT_GEN_SET, 0, MNULL,
|
|
&host_spec);
|
|
if (ret) {
|
|
PRINTM(MERROR,
|
|
"PCIE_HOST_BUF_CFG: send command failed\n");
|
|
ret = MLAN_STATUS_FAILURE;
|
|
}
|
|
}
|
|
#endif
|
|
#if defined(PCIE9098) || defined(PCIE9097) || defined(PCIENW62X)
|
|
if (pmadapter->pcard_pcie->reg->use_adma) {
|
|
/** config ADMA for Tx Data */
|
|
wlan_init_adma(pmadapter, ADMA_TX_DATA,
|
|
pmadapter->pcard_pcie->txbd_ring_pbase,
|
|
pmadapter->pcard_pcie->txrx_num_desc, MTRUE);
|
|
/** config ADMA for Rx Data */
|
|
wlan_init_adma(pmadapter, ADMA_RX_DATA,
|
|
pmadapter->pcard_pcie->rxbd_ring_pbase,
|
|
pmadapter->pcard_pcie->txrx_num_desc, MTRUE);
|
|
/** config ADMA for Rx Event */
|
|
wlan_init_adma(pmadapter, ADMA_EVENT,
|
|
pmadapter->pcard_pcie->evtbd_ring_pbase,
|
|
EVT_NUM_DESC, MTRUE);
|
|
/** config ADMA for cmd */
|
|
wlan_init_adma(pmadapter, ADMA_CMD, 0, 0, MTRUE);
|
|
/** config ADMA for cmdresp */
|
|
wlan_init_adma(pmadapter, ADMA_CMDRESP,
|
|
pmadapter->pcard_pcie->cmdrsp_buf->buf_pa, 0,
|
|
MTRUE);
|
|
}
|
|
#endif
|
|
wlan_pcie_init_fw(pmadapter);
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
#if defined(PCIE8997) || defined(PCIE8897)
|
|
/**
|
|
* @brief This function prepares command PCIE host buffer config.
|
|
*
|
|
* @param pmpriv A pointer to mlan_private structure
|
|
* @param cmd A pointer to HostCmd_DS_COMMAND structure
|
|
* @param cmd_action The action: GET or SET
|
|
* @param pdata_buf A pointer to data buffer
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS
|
|
*/
|
|
mlan_status wlan_cmd_pcie_host_buf_cfg(pmlan_private pmpriv,
|
|
HostCmd_DS_COMMAND *cmd,
|
|
t_u16 cmd_action, t_pvoid pdata_buf)
|
|
{
|
|
HostCmd_DS_PCIE_HOST_BUF_DETAILS *ppcie_hoost_spec =
|
|
&cmd->params.pcie_host_spec;
|
|
|
|
ENTER();
|
|
|
|
cmd->command = wlan_cpu_to_le16(HostCmd_CMD_PCIE_HOST_BUF_DETAILS);
|
|
cmd->size = wlan_cpu_to_le16(
|
|
(sizeof(HostCmd_DS_PCIE_HOST_BUF_DETAILS)) + S_DS_GEN);
|
|
|
|
if (cmd_action == HostCmd_ACT_GEN_SET) {
|
|
memcpy_ext(pmpriv->adapter, ppcie_hoost_spec, pdata_buf,
|
|
sizeof(HostCmd_DS_PCIE_HOST_BUF_DETAILS),
|
|
sizeof(HostCmd_DS_PCIE_HOST_BUF_DETAILS));
|
|
}
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief This function wakes up the card.
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param timeout set timeout flag
|
|
*
|
|
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
|
|
*/
|
|
static mlan_status wlan_pm_pcie_wakeup_card(pmlan_adapter pmadapter,
|
|
t_u8 timeout)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
t_u32 age_ts_usec;
|
|
|
|
ENTER();
|
|
PRINTM(MEVENT, "func%d: Wakeup device...\n",
|
|
pmadapter->pcard_pcie->func_num);
|
|
pmadapter->callbacks.moal_get_system_time(pmadapter->pmoal_handle,
|
|
&pmadapter->pm_wakeup_in_secs,
|
|
&age_ts_usec);
|
|
|
|
if (timeout) {
|
|
pmadapter->callbacks.moal_start_timer(
|
|
pmadapter->pmoal_handle, pmadapter->pwakeup_fw_timer,
|
|
MFALSE, MRVDRV_TIMER_3S);
|
|
pmadapter->wakeup_fw_timer_is_set = MTRUE;
|
|
}
|
|
|
|
ret = wlan_pcie_wakeup(pmadapter);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
static mlan_status wlan_pcie_debug_dump(pmlan_adapter pmadapter)
|
|
{
|
|
mlan_status ret = MLAN_STATUS_SUCCESS;
|
|
pmlan_buffer pmbuf = pmadapter->pcard_pcie->cmdrsp_buf;
|
|
ENTER();
|
|
|
|
if (pmbuf == MNULL) {
|
|
PRINTM(MMSG, "Rx CMD response pmbuf is null\n");
|
|
LEAVE();
|
|
return MLAN_STATUS_FAILURE;
|
|
}
|
|
PRINTM(MERROR, "Dump Rx CMD Response Buf:\n");
|
|
DBG_HEXDUMP(MERROR, "CmdResp Buf", pmbuf->pbuf + pmbuf->data_offset,
|
|
64);
|
|
|
|
LEAVE();
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* @brief This function handle data complete
|
|
*
|
|
* @param pmadapter A pointer to mlan_adapter structure
|
|
* @param pmbuf A pointer to the mlan_buffer
|
|
* @return N/A
|
|
*/
|
|
static mlan_status wlan_pcie_data_complete(pmlan_adapter pmadapter,
|
|
mlan_buffer *pmbuf,
|
|
mlan_status status)
|
|
{
|
|
ENTER();
|
|
|
|
wlan_free_mlan_buffer(pmadapter, pmbuf);
|
|
|
|
LEAVE();
|
|
return MLAN_STATUS_SUCCESS;
|
|
}
|
|
|
|
mlan_adapter_operations mlan_pcie_ops = {
|
|
.dnld_fw = wlan_pcie_dnld_fw,
|
|
.interrupt = wlan_pcie_interrupt,
|
|
.process_int_status = wlan_process_pcie_int_status,
|
|
.host_to_card = wlan_pcie_host_to_card,
|
|
.wakeup_card = wlan_pm_pcie_wakeup_card,
|
|
.reset_card = wlan_pcie_wakeup,
|
|
.event_complete = wlan_pcie_event_complete,
|
|
.data_complete = wlan_pcie_data_complete,
|
|
.cmdrsp_complete = wlan_pcie_cmdrsp_complete,
|
|
.handle_rx_packet = wlan_handle_rx_packet,
|
|
.debug_dump = wlan_pcie_debug_dump,
|
|
.intf_header_len = PCIE_INTF_HEADER_LEN,
|
|
};
|