blob: 1c7aec363fdbda725e28bc746de65b7e0cd21431 [file] [log] [blame]
/** @file mlan_shim.c
*
* @brief This file contains APIs to MOAL module.
*
* Copyright (C) 2008-2019, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this 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:
10/13/2008: 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_wmm.h"
#include "mlan_sdio.h"
#ifdef UAP_SUPPORT
#include "mlan_uap.h"
#endif
#include "mlan_11h.h"
/********************************************************
Local Variables
********************************************************/
/********************************************************
Global Variables
********************************************************/
#ifdef STA_SUPPORT
mlan_operations mlan_sta_ops = {
/* init cmd handler */
wlan_ops_sta_init_cmd,
/* ioctl handler */
wlan_ops_sta_ioctl,
/* cmd handler */
wlan_ops_sta_prepare_cmd,
/* cmdresp handler */
wlan_ops_sta_process_cmdresp,
/* rx handler */
wlan_ops_sta_process_rx_packet,
/* Event handler */
wlan_ops_sta_process_event,
/* txpd handler */
wlan_ops_sta_process_txpd,
/* BSS role: STA */
MLAN_BSS_ROLE_STA,
};
#endif
#ifdef UAP_SUPPORT
mlan_operations mlan_uap_ops = {
/* init cmd handler */
wlan_ops_uap_init_cmd,
/* ioctl handler */
wlan_ops_uap_ioctl,
/* cmd handler */
wlan_ops_uap_prepare_cmd,
/* cmdresp handler */
wlan_ops_uap_process_cmdresp,
/* rx handler */
wlan_ops_uap_process_rx_packet,
/* Event handler */
wlan_ops_uap_process_event,
/* txpd handler */
wlan_ops_uap_process_txpd,
/* BSS role: uAP */
MLAN_BSS_ROLE_UAP,
};
#endif
/** mlan function table */
mlan_operations *mlan_ops[] = {
#ifdef STA_SUPPORT
&mlan_sta_ops,
#endif
#ifdef UAP_SUPPORT
&mlan_uap_ops,
#endif
MNULL,
};
/** Global moal_assert callback */
t_void (*assert_callback) (IN t_void *pmoal_handle, IN t_u32 cond) = MNULL;
#ifdef DEBUG_LEVEL1
#ifdef DEBUG_LEVEL2
#define DEFAULT_DEBUG_MASK (0xffffffff)
#else
#define DEFAULT_DEBUG_MASK (MMSG | MFATAL | MERROR)
#endif
/** Global moal_print callback */
t_void (*print_callback) (IN t_void *pmoal_handle,
IN t_u32 level, IN char *pformat, IN ...
) = MNULL;
/** Global moal_get_system_time callback */
mlan_status (*get_sys_time_callback) (IN t_void *pmoal_handle,
OUT t_u32 *psec,
OUT t_u32 *pusec) = MNULL;
/** Global driver debug mit masks */
t_u32 mlan_drvdbg = DEFAULT_DEBUG_MASK;
#endif
/********************************************************
Local Functions
*******************************************************/
/********************************************************
Global Functions
********************************************************/
/**
* @brief This function registers MOAL to MLAN module.
*
* @param pmdevice A pointer to a mlan_device structure
* allocated in MOAL
* @param ppmlan_adapter A pointer to a t_void pointer to store
* mlan_adapter structure pointer as the context
*
* @return MLAN_STATUS_SUCCESS
* The registration succeeded.
* MLAN_STATUS_FAILURE
* The registration failed.
*
* mlan_status mlan_register (
* IN pmlan_device pmdevice,
* OUT t_void **ppmlan_adapter
* );
*
* Comments
* MOAL constructs mlan_device data structure to pass moal_handle and
* mlan_callback table to MLAN. MLAN returns mlan_adapter pointer to
* the ppmlan_adapter buffer provided by MOAL.
* Headers:
* declared in mlan_decl.h
* See Also
* mlan_unregister
*/
mlan_status
mlan_register(IN pmlan_device pmdevice, OUT t_void **ppmlan_adapter)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_adapter pmadapter = MNULL;
pmlan_callbacks pcb = MNULL;
t_u8 i = 0;
t_u32 j = 0;
MASSERT(pmdevice);
MASSERT(ppmlan_adapter);
MASSERT(pmdevice->callbacks.moal_print);
#ifdef DEBUG_LEVEL1
print_callback = pmdevice->callbacks.moal_print;
get_sys_time_callback = pmdevice->callbacks.moal_get_system_time;
#endif
assert_callback = pmdevice->callbacks.moal_assert;
ENTER();
MASSERT(pmdevice->callbacks.moal_malloc);
MASSERT(pmdevice->callbacks.moal_memset);
MASSERT(pmdevice->callbacks.moal_memmove);
/* Allocate memory for adapter structure */
if (pmdevice->callbacks.moal_vmalloc && pmdevice->callbacks.moal_vfree)
ret = pmdevice->callbacks.moal_vmalloc(pmdevice->pmoal_handle,
sizeof(mlan_adapter),
(t_u8 **)&pmadapter);
else
ret = pmdevice->callbacks.moal_malloc(pmdevice->pmoal_handle,
sizeof(mlan_adapter),
MLAN_MEM_DEF,
(t_u8 **)&pmadapter);
if ((ret != MLAN_STATUS_SUCCESS) || !pmadapter) {
ret = MLAN_STATUS_FAILURE;
goto exit_register;
}
pmdevice->callbacks.moal_memset(pmdevice->pmoal_handle, pmadapter,
0, sizeof(mlan_adapter));
pcb = &pmadapter->callbacks;
/* Save callback functions */
pmdevice->callbacks.moal_memmove(pmadapter->pmoal_handle, pcb,
&pmdevice->callbacks,
sizeof(mlan_callbacks));
/* Assertion for all callback functions */
MASSERT(pcb->moal_init_fw_complete);
MASSERT(pcb->moal_shutdown_fw_complete);
MASSERT(pcb->moal_send_packet_complete);
MASSERT(pcb->moal_recv_packet);
MASSERT(pcb->moal_recv_event);
MASSERT(pcb->moal_ioctl_complete);
MASSERT(pcb->moal_write_reg);
MASSERT(pcb->moal_read_reg);
MASSERT(pcb->moal_alloc_mlan_buffer);
MASSERT(pcb->moal_free_mlan_buffer);
MASSERT(pcb->moal_write_data_sync);
MASSERT(pcb->moal_read_data_sync);
MASSERT(pcb->moal_mfree);
MASSERT(pcb->moal_memcpy);
MASSERT(pcb->moal_memcmp);
MASSERT(pcb->moal_get_system_time);
MASSERT(pcb->moal_init_timer);
MASSERT(pcb->moal_free_timer);
MASSERT(pcb->moal_start_timer);
MASSERT(pcb->moal_stop_timer);
MASSERT(pcb->moal_init_lock);
MASSERT(pcb->moal_free_lock);
MASSERT(pcb->moal_spin_lock);
MASSERT(pcb->moal_spin_unlock);
MASSERT(pcb->moal_tcp_ack_tx_ind);
MASSERT(pcb->moal_hist_data_add);
MASSERT(pcb->moal_updata_peer_signal);
/* Save pmoal_handle */
pmadapter->pmoal_handle = pmdevice->pmoal_handle;
pmadapter->feature_control = pmdevice->feature_control;
if ((pmdevice->int_mode == INT_MODE_GPIO) && (pmdevice->gpio_pin == 0)) {
PRINTM(MERROR, "SDIO_GPIO_INT_CONFIG: Invalid GPIO Pin\n");
ret = MLAN_STATUS_FAILURE;
goto error;
}
pmadapter->init_para.int_mode = pmdevice->int_mode;
pmadapter->init_para.gpio_pin = pmdevice->gpio_pin;
pmadapter->card_type = pmdevice->card_type;
ret = wlan_get_sdio_device(pmadapter);
if (MLAN_STATUS_SUCCESS != ret) {
ret = MLAN_STATUS_FAILURE;
goto error;
}
/* card specific probing has been deferred until now .. */
ret = wlan_sdio_probe(pmadapter);
if (MLAN_STATUS_SUCCESS != ret) {
ret = MLAN_STATUS_FAILURE;
goto error;
}
#ifdef DEBUG_LEVEL1
mlan_drvdbg = pmdevice->drvdbg;
#endif
#ifdef MFG_CMD_SUPPORT
pmadapter->init_para.mfg_mode = pmdevice->mfg_mode;
#endif
#if defined(SDIO_MULTI_PORT_TX_AGGR) || defined(SDIO_MULTI_PORT_RX_AGGR)
pmadapter->max_segs = pmdevice->max_segs;
pmadapter->max_seg_size = pmdevice->max_seg_size;
#endif
#ifdef SDIO_MULTI_PORT_TX_AGGR
pmadapter->init_para.mpa_tx_cfg = pmdevice->mpa_tx_cfg;
#endif
#ifdef SDIO_MULTI_PORT_RX_AGGR
pmadapter->init_para.mpa_rx_cfg = pmdevice->mpa_rx_cfg;
#endif
pmadapter->init_para.auto_ds = pmdevice->auto_ds;
pmadapter->init_para.ps_mode = pmdevice->ps_mode;
if (pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_2K ||
pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_4K ||
pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_12K ||
pmdevice->max_tx_buf == MLAN_TX_DATA_BUF_SIZE_8K)
pmadapter->init_para.max_tx_buf = pmdevice->max_tx_buf;
#ifdef STA_SUPPORT
pmadapter->init_para.cfg_11d = pmdevice->cfg_11d;
#else
pmadapter->init_para.cfg_11d = 0;
#endif
if (IS_DFS_SUPPORT(pmadapter->feature_control))
pmadapter->init_para.dfs_master_radar_det_en =
DFS_MASTER_RADAR_DETECT_EN;
pmadapter->init_para.dfs_slave_radar_det_en = DFS_SLAVE_RADAR_DETECT_EN;
if (IS_SD8777(pmadapter->card_type) || IS_SD8787(pmadapter->card_type))
pmadapter->init_para.fw_crc_check = pmdevice->fw_crc_check;
pmadapter->init_para.dev_cap_mask = pmdevice->dev_cap_mask;
pmadapter->rx_work_flag = pmdevice->rx_work;
pmadapter->priv_num = 0;
for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
pmadapter->priv[i] = MNULL;
if (pmdevice->bss_attr[i].active == MTRUE) {
/* For valid bss_attr, allocate memory for private
structure */
if (pcb->moal_vmalloc && pcb->moal_vfree)
ret = pcb->moal_vmalloc(pmadapter->pmoal_handle,
sizeof(mlan_private),
(t_u8 **)&pmadapter->
priv[i]);
else
ret = pcb->moal_malloc(pmadapter->pmoal_handle,
sizeof(mlan_private),
MLAN_MEM_DEF,
(t_u8 **)&pmadapter->
priv[i]);
if (ret != MLAN_STATUS_SUCCESS || !pmadapter->priv[i]) {
ret = MLAN_STATUS_FAILURE;
goto error;
}
pmadapter->priv_num++;
memset(pmadapter, pmadapter->priv[i], 0,
sizeof(mlan_private));
pmadapter->priv[i]->adapter = pmadapter;
/* Save bss_type, frame_type & bss_priority */
pmadapter->priv[i]->bss_type =
(t_u8)pmdevice->bss_attr[i].bss_type;
pmadapter->priv[i]->frame_type =
(t_u8)pmdevice->bss_attr[i].frame_type;
pmadapter->priv[i]->bss_priority =
(t_u8)pmdevice->bss_attr[i].bss_priority;
if (pmdevice->bss_attr[i].bss_type == MLAN_BSS_TYPE_STA)
pmadapter->priv[i]->bss_role =
MLAN_BSS_ROLE_STA;
else if (pmdevice->bss_attr[i].bss_type ==
MLAN_BSS_TYPE_UAP)
pmadapter->priv[i]->bss_role =
MLAN_BSS_ROLE_UAP;
#ifdef WIFI_DIRECT_SUPPORT
else if (pmdevice->bss_attr[i].bss_type ==
MLAN_BSS_TYPE_WIFIDIRECT) {
pmadapter->priv[i]->bss_role =
MLAN_BSS_ROLE_STA;
if (pmdevice->bss_attr[i].bss_virtual)
pmadapter->priv[i]->bss_virtual = MTRUE;
}
#endif
/* Save bss_index and bss_num */
pmadapter->priv[i]->bss_index = i;
pmadapter->priv[i]->bss_num =
(t_u8)pmdevice->bss_attr[i].bss_num;
/* init function table */
for (j = 0; mlan_ops[j]; j++) {
if (mlan_ops[j]->bss_role ==
GET_BSS_ROLE(pmadapter->priv[i])) {
memcpy(pmadapter,
&pmadapter->priv[i]->ops,
mlan_ops[j],
sizeof(mlan_operations));
}
}
}
}
/* Initialize lock variables */
if (wlan_init_lock_list(pmadapter) != MLAN_STATUS_SUCCESS) {
ret = MLAN_STATUS_FAILURE;
goto error;
}
/* Allocate memory for member of adapter structure */
if (wlan_allocate_adapter(pmadapter)) {
ret = MLAN_STATUS_FAILURE;
goto error;
}
/* Initialize timers */
if (wlan_init_timer(pmadapter) != MLAN_STATUS_SUCCESS) {
ret = MLAN_STATUS_FAILURE;
goto error;
}
/* Return pointer of mlan_adapter to MOAL */
*ppmlan_adapter = pmadapter;
goto exit_register;
error:
PRINTM(MINFO, "Leave mlan_register with error\n");
/* Free timers */
wlan_free_timer(pmadapter);
/* Free adapter structure */
wlan_free_adapter(pmadapter);
/* Free lock variables */
wlan_free_lock_list(pmadapter);
for (i = 0; i < MLAN_MAX_BSS_NUM; i++) {
if (pmadapter->priv[i]) {
if (pcb->moal_vmalloc && pcb->moal_vfree)
pcb->moal_vfree(pmadapter->pmoal_handle,
(t_u8 *)pmadapter->priv[i]);
else
pcb->moal_mfree(pmadapter->pmoal_handle,
(t_u8 *)pmadapter->priv[i]);
}
}
if (pcb->moal_vmalloc && pcb->moal_vfree)
pcb->moal_vfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter);
else
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter);
exit_register:
LEAVE();
return ret;
}
/**
* @brief This function unregisters MOAL from MLAN module.
*
* @param pmlan_adapter A pointer to a mlan_device structure
* allocated in MOAL
*
* @return MLAN_STATUS_SUCCESS
* The deregistration succeeded.
*/
mlan_status
mlan_unregister(IN t_void *pmlan_adapter
)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
pmlan_callbacks pcb;
t_s32 i = 0;
MASSERT(pmlan_adapter);
ENTER();
pcb = &pmadapter->callbacks;
/* Free adapter structure */
wlan_free_adapter(pmadapter);
/* Free timers */
wlan_free_timer(pmadapter);
/* Free lock variables */
wlan_free_lock_list(pmadapter);
/* Free private structures */
for (i = 0; i < pmadapter->priv_num; i++) {
if (pmadapter->priv[i]) {
if (pcb->moal_vmalloc && pcb->moal_vfree)
pcb->moal_vfree(pmadapter->pmoal_handle,
(t_u8 *)pmadapter->priv[i]);
else
pcb->moal_mfree(pmadapter->pmoal_handle,
(t_u8 *)pmadapter->priv[i]);
}
}
/* Free mlan_adapter */
if (pcb->moal_vmalloc && pcb->moal_vfree)
pcb->moal_vfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter);
else
pcb->moal_mfree(pmadapter->pmoal_handle, (t_u8 *)pmadapter);
LEAVE();
return ret;
}
/**
* @brief This function downloads the firmware
*
* @param pmlan_adapter A pointer to a t_void pointer to store
* mlan_adapter structure pointer
* @param pmfw A pointer to firmware image
*
* @return MLAN_STATUS_SUCCESS
* The firmware download succeeded.
* MLAN_STATUS_FAILURE
* The firmware download failed.
*/
mlan_status
mlan_dnld_fw(IN t_void *pmlan_adapter, IN pmlan_fw_image pmfw)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
t_u32 poll_num = 1;
t_u32 winner = 0;
ENTER();
MASSERT(pmlan_adapter);
/* Card specific probing */
ret = wlan_sdio_probe(pmadapter);
if (ret == MLAN_STATUS_FAILURE) {
PRINTM(MERROR, "WLAN SDIO probe failed\n", ret);
LEAVE();
return ret;
}
/* Check if firmware is already running */
ret = wlan_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_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;
}
if (pmfw) {
/* Download helper/firmware */
ret = wlan_dnld_fw(pmadapter, pmfw);
if (ret != MLAN_STATUS_SUCCESS) {
PRINTM(MERROR, "wlan_dnld_fw fail ret=0x%x\n", ret);
LEAVE();
return ret;
}
}
poll_fw:
/* Check if the firmware is downloaded successfully or not */
ret = wlan_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_host_int(pmadapter);
LEAVE();
return ret;
}
/**
* @brief This function pass init param to MLAN
*
* @param pmlan_adapter A pointer to a t_void pointer to store
* mlan_adapter structure pointer
* @param pparam A pointer to mlan_init_param structure
*
* @return MLAN_STATUS_SUCCESS
*
*/
mlan_status
mlan_set_init_param(IN t_void *pmlan_adapter, IN pmlan_init_param pparam)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
ENTER();
MASSERT(pmlan_adapter);
/** Save cal data in MLAN */
if ((pparam->pcal_data_buf) && (pparam->cal_data_len > 0)) {
pmadapter->pcal_data = pparam->pcal_data_buf;
pmadapter->cal_data_len = pparam->cal_data_len;
}
LEAVE();
return ret;
}
/**
* @brief This function initializes the firmware
*
* @param pmlan_adapter A pointer to a t_void pointer to store
* mlan_adapter structure pointer
*
* @return MLAN_STATUS_SUCCESS
* The firmware initialization succeeded.
* MLAN_STATUS_PENDING
* The firmware initialization is pending.
* MLAN_STATUS_FAILURE
* The firmware initialization failed.
*/
mlan_status
mlan_init_fw(IN t_void *pmlan_adapter
)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
ENTER();
MASSERT(pmlan_adapter);
pmadapter->hw_status = WlanHardwareStatusInitializing;
/* Initialize firmware, may return PENDING */
ret = wlan_init_fw(pmadapter);
PRINTM(MINFO, "wlan_init_fw returned ret=0x%x\n", ret);
LEAVE();
return ret;
}
/**
* @brief Shutdown firmware
*
* @param pmlan_adapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS
* The firmware shutdown call succeeded.
* MLAN_STATUS_PENDING
* The firmware shutdown call is pending.
* MLAN_STATUS_FAILURE
* The firmware shutdown call failed.
*/
mlan_status
mlan_shutdown_fw(IN t_void *pmlan_adapter
)
{
mlan_status ret = MLAN_STATUS_PENDING;
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
pmlan_buffer pmbuf;
pmlan_callbacks pcb;
t_s32 i = 0;
ENTER();
MASSERT(pmlan_adapter);
/* MLAN already shutdown */
if (pmadapter->hw_status == WlanHardwareStatusNotReady) {
LEAVE();
return MLAN_STATUS_SUCCESS;
}
pmadapter->hw_status = WlanHardwareStatusClosing;
/* Wait for mlan_process to complete */
if (pmadapter->mlan_processing) {
PRINTM(MWARN, "MLAN main processing is still running\n");
LEAVE();
return ret;
}
/* Shut down MLAN */
PRINTM(MINFO, "Shutdown MLAN...\n");
/* Cancel all pending commands and complete ioctls */
wlan_cancel_all_pending_cmd(pmadapter);
/* Clean up priv structures */
for (i = 0; i < pmadapter->priv_num; i++) {
if (pmadapter->priv[i])
wlan_free_priv(pmadapter->priv[i]);
}
pcb = &pmadapter->callbacks;
while ((pmbuf = (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle,
&pmadapter->
rx_data_queue,
pcb->moal_spin_lock,
pcb->
moal_spin_unlock))) {
wlan_free_mlan_buffer(pmadapter, pmbuf);
}
pmadapter->rx_pkts_queued = 0;
/* Notify completion */
ret = wlan_shutdown_fw_complete(pmadapter);
LEAVE();
return ret;
}
/**
* @brief queue main work
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return N/A
*/
static t_void
mlan_queue_main_work(mlan_adapter *pmadapter)
{
pmlan_callbacks pcb = &pmadapter->callbacks;
ENTER();
pcb->moal_spin_lock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
/* Check if already processing */
if (pmadapter->mlan_processing) {
pmadapter->more_task_flag = MTRUE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
} else {
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
MLAN_EVENT_ID_DRV_DEFER_HANDLING, MNULL);
}
LEAVE();
return;
}
/**
* @brief queue rx_work
*
* @param pmadapter A pointer to mlan_adapter structure
*
* @return N/A
*/
static t_void
mlan_queue_rx_work(mlan_adapter *pmadapter)
{
pmlan_callbacks pcb = &pmadapter->callbacks;
ENTER();
pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock);
/* Check if already processing */
if (pmadapter->mlan_rx_processing) {
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->prx_proc_lock);
} else {
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->prx_proc_lock);
wlan_recv_event(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_ANY),
MLAN_EVENT_ID_DRV_DEFER_RX_WORK, MNULL);
}
LEAVE();
return;
}
/**
* @brief block main process
*
* @param pmadapter A pointer to mlan_adapter structure
* @param block MTRUE/MFALSE
*
* @return N/A
*/
void
mlan_block_main_process(mlan_adapter *pmadapter, t_u8 block)
{
pmlan_callbacks pcb = &pmadapter->callbacks;
pcb->moal_spin_lock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
if (!block) {
pmadapter->main_lock_flag = MFALSE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
} else {
pmadapter->main_lock_flag = MTRUE;
if (pmadapter->mlan_processing) {
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
PRINTM(MEVENT, "wlan: wait main work done...\n");
wlan_recv_event(wlan_get_priv
(pmadapter, MLAN_BSS_ROLE_ANY),
MLAN_EVENT_ID_DRV_FLUSH_MAIN_WORK,
MNULL);
} else {
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
}
}
}
/**
* @brief block rx process
*
* @param pmadapter A pointer to mlan_adapter structure
* @param block MTRUE/MFALSE;
*
* @return N/A
*/
void
mlan_block_rx_process(mlan_adapter *pmadapter, t_u8 block)
{
pmlan_callbacks pcb = &pmadapter->callbacks;
pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock);
if (!block) {
pmadapter->rx_lock_flag = MFALSE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->prx_proc_lock);
} else {
pmadapter->rx_lock_flag = MTRUE;
if (pmadapter->mlan_rx_processing) {
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->prx_proc_lock);
PRINTM(MEVENT, "wlan: wait rx work done...\n");
wlan_recv_event(wlan_get_priv
(pmadapter, MLAN_BSS_ROLE_ANY),
MLAN_EVENT_ID_DRV_FLUSH_RX_WORK, MNULL);
} else {
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->prx_proc_lock);
}
}
}
/**
* @brief The receive process
*
* @param pmlan_adapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
mlan_rx_process(IN t_void *pmlan_adapter
)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
pmlan_callbacks pcb;
pmlan_buffer pmbuf;
ENTER();
MASSERT(pmlan_adapter);
pcb = &pmadapter->callbacks;
pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock);
if (pmadapter->mlan_rx_processing || pmadapter->rx_lock_flag) {
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->prx_proc_lock);
goto exit_rx_proc;
} else {
pmadapter->mlan_rx_processing = MTRUE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->prx_proc_lock);
}
/* Check for Rx data */
while (MTRUE) {
pmadapter->callbacks.moal_spin_lock(pmadapter->pmoal_handle,
pmadapter->rx_data_queue.
plock);
pmbuf = (pmlan_buffer)util_dequeue_list(pmadapter->pmoal_handle,
&pmadapter->
rx_data_queue, MNULL,
MNULL);
if (!pmbuf) {
pmadapter->callbacks.moal_spin_unlock(pmadapter->
pmoal_handle,
pmadapter->
rx_data_queue.
plock);
break;
}
pmadapter->rx_pkts_queued--;
pmadapter->callbacks.moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->rx_data_queue.
plock);
if (pmadapter->delay_task_flag &&
(pmadapter->rx_pkts_queued < LOW_RX_PENDING)) {
PRINTM(MEVENT, "Run\n");
pmadapter->delay_task_flag = MFALSE;
mlan_queue_main_work(pmadapter);
}
wlan_handle_rx_packet(pmadapter, pmbuf);
}
pcb->moal_spin_lock(pmadapter->pmoal_handle, pmadapter->prx_proc_lock);
pmadapter->mlan_rx_processing = MFALSE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->prx_proc_lock);
exit_rx_proc:
LEAVE();
return ret;
}
/**
* @brief The main process
*
* @param pmlan_adapter A pointer to mlan_adapter structure
*
* @return MLAN_STATUS_SUCCESS or MLAN_STATUS_FAILURE
*/
mlan_status
mlan_main_process(IN t_void *pmlan_adapter
)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
pmlan_callbacks pcb;
ENTER();
MASSERT(pmlan_adapter);
pcb = &pmadapter->callbacks;
pcb->moal_spin_lock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
/* Check if already processing */
if (pmadapter->mlan_processing || pmadapter->main_lock_flag) {
pmadapter->more_task_flag = MTRUE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
goto exit_main_proc;
} else {
pmadapter->mlan_processing = MTRUE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
}
process_start:
do {
/* Is MLAN shutting down or not ready? */
if ((pmadapter->hw_status == WlanHardwareStatusClosing) ||
(pmadapter->hw_status == WlanHardwareStatusNotReady))
break;
if (pmadapter->rx_pkts_queued > HIGH_RX_PENDING) {
PRINTM(MEVENT, "Pause\n");
pmadapter->delay_task_flag = MTRUE;
mlan_queue_rx_work(pmadapter);
break;
}
/* Handle pending SDIO interrupts if any */
if (pmadapter->sdio_ireg) {
if (pmadapter->hs_activated == MTRUE)
wlan_process_hs_config(pmadapter);
wlan_process_int_status(pmadapter);
if (pmadapter->data_received && pmadapter->rx_work_flag)
mlan_queue_rx_work(pmadapter);
}
/* Need to wake up the card ? */
if ((pmadapter->ps_state == PS_STATE_SLEEP) &&
(pmadapter->pm_wakeup_card_req &&
!pmadapter->pm_wakeup_fw_try) &&
(util_peek_list
(pmadapter->pmoal_handle, &pmadapter->cmd_pending_q,
pcb->moal_spin_lock, pcb->moal_spin_unlock)
|| !wlan_bypass_tx_list_empty(pmadapter)
|| !wlan_wmm_lists_empty(pmadapter)
)) {
wlan_pm_wakeup_card(pmadapter);
pmadapter->pm_wakeup_fw_try = MTRUE;
continue;
}
if (IS_CARD_RX_RCVD(pmadapter)) {
pmadapter->data_received = MFALSE;
if (pmadapter->hs_activated == MTRUE) {
pmadapter->is_hs_configured = MFALSE;
wlan_host_sleep_activated_event(wlan_get_priv
(pmadapter,
MLAN_BSS_ROLE_ANY),
MFALSE);
}
pmadapter->pm_wakeup_fw_try = MFALSE;
if (pmadapter->ps_state == PS_STATE_SLEEP)
pmadapter->ps_state = PS_STATE_AWAKE;
} else {
/* We have tried to wakeup the card already */
if (pmadapter->pm_wakeup_fw_try)
break;
if (pmadapter->ps_state != PS_STATE_AWAKE ||
(pmadapter->tx_lock_flag == MTRUE))
break;
if (pmadapter->data_sent
|| wlan_is_tdls_link_chan_switching(pmadapter->
tdls_status)
|| (wlan_bypass_tx_list_empty(pmadapter) &&
wlan_wmm_lists_empty(pmadapter))
|| wlan_11h_radar_detected_tx_blocked(pmadapter)
) {
if (pmadapter->cmd_sent || pmadapter->curr_cmd
|| !wlan_is_send_cmd_allowed(pmadapter->
tdls_status) ||
(!util_peek_list
(pmadapter->pmoal_handle,
&pmadapter->cmd_pending_q,
pcb->moal_spin_lock,
pcb->moal_spin_unlock))) {
break;
}
}
}
/* Check for Cmd Resp */
if (pmadapter->cmd_resp_received) {
pmadapter->cmd_resp_received = MFALSE;
wlan_process_cmdresp(pmadapter);
/* call moal back when init_fw is done */
if (pmadapter->hw_status == WlanHardwareStatusInitdone) {
pmadapter->hw_status = WlanHardwareStatusReady;
wlan_init_fw_complete(pmadapter);
}
}
/* Check for event */
if (pmadapter->event_received) {
pmadapter->event_received = MFALSE;
wlan_process_event(pmadapter);
}
/* Check if we need to confirm Sleep Request received
previously */
if (pmadapter->ps_state == PS_STATE_PRE_SLEEP)
if (!pmadapter->cmd_sent && !pmadapter->curr_cmd)
wlan_check_ps_cond(pmadapter);
/*
* The ps_state may have been changed during processing of
* Sleep Request event.
*/
if ((pmadapter->ps_state == PS_STATE_SLEEP)
|| (pmadapter->ps_state == PS_STATE_PRE_SLEEP)
|| (pmadapter->ps_state == PS_STATE_SLEEP_CFM)
|| (pmadapter->tx_lock_flag == MTRUE)
) {
continue;
}
if (!pmadapter->cmd_sent && !pmadapter->curr_cmd
&& wlan_is_send_cmd_allowed(pmadapter->tdls_status)
) {
if (wlan_exec_next_cmd(pmadapter) ==
MLAN_STATUS_FAILURE) {
ret = MLAN_STATUS_FAILURE;
break;
}
}
if (!pmadapter->data_sent &&
!wlan_11h_radar_detected_tx_blocked(pmadapter) &&
!wlan_is_tdls_link_chan_switching(pmadapter->tdls_status) &&
!wlan_bypass_tx_list_empty(pmadapter)) {
PRINTM(MINFO, "mlan_send_pkt(): deq(bybass_txq)\n");
wlan_process_bypass_tx(pmadapter);
if (pmadapter->hs_activated == MTRUE) {
pmadapter->is_hs_configured = MFALSE;
wlan_host_sleep_activated_event(wlan_get_priv
(pmadapter,
MLAN_BSS_ROLE_ANY),
MFALSE);
}
}
if (!pmadapter->data_sent && !wlan_wmm_lists_empty(pmadapter)
&& !wlan_11h_radar_detected_tx_blocked(pmadapter)
&& !wlan_is_tdls_link_chan_switching(pmadapter->tdls_status)
) {
wlan_wmm_process_tx(pmadapter);
if (pmadapter->hs_activated == MTRUE) {
pmadapter->is_hs_configured = MFALSE;
wlan_host_sleep_activated_event(wlan_get_priv
(pmadapter,
MLAN_BSS_ROLE_ANY),
MFALSE);
}
}
#ifdef STA_SUPPORT
if (pmadapter->delay_null_pkt && !pmadapter->cmd_sent &&
!pmadapter->curr_cmd && !IS_COMMAND_PENDING(pmadapter) &&
wlan_bypass_tx_list_empty(pmadapter) &&
wlan_wmm_lists_empty(pmadapter)) {
if (wlan_send_null_packet
(wlan_get_priv(pmadapter, MLAN_BSS_ROLE_STA),
MRVDRV_TxPD_POWER_MGMT_NULL_PACKET |
MRVDRV_TxPD_POWER_MGMT_LAST_PACKET)
== MLAN_STATUS_SUCCESS) {
pmadapter->delay_null_pkt = MFALSE;
}
break;
}
#endif
} while (MTRUE);
pcb->moal_spin_lock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
if (pmadapter->more_task_flag == MTRUE) {
pmadapter->more_task_flag = MFALSE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
goto process_start;
}
pmadapter->mlan_processing = MFALSE;
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
exit_main_proc:
if (pmadapter->hw_status == WlanHardwareStatusClosing)
mlan_shutdown_fw(pmadapter);
LEAVE();
return ret;
}
/**
* @brief Function to send packet
*
* @param pmlan_adapter A pointer to mlan_adapter structure
* @param pmbuf A pointer to mlan_buffer structure
*
* @return MLAN_STATUS_PENDING
*/
mlan_status
mlan_send_packet(IN t_void *pmlan_adapter, IN pmlan_buffer pmbuf)
{
mlan_status ret = MLAN_STATUS_PENDING;
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
mlan_private *pmpriv;
t_u16 eth_type = 0;
t_u8 ra[MLAN_MAC_ADDR_LENGTH];
tdlsStatus_e tdls_status;
ENTER();
MASSERT(pmlan_adapter &&pmbuf);
MASSERT(pmbuf->bss_index < pmadapter->priv_num);
pmbuf->flags |= MLAN_BUF_FLAG_MOAL_TX_BUF;
pmpriv = pmadapter->priv[pmbuf->bss_index];
eth_type =
mlan_ntohs(*(t_u16 *)&pmbuf->
pbuf[pmbuf->data_offset +
MLAN_ETHER_PKT_TYPE_OFFSET]);
if (((pmadapter->priv[pmbuf->bss_index]->port_ctrl_mode == MTRUE) &&
((eth_type == MLAN_ETHER_PKT_TYPE_EAPOL)
|| (eth_type == MLAN_ETHER_PKT_TYPE_WAPI)
))
|| (eth_type == MLAN_ETHER_PKT_TYPE_TDLS_ACTION)
|| (pmbuf->buf_type == MLAN_BUF_TYPE_RAW_DATA)
) {
if (eth_type == MLAN_ETHER_PKT_TYPE_TDLS_ACTION) {
memcpy(pmadapter, ra, pmbuf->pbuf + pmbuf->data_offset,
MLAN_MAC_ADDR_LENGTH);
tdls_status = wlan_get_tdls_link_status(pmpriv, ra);
if (MTRUE == wlan_is_tdls_link_setup(tdls_status) ||
!pmpriv->media_connected)
pmbuf->flags |= MLAN_BUF_FLAG_TDLS;
}
PRINTM(MINFO, "mlan_send_pkt(): enq(bybass_txq)\n");
wlan_add_buf_bypass_txqueue(pmadapter, pmbuf);
} else {
/* Transmit the packet */
wlan_wmm_add_buf_txqueue(pmadapter, pmbuf);
}
LEAVE();
return ret;
}
/**
* @brief MLAN ioctl handler
*
* @param adapter A pointer to mlan_adapter structure
* @param pioctl_req A pointer to ioctl request buffer
*
* @return MLAN_STATUS_SUCCESS/MLAN_STATUS_PENDING --success, otherwise fail
*/
mlan_status
mlan_ioctl(IN t_void *adapter, IN pmlan_ioctl_req pioctl_req)
{
mlan_status ret = MLAN_STATUS_SUCCESS;
pmlan_adapter pmadapter = (pmlan_adapter)adapter;
pmlan_private pmpriv = MNULL;
ENTER();
if (pioctl_req == MNULL) {
PRINTM(MERROR, "MLAN IOCTL information buffer is NULL\n");
ret = MLAN_STATUS_FAILURE;
goto exit;
}
if (pioctl_req->action == MLAN_ACT_CANCEL) {
wlan_cancel_pending_ioctl(pmadapter, pioctl_req);
ret = MLAN_STATUS_SUCCESS;
goto exit;
}
pmpriv = pmadapter->priv[pioctl_req->bss_index];
ret = pmpriv->ops.ioctl(adapter, pioctl_req);
exit:
LEAVE();
return ret;
}
/**
* @brief Packet receive completion callback handler
*
* @param pmlan_adapter A pointer to mlan_adapter structure
* @param pmbuf A pointer to mlan_buffer structure
* @param status Callback status
*
* @return MLAN_STATUS_SUCCESS
*/
mlan_status
mlan_recv_packet_complete(IN t_void *pmlan_adapter,
IN pmlan_buffer pmbuf, IN mlan_status status)
{
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
ENTER();
wlan_recv_packet_complete(pmadapter, pmbuf, status);
LEAVE();
return MLAN_STATUS_SUCCESS;
}
/**
* @brief select wmm queue
*
* @param pmlan_adapter A pointer to mlan_adapter structure
* @param bss_num BSS number
* @param tid TID
*
* @return wmm queue priority (0 - 3)
*/
t_u8
mlan_select_wmm_queue(IN t_void *pmlan_adapter, IN t_u8 bss_num, IN t_u8 tid)
{
mlan_adapter *pmadapter = (mlan_adapter *)pmlan_adapter;
pmlan_private pmpriv = pmadapter->priv[bss_num];
t_u8 ret;
ENTER();
ret = wlan_wmm_select_queue(pmpriv, tid);
LEAVE();
return ret;
}
/**
* @brief This function gets interrupt status.
*
* @param adapter A pointer to mlan_adapter structure
* @return N/A
*/
t_void
mlan_interrupt(IN t_void *adapter)
{
mlan_adapter *pmadapter = (mlan_adapter *)adapter;
ENTER();
if (!pmadapter->pps_uapsd_mode && pmadapter->ps_state == PS_STATE_SLEEP) {
pmadapter->pm_wakeup_fw_try = MFALSE;
pmadapter->ps_state = PS_STATE_AWAKE;
}
wlan_interrupt(pmadapter);
LEAVE();
}
/**
* @brief This function wakeup firmware.
*
* @param adapter A pointer to mlan_adapter structure
* @return N/A
*/
t_void
mlan_pm_wakeup_card(IN t_void *adapter)
{
mlan_adapter *pmadapter = (mlan_adapter *)adapter;
ENTER();
wlan_pm_wakeup_card(pmadapter);
LEAVE();
}
/**
* @brief This function check main_process status.
*
* @param adapter A pointer to mlan_adapter structure
* @return MTRUE/MFALSE
*/
t_u8
mlan_is_main_process_running(IN t_void *adapter)
{
mlan_adapter *pmadapter = (mlan_adapter *)adapter;
pmlan_callbacks pcb = &pmadapter->callbacks;
t_u8 ret = MFALSE;
ENTER();
pcb->moal_spin_lock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
/* Check if already processing */
if (pmadapter->mlan_processing) {
pmadapter->more_task_flag = MTRUE;
ret = MTRUE;
}
pcb->moal_spin_unlock(pmadapter->pmoal_handle,
pmadapter->pmain_proc_lock);
LEAVE();
return ret;
}