blob: d02a7b3bbfedab22729669debc20d369de94fb27 [file] [log] [blame]
/******************************************************************************
*
* This file is provided under a dual license. When you use or
* distribute this software, you may choose to be licensed under
* version 2 of the GNU General Public License ("GPLv2 License")
* or BSD License.
*
* GPLv2 License
*
* Copyright(C) 2016 MediaTek Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See http://www.gnu.org/licenses/gpl-2.0.html for more details.
*
* BSD LICENSE
*
* Copyright(C) 2016 MediaTek Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*****************************************************************************/
/*! \file wlan_lib.c
* \brief Internal driver stack will export the required procedures here for GLUE Layer.
*
* This file contains all routines which are exported from MediaTek 802.11 Wireless
* LAN driver stack to GLUE Layer.
*/
/*******************************************************************************
* C O M P I L E R F L A G S
********************************************************************************
*/
/*******************************************************************************
* E X T E R N A L R E F E R E N C E S
********************************************************************************
*/
#include "precomp.h"
#include "mgmt/ais_fsm.h"
/*******************************************************************************
* C O N S T A N T S
********************************************************************************
*/
/* 6.1.1.2 Interpretation of priority parameter in MAC service primitives */
/* Static convert the Priority Parameter/TID(User Priority/TS Identifier) to Traffic Class */
const UINT_8 aucPriorityParam2TC[] = {
TC1_INDEX,
TC0_INDEX,
TC0_INDEX,
TC1_INDEX,
TC2_INDEX,
TC2_INDEX,
TC3_INDEX,
TC3_INDEX
};
/*******************************************************************************
* D A T A T Y P E S
********************************************************************************
*/
typedef struct _CODE_MAPPING_T {
UINT_32 u4RegisterValue;
INT_32 u4TxpowerOffset;
} CODE_MAPPING_T, *P_CODE_MAPPING_T;
/*******************************************************************************
* P U B L I C D A T A
********************************************************************************
*/
BOOLEAN fgIsBusAccessFailed = FALSE;
/*******************************************************************************
* P R I V A T E D A T A
********************************************************************************
*/
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
#define SIGNED_EXTEND(n, _sValue) \
(((_sValue) & BIT((n)-1)) ? ((_sValue) | BITS(n, 31)) : \
((_sValue) & ~BITS(n, 31)))
/* TODO: Check */
/* OID set handlers without the need to access HW register */
PFN_OID_HANDLER_FUNC apfnOidSetHandlerWOHwAccess[] = {
wlanoidSetChannel,
wlanoidSetBeaconInterval,
wlanoidSetAtimWindow,
wlanoidSetFrequency,
};
/* TODO: Check */
/* OID query handlers without the need to access HW register */
PFN_OID_HANDLER_FUNC apfnOidQueryHandlerWOHwAccess[] = {
wlanoidQueryBssid,
wlanoidQuerySsid,
wlanoidQueryInfrastructureMode,
wlanoidQueryAuthMode,
wlanoidQueryEncryptionStatus,
wlanoidQueryPmkid,
wlanoidQueryNetworkTypeInUse,
wlanoidQueryBssidList,
wlanoidQueryAcpiDevicePowerState,
wlanoidQuerySupportedRates,
wlanoidQueryDesiredRates,
wlanoidQuery802dot11PowerSaveProfile,
wlanoidQueryBeaconInterval,
wlanoidQueryAtimWindow,
wlanoidQueryFrequency,
};
/* OID set handlers allowed in RF test mode */
PFN_OID_HANDLER_FUNC apfnOidSetHandlerAllowedInRFTest[] = {
wlanoidRftestSetTestMode,
wlanoidRftestSetAbortTestMode,
wlanoidRftestSetAutoTest,
wlanoidSetMcrWrite,
wlanoidSetEepromWrite
};
/* OID query handlers allowed in RF test mode */
PFN_OID_HANDLER_FUNC apfnOidQueryHandlerAllowedInRFTest[] = {
wlanoidRftestQueryAutoTest,
wlanoidQueryMcrRead,
wlanoidQueryEepromRead
}
;
PFN_OID_HANDLER_FUNC apfnOidWOTimeoutCheck[] = {
wlanoidRftestSetTestMode,
wlanoidRftestSetAbortTestMode,
wlanoidSetAcpiDevicePowerState,
};
#if CFG_SUPPORT_COMPRESSION_FW_OPTION
#define COMPRESSION_OPTION_OFFSET 4
#define COMPRESSION_OPTION_MASK BIT(4)
#endif
/*******************************************************************************
* M A C R O S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N D E C L A R A T I O N S
********************************************************************************
*/
/*******************************************************************************
* F U N C T I O N S
********************************************************************************
*/
/*----------------------------------------------------------------------------*/
/*!
* \brief This is a private routine, which is used to check if HW access is needed
* for the OID query/ set handlers.
*
* \param[IN] pfnOidHandler Pointer to the OID handler.
* \param[IN] fgSetInfo It is a Set information handler.
*
* \retval TRUE This function needs HW access
* \retval FALSE This function does not need HW access
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wlanIsHandlerNeedHwAccess(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo)
{
PFN_OID_HANDLER_FUNC *apfnOidHandlerWOHwAccess;
UINT_32 i;
UINT_32 u4NumOfElem;
if (fgSetInfo) {
apfnOidHandlerWOHwAccess = apfnOidSetHandlerWOHwAccess;
u4NumOfElem = sizeof(apfnOidSetHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC);
} else {
apfnOidHandlerWOHwAccess = apfnOidQueryHandlerWOHwAccess;
u4NumOfElem = sizeof(apfnOidQueryHandlerWOHwAccess) / sizeof(PFN_OID_HANDLER_FUNC);
}
for (i = 0; i < u4NumOfElem; i++) {
if (apfnOidHandlerWOHwAccess[i] == pfnOidHandler)
return FALSE;
}
return TRUE;
} /* wlanIsHandlerNeedHwAccess */
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is called to set flag for later handling card
* ejected event.
*
* \param[in] prAdapter Pointer to the Adapter structure.
*
* \return (none)
*
* \note When surprised removal happens, Glue layer should invoke this
* function to notify WPDD not to do any hw access.
*/
/*----------------------------------------------------------------------------*/
VOID wlanCardEjected(IN P_ADAPTER_T prAdapter)
{
DEBUGFUNC("wlanCardEjected");
/* INITLOG(("\n")); */
ASSERT(prAdapter);
/* mark that the card is being ejected, NDIS will shut us down soon */
nicTxRelease(prAdapter, FALSE);
} /* wlanCardEjected */
/*----------------------------------------------------------------------------*/
/*!
* \brief Create adapter object
*
* \param prAdapter This routine is call to allocate the driver software objects.
* If fails, return NULL.
* \retval NULL If it fails, NULL is returned.
* \retval NOT NULL If the adapter was initialized successfully.
*/
/*----------------------------------------------------------------------------*/
P_ADAPTER_T wlanAdapterCreate(IN P_GLUE_INFO_T prGlueInfo)
{
P_ADAPTER_T prAdpater = (P_ADAPTER_T) NULL;
DEBUGFUNC("wlanAdapterCreate");
do {
prAdpater = (P_ADAPTER_T) kalMemAlloc(sizeof(ADAPTER_T), VIR_MEM_TYPE);
if (!prAdpater) {
DBGLOG(INIT, ERROR, "Allocate ADAPTER memory ==> FAILED\n");
break;
}
#if QM_TEST_MODE
g_rQM.prAdapter = prAdpater;
#endif
kalMemZero(prAdpater, sizeof(ADAPTER_T));
prAdpater->prGlueInfo = prGlueInfo;
} while (FALSE);
return prAdpater;
} /* wlanAdapterCreate */
/*----------------------------------------------------------------------------*/
/*!
* \brief Destroy adapter object
*
* \param prAdapter This routine is call to destroy the driver software objects.
* If fails, return NULL.
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID wlanAdapterDestroy(IN P_ADAPTER_T prAdapter)
{
if (!prAdapter)
return;
kalMemFree(prAdapter, VIR_MEM_TYPE, sizeof(ADAPTER_T));
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Initialize the adapter. The sequence is
* 1. Disable interrupt
* 2. Read adapter configuration from EEPROM and registry, verify chip ID.
* 3. Create NIC Tx/Rx resource.
* 4. Initialize the chip
* 5. Initialize the protocol
* 6. Enable Interrupt
*
* \param prAdapter Pointer of Adapter Data Structure
*
* \retval WLAN_STATUS_SUCCESS: Success
* \retval WLAN_STATUS_FAILURE: Failed
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanAdapterStart(IN P_ADAPTER_T prAdapter, IN P_REG_INFO_T prRegInfo)
{
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
UINT_32 i;
ASSERT(prAdapter);
DEBUGFUNC("wlanAdapterStart");
/* 4 <0> Reset variables in ADAPTER_T */
/* prAdapter->fgIsFwOwn = TRUE; */
prAdapter->fgIsEnterD3ReqIssued = FALSE;
prAdapter->u4OwnFailedCount = 0;
prAdapter->u4OwnFailedLogCount = 0;
QUEUE_INITIALIZE(&(prAdapter->rPendingCmdQueue));
#if CFG_SUPPORT_MULTITHREAD
QUEUE_INITIALIZE(&prAdapter->rTxCmdQueue);
QUEUE_INITIALIZE(&prAdapter->rTxCmdDoneQueue);
#if CFG_FIX_2_TX_PORT
QUEUE_INITIALIZE(&prAdapter->rTxP0Queue);
QUEUE_INITIALIZE(&prAdapter->rTxP1Queue);
#else
for (i = 0; i < TX_PORT_NUM; i++)
QUEUE_INITIALIZE(&prAdapter->rTxPQueue[i]);
#endif
QUEUE_INITIALIZE(&prAdapter->rRxQueue);
QUEUE_INITIALIZE(&prAdapter->rTxDataDoneQueue);
#endif
/* Initialize rWlanInfo */
kalMemSet(&(prAdapter->rWlanInfo), 0, sizeof(WLAN_INFO_T));
/* Initialize aprBssInfo[].
* Important: index shall be same when mapping between aprBssInfo[]
* and arBssInfoPool[]. rP2pDevInfo is indexed to final one.
*/
for (i = 0; i < BSS_INFO_NUM; i++)
prAdapter->aprBssInfo[i] = &prAdapter->rWifiVar.arBssInfoPool[i];
prAdapter->aprBssInfo[P2P_DEV_BSS_INDEX] = &prAdapter->rWifiVar.rP2pDevInfo;
/* 4 <0.1> reset fgIsBusAccessFailed */
fgIsBusAccessFailed = FALSE;
do {
u4Status = nicAllocateAdapterMemory(prAdapter);
if (u4Status != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "nicAllocateAdapterMemory Error!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
prAdapter->u4OsPacketFilter = PARAM_PACKET_FILTER_SUPPORTED;
DBGLOG(INIT, INFO, "wlanAdapterStart(): Acquiring LP-OWN\n");
ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter);
DBGLOG(INIT, INFO, "wlanAdapterStart(): Acquiring LP-OWN-end\n");
#if (CFG_ENABLE_FULL_PM == 0)
nicpmSetDriverOwn(prAdapter);
#endif
if (prAdapter->fgIsFwOwn == TRUE) {
DBGLOG(INIT, ERROR, "nicpmSetDriverOwn() failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
/* 4 <1> Initialize the Adapter */
u4Status = nicInitializeAdapter(prAdapter);
if (u4Status != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "nicInitializeAdapter failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
/* 4 <2.1> Initialize System Service (MGMT Memory pool and STA_REC) */
nicInitSystemService(prAdapter);
/* 4 <2.2> Initialize Feature Options */
wlanInitFeatureOption(prAdapter);
#if CFG_SUPPORT_MTK_SYNERGY
if (kalIsConfigurationExist(prAdapter->prGlueInfo) == TRUE) {
if (prRegInfo->prNvramSettings->u2FeatureReserved & BIT(MTK_FEATURE_2G_256QAM_DISABLED))
prAdapter->rWifiVar.aucMtkFeature[0] &= ~(MTK_SYNERGY_CAP_SUPPORT_24G_MCS89);
}
#endif
/* 4 <2.3> Overwrite debug level settings */
wlanCfgSetDebugLevel(prAdapter);
/* 4 <3> Initialize Tx */
nicTxInitialize(prAdapter);
wlanDefTxPowerCfg(prAdapter);
/* 4 <4> Initialize Rx */
nicRxInitialize(prAdapter);
/* 4 <5> HIF SW info initialize */
halHifSwInfoInit(prAdapter);
/* 4 <6> Enable HIF cut-through to N9 mode, not visiting CR4 */
HAL_ENABLE_FWDL(prAdapter, TRUE);
/* 4 <7> Get ECO Version */
u4Status = wlanSetChipEcoInfo(prAdapter);
if (u4Status != WLAN_STATUS_SUCCESS)
break;
#if CFG_ENABLE_FW_DOWNLOAD
/* 4 <8> FW/patch download */
/* 1. disable interrupt, download is done by polling mode only */
nicDisableInterrupt(prAdapter);
/* 2. Initialize Tx Resource to fw download state */
nicTxInitResetResource(prAdapter);
u4Status = wlanDownloadFW(prAdapter);
if (u4Status != WLAN_STATUS_SUCCESS)
break;
#endif
DBGLOG(INIT, INFO, "Waiting for Ready bit..\n");
/* 4 <9> check Wi-Fi FW asserts ready bit */
u4Status = wlanCheckWifiFunc(prAdapter, TRUE);
if (u4Status == WLAN_STATUS_SUCCESS) {
#if defined(_HIF_SDIO)
UINT_32 u4WHISR = 0;
UINT_16 au2TxCount[16];
/* 1. reset interrupt status */
HAL_READ_INTR_STATUS(prAdapter, 4, (PUINT_8)&u4WHISR);
if (HAL_IS_TX_DONE_INTR(u4WHISR))
HAL_READ_TX_RELEASED_COUNT(prAdapter, au2TxCount);
#endif
/* Set FW download success flag */
prAdapter->fgIsFwDownloaded = TRUE;
/* 2. query & reset TX Resource for normal operation */
wlanQueryNicResourceInformation(prAdapter);
#if (CFG_SUPPORT_NIC_CAPABILITY == 1)
/* 2.9 Workaround for Capability CMD packet lost issue */
DBGLOG(INIT, WARN, "Send a Dummy CMD as workaround\n");
wlanSendDummyCmd(prAdapter, TRUE);
/* 3. query for NIC capability */
wlanQueryNicCapability(prAdapter);
/* 4. query for NIC capability V2 */
wlanQueryNicCapabilityV2(prAdapter);
/* 5. reset TX Resource for normal operation
* based on the information reported from CMD_NicCapabilityV2
*/
wlanUpdateNicResourceInformation(prAdapter);
wlanPrintVersion(prAdapter);
#endif
/* 6. update basic configuration */
wlanUpdateBasicConfig(prAdapter);
/* 7. Override network address */
wlanUpdateNetworkAddress(prAdapter);
/* 8. Apply Network Address */
#if KERNEL_VERSION(4, 5, 0) > LINUX_VERSION_CODE
nicApplyNetworkAddress(prAdapter);
#endif
/* 9. indicate disconnection as default status */
kalIndicateStatusAndComplete(prAdapter->prGlueInfo, WLAN_STATUS_MEDIA_DISCONNECT, NULL, 0);
}
RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE);
if (u4Status != WLAN_STATUS_SUCCESS)
break;
/* OID timeout timer initialize */
cnmTimerInitTimer(prAdapter,
&prAdapter->rOidTimeoutTimer,
(PFN_MGMT_TIMEOUT_FUNC) wlanReleasePendingOid, (ULONG) NULL);
prAdapter->ucOidTimeoutCount = 0;
prAdapter->fgIsChipNoAck = FALSE;
/* Return Indicated Rfb list timer */
cnmTimerInitTimer(prAdapter,
&prAdapter->rPacketDelaySetupTimer,
(PFN_MGMT_TIMEOUT_FUNC) wlanReturnPacketDelaySetupTimeout, (ULONG) NULL);
/* Power state initialization */
prAdapter->fgWiFiInSleepyState = FALSE;
prAdapter->rAcpiState = ACPI_STATE_D0;
#if 0
/* Online scan option */
if (prRegInfo->fgDisOnlineScan == 0)
prAdapter->fgEnOnlineScan = TRUE;
else
prAdapter->fgEnOnlineScan = FALSE;
/* Beacon lost detection option */
if (prRegInfo->fgDisBcnLostDetection != 0)
prAdapter->fgDisBcnLostDetection = TRUE;
#else
if (prAdapter->rWifiVar.fgDisOnlineScan == 0)
prAdapter->fgEnOnlineScan = TRUE;
else
prAdapter->fgEnOnlineScan = FALSE;
/* Beacon lost detection option */
if (prAdapter->rWifiVar.fgDisBcnLostDetection != 0)
prAdapter->fgDisBcnLostDetection = TRUE;
#endif
/* Load compile time constant */
prAdapter->rWlanInfo.u2BeaconPeriod = CFG_INIT_ADHOC_BEACON_INTERVAL;
prAdapter->rWlanInfo.u2AtimWindow = CFG_INIT_ADHOC_ATIM_WINDOW;
#if 1 /* set PM parameters */
prAdapter->u4PsCurrentMeasureEn = prRegInfo->u4PsCurrentMeasureEn;
#if 0
prAdapter->fgEnArpFilter = prRegInfo->fgEnArpFilter;
prAdapter->u4UapsdAcBmp = prRegInfo->u4UapsdAcBmp;
prAdapter->u4MaxSpLen = prRegInfo->u4MaxSpLen;
#else
prAdapter->fgEnArpFilter = prAdapter->rWifiVar.fgEnArpFilter;
prAdapter->u4UapsdAcBmp = prAdapter->rWifiVar.u4UapsdAcBmp;
prAdapter->u4MaxSpLen = prAdapter->rWifiVar.u4MaxSpLen;
#endif
DBGLOG(INIT, TRACE, "[1] fgEnArpFilter:0x%x, u4UapsdAcBmp:0x%x, u4MaxSpLen:0x%x",
prAdapter->fgEnArpFilter, prAdapter->u4UapsdAcBmp, prAdapter->u4MaxSpLen);
prAdapter->fgEnCtiaPowerMode = FALSE;
#endif
/* MGMT Initialization */
nicInitMGMT(prAdapter, prRegInfo);
/* Enable WZC Disassociation */
prAdapter->rWifiVar.fgSupportWZCDisassociation = TRUE;
/* Apply Rate Setting */
if ((ENUM_REGISTRY_FIXED_RATE_T) (prRegInfo->u4FixedRate) < FIXED_RATE_NUM)
prAdapter->rWifiVar.eRateSetting = (ENUM_REGISTRY_FIXED_RATE_T) (prRegInfo->u4FixedRate);
else
prAdapter->rWifiVar.eRateSetting = FIXED_RATE_NONE;
if (prAdapter->rWifiVar.eRateSetting == FIXED_RATE_NONE) {
/* Enable Auto (Long/Short) Preamble */
prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_AUTO;
} else if ((prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_20M_400NS &&
prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS7_20M_400NS)
|| (prAdapter->rWifiVar.eRateSetting >= FIXED_RATE_MCS0_40M_400NS &&
prAdapter->rWifiVar.eRateSetting <= FIXED_RATE_MCS32_400NS)) {
/* Force Short Preamble */
prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_SHORT;
} else {
/* Force Long Preamble */
prAdapter->rWifiVar.ePreambleType = PREAMBLE_TYPE_LONG;
}
/* Disable Hidden SSID Join */
prAdapter->rWifiVar.fgEnableJoinToHiddenSSID = FALSE;
/* Enable Short Slot Time */
prAdapter->rWifiVar.fgIsShortSlotTimeOptionEnable = TRUE;
/* configure available PHY type set */
nicSetAvailablePhyTypeSet(prAdapter);
#if 0 /* Marked for MT6630 */
#if 1 /* set PM parameters */
{
#if CFG_SUPPORT_PWR_MGT
prAdapter->u4PowerMode = prRegInfo->u4PowerMode;
#if CFG_ENABLE_WIFI_DIRECT
prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucNetTypeIndex =
NETWORK_TYPE_P2P_INDEX;
prAdapter->rWlanInfo.arPowerSaveMode[NETWORK_TYPE_P2P_INDEX].ucPsProfile = ENUM_PSP_FAST_SWITCH;
#endif
#else
prAdapter->u4PowerMode = ENUM_PSP_CONTINUOUS_ACTIVE;
#endif
nicConfigPowerSaveProfile(prAdapter,
prAdapter->prAisBssInfo->ucBssIndex, prAdapter->u4PowerMode, FALSE);
}
#endif
#endif
/* Check if it is disabled by hardware */
if (prAdapter->fgIsHw5GBandDisabled)
prAdapter->fgEnable5GBand = FALSE;
else
prAdapter->fgEnable5GBand = TRUE;
#if CFG_SUPPORT_NVRAM
/* load manufacture data */
if (kalIsConfigurationExist(prAdapter->prGlueInfo) == TRUE)
wlanLoadManufactureData(prAdapter, prRegInfo);
else
DBGLOG(INIT, WARN, "%s: load manufacture data fail\n", __func__);
#endif
#if 0
/* Update Auto rate parameters in FW */
nicRlmArUpdateParms(prAdapter,
prRegInfo->u4ArSysParam0,
prRegInfo->u4ArSysParam1, prRegInfo->u4ArSysParam2, prRegInfo->u4ArSysParam3);
#endif
} while (FALSE);
if (u4Status == WLAN_STATUS_SUCCESS) {
/* restore to hardware default */
HAL_SET_INTR_STATUS_READ_CLEAR(prAdapter);
HAL_SET_MAILBOX_READ_CLEAR(prAdapter, FALSE);
/* Enable interrupt */
nicEnableInterrupt(prAdapter);
} else {
/* release allocated memory */
nicReleaseAdapterMemory(prAdapter);
}
return u4Status;
} /* wlanAdapterStart */
/*----------------------------------------------------------------------------*/
/*!
* \brief Uninitialize the adapter
*
* \param prAdapter Pointer of Adapter Data Structure
*
* \retval WLAN_STATUS_SUCCESS: Success
* \retval WLAN_STATUS_FAILURE: Failed
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanAdapterStop(IN P_ADAPTER_T prAdapter)
{
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
ASSERT(prAdapter);
/* MGMT - unitialization */
nicUninitMGMT(prAdapter);
/* Release all CMD/MGMT/SEC frame in command queue */
kalClearCommandQueue(prAdapter->prGlueInfo);
#if CFG_SUPPORT_MULTITHREAD
/* Flush all items in queues for multi-thread */
wlanClearTxCommandQueue(prAdapter);
wlanClearTxCommandDoneQueue(prAdapter);
wlanClearDataQueue(prAdapter);
wlanClearRxToOsQueue(prAdapter);
#endif
/* Hif power off wifi */
#if 1
wlanPowerOffWifi(prAdapter);
#else
if (prAdapter->rAcpiState == ACPI_STATE_D0 &&
!wlanIsChipNoAck(prAdapter) && !kalIsCardRemoved(prAdapter->prGlueInfo)) {
/* 0. Disable interrupt, this can be done without Driver own */
nicDisableInterrupt(prAdapter);
ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter);
/* 1. Set CMD to FW to tell WIFI to stop (enter power off state) */
if (prAdapter->fgIsFwOwn == FALSE && wlanSendNicPowerCtrlCmd(prAdapter, 1) == WLAN_STATUS_SUCCESS) {
UINT_32 i;
/* 2. Clear pending interrupt */
i = 0;
while (i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) {
i++;
};
/* 3. Wait til RDY bit has been cleaerd */
wlanCheckWifiFunc(prAdapter, FALSE);
}
#if !CFG_ENABLE_FULL_PM
/* 4. Set Onwership to F/W */
nicpmSetFWOwn(prAdapter, FALSE);
#endif
#if CFG_FORCE_RESET_UNDER_BUS_ERROR
if (HAL_TEST_FLAG(prAdapter, ADAPTER_FLAG_HW_ERR) == TRUE) {
/* force acquire firmware own */
kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_CLR);
/* delay for 10ms */
kalMdelay(10);
/* force firmware reset via software interrupt */
kalDevRegWrite(prAdapter->prGlueInfo, MCR_WSICR, WSICR_H2D_SW_INT_SET);
/* force release firmware own */
kalDevRegWrite(prAdapter->prGlueInfo, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET);
}
#endif
RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE);
}
#endif
nicRxUninitialize(prAdapter);
nicTxRelease(prAdapter, FALSE);
/* System Service Uninitialization */
nicUninitSystemService(prAdapter);
nicReleaseAdapterMemory(prAdapter);
#if defined(_HIF_SPI)
/* Note: restore the SPI Mode Select from 32 bit to default */
nicRestoreSpiDefMode(prAdapter);
#endif
return u4Status;
} /* wlanAdapterStop */
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called by ISR (interrupt).
*
* \param prAdapter Pointer of Adapter Data Structure
*
* \retval TRUE: NIC's interrupt
* \retval FALSE: Not NIC's interrupt
*/
/*----------------------------------------------------------------------------*/
BOOL wlanISR(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgGlobalIntrCtrl)
{
ASSERT(prAdapter);
if (fgGlobalIntrCtrl) {
nicDisableInterrupt(prAdapter);
/* wlanIST(prAdapter); */
}
return TRUE;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called by IST (task_let).
*
* \param prAdapter Pointer of Adapter Data Structure
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID wlanIST(IN P_ADAPTER_T prAdapter)
{
ASSERT(prAdapter);
ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter);
nicProcessIST(prAdapter);
#if defined(CONFIG_ANDROID) && (CFG_ENABLE_WAKE_LOCK)
if (KAL_WAKE_LOCK_ACTIVE(prAdapter, &prAdapter->prGlueInfo->rIntrWakeLock))
KAL_WAKE_UNLOCK(prAdapter, &prAdapter->prGlueInfo->rIntrWakeLock);
#endif
nicEnableInterrupt(prAdapter);
RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE);
}
VOID wlanClearPendingInterrupt(IN P_ADAPTER_T prAdapter)
{
UINT_32 i;
i = 0;
while (i < CFG_IST_LOOP_COUNT && nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) {
i++;
};
}
WLAN_STATUS wlanCheckWifiFunc(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgRdyChk)
{
BOOLEAN fgResult, fgTimeout;
UINT_32 u4Result, u4Status, u4StartTime, u4CurTime;
u4StartTime = kalGetTimeTick();
fgTimeout = FALSE;
#if defined(_HIF_USB)
if (prAdapter->prGlueInfo->rHifInfo.state == USB_STATE_LINK_DOWN)
return WLAN_STATUS_FAILURE;
#endif
while (TRUE) {
if (fgRdyChk)
HAL_WIFI_FUNC_READY_CHECK(prAdapter, WIFI_FUNC_READY_BITS, &fgResult);
else {
HAL_WIFI_FUNC_OFF_CHECK(prAdapter, WIFI_FUNC_READY_BITS, &fgResult);
if (nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING)
DBGLOG(INIT, INFO, "Handle pending interrupt\n");
}
u4CurTime = kalGetTimeTick();
if (CHECK_FOR_TIMEOUT(u4CurTime, u4StartTime,
CFG_RESPONSE_POLLING_TIMEOUT * CFG_RESPONSE_POLLING_DELAY)) {
fgTimeout = TRUE;
}
if (fgResult) {
if (fgRdyChk)
DBGLOG(INIT, INFO, "Ready bit asserted\n");
else
DBGLOG(INIT, INFO, "Wi-Fi power off done!\n");
u4Status = WLAN_STATUS_SUCCESS;
break;
} else if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) {
u4Status = WLAN_STATUS_FAILURE;
break;
} else if (fgTimeout) {
HAL_WIFI_FUNC_GET_STATUS(prAdapter, u4Result);
DBGLOG(INIT, ERROR, "Waiting for %s: Timeout, Status=0x%08x\n",
fgRdyChk ? "ready bit" : "power off", u4Result);
u4Status = WLAN_STATUS_FAILURE;
break;
}
kalMsleep(CFG_RESPONSE_POLLING_DELAY);
}
return u4Status;
}
WLAN_STATUS wlanPowerOffWifi(IN P_ADAPTER_T prAdapter)
{
WLAN_STATUS rStatus;
/* Hif power off wifi */
rStatus = halHifPowerOffWifi(prAdapter);
prAdapter->fgIsCr4FwDownloaded = FALSE;
return rStatus;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function will check command queue to find out if any could be dequeued
* and/or send to HIF to MT6620
*
* \param prAdapter Pointer of Adapter Data Structure
* \param prCmdQue Pointer of Command Queue (in Glue Layer)
*
* \retval WLAN_STATUS_SUCCESS
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanProcessCommandQueue(IN P_ADAPTER_T prAdapter, IN P_QUE_T prCmdQue)
{
WLAN_STATUS rStatus;
QUE_T rTempCmdQue, rMergeCmdQue, rStandInCmdQue;
P_QUE_T prTempCmdQue, prMergeCmdQue, prStandInCmdQue;
P_QUE_ENTRY_T prQueueEntry;
P_CMD_INFO_T prCmdInfo;
P_MSDU_INFO_T prMsduInfo;
ENUM_FRAME_ACTION_T eFrameAction = FRAME_ACTION_DROP_PKT;
KAL_SPIN_LOCK_DECLARATION();
ASSERT(prAdapter);
ASSERT(prCmdQue);
prTempCmdQue = &rTempCmdQue;
prMergeCmdQue = &rMergeCmdQue;
prStandInCmdQue = &rStandInCmdQue;
QUEUE_INITIALIZE(prTempCmdQue);
QUEUE_INITIALIZE(prMergeCmdQue);
QUEUE_INITIALIZE(prStandInCmdQue);
/* 4 <1> Move whole list of CMD_INFO to temp queue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE);
QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE);
/* 4 <2> Dequeue from head and check it is able to be sent */
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
switch (prCmdInfo->eCmdType) {
case COMMAND_TYPE_GENERAL_IOCTL:
case COMMAND_TYPE_NETWORK_IOCTL:
/* command packet will be always sent */
eFrameAction = FRAME_ACTION_TX_PKT;
break;
case COMMAND_TYPE_SECURITY_FRAME:
/* inquire with QM */
prMsduInfo = prCmdInfo->prMsduInfo;
eFrameAction = qmGetFrameAction(prAdapter, prMsduInfo->ucBssIndex,
prMsduInfo->ucStaRecIndex, NULL, FRAME_TYPE_802_1X,
prCmdInfo->u2InfoBufLen);
break;
case COMMAND_TYPE_MANAGEMENT_FRAME:
/* inquire with QM */
prMsduInfo = prCmdInfo->prMsduInfo;
eFrameAction = qmGetFrameAction(prAdapter, prMsduInfo->ucBssIndex,
prMsduInfo->ucStaRecIndex, prMsduInfo, FRAME_TYPE_MMPDU,
prMsduInfo->u2FrameLength);
break;
default:
ASSERT(0);
break;
}
/* 4 <3> handling upon dequeue result */
if (eFrameAction == FRAME_ACTION_DROP_PKT) {
DBGLOG(INIT, INFO, "DROP CMD TYPE[%u] ID[0x%02X] SEQ[%u]\n",
prCmdInfo->eCmdType, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum);
wlanReleaseCommand(prAdapter, prCmdInfo, TX_RESULT_DROPPED_IN_DRIVER);
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
} else if (eFrameAction == FRAME_ACTION_QUEUE_PKT) {
DBGLOG(INIT, TRACE, "QUE back CMD TYPE[%u] ID[0x%02X] SEQ[%u]\n",
prCmdInfo->eCmdType, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum);
QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry);
} else if (eFrameAction == FRAME_ACTION_TX_PKT) {
/* 4 <4> Send the command */
#if CFG_SUPPORT_MULTITHREAD
rStatus = wlanSendCommandMthread(prAdapter, prCmdInfo);
if (rStatus == WLAN_STATUS_RESOURCES) {
/* no more TC4 resource for further transmission */
DBGLOG(INIT, WARN, "NO Res CMD TYPE[%u] ID[0x%02X] SEQ[%u]\n",
prCmdInfo->eCmdType, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum);
set_bit(GLUE_FLAG_HIF_PRT_HIF_DBG_INFO_BIT, &(prAdapter->prGlueInfo->ulFlag));
QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry);
break;
} else if (rStatus == WLAN_STATUS_PENDING) {
/* Do nothing */
/* Do nothing */
} else if (rStatus == WLAN_STATUS_SUCCESS) {
/* Do nothing */
/* Do nothing */
} else {
P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
if (prCmdInfo->fgIsOid) {
kalOidComplete(prAdapter->prGlueInfo, prCmdInfo->fgSetQuery,
prCmdInfo->u4SetInfoLen, rStatus);
}
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
}
#else
rStatus = wlanSendCommand(prAdapter, prCmdInfo);
if (rStatus == WLAN_STATUS_RESOURCES) {
/* no more TC4 resource for further transmission */
DBGLOG(INIT, WARN, "NO Resource for CMD TYPE[%u] ID[0x%02X] SEQ[%u]\n",
prCmdInfo->eCmdType, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum);
QUEUE_INSERT_TAIL(prMergeCmdQue, prQueueEntry);
break;
} else if (rStatus == WLAN_STATUS_PENDING) {
/* command packet which needs further handling upon response */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), prQueueEntry);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
} else {
P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
if (rStatus == WLAN_STATUS_SUCCESS) {
if (prCmdInfo->pfCmdDoneHandler) {
prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo,
prCmdInfo->pucInfoBuffer);
}
} else {
if (prCmdInfo->fgIsOid) {
kalOidComplete(prAdapter->prGlueInfo,
prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, rStatus);
}
}
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
}
#endif
} else {
ASSERT(0);
}
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
}
/* 4 <3> Merge back to original queue */
/* 4 <3.1> Merge prMergeCmdQue & prTempCmdQue */
QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prTempCmdQue);
/* 4 <3.2> Move prCmdQue to prStandInQue, due to prCmdQue might differ due to incoming 802.1X frames */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE);
QUEUE_MOVE_ALL(prStandInCmdQue, prCmdQue);
/* 4 <3.3> concatenate prStandInQue to prMergeCmdQue */
QUEUE_CONCATENATE_QUEUES(prMergeCmdQue, prStandInCmdQue);
/* 4 <3.4> then move prMergeCmdQue to prCmdQue */
QUEUE_MOVE_ALL(prCmdQue, prMergeCmdQue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_QUE);
#if CFG_SUPPORT_MULTITHREAD
kalSetTxCmdEvent2Hif(prAdapter->prGlueInfo);
#endif
return WLAN_STATUS_SUCCESS;
} /* end of wlanProcessCommandQueue() */
/*----------------------------------------------------------------------------*/
/*!
* \brief This function will take CMD_INFO_T which carry some information of
* incoming OID and notify the NIC_TX to send CMD.
*
* \param prAdapter Pointer of Adapter Data Structure
* \param prCmdInfo Pointer of P_CMD_INFO_T
*
* \retval WLAN_STATUS_SUCCESS : CMD was written to HIF and be freed(CMD Done) immediately.
* \retval WLAN_STATUS_RESOURCE : No resource for current command, need to wait for previous
* frame finishing their transmission.
* \retval WLAN_STATUS_FAILURE : Get failure while access HIF or been rejected.
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanSendCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo)
{
P_TX_CTRL_T prTxCtrl;
UINT_8 ucTC; /* "Traffic Class" SW(Driver) resource classification */
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
ASSERT(prAdapter);
ASSERT(prCmdInfo);
prTxCtrl = &prAdapter->rTxCtrl;
do {
/* <0> card removal check */
if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) {
rStatus = WLAN_STATUS_FAILURE;
break;
}
/* <1.1> Assign Traffic Class(TC) */
ucTC = nicTxGetCmdResourceType(prCmdInfo);
/* <1.2> Check if pending packet or resource was exhausted */
rStatus = nicTxAcquireResource(prAdapter, ucTC, nicTxGetCmdPageCount(prCmdInfo), TRUE);
if (rStatus == WLAN_STATUS_RESOURCES) {
DBGLOG(INIT, INFO, "NO Resource:%d\n", ucTC);
break;
}
/* <1.3> Forward CMD_INFO_T to NIC Layer */
rStatus = nicTxCmd(prAdapter, prCmdInfo, ucTC);
/* <1.4> Set Pending in response to Query Command/Need Response */
if (rStatus == WLAN_STATUS_SUCCESS) {
if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp))
rStatus = WLAN_STATUS_PENDING;
}
} while (FALSE);
return rStatus;
} /* end of wlanSendCommand() */
#if CFG_SUPPORT_MULTITHREAD
/*----------------------------------------------------------------------------*/
/*!
* \brief This function will take CMD_INFO_T which carry some information of
* incoming OID and notify the NIC_TX to send CMD.
*
* \param prAdapter Pointer of Adapter Data Structure
* \param prCmdInfo Pointer of P_CMD_INFO_T
*
* \retval WLAN_STATUS_SUCCESS : CMD was written to HIF and be freed(CMD Done) immediately.
* \retval WLAN_STATUS_RESOURCE : No resource for current command, need to wait for previous
* frame finishing their transmission.
* \retval WLAN_STATUS_FAILURE : Get failure while access HIF or been rejected.
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanSendCommandMthread(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo)
{
P_TX_CTRL_T prTxCtrl;
UINT_8 ucTC; /* "Traffic Class" SW(Driver) resource classification */
WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS;
QUE_T rTempCmdQue;
P_QUE_T prTempCmdQue;
KAL_SPIN_LOCK_DECLARATION();
ASSERT(prAdapter);
ASSERT(prCmdInfo);
prTxCtrl = &prAdapter->rTxCtrl;
prTempCmdQue = &rTempCmdQue;
QUEUE_INITIALIZE(prTempCmdQue);
do {
/* <0> card removal check */
if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) {
rStatus = WLAN_STATUS_FAILURE;
break;
}
/* <1> Normal case of sending CMD Packet */
/* <1.1> Assign Traffic Class(TC) */
ucTC = nicTxGetCmdResourceType(prCmdInfo);
/* <1.2> Check if pending packet or resource was exhausted */
rStatus = nicTxAcquireResource(prAdapter, ucTC, nicTxGetCmdPageCount(prCmdInfo), TRUE);
if (rStatus == WLAN_STATUS_RESOURCES) {
#if 0
DBGLOG(INIT, WARN, "%s: NO Resource for CMD TYPE[%u] ID[0x%02X] SEQ[%u] TC[%u]\n",
__func__, prCmdInfo->eCmdType, prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, ucTC);
#endif
break;
}
/* Process to pending command queue firest */
if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) {
/* command packet which needs further handling upon response */
/*
* KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
* QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), (P_QUE_ENTRY_T)prCmdInfo);
* KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
*/
}
QUEUE_INSERT_TAIL(prTempCmdQue, (P_QUE_ENTRY_T) prCmdInfo);
/* <1.4> Set Pending in response to Query Command/Need Response */
if (rStatus == WLAN_STATUS_SUCCESS) {
if ((!prCmdInfo->fgSetQuery) ||
(prCmdInfo->fgNeedResp) || (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME)) {
rStatus = WLAN_STATUS_PENDING;
}
}
} while (FALSE);
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE);
QUEUE_CONCATENATE_QUEUES(&(prAdapter->rTxCmdQueue), prTempCmdQue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE);
return rStatus;
} /* end of wlanSendCommandMthread() */
VOID wlanTxCmdDoneCb(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo)
{
KAL_SPIN_LOCK_DECLARATION();
if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) {
#if 0
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
QUEUE_INSERT_TAIL(&prAdapter->rPendingCmdQueue, (P_QUE_ENTRY_T) prCmdInfo);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
#endif
} else {
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE);
QUEUE_INSERT_TAIL(&prAdapter->rTxCmdDoneQueue, (P_QUE_ENTRY_T) prCmdInfo);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE);
}
/* call tx thread to work */
set_bit(GLUE_FLAG_TX_CMD_DONE_BIT, &prAdapter->prGlueInfo->ulFlag);
wake_up_interruptible(&prAdapter->prGlueInfo->waitq);
}
WLAN_STATUS wlanTxCmdMthread(IN P_ADAPTER_T prAdapter)
{
QUE_T rTempCmdQue;
P_QUE_T prTempCmdQue;
QUE_T rTempCmdDoneQue;
P_QUE_T prTempCmdDoneQue;
P_QUE_ENTRY_T prQueueEntry;
P_CMD_INFO_T prCmdInfo;
/* P_CMD_ACCESS_REG prCmdAccessReg;
* P_CMD_ACCESS_REG prEventAccessReg;
* UINT_32 u4Address;
*/
UINT_32 u4TxDoneQueueSize;
KAL_SPIN_LOCK_DECLARATION();
ASSERT(prAdapter);
prTempCmdQue = &rTempCmdQue;
QUEUE_INITIALIZE(prTempCmdQue);
prTempCmdDoneQue = &rTempCmdDoneQue;
QUEUE_INITIALIZE(prTempCmdDoneQue);
KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_CMD_CLEAR);
/* TX Command Queue */
/* 4 <1> Move whole list of CMD_INFO to temp queue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE);
QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rTxCmdQueue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE);
/* 4 <2> Dequeue from head and check it is able to be sent */
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
prCmdInfo->pfHifTxCmdDoneCb = wlanTxCmdDoneCb;
if ((!prCmdInfo->fgSetQuery) || (prCmdInfo->fgNeedResp)) {
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
QUEUE_INSERT_TAIL(&(prAdapter->rPendingCmdQueue), (P_QUE_ENTRY_T) prCmdInfo);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
} else {
QUEUE_INSERT_TAIL(prTempCmdDoneQue, prQueueEntry);
}
nicTxCmd(prAdapter, prCmdInfo, TC4_INDEX);
/* DBGLOG(INIT, INFO,
* ("==> TX CMD QID: %d (Q:%d)\n", prCmdInfo->ucCID, prTempCmdQue->u4NumElem));
*/
GLUE_DEC_REF_CNT(prAdapter->prGlueInfo->i4TxPendingCmdNum);
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
}
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE);
QUEUE_CONCATENATE_QUEUES(&prAdapter->rTxCmdDoneQueue, prTempCmdDoneQue);
u4TxDoneQueueSize = prAdapter->rTxCmdDoneQueue.u4NumElem;
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE);
KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_CMD_CLEAR);
if (u4TxDoneQueueSize > 0) {
/* call tx thread to work */
set_bit(GLUE_FLAG_TX_CMD_DONE_BIT, &prAdapter->prGlueInfo->ulFlag);
wake_up_interruptible(&prAdapter->prGlueInfo->waitq);
}
return WLAN_STATUS_SUCCESS;
}
WLAN_STATUS wlanTxCmdDoneMthread(IN P_ADAPTER_T prAdapter)
{
QUE_T rTempCmdQue;
P_QUE_T prTempCmdQue;
P_QUE_ENTRY_T prQueueEntry;
P_CMD_INFO_T prCmdInfo;
KAL_SPIN_LOCK_DECLARATION();
ASSERT(prAdapter);
prTempCmdQue = &rTempCmdQue;
QUEUE_INITIALIZE(prTempCmdQue);
/* 4 <1> Move whole list of CMD_INFO to temp queue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE);
QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rTxCmdDoneQueue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE);
/* 4 <2> Dequeue from head and check it is able to be sent */
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
if (prCmdInfo->pfCmdDoneHandler)
prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prCmdInfo->pucInfoBuffer);
/* Not pending cmd, free it after TX succeed! */
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
}
return WLAN_STATUS_SUCCESS;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is used to clear all commands in TX command queue
* \param prAdapter Pointer of Adapter Data Structure
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID wlanClearTxCommandQueue(IN P_ADAPTER_T prAdapter)
{
QUE_T rTempCmdQue;
P_QUE_T prTempCmdQue = &rTempCmdQue;
P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL;
P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL;
KAL_SPIN_LOCK_DECLARATION();
QUEUE_INITIALIZE(prTempCmdQue);
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE);
QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rTxCmdQueue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE);
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
if (prCmdInfo->pfCmdTimeoutHandler)
prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo);
else
wlanReleaseCommand(prAdapter, prCmdInfo, TX_RESULT_QUEUE_CLEARANCE);
/* Release Tx resource for CMD which resource is allocated but not used */
nicTxReleaseResource(prAdapter, nicTxGetCmdResourceType(prCmdInfo),
nicTxGetCmdPageCount(prCmdInfo), TRUE);
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is used to clear OID commands in TX command queue
* \param prAdapter Pointer of Adapter Data Structure
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID wlanClearTxOidCommand(IN P_ADAPTER_T prAdapter)
{
QUE_T rTempCmdQue;
P_QUE_T prTempCmdQue = &rTempCmdQue;
P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL;
P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL;
KAL_SPIN_LOCK_DECLARATION();
QUEUE_INITIALIZE(prTempCmdQue);
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE);
QUEUE_MOVE_ALL(prTempCmdQue, &prAdapter->rTxCmdQueue);
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
if (prCmdInfo->fgIsOid) {
if (prCmdInfo->pfCmdTimeoutHandler)
prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo);
else
wlanReleaseCommand(prAdapter, prCmdInfo, TX_RESULT_QUEUE_CLEARANCE);
/* Release Tx resource for CMD which resource is allocated but not used */
nicTxReleaseResource(prAdapter, nicTxGetCmdResourceType(prCmdInfo),
nicTxGetCmdPageCount(prCmdInfo), TRUE);
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
} else {
QUEUE_INSERT_TAIL(&prAdapter->rTxCmdQueue, prQueueEntry);
}
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
}
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_QUE);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is used to clear all commands in TX command done queue
* \param prAdapter Pointer of Adapter Data Structure
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID wlanClearTxCommandDoneQueue(IN P_ADAPTER_T prAdapter)
{
QUE_T rTempCmdDoneQue;
P_QUE_T prTempCmdDoneQue = &rTempCmdDoneQue;
P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL;
P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL;
KAL_SPIN_LOCK_DECLARATION();
QUEUE_INITIALIZE(prTempCmdDoneQue);
/* 4 <1> Move whole list of CMD_INFO to temp queue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE);
QUEUE_MOVE_ALL(prTempCmdDoneQue, &prAdapter->rTxCmdDoneQueue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_CMD_DONE_QUE);
/* 4 <2> Dequeue from head and check it is able to be sent */
QUEUE_REMOVE_HEAD(prTempCmdDoneQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
if (prCmdInfo->pfCmdDoneHandler)
prCmdInfo->pfCmdDoneHandler(prAdapter, prCmdInfo, prCmdInfo->pucInfoBuffer);
/* Not pending cmd, free it after TX succeed! */
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
QUEUE_REMOVE_HEAD(prTempCmdDoneQue, prQueueEntry, P_QUE_ENTRY_T);
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is used to clear all buffer in port 0/1 queue
* \param prAdapter Pointer of Adapter Data Structure
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID wlanClearDataQueue(IN P_ADAPTER_T prAdapter)
{
if (HAL_IS_TX_DIRECT())
nicTxDirectClearHifQ(prAdapter);
else {
#if CFG_FIX_2_TX_PORT
QUE_T qDataPort0, qDataPort1;
P_QUE_T prDataPort0, prDataPort1;
P_MSDU_INFO_T prMsduInfo;
KAL_SPIN_LOCK_DECLARATION();
prDataPort0 = &qDataPort0;
prDataPort1 = &qDataPort1;
QUEUE_INITIALIZE(prDataPort0);
QUEUE_INITIALIZE(prDataPort1);
/* <1> Move whole list of CMD_INFO to temp queue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE);
QUEUE_MOVE_ALL(prDataPort0, &prAdapter->rTxP0Queue);
QUEUE_MOVE_ALL(prDataPort1, &prAdapter->rTxP1Queue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE);
/* <2> Release Tx resource */
nicTxReleaseMsduResource(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prDataPort0));
nicTxReleaseMsduResource(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prDataPort1));
/* <3> Return sk buffer */
nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prDataPort0));
nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prDataPort1));
/* <4> Clear pending MSDU info in data done queue */
KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE);
while (QUEUE_IS_NOT_EMPTY(&prAdapter->rTxDataDoneQueue)) {
QUEUE_REMOVE_HEAD(&prAdapter->rTxDataDoneQueue, prMsduInfo, P_MSDU_INFO_T);
nicTxFreePacket(prAdapter, prMsduInfo, FALSE);
nicTxReturnMsduInfo(prAdapter, prMsduInfo);
}
KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE);
#else
QUE_T qDataPort[TX_PORT_NUM];
P_QUE_T prDataPort[TX_PORT_NUM];
P_MSDU_INFO_T prMsduInfo;
INT_32 i;
KAL_SPIN_LOCK_DECLARATION();
for (i = 0; i < TX_PORT_NUM; i++) {
prDataPort[i] = &qDataPort[i];
QUEUE_INITIALIZE(prDataPort[i]);
}
/* <1> Move whole list of CMD_INFO to temp queue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE);
for (i = 0; i < TX_PORT_NUM; i++)
QUEUE_MOVE_ALL(prDataPort[i], &prAdapter->rTxPQueue[i]);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE);
/* <2> Return sk buffer */
for (i = 0; i < TX_PORT_NUM; i++) {
nicTxReleaseMsduResource(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prDataPort[i]));
nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prDataPort[i]));
}
/* <3> Clear pending MSDU info in data done queue */
KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE);
while (QUEUE_IS_NOT_EMPTY(&prAdapter->rTxDataDoneQueue)) {
QUEUE_REMOVE_HEAD(&prAdapter->rTxDataDoneQueue, prMsduInfo, P_MSDU_INFO_T);
nicTxFreePacket(prAdapter, prMsduInfo, FALSE);
nicTxReturnMsduInfo(prAdapter, prMsduInfo);
}
KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_DATA_DONE_QUE);
#endif
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This routine is used to clear all buffer in port 0/1 queue
* \param prAdapter Pointer of Adapter Data Structure
*
* \retval none
*/
/*----------------------------------------------------------------------------*/
VOID wlanClearRxToOsQueue(IN P_ADAPTER_T prAdapter)
{
QUE_T rTempRxQue;
P_QUE_T prTempRxQue = &rTempRxQue;
P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL;
KAL_SPIN_LOCK_DECLARATION();
QUEUE_INITIALIZE(prTempRxQue);
/* 4 <1> Move whole list of CMD_INFO to temp queue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_TO_OS_QUE);
QUEUE_MOVE_ALL(prTempRxQue, &prAdapter->rRxQueue);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_TO_OS_QUE);
/* 4 <2> Remove all skbuf */
QUEUE_REMOVE_HEAD(prTempRxQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
kalRxIndicateOnePkt(prAdapter->prGlueInfo, (PVOID) GLUE_GET_PKT_DESCRIPTOR(prQueueEntry));
QUEUE_REMOVE_HEAD(prTempRxQue, prQueueEntry, P_QUE_ENTRY_T);
}
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief This function will release thd CMD_INFO upon its attribution
*
* \param prAdapter Pointer of Adapter Data Structure
* \param prCmdInfo Pointer of CMD_INFO_T
* \param rTxDoneStatus Tx done status
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID wlanReleaseCommand(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus)
{
P_TX_CTRL_T prTxCtrl;
P_MSDU_INFO_T prMsduInfo;
ASSERT(prAdapter);
ASSERT(prCmdInfo);
prTxCtrl = &prAdapter->rTxCtrl;
switch (prCmdInfo->eCmdType) {
case COMMAND_TYPE_GENERAL_IOCTL:
case COMMAND_TYPE_NETWORK_IOCTL:
DBGLOG(INIT, INFO, "Free CMD: ID[0x%x] SeqNum[%u] OID[%u]\n",
prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, prCmdInfo->fgIsOid);
if (prCmdInfo->fgIsOid) {
kalOidComplete(prAdapter->prGlueInfo,
prCmdInfo->fgSetQuery, prCmdInfo->u4SetInfoLen, WLAN_STATUS_FAILURE);
}
break;
case COMMAND_TYPE_SECURITY_FRAME:
case COMMAND_TYPE_MANAGEMENT_FRAME:
prMsduInfo = prCmdInfo->prMsduInfo;
if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) {
kalSecurityFrameSendComplete(prAdapter->prGlueInfo, prCmdInfo->prPacket, WLAN_STATUS_FAILURE);
/* Avoid skb multiple free */
prMsduInfo->prPacket = NULL;
}
DBGLOG(INIT, INFO,
"Free %s Frame: BSS[%u] WIDX:PID[%u:%u] SEQ[%u] STA[%u] RSP[%u] CMDSeq[%u]\n",
prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME ? "SEC" : "MGMT",
prMsduInfo->ucBssIndex,
prMsduInfo->ucWlanIndex,
prMsduInfo->ucPID,
prMsduInfo->ucTxSeqNum,
prMsduInfo->ucStaRecIndex, prMsduInfo->pfTxDoneHandler ? TRUE : FALSE, prCmdInfo->ucCmdSeqNum);
/* invoke callbacks */
if (prMsduInfo->pfTxDoneHandler != NULL)
prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, rTxDoneStatus);
if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME)
GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum);
cnmMgtPktFree(prAdapter, prMsduInfo);
break;
default:
ASSERT(0);
break;
}
} /* end of wlanReleaseCommand() */
/*----------------------------------------------------------------------------*/
/*!
* \brief This function will search the CMD Queue to look for the pending OID and
* compelete it immediately when system request a reset.
*
* \param prAdapter ointer of Adapter Data Structure
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID wlanReleasePendingOid(IN P_ADAPTER_T prAdapter, IN ULONG ulParamPtr)
{
P_QUE_T prCmdQue;
QUE_T rTempCmdQue;
P_QUE_T prTempCmdQue = &rTempCmdQue;
P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL;
P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL;
KAL_SPIN_LOCK_DECLARATION();
DEBUGFUNC("wlanReleasePendingOid");
ASSERT(prAdapter);
if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) {
DBGLOG(OID, TRACE, "%s stopped! Releasing pending OIDs ..\n", KAL_GET_CURRENT_THREAD_NAME());
} else {
DBGLOG(OID, ERROR, "OID Timeout! Releasing pending OIDs ..\n");
prAdapter->ucOidTimeoutCount++;
if (prAdapter->ucOidTimeoutCount >= WLAN_OID_NO_ACK_THRESHOLD) {
if (!prAdapter->fgIsChipNoAck) {
DBGLOG(INIT, WARN,
"No response from chip for %u times, set NoAck flag!\n",
prAdapter->ucOidTimeoutCount);
}
prAdapter->fgIsChipNoAck = TRUE;
}
set_bit(GLUE_FLAG_HIF_PRT_HIF_DBG_INFO_BIT, &(prAdapter->prGlueInfo->ulFlag));
}
do {
#if CFG_SUPPORT_MULTITHREAD
KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_TX_CMD_CLEAR);
#endif
/* 1: Clear Pending OID in prAdapter->rPendingCmdQueue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
prCmdQue = &prAdapter->rPendingCmdQueue;
QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue);
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
if (prCmdInfo->fgIsOid) {
DBGLOG(OID, INFO, "Clear pending OID CMD ID[0x%02X] SEQ[%u] buf[0x%p]\n",
prCmdInfo->ucCID, prCmdInfo->ucCmdSeqNum, prCmdInfo->pucInfoBuffer);
if (prCmdInfo->pfCmdTimeoutHandler) {
prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo);
} else {
kalOidComplete(prAdapter->prGlueInfo,
prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE);
}
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
nicTxCancelSendingCmd(prAdapter, prCmdInfo);
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
} else {
QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry);
}
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
}
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
#if CFG_SUPPORT_MULTITHREAD
/* Clear pending OID in main_thread to hif_thread command queue */
wlanClearTxOidCommand(prAdapter);
#endif
/* 2: Clear pending OID in glue layer command queue */
kalOidCmdClearance(prAdapter->prGlueInfo);
/* 3: Clear pending OID queued in pvOidEntry with REQ_FLAG_OID set */
kalOidClearance(prAdapter->prGlueInfo);
#if CFG_SUPPORT_MULTITHREAD
KAL_RELEASE_MUTEX(prAdapter, MUTEX_TX_CMD_CLEAR);
#endif
} while (FALSE);
DBGLOG(OID, INFO, "End of Release pending OID\n");
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function will search the CMD Queue to look for the pending CMD/OID for specific
* NETWORK TYPE and compelete it immediately when system request a reset.
*
* \param prAdapter ointer of Adapter Data Structure
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID wlanReleasePendingCMDbyBssIdx(IN P_ADAPTER_T prAdapter, IN UINT_8 ucBssIndex)
{
#if 0
P_QUE_T prCmdQue;
QUE_T rTempCmdQue;
P_QUE_T prTempCmdQue = &rTempCmdQue;
P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL;
P_CMD_INFO_T prCmdInfo = (P_CMD_INFO_T) NULL;
KAL_SPIN_LOCK_DECLARATION();
ASSERT(prAdapter);
do {
/* 1: Clear Pending OID in prAdapter->rPendingCmdQueue */
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
prCmdQue = &prAdapter->rPendingCmdQueue;
QUEUE_MOVE_ALL(prTempCmdQue, prCmdQue);
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
while (prQueueEntry) {
prCmdInfo = (P_CMD_INFO_T) prQueueEntry;
DBGLOG(P2P, TRACE, "Pending CMD for BSS:%d\n", prCmdInfo->ucBssIndex);
if (prCmdInfo->ucBssIndex == ucBssIndex) {
if (prCmdInfo->pfCmdTimeoutHandler) {
prCmdInfo->pfCmdTimeoutHandler(prAdapter, prCmdInfo);
} else if (prCmdInfo->fgIsOid) {
kalOidComplete(prAdapter->prGlueInfo,
prCmdInfo->fgSetQuery, 0, WLAN_STATUS_FAILURE);
}
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
} else {
QUEUE_INSERT_TAIL(prCmdQue, prQueueEntry);
}
QUEUE_REMOVE_HEAD(prTempCmdQue, prQueueEntry, P_QUE_ENTRY_T);
}
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_PENDING);
} while (FALSE);
#endif
} /* wlanReleasePendingCMDbyBssIdx */
/*----------------------------------------------------------------------------*/
/*!
* \brief Return the indicated packet buffer and reallocate one to the RFB
*
* \param prAdapter Pointer of Adapter Data Structure
* \param pvPacket Pointer of returned packet
*
* \retval WLAN_STATUS_SUCCESS: Success
* \retval WLAN_STATUS_FAILURE: Failed
*/
/*----------------------------------------------------------------------------*/
VOID wlanReturnPacketDelaySetupTimeout(IN P_ADAPTER_T prAdapter, IN ULONG ulParamPtr)
{
P_RX_CTRL_T prRxCtrl;
P_SW_RFB_T prSwRfb = NULL;
KAL_SPIN_LOCK_DECLARATION();
WLAN_STATUS status = WLAN_STATUS_SUCCESS;
P_QUE_T prQueList;
ASSERT(prAdapter);
prRxCtrl = &prAdapter->rRxCtrl;
ASSERT(prRxCtrl);
prQueList = &prRxCtrl->rIndicatedRfbList;
DBGLOG(RX, WARN, "%s: IndicatedRfbList num = %u\n", __func__, prQueList->u4NumElem);
while (QUEUE_IS_NOT_EMPTY(&prRxCtrl->rIndicatedRfbList)) {
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
status = nicRxSetupRFB(prAdapter, prSwRfb);
nicRxReturnRFB(prAdapter, prSwRfb);
if (status != WLAN_STATUS_SUCCESS)
break;
}
if (status != WLAN_STATUS_SUCCESS) {
DBGLOG(RX, WARN, "Restart ReturnIndicatedRfb Timer (%u)\n", RX_RETURN_INDICATED_RFB_TIMEOUT_SEC);
/* restart timer */
cnmTimerStartTimer(prAdapter,
&prAdapter->rPacketDelaySetupTimer,
SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC));
}
}
/*----------------------------------------------------------------------------*/
/*!
* \brief Return the packet buffer and reallocate one to the RFB
*
* \param prAdapter Pointer of Adapter Data Structure
* \param pvPacket Pointer of returned packet
*
* \retval WLAN_STATUS_SUCCESS: Success
* \retval WLAN_STATUS_FAILURE: Failed
*/
/*----------------------------------------------------------------------------*/
VOID wlanReturnPacket(IN P_ADAPTER_T prAdapter, IN PVOID pvPacket)
{
P_RX_CTRL_T prRxCtrl;
P_SW_RFB_T prSwRfb = NULL;
KAL_SPIN_LOCK_DECLARATION();
DEBUGFUNC("wlanReturnPacket");
ASSERT(prAdapter);
prRxCtrl = &prAdapter->rRxCtrl;
ASSERT(prRxCtrl);
if (pvPacket) {
kalPacketFree(prAdapter->prGlueInfo, pvPacket);
RX_ADD_CNT(prRxCtrl, RX_DATA_RETURNED_COUNT, 1);
#if CFG_NATIVE_802_11
if (GLUE_TEST_FLAG(prAdapter->prGlueInfo, GLUE_FLAG_HALT)) {
/*Todo:: nothing */
/*Todo:: nothing */
}
#endif
}
KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
QUEUE_REMOVE_HEAD(&prRxCtrl->rIndicatedRfbList, prSwRfb, P_SW_RFB_T);
KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE);
if (!prSwRfb) {
DBGLOG(RX, WARN, "No free SwRfb!\n");
return;
}
if (nicRxSetupRFB(prAdapter, prSwRfb)) {
DBGLOG(RX, WARN, "Cannot allocate packet buffer for SwRfb!\n");
if (!timerPendingTimer(&prAdapter->rPacketDelaySetupTimer)) {
DBGLOG(RX, WARN, "Start ReturnIndicatedRfb Timer (%u)\n", RX_RETURN_INDICATED_RFB_TIMEOUT_SEC);
cnmTimerStartTimer(prAdapter, &prAdapter->rPacketDelaySetupTimer,
SEC_TO_MSEC(RX_RETURN_INDICATED_RFB_TIMEOUT_SEC));
}
}
nicRxReturnRFB(prAdapter, prSwRfb);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is a required function that returns information about
* the capabilities and status of the driver and/or its network adapter.
*
* \param[IN] prAdapter Pointer to the Adapter structure.
* \param[IN] pfnOidQryHandler Function pointer for the OID query handler.
* \param[IN] pvInfoBuf Points to a buffer for return the query information.
* \param[IN] u4QueryBufferLen Specifies the number of bytes at pvInfoBuf.
* \param[OUT] pu4QueryInfoLen Points to the number of bytes it written or is needed.
*
* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers.
*
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS
wlanQueryInformation(IN P_ADAPTER_T prAdapter,
IN PFN_OID_HANDLER_FUNC pfnOidQryHandler,
IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4QryInfoLen)
{
WLAN_STATUS status = WLAN_STATUS_FAILURE;
ASSERT(prAdapter);
ASSERT(pu4QryInfoLen);
/* ignore any OID request after connected, under PS current measurement mode */
if (prAdapter->u4PsCurrentMeasureEn &&
(prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) {
/* note: return WLAN_STATUS_FAILURE or
* WLAN_STATUS_SUCCESS for blocking OIDs during current measurement ??
*/
return WLAN_STATUS_SUCCESS;
}
#if 1
/* most OID handler will just queue a command packet */
status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen);
#else
if (wlanIsHandlerNeedHwAccess(pfnOidQryHandler, FALSE)) {
ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter);
/* Reset sleepy state */
if (prAdapter->fgWiFiInSleepyState == TRUE)
prAdapter->fgWiFiInSleepyState = FALSE;
status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen);
RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE);
} else
status = pfnOidQryHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4QryInfoLen);
#endif
return status;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is a required function that allows bound protocol drivers,
* or NDIS, to request changes in the state information that the miniport
* maintains for particular object identifiers, such as changes in multicast
* addresses.
*
* \param[IN] prAdapter Pointer to the Glue info structure.
* \param[IN] pfnOidSetHandler Points to the OID set handlers.
* \param[IN] pvInfoBuf Points to a buffer containing the OID-specific data for the set.
* \param[IN] u4InfoBufLen Specifies the number of bytes at prSetBuffer.
* \param[OUT] pu4SetInfoLen Points to the number of bytes it read or is needed.
*
* \retval WLAN_STATUS_xxx Different WLAN_STATUS code returned by different handlers.
*
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS
wlanSetInformation(IN P_ADAPTER_T prAdapter,
IN PFN_OID_HANDLER_FUNC pfnOidSetHandler,
IN PVOID pvInfoBuf, IN UINT_32 u4InfoBufLen, OUT PUINT_32 pu4SetInfoLen)
{
WLAN_STATUS status = WLAN_STATUS_FAILURE;
ASSERT(prAdapter);
ASSERT(pu4SetInfoLen);
/* ignore any OID request after connected, under PS current measurement mode */
if (prAdapter->u4PsCurrentMeasureEn &&
(prAdapter->prGlueInfo->eParamMediaStateIndicated == PARAM_MEDIA_STATE_CONNECTED)) {
/* note: return WLAN_STATUS_FAILURE or WLAN_STATUS_SUCCESS
* for blocking OIDs during current measurement ??
*/
return WLAN_STATUS_SUCCESS;
}
#if 1
/* most OID handler will just queue a command packet
* for power state transition OIDs, handler will acquire power control by itself
*/
status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen);
#else
if (wlanIsHandlerNeedHwAccess(pfnOidSetHandler, TRUE)) {
ACQUIRE_POWER_CONTROL_FROM_PM(prAdapter);
/* Reset sleepy state */
if (prAdapter->fgWiFiInSleepyState == TRUE)
prAdapter->fgWiFiInSleepyState = FALSE;
status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen);
RECLAIM_POWER_CONTROL_TO_PM(prAdapter, FALSE);
} else {
status = pfnOidSetHandler(prAdapter, pvInfoBuf, u4InfoBufLen, pu4SetInfoLen);
}
#endif
return status;
}
#if CFG_SUPPORT_WAPI
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is a used to query driver's config wapi mode or not
*
* \param[IN] prAdapter Pointer to the Glue info structure.
*
* \retval TRUE for use wapi mode
*
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wlanQueryWapiMode(IN P_ADAPTER_T prAdapter)
{
ASSERT(prAdapter);
return prAdapter->rWifiVar.rConnSettings.fgWapiMode;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to set RX filter to Promiscuous Mode.
*
* \param[IN] prAdapter Pointer to the Adapter structure.
* \param[IN] fgEnablePromiscuousMode Enable/ disable RX Promiscuous Mode.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID wlanSetPromiscuousMode(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnablePromiscuousMode)
{
ASSERT(prAdapter);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to set RX filter to allow to receive
* broadcast address packets.
*
* \param[IN] prAdapter Pointer to the Adapter structure.
* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
VOID wlanRxSetBroadcast(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableBroadcast)
{
ASSERT(prAdapter);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to send out CMD_ID_DUMMY command packet
*
* \param[IN] prAdapter Pointer to the Adapter structure.
*
* \return WLAN_STATUS_SUCCESS
* \return WLAN_STATUS_FAILURE
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanSendDummyCmd(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgIsReqTxRsrc)
{
WLAN_STATUS status = WLAN_STATUS_SUCCESS;
P_GLUE_INFO_T prGlueInfo;
P_CMD_INFO_T prCmdInfo;
P_WIFI_CMD_T prWifiCmd;
ASSERT(prAdapter);
prGlueInfo = prAdapter->prGlueInfo;
prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, CMD_HDR_SIZE);
if (!prCmdInfo) {
DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n");
return WLAN_STATUS_FAILURE;
}
prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL;
prCmdInfo->u2InfoBufLen = (UINT_16) CMD_HDR_SIZE;
prCmdInfo->pfCmdDoneHandler = NULL;
prCmdInfo->pfCmdTimeoutHandler = NULL;
prCmdInfo->fgIsOid = TRUE;
prCmdInfo->ucCID = CMD_ID_DUMMY_RSV;
prCmdInfo->fgSetQuery = TRUE;
prCmdInfo->fgNeedResp = FALSE;
prCmdInfo->ucCmdSeqNum = 0;
prCmdInfo->u4SetInfoLen = 0;
prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer);
prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen;
prWifiCmd->u2PQ_ID = CMD_PQ_ID;
prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID;
prWifiCmd->ucCID = prCmdInfo->ucCID;
prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery;
prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum;
if (fgIsReqTxRsrc) {
if (wlanSendCommand(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Fail to transmit CMD_ID_DUMMY command\n");
status = WLAN_STATUS_FAILURE;
}
} else {
if (nicTxCmd(prAdapter, prCmdInfo, TC4_INDEX) != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Fail to transmit CMD_ID_DUMMY command\n");
status = WLAN_STATUS_FAILURE;
}
}
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
return status;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to send out CMD_NIC_POWER_CTRL command packet
*
* \param[IN] prAdapter Pointer to the Adapter structure.
* \param[IN] ucPowerMode refer to CMD/EVENT document
*
* \return WLAN_STATUS_SUCCESS
* \return WLAN_STATUS_FAILURE
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanSendNicPowerCtrlCmd(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPowerMode)
{
WLAN_STATUS status = WLAN_STATUS_SUCCESS;
P_GLUE_INFO_T prGlueInfo;
P_CMD_INFO_T prCmdInfo;
P_WIFI_CMD_T prWifiCmd;
UINT_8 ucTC, ucCmdSeqNum;
ASSERT(prAdapter);
prGlueInfo = prAdapter->prGlueInfo;
/* 1. Prepare CMD */
prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL)));
if (!prCmdInfo) {
DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n");
return WLAN_STATUS_FAILURE;
}
/* 2.1 increase command sequence number */
ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter);
DBGLOG(REQ, TRACE, "ucCmdSeqNum =%d\n", ucCmdSeqNum);
/* 2.2 Setup common CMD Info Packet */
prCmdInfo->eCmdType = COMMAND_TYPE_GENERAL_IOCTL;
prCmdInfo->u2InfoBufLen = (UINT_16) (CMD_HDR_SIZE + sizeof(CMD_NIC_POWER_CTRL));
prCmdInfo->pfCmdDoneHandler = NULL;
prCmdInfo->pfCmdTimeoutHandler = NULL;
prCmdInfo->fgIsOid = TRUE;
prCmdInfo->ucCID = CMD_ID_NIC_POWER_CTRL;
prCmdInfo->fgSetQuery = TRUE;
prCmdInfo->fgNeedResp = FALSE;
prCmdInfo->ucCmdSeqNum = ucCmdSeqNum;
prCmdInfo->u4SetInfoLen = sizeof(CMD_NIC_POWER_CTRL);
/* 2.3 Setup WIFI_CMD_T */
prWifiCmd = (P_WIFI_CMD_T) (prCmdInfo->pucInfoBuffer);
prWifiCmd->u2TxByteCount = prCmdInfo->u2InfoBufLen;
prWifiCmd->u2PQ_ID = CMD_PQ_ID;
prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID;
prWifiCmd->ucCID = prCmdInfo->ucCID;
prWifiCmd->ucSetQuery = prCmdInfo->fgSetQuery;
prWifiCmd->ucSeqNum = prCmdInfo->ucCmdSeqNum;
kalMemZero(prWifiCmd->aucBuffer, sizeof(CMD_NIC_POWER_CTRL));
((P_CMD_NIC_POWER_CTRL) (prWifiCmd->aucBuffer))->ucPowerMode = ucPowerMode;
/* 3. Issue CMD for entering specific power mode */
ucTC = TC4_INDEX;
while (1) {
/* 3.0 Removal check */
if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) {
status = WLAN_STATUS_FAILURE;
break;
}
/* 3.1 Acquire TX Resource */
if (nicTxAcquireResource(prAdapter, ucTC, nicTxGetCmdPageCount(prCmdInfo), TRUE)
== WLAN_STATUS_RESOURCES) {
if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n");
status = WLAN_STATUS_FAILURE;
prAdapter->fgIsChipNoAck = TRUE;
break;
}
continue;
}
break;
};
/* 3.2 Send CMD Info Packet */
if (nicTxCmd(prAdapter, prCmdInfo, ucTC) != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Fail to transmit CMD_NIC_POWER_CTRL command\n");
status = WLAN_STATUS_FAILURE;
}
/* 4. Free CMD Info Packet. */
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
/* 5. Add flag */
if (ucPowerMode == 1)
prAdapter->fgIsEnterD3ReqIssued = TRUE;
return status;
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to set g_fgKeepFullPwr flag in firmware
*
* \param[IN] prAdapter Pointer to the Adapter structure.
* \param[IN] fgEnable Boolean of enable
* True: wlan stays awake and keeps working in full power state
* False: wlan may go to sleep and consumes less power.
*
* \return WLAN_STATUS_SUCCESS
* \return WLAN_STATUS_FAILURE
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanKeepFullPwr(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnable)
{
struct CMD_KEEP_FULL_PWR_T rCmdKeepFullPwr;
ASSERT(prAdapter);
rCmdKeepFullPwr.ucEnable = fgEnable;
DBGLOG(HAL, STATE, "KeepFullPwr: %d\n", rCmdKeepFullPwr.ucEnable);
return wlanSendSetQueryCmd(prAdapter,
CMD_ID_KEEP_FULL_PWR, TRUE, FALSE, FALSE, NULL, NULL,
sizeof(struct CMD_KEEP_FULL_PWR_T), (PUINT_8)&rCmdKeepFullPwr, NULL, 0);
}
/*----------------------------------------------------------------------------*/
/*!
* \brief This function is called to check if it is RF test mode and
* the OID is allowed to be called or not
*
* \param[IN] prAdapter Pointer to the Adapter structure.
* \param[IN] fgEnableBroadcast Enable/ disable broadcast packet to be received.
*
* \return (none)
*/
/*----------------------------------------------------------------------------*/
BOOLEAN wlanIsHandlerAllowedInRFTest(IN PFN_OID_HANDLER_FUNC pfnOidHandler, IN BOOLEAN fgSetInfo)
{
PFN_OID_HANDLER_FUNC *apfnOidHandlerAllowedInRFTest;
UINT_32 i;
UINT_32 u4NumOfElem;
if (fgSetInfo) {
apfnOidHandlerAllowedInRFTest = apfnOidSetHandlerAllowedInRFTest;
u4NumOfElem = sizeof(apfnOidSetHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC);
} else {
apfnOidHandlerAllowedInRFTest = apfnOidQueryHandlerAllowedInRFTest;
u4NumOfElem = sizeof(apfnOidQueryHandlerAllowedInRFTest) / sizeof(PFN_OID_HANDLER_FUNC);
}
for (i = 0; i < u4NumOfElem; i++) {
if (apfnOidHandlerAllowedInRFTest[i] == pfnOidHandler)
return TRUE;
}
return FALSE;
}
#if CFG_ENABLE_FW_DOWNLOAD
VOID wlanImageSectionGetFwInfo(IN P_ADAPTER_T prAdapter,
IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength,
IN UINT_8 ucTotSecNum, IN UINT_8 ucCurSecNum, IN ENUM_IMG_DL_IDX_T eDlIdx,
OUT PUINT_32 pu4StartOffset, OUT PUINT_32 pu4Addr, OUT PUINT_32 pu4Len,
OUT PUINT_32 pu4DataMode)
{
UINT_32 u4DataMode = 0;
fw_image_tailer_t *prFwHead;
tailer_format_t *prTailer;
prFwHead = (fw_image_tailer_t *) (pvFwImageMapFile + u4FwImageFileLength - sizeof(fw_image_tailer_t));
if (ucTotSecNum == 1)
prTailer = &prFwHead->dlm_info;
else
prTailer = &prFwHead->ilm_info;
prTailer = &prTailer[ucCurSecNum];
*pu4StartOffset = 0;
*pu4Addr = prTailer->addr;
*pu4Len = (prTailer->len + LEN_4_BYTE_CRC);
if (prTailer->feature_set & DOWNLOAD_CONFIG_ENCRYPTION_MODE) {
u4DataMode |= DOWNLOAD_CONFIG_RESET_OPTION;
u4DataMode |= (prTailer->feature_set & DOWNLOAD_CONFIG_KEY_INDEX_MASK);
u4DataMode |= DOWNLOAD_CONFIG_ENCRYPTION_MODE;
}
if (eDlIdx == IMG_DL_IDX_CR4_FW)
u4DataMode |= DOWNLOAD_CONFIG_WORKING_PDA_OPTION;
#if CFG_ENABLE_FW_DOWNLOAD_ACK
u4DataMode |= DOWNLOAD_CONFIG_ACK_OPTION; /* ACK needed */
#endif
*pu4DataMode = u4DataMode;
/* Dump image information */
if (ucCurSecNum == 0) {
DBGLOG(INIT, INFO, "%s INFO: chip_info[%u:E%u] feature[0x%02X]\n",
(eDlIdx == IMG_DL_IDX_N9_FW) ? "N9" : "CR4", prTailer->chip_info,
prTailer->eco_code + 1, prTailer->feature_set);
DBGLOG(INIT, INFO, "date[%s] version[%c%c%c%c%c%c%c%c%c%c]\n",
prTailer->ram_built_date,
prTailer->ram_version[0], prTailer->ram_version[1],
prTailer->ram_version[2], prTailer->ram_version[3],
prTailer->ram_version[4], prTailer->ram_version[5],
prTailer->ram_version[6], prTailer->ram_version[7],
prTailer->ram_version[8], prTailer->ram_version[9]);
}
/* Backup to FW version info */
if (eDlIdx == IMG_DL_IDX_N9_FW)
kalMemCopy(&prAdapter->rVerInfo.rN9tailer, prTailer, sizeof(tailer_format_t));
else
kalMemCopy(&prAdapter->rVerInfo.rCR4tailer, prTailer, sizeof(tailer_format_t));
}
#if CFG_SUPPORT_COMPRESSION_FW_OPTION
VOID wlanImageSectionGetCompressFwInfo(IN P_ADAPTER_T prAdapter,
IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength, IN UINT_8 ucTotSecNum, IN UINT_8 ucCurSecNum,
IN ENUM_IMG_DL_IDX_T eDlIdx, OUT PUINT_32 pu4StartOffset, OUT PUINT_32 pu4Addr, OUT PUINT_32 pu4Len,
OUT PUINT_32 pu4DataMode, OUT PUINT_32 pu4BlockSize, OUT PUINT_32 pu4CRC, OUT PUINT_32 pu4UncompressedLength)
{
UINT_32 u4DataMode = 0;
fw_image_tailer_t_2 *prFwHead;
tailer_format_t_2 *prTailer;
prFwHead = (fw_image_tailer_t_2 *) (pvFwImageMapFile + u4FwImageFileLength - sizeof(fw_image_tailer_t_2));
if (ucTotSecNum == 1)
prTailer = &prFwHead->dlm_info;
else
prTailer = &prFwHead->ilm_info;
prTailer = &prTailer[ucCurSecNum];
*pu4StartOffset = 0;
*pu4Addr = prTailer->addr;
*pu4Len = (prTailer->len);
*pu4BlockSize = (prTailer->block_size);
*pu4CRC = (prTailer->crc);
*pu4UncompressedLength = (prTailer->real_size);
if (prTailer->feature_set & DOWNLOAD_CONFIG_ENCRYPTION_MODE) {
u4DataMode |= DOWNLOAD_CONFIG_RESET_OPTION;
u4DataMode |= (prTailer->feature_set & DOWNLOAD_CONFIG_KEY_INDEX_MASK);
u4DataMode |= DOWNLOAD_CONFIG_ENCRYPTION_MODE;
}
if (eDlIdx == IMG_DL_IDX_CR4_FW)
u4DataMode |= DOWNLOAD_CONFIG_WORKING_PDA_OPTION;
#if CFG_ENABLE_FW_DOWNLOAD_ACK
u4DataMode |= DOWNLOAD_CONFIG_ACK_OPTION; /* ACK needed */
#endif
*pu4DataMode = u4DataMode;
/* Dump image information */
if (ucCurSecNum == 0) {
DBGLOG(INIT, INFO, "%s INFO: chip_info[%u:E%u] feature[0x%02X]\n",
(eDlIdx == IMG_DL_IDX_N9_FW) ? "N9" : "CR4", prTailer->chip_info,
prTailer->eco_code, prTailer->feature_set);
DBGLOG(INIT, INFO, "date[%s] version[%c%c%c%c%c%c%c%c%c%c]\n", prTailer->ram_built_date,
prTailer->ram_version[0], prTailer->ram_version[1],
prTailer->ram_version[2], prTailer->ram_version[3],
prTailer->ram_version[4], prTailer->ram_version[5],
prTailer->ram_version[6], prTailer->ram_version[7],
prTailer->ram_version[8], prTailer->ram_version[9]);
}
/* Backup to FW version info */
if (eDlIdx == IMG_DL_IDX_N9_FW) {
kalMemCopy(&prAdapter->rVerInfo.rN9Compressedtailer, prTailer, sizeof(tailer_format_t_2));
prAdapter->rVerInfo.fgIsN9CompressedFW = TRUE;
} else {
kalMemCopy(&prAdapter->rVerInfo.rCR4Compressedtailer, prTailer, sizeof(tailer_format_t_2));
prAdapter->rVerInfo.fgIsCR4CompressedFW = TRUE;
}
}
#endif
VOID wlanImageSectionGetPatchInfo(IN P_ADAPTER_T prAdapter,
IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength,
IN UINT_8 ucTotSecNum, IN UINT_8 ucCurSecNum, IN ENUM_IMG_DL_IDX_T eDlIdx,
OUT PUINT_32 pu4StartOffset, OUT PUINT_32 pu4Addr, OUT PUINT_32 pu4Len,
OUT PUINT_32 pu4DataMode)
{
P_PATCH_FORMAT_T prPatchFormat;
UINT_32 u4DataMode = 0;
UINT_8 aucBuffer[32];
struct mt66xx_chip_info *prChipInfo = prAdapter->chip_info;
prPatchFormat = (P_PATCH_FORMAT_T) pvFwImageMapFile;
*pu4StartOffset = offsetof(PATCH_FORMAT_T, ucPatchImage);
*pu4Addr = prChipInfo->patch_addr;
*pu4Len = u4FwImageFileLength - offsetof(PATCH_FORMAT_T, ucPatchImage);
#if CFG_ENABLE_FW_DOWNLOAD_ACK
u4DataMode |= DOWNLOAD_CONFIG_ACK_OPTION; /* ACK needed */
#endif
*pu4DataMode = u4DataMode;
/* Dump image information */
kalStrnCpy(aucBuffer, prPatchFormat->aucPlatform, 4);
aucBuffer[4] = '\0';
DBGLOG(INIT, INFO, "PATCH INFO: platform[%s] HW/SW ver[0x%04X] ver[0x%04X]\n",
aucBuffer, prPatchFormat->u4SwHwVersion, prPatchFormat->u4PatchVersion);
kalStrnCpy(aucBuffer, prPatchFormat->aucBuildDate, 16);
aucBuffer[16] = '\0';
DBGLOG(INIT, INFO, "date[%s]\n", aucBuffer);
/* Backup to FW version info */
kalMemCopy(&prAdapter->rVerInfo.rPatchHeader, prPatchFormat, sizeof(PATCH_FORMAT_T));
}
VOID wlanImageSectionGetInfo(IN P_ADAPTER_T prAdapter,
IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength,
IN UINT_8 ucTotSecNum, IN UINT_8 ucCurSecNum, IN ENUM_IMG_DL_IDX_T eDlIdx,
OUT PUINT_32 pu4StartOffset, OUT PUINT_32 pu4Addr, OUT PUINT_32 pu4Len,
OUT PUINT_32 pu4DataMode)
{
if (eDlIdx == IMG_DL_IDX_PATCH) {
wlanImageSectionGetPatchInfo(prAdapter, pvFwImageMapFile, u4FwImageFileLength,
ucTotSecNum, ucCurSecNum, eDlIdx, pu4StartOffset, pu4Addr, pu4Len,
pu4DataMode);
} else {
wlanImageSectionGetFwInfo(prAdapter, pvFwImageMapFile, u4FwImageFileLength,
ucTotSecNum, ucCurSecNum, eDlIdx, pu4StartOffset, pu4Addr, pu4Len,
pu4DataMode);
}
}
#if CFG_SUPPORT_COMPRESSION_FW_OPTION
BOOLEAN wlanImageSectionCheckFwCompressInfo(IN P_ADAPTER_T prAdapter,
IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength, IN ENUM_IMG_DL_IDX_T eDlIdx) {
UINT_8 ucCompression;
fw_image_tailer_check *prCheckInfo;
if (eDlIdx == IMG_DL_IDX_PATCH)
return FALSE;
prCheckInfo = (fw_image_tailer_check *)
(pvFwImageMapFile + u4FwImageFileLength - sizeof(fw_image_tailer_check));
DBGLOG(INIT, INFO, "feature_set %d\n", prCheckInfo->feature_set);
ucCompression = (UINT_8)((prCheckInfo->feature_set & COMPRESSION_OPTION_MASK)
>> COMPRESSION_OPTION_OFFSET);
DBGLOG(INIT, INFO, "Compressed Check INFORMATION %d\n", ucCompression);
if (ucCompression == 1) {
DBGLOG(INIT, INFO, "Compressed FW\n");
return TRUE;
}
return FALSE;
}
WLAN_STATUS wlanImageSectionDownloadStage(IN P_ADAPTER_T prAdapter, IN PVOID pvFwImageMapFile,
IN UINT_32 u4FwImageFileLength, IN UINT_8 ucSectionNumber, IN ENUM_IMG_DL_IDX_T eDlIdx,
OUT PUINT_8 pucIsCompressed, OUT P_INIT_CMD_WIFI_DECOMPRESSION_START prFwImageInFo)
{
UINT_32 u4ImgSecSize;
UINT_32 j, i;
INT_32 i4TotalLen;
UINT_32 u4FileOffset = 0;
UINT_32 u4StartOffset = 0;
UINT_32 u4DataMode = 0;
UINT_32 u4Addr, u4Len, u4BlockSize, u4CRC, u4UnCompressedLength;
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
PUINT_8 pucSecBuf, pucStartPtr;
UINT_32 u4offset = 0, u4ChunkSize;
/* 3a. parse file header for decision of divided firmware download or not */
for (i = 0; i < ucSectionNumber; ++i) {
if (wlanImageSectionCheckFwCompressInfo(prAdapter, pvFwImageMapFile,
u4FwImageFileLength, eDlIdx) == TRUE){
wlanImageSectionGetCompressFwInfo(prAdapter, pvFwImageMapFile,
u4FwImageFileLength, ucSectionNumber, i, eDlIdx,
&u4StartOffset, &u4Addr, &u4Len, &u4DataMode,
&u4BlockSize, &u4CRC, &u4UnCompressedLength);
u4offset = 0;
if (i == 0) {
prFwImageInFo->u4BlockSize = u4BlockSize;
prFwImageInFo->u4Region1Address = u4Addr;
prFwImageInFo->u4Region1CRC = u4CRC;
prFwImageInFo->u4Region1length = u4UnCompressedLength;
} else {
prFwImageInFo->u4Region2Address = u4Addr;
prFwImageInFo->u4Region2CRC = u4CRC;
prFwImageInFo->u4Region2length = u4UnCompressedLength;
}
i4TotalLen = u4Len;
DBGLOG(INIT, INFO, "DL Offset[%u] addr[0x%08x] len[%u] datamode[0x%08x]\n",
u4FileOffset, u4Addr, u4Len, u4DataMode);
DBGLOG(INIT, INFO, "DL BLOCK[%u] COMlen[%u] CRC[%u]\n",
u4BlockSize, u4UnCompressedLength, u4CRC);
pucStartPtr = (PUINT_8)pvFwImageMapFile + u4StartOffset;
while (i4TotalLen) {
u4ChunkSize = *((unsigned int *)(pucStartPtr+u4FileOffset));
u4FileOffset += 4;
DBGLOG(INIT, INFO, "Downloaded Length %d! Addr %x\n", i4TotalLen, u4Addr + u4offset);
DBGLOG(INIT, INFO, "u4ChunkSize Length %d!\n", u4ChunkSize);
if (wlanImageSectionConfig(prAdapter, (u4Addr + u4offset), u4ChunkSize,
u4DataMode, eDlIdx) != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Firmware download configuration failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
for (j = 0; j < u4ChunkSize; j += CMD_PKT_SIZE_FOR_IMAGE) {
if (j + CMD_PKT_SIZE_FOR_IMAGE < u4ChunkSize)
u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE;
else
u4ImgSecSize = u4ChunkSize - j;
pucSecBuf = (PUINT_8)pucStartPtr + u4FileOffset + j;
if (wlanImageSectionDownload(prAdapter, u4ImgSecSize, pucSecBuf)
!= WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
}
/* escape from loop if any pending error occurs */
if (u4Status == WLAN_STATUS_FAILURE)
break;
i4TotalLen -= u4ChunkSize;
u4offset += u4BlockSize;
u4FileOffset += u4ChunkSize;
if (i4TotalLen < 0) {
DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
}
*pucIsCompressed = TRUE;
} else {
wlanImageSectionGetInfo(prAdapter, pvFwImageMapFile,
u4FwImageFileLength, ucSectionNumber, i, eDlIdx,
&u4StartOffset, &u4Addr, &u4Len, &u4DataMode);
pucStartPtr = (PUINT_8)pvFwImageMapFile + u4StartOffset;
DBGLOG(INIT, INFO, "DL Offset[%u] addr[0x%08x] len[%u] datamode[0x%08x]\n",
u4FileOffset, u4Addr, u4Len, u4DataMode);
if (wlanImageSectionConfig(prAdapter, u4Addr, u4Len, u4DataMode, eDlIdx)
!= WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Firmware download configuration failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
for (j = 0; j < u4Len; j += CMD_PKT_SIZE_FOR_IMAGE) {
if (j + CMD_PKT_SIZE_FOR_IMAGE < u4Len)
u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE;
else
u4ImgSecSize = u4Len - j;
pucSecBuf = (PUINT_8)pucStartPtr + u4FileOffset + j;
if (wlanImageSectionDownload(prAdapter, u4ImgSecSize, pucSecBuf)
!= WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
}
/* escape from loop if any pending error occurs */
if (u4Status == WLAN_STATUS_FAILURE)
break;
u4FileOffset += u4Len;
*pucIsCompressed = FALSE;
}
}
return u4Status;
}
#else
WLAN_STATUS wlanImageSectionDownloadStage(IN P_ADAPTER_T prAdapter,
IN PVOID pvFwImageMapFile, IN UINT_32 u4FwImageFileLength,
IN UINT_8 ucSectionNumber, IN ENUM_IMG_DL_IDX_T eDlIdx)
{
UINT_32 u4ImgSecSize;
UINT_32 j, i;
UINT_32 u4FileOffset = 0;
UINT_32 u4StartOffset = 0;
UINT_32 u4DataMode = 0;
UINT_32 u4Addr, u4Len;
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
PUINT_8 pucSecBuf, pucStartPtr;
/* 3a. parse file header for decision of divided firmware download or not */
for (i = 0; i < ucSectionNumber; ++i) {
wlanImageSectionGetInfo(prAdapter, pvFwImageMapFile,
u4FwImageFileLength, ucSectionNumber, i, eDlIdx,
&u4StartOffset, &u4Addr, &u4Len, &u4DataMode);
pucStartPtr = (PUINT_8) pvFwImageMapFile + u4StartOffset;
DBGLOG(INIT, INFO, "DL Offset[%u] addr[0x%08x] len[%u] datamode[0x%08x]\n",
u4FileOffset, u4Addr, u4Len, u4DataMode);
if (wlanImageSectionConfig(prAdapter, u4Addr, u4Len, u4DataMode, eDlIdx)
!= WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Firmware download configuration failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
for (j = 0; j < u4Len; j += CMD_PKT_SIZE_FOR_IMAGE) {
if (j + CMD_PKT_SIZE_FOR_IMAGE < u4Len)
u4ImgSecSize = CMD_PKT_SIZE_FOR_IMAGE;
else
u4ImgSecSize = u4Len - j;
pucSecBuf = (PUINT_8) pucStartPtr + u4FileOffset + j;
if (wlanImageSectionDownload(prAdapter, u4ImgSecSize, pucSecBuf)
!= WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, ERROR, "Firmware scatter download failed!\n");
u4Status = WLAN_STATUS_FAILURE;
break;
}
kalMdelay(1);
}
/* escape from loop if any pending error occurs */
if (u4Status == WLAN_STATUS_FAILURE)
break;
u4FileOffset += u4Len;
}
return u4Status;
}
#endif
/*----------------------------------------------------------------------------*/
/*!
* @brief This function is called to confirm the status of
* previously patch semaphore control
*
* @param prAdapter Pointer to the Adapter structure.
* ucCmdSeqNum Sequence number of previous firmware scatter
*
* @return WLAN_STATUS_SUCCESS
* WLAN_STATUS_FAILURE
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanPatchRecvSemaResp(IN P_ADAPTER_T prAdapter, IN UINT_8 ucCmdSeqNum, OUT PUINT_8 pucPatchStatus)
{
UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT)];
P_INIT_HIF_RX_HEADER_T prInitHifRxHeader;
P_INIT_EVENT_CMD_RESULT prEventCmdResult;
UINT_32 u4RxPktLength;
ASSERT(prAdapter);
if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE)
return WLAN_STATUS_FAILURE;
if (nicRxWaitResponse(prAdapter, 0, aucBuffer,
sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT),
&u4RxPktLength) != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, WARN, "Wait patch semaphore response fail\n");
return WLAN_STATUS_FAILURE;
}
prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer;
if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_PATCH_SEMA_CTRL) {
DBGLOG(INIT, WARN, "Unexpected EVENT ID, get 0x%0x\n", prInitHifRxHeader->rInitWifiEvent.ucEID);
return WLAN_STATUS_FAILURE;
}
if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) {
DBGLOG(INIT, WARN, "Unexpected SeqNum %d, %d\n", ucCmdSeqNum,
prInitHifRxHeader->rInitWifiEvent.ucSeqNum);
return WLAN_STATUS_FAILURE;
}
prEventCmdResult = (P_INIT_EVENT_CMD_RESULT) (prInitHifRxHeader->rInitWifiEvent.aucBuffer);
*pucPatchStatus = prEventCmdResult->ucStatus;
#if 0
if (prEventCmdResult->ucStatus != PATCH_STATUS_GET_SEMA_NEED_PATCH) {
DBGLOG(INIT, INFO, "Patch status[%d], skip patch\n", prEventCmdResult->ucStatus);
return WLAN_STATUS_FAILURE;
}
DBGLOG(INIT, INFO, "Status[%d], ready to patch\n", prEventCmdResult->ucStatus);
return WLAN_STATUS_SUCCESS;
#endif
return WLAN_STATUS_SUCCESS;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This function is called to check the patch semaphore control.
*
* @param prAdapter Pointer to the Adapter structure.
*
* @return (none)
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanPatchSendSemaControl(IN P_ADAPTER_T prAdapter, OUT PUINT_8 pucSeqNum)
{
P_CMD_INFO_T prCmdInfo;
P_INIT_HIF_TX_HEADER_T prInitHifTxHeader;
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
P_INIT_CMD_PATCH_SEMA_CONTROL prPatchSemaControl;
ASSERT(prAdapter);
DEBUGFUNC("wlanImagePatchSemaphoreCheck");
/* 1. Allocate CMD Info Packet and its Buffer. */
prCmdInfo =
cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_PATCH_SEMA_CONTROL));
/* DBGLOG(INIT, ERROR, "sizeof INIT_HIF_TX_HEADER_T = %d\n", sizeof(INIT_HIF_TX_HEADER_T)); */
if (!prCmdInfo) {
DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n");
return WLAN_STATUS_FAILURE;
}
prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_PATCH_SEMA_CONTROL);
/* 2. Setup common CMD Info Packet */
prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer);
prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen;
prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID;
prInitHifTxHeader->ucHeaderFormat = INIT_CMD_PACKET_TYPE_ID;
prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD;
prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_PATCH_SEMAPHORE_CONTROL;
prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PDA_PACKET_TYPE_ID;
prInitHifTxHeader->rInitWifiCmd.ucSeqNum = nicIncreaseCmdSeqNum(prAdapter);
*pucSeqNum = prInitHifTxHeader->rInitWifiCmd.ucSeqNum;
/* 3. Setup DOWNLOAD_BUF */
prPatchSemaControl = (P_INIT_CMD_PATCH_SEMA_CONTROL) prInitHifTxHeader->rInitWifiCmd.aucBuffer;
kalMemZero(prPatchSemaControl, sizeof(INIT_CMD_PATCH_SEMA_CONTROL));
prPatchSemaControl->ucGetSemaphore = PATCH_GET_SEMA_CONTROL;
/* 4. Send FW_Download command */
if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
DBGLOG(INIT, ERROR, "Fail to transmit image download command\n");
}
/* 5. Free CMD Info Packet. */
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
return u4Status;
}
BOOLEAN wlanPatchIsDownloaded(IN P_ADAPTER_T prAdapter)
{
UINT_8 ucSeqNum, ucPatchStatus;
WLAN_STATUS rStatus;
UINT_32 u4Count;
ucPatchStatus = PATCH_STATUS_NO_SEMA_NEED_PATCH;
u4Count = 0;
while (ucPatchStatus == PATCH_STATUS_NO_SEMA_NEED_PATCH) {
if (u4Count)
kalMdelay(100);
rStatus = wlanPatchSendSemaControl(prAdapter, &ucSeqNum);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, WARN, "Send patch SEMA control CMD failed!!\n");
break;
}
rStatus = wlanPatchRecvSemaResp(prAdapter, ucSeqNum, &ucPatchStatus);
if (rStatus != WLAN_STATUS_SUCCESS) {
DBGLOG(INIT, WARN, "Recv patch SEMA control EVT failed!!\n");
break;
}
u4Count++;
if (u4Count > 50) {
DBGLOG(INIT, WARN, "Patch status check timeout!!\n");
break;
}
}
if (ucPatchStatus == PATCH_STATUS_NO_NEED_TO_PATCH)
return TRUE;
else
return FALSE;
}
WLAN_STATUS wlanPatchSendComplete(IN P_ADAPTER_T prAdapter)
{
P_CMD_INFO_T prCmdInfo;
P_INIT_HIF_TX_HEADER_T prInitHifTxHeader;
UINT_8 ucTC, ucCmdSeqNum;
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
ASSERT(prAdapter);
/* 1. Allocate CMD Info Packet and its Buffer. */
prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T));
if (!prCmdInfo) {
DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n");
return WLAN_STATUS_FAILURE;
}
kalMemZero(prCmdInfo->pucInfoBuffer, sizeof(INIT_HIF_TX_HEADER_T));
prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T);
#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1)
/* 2. Always use TC4 (TC4 as CPU) */
ucTC = TC4_INDEX;
#else
/* 2. Use TC0's resource to send patch finish command.
* Only TC0 is allowed because SDIO HW always reports
* MCU's TXQ_CNT at TXQ0_CNT in CR4 architecutre)
*/
ucTC = TC0_INDEX;
#endif
/* 3. increase command sequence number */
ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter);
/* 4. Setup common CMD Info Packet */
prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer);
prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen;
prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID;
prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD;
prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_PATCH_FINISH;
prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID;
prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum;
/* 5. Seend WIFI start command */
while (1) {
/* 5.1 Acquire TX Resource */
if (nicTxAcquireResource(prAdapter, ucTC, nicTxGetPageCount(prCmdInfo->u2InfoBufLen, TRUE), TRUE)
== WLAN_STATUS_RESOURCES) {
if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n");
goto exit;
}
continue;
}
/* 5.2 Send CMD Info Packet */
if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
DBGLOG(INIT, ERROR, "Fail to transmit WIFI start command\n");
goto exit;
}
break;
};
DBGLOG(INIT, INFO, "PATCH FINISH CMD send, waiting for RSP\n");
/* kalMdelay(10000); */
u4Status = wlanConfigWifiFuncStatus(prAdapter, ucCmdSeqNum);
if (u4Status != WLAN_STATUS_SUCCESS)
DBGLOG(INIT, INFO, "PATCH FINISH EVT failed\n");
else
DBGLOG(INIT, INFO, "PATCH FINISH EVT success!!\n");
exit:
/* 6. Free CMD Info Packet. */
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
return u4Status;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This function is called to configure FWDL parameters
*
* @param prAdapter Pointer to the Adapter structure.
* u4DestAddr Address of destination address
* u4ImgSecSize Length of the firmware block
* fgReset should be set to TRUE if this is the 1st configuration
*
* @return WLAN_STATUS_SUCCESS
* WLAN_STATUS_FAILURE
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanImageSectionConfig(IN P_ADAPTER_T prAdapter,
IN UINT_32 u4DestAddr, IN UINT_32 u4ImgSecSize, IN UINT_32 u4DataMode,
IN ENUM_IMG_DL_IDX_T eDlIdx)
{
P_CMD_INFO_T prCmdInfo;
P_INIT_HIF_TX_HEADER_T prInitHifTxHeader;
P_INIT_CMD_DOWNLOAD_CONFIG prInitCmdDownloadConfig;
UINT_8 ucTC, ucCmdSeqNum;
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
ASSERT(prAdapter);
DEBUGFUNC("wlanImageSectionConfig");
if (u4ImgSecSize == 0)
return WLAN_STATUS_SUCCESS;
/* 1. Allocate CMD Info Packet and its Buffer. */
prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_CONFIG));
if (!prCmdInfo) {
DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n");
return WLAN_STATUS_FAILURE;
}
prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_DOWNLOAD_CONFIG);
#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1)
/* 2. Use TC4's resource to download image. (TC4 as CPU) */
ucTC = TC4_INDEX;
#else
/* 2. Use TC0's resource to send init_cmd.
* Only TC0 is allowed because SDIO HW always reports
* MCU's TXQ_CNT at TXQ0_CNT in CR4 architecutre)
*/
ucTC = TC0_INDEX;
#endif
/* 3. increase command sequence number */
ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter);
/* 4. Setup common CMD Info Packet */
prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer);
prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen;
prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID;
prInitHifTxHeader->ucHeaderFormat = INIT_CMD_PACKET_TYPE_ID;
prInitHifTxHeader->ucPktFt = INIT_PKT_FT_CMD;
if (eDlIdx == IMG_DL_IDX_PATCH)
prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_PATCH_START;
else
prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_DOWNLOAD_CONFIG;
prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID;
prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum;
/* 5. Setup CMD_DOWNLOAD_CONFIG */
prInitCmdDownloadConfig = (P_INIT_CMD_DOWNLOAD_CONFIG) (prInitHifTxHeader->rInitWifiCmd.aucBuffer);
prInitCmdDownloadConfig->u4Address = u4DestAddr;
prInitCmdDownloadConfig->u4Length = u4ImgSecSize;
prInitCmdDownloadConfig->u4DataMode = u4DataMode;
/* 6. Send FW_Download command */
while (1) {
/* 6.1 Acquire TX Resource */
if (nicTxAcquireResource(prAdapter, ucTC, nicTxGetPageCount(prCmdInfo->u2InfoBufLen, TRUE), TRUE)
== WLAN_STATUS_RESOURCES) {
if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n");
goto exit;
}
continue;
}
/* 6.2 Send CMD Info Packet */
if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
DBGLOG(INIT, ERROR, "Fail to transmit image download command\n");
goto exit;
}
break;
};
#if CFG_ENABLE_FW_DOWNLOAD_ACK
/* 7. Wait for INIT_EVENT_ID_CMD_RESULT */
u4Status = wlanImageSectionDownloadStatus(prAdapter, ucCmdSeqNum);
#endif
exit:
/* 8. Free CMD Info Packet. */
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
return u4Status;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This function is called to download FW image.
*
* @param prAdapter Pointer to the Adapter structure.
*
* @return (none)
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanImageSectionDownload(IN P_ADAPTER_T prAdapter, IN UINT_32 u4ImgSecSize, IN PUINT_8 pucImgSecBuf)
{
P_CMD_INFO_T prCmdInfo;
P_INIT_HIF_TX_HEADER_T prInitHifTxHeader;
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
ASSERT(prAdapter);
ASSERT(pucImgSecBuf);
ASSERT(u4ImgSecSize <= CMD_PKT_SIZE_FOR_IMAGE);
DEBUGFUNC("wlanImageSectionDownload");
if (u4ImgSecSize == 0)
return WLAN_STATUS_SUCCESS;
/* 1. Allocate CMD Info Packet and its Buffer. */
prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + u4ImgSecSize);
if (!prCmdInfo) {
DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n");
return WLAN_STATUS_FAILURE;
}
prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + (UINT_16) u4ImgSecSize;
/* 2. Setup common CMD Info Packet */
prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer);
prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen;
prInitHifTxHeader->u2PQ_ID = INIT_CMD_PDA_PQ_ID;
prInitHifTxHeader->ucHeaderFormat = INIT_CMD_PDA_PACKET_TYPE_ID;
prInitHifTxHeader->ucPktFt = INIT_PKT_FT_PDA_FWDL;
prInitHifTxHeader->rInitWifiCmd.ucCID = 0;
prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PDA_PACKET_TYPE_ID;
prInitHifTxHeader->rInitWifiCmd.ucSeqNum = 0;
/* 3. Setup DOWNLOAD_BUF */
kalMemCopy(prInitHifTxHeader->rInitWifiCmd.aucBuffer, pucImgSecBuf, u4ImgSecSize);
/* 4. Send FW_Download command */
if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
DBGLOG(INIT, ERROR, "Fail to transmit image download command\n");
}
/* 5. Free CMD Info Packet. */
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
return u4Status;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This function is called to confirm previously firmware download is done without error
*
* @param prAdapter Pointer to the Adapter structure.
*
* @return (none)
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanImageQueryStatus(IN P_ADAPTER_T prAdapter)
{
P_CMD_INFO_T prCmdInfo;
P_INIT_HIF_TX_HEADER_T prInitHifTxHeader;
UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_PENDING_ERROR)];
UINT_32 u4RxPktLength;
P_INIT_HIF_RX_HEADER_T prInitHifRxHeader;
P_INIT_EVENT_PENDING_ERROR prEventPendingError;
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
UINT_8 ucTC, ucCmdSeqNum;
ASSERT(prAdapter);
DEBUGFUNC("wlanImageQueryStatus");
/* 1. Allocate CMD Info Packet and it Buffer. */
prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T));
if (!prCmdInfo) {
DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n");
return WLAN_STATUS_FAILURE;
}
kalMemZero(prCmdInfo->pucInfoBuffer, sizeof(INIT_HIF_TX_HEADER_T));
prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T);
#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1)
/* 2. Always use TC4 */
ucTC = TC4_INDEX;
#else
/* 2. Use TC0's resource to send init_cmd
* Only TC0 is allowed because SDIO HW always reports
* CPU's TXQ_CNT at TXQ0_CNT in CR4 architecutre)
*/
ucTC = TC0_INDEX;
#endif
/* 3. increase command sequence number */
ucCmdSeqNum = nicIncreaseCmdSeqNum(prAdapter);
/* 4. Setup common CMD Info Packet */
prInitHifTxHeader = (P_INIT_HIF_TX_HEADER_T) (prCmdInfo->pucInfoBuffer);
prInitHifTxHeader->u2TxByteCount = prCmdInfo->u2InfoBufLen;
prInitHifTxHeader->u2PQ_ID = INIT_CMD_PQ_ID;
prInitHifTxHeader->rInitWifiCmd.ucCID = INIT_CMD_ID_QUERY_PENDING_ERROR;
prInitHifTxHeader->rInitWifiCmd.ucPktTypeID = INIT_CMD_PACKET_TYPE_ID;
prInitHifTxHeader->rInitWifiCmd.ucSeqNum = ucCmdSeqNum;
/* 5. Send command */
while (1) {
/* 5.1 Acquire TX Resource */
if (nicTxAcquireResource(prAdapter, ucTC, nicTxGetPageCount(prCmdInfo->u2InfoBufLen, TRUE), TRUE)
== WLAN_STATUS_RESOURCES) {
if (nicTxPollingResource(prAdapter, ucTC) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
DBGLOG(INIT, ERROR, "Fail to get TX resource return within timeout\n");
break;
}
continue;
}
/* 5.2 Send CMD Info Packet */
if (nicTxInitCmd(prAdapter, prCmdInfo) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
DBGLOG(INIT, ERROR, "Fail to transmit image download command\n");
}
break;
};
/* 6. Wait for INIT_EVENT_ID_PENDING_ERROR */
do {
if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) {
u4Status = WLAN_STATUS_FAILURE;
} else if (nicRxWaitResponse(prAdapter,
0,
aucBuffer,
sizeof(INIT_HIF_RX_HEADER_T) +
sizeof(INIT_EVENT_PENDING_ERROR), &u4RxPktLength) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
} else {
prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer;
/* EID / SeqNum check */
if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_PENDING_ERROR) {
u4Status = WLAN_STATUS_FAILURE;
} else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) {
u4Status = WLAN_STATUS_FAILURE;
} else {
prEventPendingError =
(P_INIT_EVENT_PENDING_ERROR) (prInitHifRxHeader->rInitWifiEvent.aucBuffer);
if (prEventPendingError->ucStatus != 0) { /* 0 for download success */
u4Status = WLAN_STATUS_FAILURE;
} else {
u4Status = WLAN_STATUS_SUCCESS;
}
}
}
} while (FALSE);
/* 7. Free CMD Info Packet. */
cmdBufFreeCmdInfo(prAdapter, prCmdInfo);
return u4Status;
}
/*----------------------------------------------------------------------------*/
/*!
* @brief This function is called to confirm the status of
* previously downloaded firmware scatter
*
* @param prAdapter Pointer to the Adapter structure.
* ucCmdSeqNum Sequence number of previous firmware scatter
*
* @return WLAN_STATUS_SUCCESS
* WLAN_STATUS_FAILURE
*/
/*----------------------------------------------------------------------------*/
WLAN_STATUS wlanImageSectionDownloadStatus(IN P_ADAPTER_T prAdapter, IN UINT_8 ucCmdSeqNum)
{
UINT_8 aucBuffer[sizeof(INIT_HIF_RX_HEADER_T) + sizeof(INIT_EVENT_CMD_RESULT)];
P_INIT_HIF_RX_HEADER_T prInitHifRxHeader;
P_INIT_EVENT_CMD_RESULT prEventCmdResult;
UINT_32 u4RxPktLength;
WLAN_STATUS u4Status;
UINT_8 ucPortIdx = IMG_DL_STATUS_PORT_IDX;
ASSERT(prAdapter);
do {
if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) {
u4Status = WLAN_STATUS_FAILURE;
} else if (nicRxWaitResponse(prAdapter,
ucPortIdx,
aucBuffer,
sizeof(INIT_HIF_RX_HEADER_T) +
sizeof(INIT_EVENT_CMD_RESULT), &u4RxPktLength) != WLAN_STATUS_SUCCESS) {
u4Status = WLAN_STATUS_FAILURE;
} else {
prInitHifRxHeader = (P_INIT_HIF_RX_HEADER_T) aucBuffer;
/* EID / SeqNum check */
if (prInitHifRxHeader->rInitWifiEvent.ucEID != INIT_EVENT_ID_CMD_RESULT) {
u4Status = WLAN_STATUS_FAILURE;
} else if (prInitHifRxHeader->rInitWifiEvent.ucSeqNum != ucCmdSeqNum) {
u4Status = WLAN_STATUS_FAILURE;
} else {
prEventCmdResult =
(P_INIT_EVENT_CMD_RESULT) (prInitHifRxHeader->rInitWifiEvent.aucBuffer);
if (prEventCmdResult->ucStatus != 0) { /* 0 for download success */
DBGLOG(INIT, ERROR, "Start CMD failed, status[%u]\n",
prEventCmdResult->ucStatus);
#if CFG_SUPPORT_COMPRESSION_FW_OPTION
if (prEventCmdResult->ucStatus == WIFI_FW_DECOMPRESSION_FAILED)
DBGLOG(INIT, ERROR, "Start Decompression CMD failed, status[%u]\n",
prEventCmdResult->ucStatus);
#endif
u4Status = WLAN_STATUS_FAILURE;
} else {
u4Status = WLAN_STATUS_SUCCESS;
}
}
}
} while (FALSE);
return u4Status;
}
WLAN_STATUS wlanConfigWifiFunc(IN P_ADAPTER_T prAdapter,
IN BOOLEAN fgEnable, IN UINT_32 u4StartAddress, IN UINT_8 ucPDA)
{
P_CMD_INFO_T prCmdInfo;
P_INIT_HIF_TX_HEADER_T prInitHifTxHeader;
P_INIT_CMD_WIFI_START prInitCmdWifiStart;
UINT_8 ucTC, ucCmdSeqNum;
WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS;
ASSERT(prAdapter);
DEBUGFUNC("wlanConfigWifiFunc");
/* 1. Allocate CMD Info Packet and its Buffer. */
prCmdInfo = cmdBufAllocateCmdInfo(prAdapter, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START));
if (!prCmdInfo) {
DBGLOG(INIT, ERROR, "Allocate CMD_INFO_T ==> FAILED.\n");
return WLAN_STATUS_FAILURE;
}
kalMemZero(prCmdInfo->pucInfoBuffer, sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START));
prCmdInfo->u2InfoBufLen = sizeof(INIT_HIF_TX_HEADER_T) + sizeof(INIT_CMD_WIFI_START);
#if (CFG_USE_TC4_RESOURCE_FOR_INIT_CMD == 1)
/* 2. Always use TC4 (TC4 as CPU) */
ucTC = TC4_INDEX;
#else
/* 2. Use TC0's resource to send init_cmd.
* Only TC0 is allowed because SDIO HW always reports