| /****************************************************************************** |
| * |
| * 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 |
|