| /****************************************************************************** |
| * |
| * 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] hif_api.c |
| *[Version] v1.0 |
| *[Revision Date] 2015-09-08 |
| *[Author] |
| *[Description] |
| * The program provides SDIO HIF APIs |
| *[Copyright] |
| * Copyright (C) 2015 MediaTek Incorporation. All Rights Reserved. |
| ******************************************************************************/ |
| |
| /******************************************************************************* |
| * 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" |
| |
| #if MTK_WCN_HIF_SDIO |
| #include "hif_sdio.h" |
| #else |
| #include <linux/mmc/card.h> |
| #include <linux/mmc/host.h> |
| #include <linux/mmc/sdio.h> |
| #include <linux/mmc/sdio_func.h> /* sdio_readl(), etc */ |
| #include <linux/mmc/sdio_ids.h> |
| #endif |
| |
| #include <linux/mm.h> |
| #ifndef CONFIG_X86 |
| #include <asm/memory.h> |
| #endif |
| |
| #include "mt66xx_reg.h" |
| |
| /******************************************************************************* |
| * C O N S T A N T S |
| ******************************************************************************** |
| */ |
| #define RX_RESPONSE_TIMEOUT (15000) |
| |
| /******************************************************************************* |
| * D A T A T Y P E S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * P U B L I C D A T A |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * P R I V A T E D A T A |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * 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 Verify the CHIP ID |
| * |
| * @param prAdapter a pointer to adapter private data structure. |
| * |
| * |
| * @retval TRUE CHIP ID is the same as the setting compiled |
| * @retval FALSE CHIP ID is different from the setting compiled |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOL halVerifyChipID(IN P_ADAPTER_T prAdapter) |
| { |
| UINT_32 u4CIR = 0; |
| struct mt66xx_chip_info *prChipInfo; |
| |
| ASSERT(prAdapter); |
| |
| if (prAdapter->fgIsReadRevID) |
| return TRUE; |
| |
| HAL_MCR_RD(prAdapter, MCR_WCIR, &u4CIR); |
| |
| DBGLOG(INIT, TRACE, "Chip ID: 0x%lx\n", u4CIR & WCIR_CHIP_ID); |
| DBGLOG(INIT, TRACE, "Revision ID: 0x%lx\n", ((u4CIR & WCIR_REVISION_ID) >> 16)); |
| |
| prChipInfo = prAdapter->chip_info; |
| |
| if ((u4CIR & WCIR_CHIP_ID) != prChipInfo->chip_id) |
| return FALSE; |
| |
| prAdapter->ucRevID = (UINT_8) (((u4CIR & WCIR_REVISION_ID) >> 16) & 0xF); |
| prAdapter->fgIsReadRevID = TRUE; |
| |
| return TRUE; |
| } |
| |
| WLAN_STATUS |
| halRxWaitResponse(IN P_ADAPTER_T prAdapter, IN UINT_8 ucPortIdx, OUT PUINT_8 pucRspBuffer, |
| IN UINT_32 u4MaxRespBufferLen, OUT PUINT_32 pu4Length) |
| { |
| UINT_32 u4Value = 0, u4PktLen = 0, i = 0, u4CpyLen; |
| WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; |
| UINT_32 u4Time, u4Current; |
| P_RX_CTRL_T prRxCtrl; |
| |
| DEBUGFUNC("halRxWaitResponse"); |
| |
| ASSERT(prAdapter); |
| ASSERT(pucRspBuffer); |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| |
| u4Time = (UINT_32) kalGetTimeTick(); |
| |
| do { |
| /* Read the packet length */ |
| HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4Value); |
| |
| if ((u4Value & 0xFFFF) != 0) { |
| u4PktLen = u4Value & 0xFFFF; |
| i = 0; |
| } else { |
| u4PktLen = (u4Value >> 16) & 0xFFFF; |
| i = 1; |
| } |
| |
| if (u4PktLen == 0) { |
| /* timeout exceeding check */ |
| u4Current = (UINT_32) kalGetTimeTick(); |
| |
| if ((u4Current > u4Time) && ((u4Current - u4Time) > RX_RESPONSE_TIMEOUT)) |
| return WLAN_STATUS_FAILURE; |
| else if (u4Current < u4Time && ((u4Current + (0xFFFFFFFF - u4Time)) > RX_RESPONSE_TIMEOUT)) |
| return WLAN_STATUS_FAILURE; |
| |
| /* Response packet is not ready */ |
| kalUdelay(50); |
| } else { |
| |
| #if (CFG_ENABLE_READ_EXTRA_4_BYTES == 1) |
| #if CFG_SDIO_RX_AGG |
| /* decide copy length */ |
| if (u4PktLen > u4MaxRespBufferLen) |
| u4CpyLen = u4MaxRespBufferLen; |
| else |
| u4CpyLen = u4PktLen; |
| |
| /* read from SDIO to tmp. buffer */ |
| HAL_PORT_RD(prAdapter, i == 0 ? MCR_WRDR0 : MCR_WRDR1, |
| ALIGN_4(u4PktLen + 4), prRxCtrl->pucRxCoalescingBufPtr, |
| HIF_RX_COALESCING_BUFFER_SIZE); |
| |
| /* copy to destination buffer */ |
| kalMemCopy(pucRspBuffer, prRxCtrl->pucRxCoalescingBufPtr, u4CpyLen); |
| |
| /* update valid buffer count */ |
| u4PktLen = u4CpyLen; |
| #else |
| #error "Please turn on RX coalescing" |
| #endif |
| #else |
| HAL_PORT_RD(prAdapter, |
| i == 0 ? MCR_WRDR0 : MCR_WRDR1, u4PktLen, pucRspBuffer, u4MaxRespBufferLen); |
| #endif |
| *pu4Length = u4PktLen; |
| break; |
| } |
| } while (TRUE); |
| |
| return u4Status; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief enable global interrupt |
| * |
| * @param prAdapter pointer to the Adapter handler |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID halEnableInterrupt(IN P_ADAPTER_T prAdapter) |
| { |
| BOOLEAN fgIsIntEnableCache, fgIsPendingInt; |
| |
| ASSERT(prAdapter); |
| fgIsIntEnableCache = prAdapter->fgIsIntEnable; |
| /* Not to enable interrupt if there is pending interrupt */ |
| fgIsPendingInt = prAdapter->prGlueInfo->rHifInfo.fgIsPendingInt; |
| |
| if (!fgIsPendingInt) |
| prAdapter->fgIsIntEnable = TRUE; /* NOTE(Kevin): It must be placed before MCR GINT write. */ |
| |
| /* If need enable INT and also set LPOwn at the same time. */ |
| if (prAdapter->fgIsIntEnableWithLPOwnSet) { |
| prAdapter->fgIsIntEnableWithLPOwnSet = FALSE; /* NOTE(Kevin): It's better to place it |
| * before MCR GINT write. |
| */ |
| /* If INT was enabled, only set LPOwn */ |
| if (fgIsIntEnableCache) { |
| HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET); |
| prAdapter->fgIsFwOwn = TRUE; |
| } |
| /* If INT was not enabled, enable it and also set LPOwn now */ |
| else if (!fgIsPendingInt) { |
| HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_FW_OWN_REQ_SET | WHLPCR_INT_EN_SET); |
| prAdapter->fgIsFwOwn = TRUE; |
| } |
| } |
| /* If INT was not enabled, enable it now */ |
| else if (!fgIsIntEnableCache && !fgIsPendingInt) |
| HAL_BYTE_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_SET); |
| |
| if (fgIsPendingInt) |
| kalSetIntEvent(prAdapter->prGlueInfo); |
| } /* end of nicEnableInterrupt() */ |
| |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief disable global interrupt |
| * |
| * @param prAdapter pointer to the Adapter handler |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID halDisableInterrupt(IN P_ADAPTER_T prAdapter) |
| { |
| |
| ASSERT(prAdapter); |
| |
| HAL_BYTE_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); |
| |
| prAdapter->fgIsIntEnable = FALSE; |
| |
| } |
| |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to process the POWER OFF procedure. |
| * |
| * \param[in] pvAdapter Pointer to the Adapter structure. |
| * |
| * \return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN halSetDriverOwn(IN P_ADAPTER_T prAdapter) |
| { |
| BOOLEAN fgStatus = TRUE; |
| UINT_32 i, u4CurrTick = 0; |
| BOOLEAN fgTimeout; |
| BOOLEAN fgResult; |
| BOOLEAN fgReady = FALSE; |
| |
| ASSERT(prAdapter); |
| |
| GLUE_INC_REF_CNT(prAdapter->u4PwrCtrlBlockCnt); |
| |
| if (prAdapter->fgIsFwOwn == FALSE) |
| return fgStatus; |
| |
| DBGLOG(INIT, INFO, "DRIVER OWN\n"); |
| |
| u4CurrTick = kalGetTimeTick(); |
| i = 0; |
| |
| glWakeupSdio(prAdapter->prGlueInfo); |
| |
| while (1) { |
| HAL_LP_OWN_RD(prAdapter, &fgResult); |
| |
| if (TIME_BEFORE(kalGetTimeTick(), u4CurrTick)) { /* To prevent timer wraparound */ |
| fgTimeout = |
| ((kalGetTimeTick() + (~u4CurrTick)) > LP_OWN_BACK_TOTAL_DELAY_MS) ? TRUE : FALSE; |
| } else { |
| fgTimeout = |
| ((kalGetTimeTick() - u4CurrTick) > LP_OWN_BACK_TOTAL_DELAY_MS) ? TRUE : FALSE; |
| } |
| |
| if (fgResult) { |
| prAdapter->fgIsFwOwn = FALSE; |
| prAdapter->u4OwnFailedCount = 0; |
| prAdapter->u4OwnFailedLogCount = 0; |
| |
| if (nicSerIsWaitingReset(prAdapter)) { |
| /* SER is done, start Tx/Rx */ |
| nicSerStartTxRx(prAdapter); |
| } |
| break; |
| } else if ((i > LP_OWN_BACK_FAILED_RETRY_CNT) && |
| (kalIsCardRemoved(prAdapter->prGlueInfo) || fgIsBusAccessFailed || fgTimeout |
| || wlanIsChipNoAck(prAdapter))) { |
| |
| #if CFG_SUPPORT_LOW_POWER_DEBUG |
| /* For driver own back fail debug, get current PC value */ |
| halPrintMailbox(prAdapter); |
| halPollDbgCr(prAdapter, LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND); |
| #endif |
| if ((prAdapter->u4OwnFailedCount == 0) || |
| CHECK_FOR_TIMEOUT(u4CurrTick, prAdapter->rLastOwnFailedLogTime, |
| MSEC_TO_SYSTIME(LP_OWN_BACK_FAILED_LOG_SKIP_MS))) { |
| |
| DBGLOG(INIT, ERROR, |
| "LP cannot be own back, Timeout[%u](%ums), BusAccessError[%u]", |
| fgTimeout, kalGetTimeTick() - u4CurrTick, fgIsBusAccessFailed); |
| DBGLOG(INIT, ERROR, |
| "Resetting[%u], CardRemoved[%u] NoAck[%u] Cnt[%u]\n", |
| kalIsResetting(), |
| kalIsCardRemoved(prAdapter->prGlueInfo), wlanIsChipNoAck(prAdapter), |
| prAdapter->u4OwnFailedCount); |
| |
| DBGLOG(INIT, INFO, |
| "Skip LP own back failed log for next %ums\n", LP_OWN_BACK_FAILED_LOG_SKIP_MS); |
| |
| prAdapter->u4OwnFailedLogCount++; |
| if (prAdapter->u4OwnFailedLogCount > LP_OWN_BACK_FAILED_RESET_CNT) { |
| /* Trigger RESET */ |
| #if CFG_CHIP_RESET_SUPPORT |
| glResetTrigger(prAdapter); |
| #endif |
| } |
| GET_CURRENT_SYSTIME(&prAdapter->rLastOwnFailedLogTime); |
| } |
| |
| prAdapter->u4OwnFailedCount++; |
| fgStatus = FALSE; |
| break; |
| } |
| |
| #if 1 |
| if (i == 0) { |
| /* Software get LP ownership - only one time. |
| * Suppose one CLR_LP_OWN will trigger firmware to return the hif_own. |
| * If not, there is something wrong in chipset. |
| */ |
| HAL_LP_OWN_CLR(prAdapter, &fgResult); |
| } |
| #else |
| if ((i & (LP_OWN_BACK_CLR_OWN_ITERATION - 1)) == 0) { |
| /* Software get LP ownership - per 256 iterations */ |
| HAL_LP_OWN_CLR(prAdapter, &fgResult); |
| } |
| #endif |
| /* Delay for LP engine to complete its operation. */ |
| kalMsleep(LP_OWN_BACK_LOOP_DELAY_MS); |
| i++; |
| } |
| |
| /* For Low power Test */ |
| /* 1. Driver need to polling until CR4 ready, then could do normal Tx/Rx */ |
| /* 2. Send a dummy command to change data path to store-forward mode */ |
| #if 1 |
| if (prAdapter->fgIsFwDownloaded) { |
| u4CurrTick = kalGetTimeTick(); |
| while (1) { |
| HAL_WIFI_FUNC_READY_CHECK(prAdapter, WIFI_FUNC_READY_BITS, &fgReady); |
| |
| if (TIME_BEFORE(kalGetTimeTick(), u4CurrTick)) { /* To prevent timer wraparound */ |
| fgTimeout = |
| ((kalGetTimeTick() + (~u4CurrTick)) > LP_OWN_BACK_TOTAL_DELAY_MS) |
| ? TRUE : FALSE; |
| } else { |
| fgTimeout = |
| ((kalGetTimeTick() - u4CurrTick) > LP_OWN_BACK_TOTAL_DELAY_MS) |
| ? TRUE : FALSE; |
| } |
| |
| if (fgReady) { |
| break; |
| } else if (kalIsCardRemoved(prAdapter->prGlueInfo) || fgIsBusAccessFailed || fgTimeout |
| || wlanIsChipNoAck(prAdapter)) { |
| |
| #if CFG_SUPPORT_LOW_POWER_DEBUG |
| /* For driver own back fail debug, get current PC value */ |
| halPrintMailbox(prAdapter); |
| halPollDbgCr(prAdapter, LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND); |
| #endif |
| |
| DBGLOG(INIT, ERROR, |
| "Resetting[%u], CardRemoved[%u] NoAck[%u] Timeout[%u](%u - %u)ms\n", |
| kalIsResetting(), |
| kalIsCardRemoved(prAdapter->prGlueInfo), wlanIsChipNoAck(prAdapter), |
| fgTimeout, kalGetTimeTick(), u4CurrTick); |
| |
| |
| DBGLOG(INIT, INFO, |
| "Skip waiting CR4 ready for next %ums\n", LP_OWN_BACK_FAILED_LOG_SKIP_MS); |
| fgStatus = FALSE; |
| |
| if (fgTimeout) { |
| /* Trigger RESET */ |
| #if CFG_CHIP_RESET_SUPPORT |
| glResetTrigger(prAdapter); |
| #endif |
| } |
| |
| break; |
| } |
| /* Delay for CR4 to complete its operation. */ |
| kalMsleep(LP_OWN_BACK_LOOP_DELAY_MS); |
| } |
| |
| HAL_MCR_RD(prAdapter, MCR_D2HRM1R, &i); |
| if (i == 0x77889901) { |
| /* fgIsWakeupFromDeepSleep */ |
| wlanSendDummyCmd(prAdapter, FALSE); |
| |
| /* Workaround for dummy command which is not count in Tx done count */ |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[TC4_INDEX]--; |
| } |
| } |
| #endif |
| |
| return fgStatus; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief This routine is used to process the POWER ON procedure. |
| * |
| * \param[in] pvAdapter Pointer to the Adapter structure. |
| * |
| * \return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID halSetFWOwn(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgEnableGlobalInt) |
| { |
| |
| BOOLEAN fgResult; |
| |
| ASSERT(prAdapter); |
| |
| ASSERT(prAdapter->u4PwrCtrlBlockCnt != 0); |
| /* Decrease Block to Enter Low Power Semaphore count */ |
| GLUE_DEC_REF_CNT(prAdapter->u4PwrCtrlBlockCnt); |
| |
| if (prAdapter->u4PwrCtrlBlockCnt != 0) |
| return; |
| |
| if (prAdapter->fgForceFwOwn == FALSE) |
| if (prAdapter->fgWiFiInSleepyState == FALSE) |
| return; |
| |
| if (prAdapter->fgIsFwOwn == TRUE) |
| return; |
| |
| if ((nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) && !nicSerIsWaitingReset(prAdapter)) { |
| DBGLOG(INIT, STATE, "FW OWN Skipped due to pending INT\n"); |
| /* pending interrupts */ |
| return; |
| } |
| |
| if (fgEnableGlobalInt) { |
| prAdapter->fgIsIntEnableWithLPOwnSet = TRUE; |
| } else { |
| HAL_LP_OWN_SET(prAdapter, &fgResult); |
| |
| if (fgResult) { |
| /* if set firmware own not successful (possibly pending interrupts), */ |
| /* indicate an own clear event */ |
| HAL_LP_OWN_CLR(prAdapter, &fgResult); |
| |
| return; |
| } |
| |
| prAdapter->fgIsFwOwn = TRUE; |
| |
| DBGLOG(INIT, INFO, "FW OWN\n"); |
| } |
| |
| } |
| |
| VOID halWakeUpWiFi(IN P_ADAPTER_T prAdapter) |
| { |
| |
| BOOLEAN fgResult; |
| |
| ASSERT(prAdapter); |
| |
| HAL_LP_OWN_RD(prAdapter, &fgResult); |
| |
| if (fgResult) |
| prAdapter->fgIsFwOwn = FALSE; |
| else |
| HAL_LP_OWN_CLR(prAdapter, &fgResult); |
| |
| #if CFG_SUPPORT_LOW_POWER_DEBUG |
| /* Polling MCU programming counter */ |
| halPollDbgCr(prAdapter, LP_DBGCR_POLL_ROUND); |
| #endif |
| } |
| |
| VOID halDevInit(IN P_ADAPTER_T prAdapter) |
| { |
| UINT_32 u4Value = 0; |
| |
| ASSERT(prAdapter); |
| |
| #if CFG_SDIO_INTR_ENHANCE |
| /* 4 <1> Check STATUS Buffer is DW alignment. */ |
| ASSERT(IS_ALIGN_4((ULONG)&prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl->u4WHISR)); |
| |
| /* 4 <2> Setup STATUS count. */ |
| { |
| HAL_MCR_RD(prAdapter, MCR_WHCR, &u4Value); |
| |
| /* 4 <2.1> Setup the number of maximum RX length to be report */ |
| u4Value &= ~(WHCR_MAX_HIF_RX_LEN_NUM); |
| u4Value |= ((SDIO_MAXIMUM_RX_LEN_NUM << WHCR_OFFSET_MAX_HIF_RX_LEN_NUM)); |
| |
| /* 4 <2.2> Setup RX enhancement mode */ |
| #if CFG_SDIO_RX_ENHANCE |
| u4Value |= WHCR_RX_ENHANCE_MODE_EN; |
| #else |
| u4Value &= ~WHCR_RX_ENHANCE_MODE_EN; |
| #endif /* CFG_SDIO_RX_AGG */ |
| |
| HAL_MCR_WR(prAdapter, MCR_WHCR, u4Value); |
| } |
| #endif /* CFG_SDIO_INTR_ENHANCE */ |
| |
| HAL_MCR_WR(prAdapter, MCR_WHIER, WHIER_DEFAULT); |
| |
| HAL_CFG_MAX_HIF_RX_LEN_NUM(prAdapter, HIF_RX_MAX_AGG_NUM); |
| } |
| |
| VOID halTxCancelSendingCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) |
| { |
| } |
| |
| BOOLEAN halTxIsDataBufEnough(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) |
| { |
| return TRUE; |
| } |
| |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Driver maintain a variable that is synchronous with the usage of individual |
| * TC Buffer Count. This function will calculate TC page count according to |
| * the given TX_STATUS COUNTER after TX Done. |
| * |
| * \param[in] prAdapter Pointer to the Adapter structure. |
| * \param[in] au2TxRlsCnt array of TX STATUS |
| * \param[in] au2FreeTcResource array of free & available resource count |
| * |
| * @return TRUE there are available resource to release |
| * @return FALSE no available resource to release |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN halTxCalculateResource(IN P_ADAPTER_T prAdapter, IN PUINT_16 au2TxRlsCnt, OUT PUINT_16 au2FreeTcResource) |
| { |
| P_TX_TCQ_STATUS_T prTcqStatus; |
| BOOLEAN bStatus = FALSE; |
| UINT_8 ucTcIdx; |
| UINT_32 u4TotalTxDoneCnt = 0; |
| UINT_32 u4TotalExtraTxDone = 0; |
| UINT_32 au4UsedCnt[TC_NUM]; |
| UINT_32 au4ExtraTxDone[TC_NUM]; |
| |
| PUINT_32 au4TxDoneCnt; |
| PUINT_32 au4PreUsedCnt; |
| UINT_32 u4AvaliableCnt; |
| BOOLEAN fgEnExtraTxDone; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| prTcqStatus = &prAdapter->rTxCtrl.rTc; |
| |
| au4TxDoneCnt = prTcqStatus->au4TxDonePageCount; |
| au4PreUsedCnt = prTcqStatus->au4PreUsedPageCount; |
| u4AvaliableCnt = prTcqStatus->u4AvaliablePageCount; |
| fgEnExtraTxDone = prAdapter->rWifiVar.ucExtraTxDone; |
| |
| /* Get used page count */ |
| if (fgEnExtraTxDone) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| for (ucTcIdx = TC0_INDEX; ucTcIdx < TC_NUM; ucTcIdx++) { |
| au4UsedCnt[ucTcIdx] = prTcqStatus->au4MaxNumOfPage[ucTcIdx] - |
| prTcqStatus->au4FreePageCount[ucTcIdx]; |
| } |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| } |
| |
| /* Get Tx done & available page count */ |
| u4AvaliableCnt += au2TxRlsCnt[HIF_TX_FFA_INDEX]; |
| for (ucTcIdx = TC0_INDEX; ucTcIdx < TC_NUM; ucTcIdx++) { |
| |
| /* Get Tx done count from Tx interrupt status */ |
| au4TxDoneCnt[ucTcIdx] += au2TxRlsCnt[nicTxGetTxQByTc(prAdapter, ucTcIdx)]; |
| |
| /* Get available EXTRA Tx done */ |
| if (fgEnExtraTxDone) { |
| /* Release Tx done if there are pre-used resource */ |
| if (au4TxDoneCnt[ucTcIdx] >= au4PreUsedCnt[ucTcIdx]) { |
| au4TxDoneCnt[ucTcIdx] -= au4PreUsedCnt[ucTcIdx]; |
| au4PreUsedCnt[ucTcIdx] = 0; |
| } else { |
| au4PreUsedCnt[ucTcIdx] -= au4TxDoneCnt[ucTcIdx]; |
| au4TxDoneCnt[ucTcIdx] = 0; |
| } |
| |
| /* Calculate extra Tx done to share rest FFA resource */ |
| if (au4TxDoneCnt[ucTcIdx] >= au4UsedCnt[ucTcIdx]) { |
| au4TxDoneCnt[ucTcIdx] = au4UsedCnt[ucTcIdx]; |
| au4ExtraTxDone[ucTcIdx] = 0; |
| } else { |
| au4ExtraTxDone[ucTcIdx] = au4UsedCnt[ucTcIdx] - au4TxDoneCnt[ucTcIdx]; |
| } |
| u4TotalExtraTxDone += au4ExtraTxDone[ucTcIdx]; |
| } |
| |
| u4TotalTxDoneCnt += au4TxDoneCnt[ucTcIdx]; |
| |
| } |
| |
| DBGLOG(TX, TRACE, "TxDone result, FFA[%u] AC[%u:%u:%u:%u] CPU[%u]\n", |
| au2TxRlsCnt[HIF_TX_FFA_INDEX], au2TxRlsCnt[HIF_TX_AC0_INDEX], |
| au2TxRlsCnt[HIF_TX_AC1_INDEX], au2TxRlsCnt[HIF_TX_AC2_INDEX], |
| au2TxRlsCnt[HIF_TX_AC3_INDEX], au2TxRlsCnt[HIF_TX_CPU_INDEX]); |
| |
| DBGLOG(TX, TRACE, "TxDone Page count, TC[%u:%u:%u:%u:%u:%u]\n", |
| au4TxDoneCnt[TC0_INDEX], au4TxDoneCnt[TC1_INDEX], au4TxDoneCnt[TC2_INDEX], |
| au4TxDoneCnt[TC3_INDEX], au4TxDoneCnt[TC4_INDEX], au4TxDoneCnt[TC5_INDEX]); |
| |
| /* Calculate free Tc page count */ |
| if (u4AvaliableCnt && u4TotalTxDoneCnt) { |
| /* Distribute resource by Tx done counter */ |
| if (u4AvaliableCnt >= u4TotalTxDoneCnt) { |
| /* Fulfill all TC resource */ |
| kalMemCopy(au2FreeTcResource, prTcqStatus->au4TxDonePageCount, |
| sizeof(prTcqStatus->au4TxDonePageCount)); |
| |
| kalMemZero(prTcqStatus->au4TxDonePageCount, sizeof(prTcqStatus->au4TxDonePageCount)); |
| |
| u4AvaliableCnt -= u4TotalTxDoneCnt; |
| } else { |
| /* Round-robin distribute resource */ |
| ucTcIdx = prTcqStatus->ucNextTcIdx; |
| while (u4AvaliableCnt) { |
| /* Enough resource, fulfill this TC */ |
| if (u4AvaliableCnt >= au4TxDoneCnt[ucTcIdx]) { |
| au2FreeTcResource[ucTcIdx] = au4TxDoneCnt[ucTcIdx]; |
| u4AvaliableCnt -= au4TxDoneCnt[ucTcIdx]; |
| au4TxDoneCnt[ucTcIdx] = 0; |
| |
| /* Round-robin get next TC */ |
| ucTcIdx++; |
| ucTcIdx %= TC_NUM; |
| } |
| /* no more resource, distribute rest of resource to this TC */ |
| else { |
| au2FreeTcResource[ucTcIdx] = u4AvaliableCnt; |
| au4TxDoneCnt[ucTcIdx] -= u4AvaliableCnt; |
| u4AvaliableCnt = 0; |
| } |
| } |
| prTcqStatus->ucNextTcIdx = ucTcIdx; |
| } |
| bStatus = TRUE; |
| } |
| |
| if (u4AvaliableCnt && u4TotalExtraTxDone && fgEnExtraTxDone) { |
| /* Distribute resource by EXTRA Tx done counter */ |
| if (u4AvaliableCnt >= u4TotalExtraTxDone) { |
| for (ucTcIdx = TC0_INDEX; ucTcIdx < TC_NUM; ucTcIdx++) { |
| au2FreeTcResource[ucTcIdx] += au4ExtraTxDone[ucTcIdx]; |
| au4PreUsedCnt[ucTcIdx] += au4ExtraTxDone[ucTcIdx]; |
| au4ExtraTxDone[ucTcIdx] = 0; |
| } |
| |
| u4AvaliableCnt -= u4TotalExtraTxDone; |
| } else { |
| /* Round-robin distribute resource */ |
| ucTcIdx = prTcqStatus->ucNextTcIdx; |
| while (u4AvaliableCnt) { |
| /* Enough resource, fulfill this TC */ |
| if (u4AvaliableCnt >= au4ExtraTxDone[ucTcIdx]) { |
| au2FreeTcResource[ucTcIdx] += au4ExtraTxDone[ucTcIdx]; |
| au4PreUsedCnt[ucTcIdx] += au4ExtraTxDone[ucTcIdx]; |
| u4AvaliableCnt -= au4ExtraTxDone[ucTcIdx]; |
| au4ExtraTxDone[ucTcIdx] = 0; |
| |
| /* Round-robin get next TC */ |
| ucTcIdx++; |
| ucTcIdx %= TC_NUM; |
| } |
| /* no more resource, distribute rest of resource to this TC */ |
| else { |
| au2FreeTcResource[ucTcIdx] += u4AvaliableCnt; |
| au4PreUsedCnt[ucTcIdx] += u4AvaliableCnt; |
| au4ExtraTxDone[ucTcIdx] -= u4AvaliableCnt; |
| u4AvaliableCnt = 0; |
| } |
| } |
| prTcqStatus->ucNextTcIdx = ucTcIdx; |
| } |
| bStatus = TRUE; |
| } |
| |
| prTcqStatus->u4AvaliablePageCount = u4AvaliableCnt; |
| |
| return bStatus; |
| } |
| BOOLEAN halTxReleaseResource(IN P_ADAPTER_T prAdapter, IN PUINT_16 au2TxRlsCnt) |
| { |
| P_TX_TCQ_STATUS_T prTcqStatus; |
| BOOLEAN bStatus = FALSE; |
| UINT_32 i; |
| P_SDIO_STAT_COUNTER_T prStatCnt; |
| UINT_16 au2TxDoneCnt[HIF_TX_NUM] = { 0 }; |
| UINT_16 u2ReturnCnt; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| prTcqStatus = &prAdapter->rTxCtrl.rTc; |
| prStatCnt = &prAdapter->prGlueInfo->rHifInfo.rStatCounter; |
| |
| /* Update Free Tc resource counter */ |
| for (i = HIF_TX_AC0_INDEX; i <= HIF_TX_AC23_INDEX; i++) |
| au2TxDoneCnt[i % WMM_AC_INDEX_NUM] += au2TxRlsCnt[i]; |
| au2TxDoneCnt[HIF_TX_CPU_INDEX] = au2TxRlsCnt[HIF_TX_CPU_INDEX]; |
| |
| /* Return free Tc page count */ |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| for (i = TC0_INDEX; i < TC5_INDEX; i++) { |
| u2ReturnCnt = au2TxDoneCnt[nicTxGetTxQByTc(prAdapter, i)]; |
| nicTxReleaseResource(prAdapter, i, u2ReturnCnt, FALSE); |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[i] -= u2ReturnCnt; |
| } |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| bStatus = TRUE; |
| |
| /* Update Statistic counter */ |
| prStatCnt->u4TxDonePendingPktCnt += nicTxGetMsduPendingCnt(prAdapter); |
| prStatCnt->u4TxDoneIntTotCnt++; |
| |
| for (i = HIF_TX_AC0_INDEX; i < HIF_TX_NUM; i++) { |
| if (au2TxRlsCnt[i]) { |
| prStatCnt->u4TxDoneCnt[i] += au2TxRlsCnt[i]; |
| prStatCnt->u4TxDoneIntCnt[i]++; |
| } |
| } |
| |
| if (!nicTxSanityCheckResource(prAdapter)) |
| DBGLOG(TX, ERROR, "Tx Done INT result, FFA[%u] AC[%u:%u:%u:%u] CPU[%u]\n", |
| au2TxRlsCnt[HIF_TX_FFA_INDEX], au2TxRlsCnt[HIF_TX_AC0_INDEX], |
| au2TxRlsCnt[HIF_TX_AC1_INDEX], au2TxRlsCnt[HIF_TX_AC2_INDEX], |
| au2TxRlsCnt[HIF_TX_AC3_INDEX], au2TxRlsCnt[HIF_TX_CPU_INDEX]); |
| |
| DBGLOG(TX, LOUD, "TCQ Status Free Page:Buf[%u:%u, %u:%u, %u:%u, %u:%u, %u:%u, %u:%u]\n", |
| prTcqStatus->au4FreePageCount[TC0_INDEX], prTcqStatus->au4FreeBufferCount[TC0_INDEX], |
| prTcqStatus->au4FreePageCount[TC1_INDEX], prTcqStatus->au4FreeBufferCount[TC1_INDEX], |
| prTcqStatus->au4FreePageCount[TC2_INDEX], prTcqStatus->au4FreeBufferCount[TC2_INDEX], |
| prTcqStatus->au4FreePageCount[TC3_INDEX], prTcqStatus->au4FreeBufferCount[TC3_INDEX], |
| prTcqStatus->au4FreePageCount[TC4_INDEX], prTcqStatus->au4FreeBufferCount[TC4_INDEX], |
| prTcqStatus->au4FreePageCount[TC5_INDEX], prTcqStatus->au4FreeBufferCount[TC5_INDEX]); |
| |
| return bStatus; |
| } |
| |
| WLAN_STATUS halTxPollingResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES; |
| UINT_32 au4WTSR[8]; |
| P_GL_HIF_INFO_T prHifInfo; |
| |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| if (prHifInfo->fgIsPendingInt && (prHifInfo->prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT)) { |
| /* Get Tx done resource from pending interrupt status */ |
| kalMemCopy(au4WTSR, &prHifInfo->prSDIOCtrl->rTxInfo, sizeof(UINT_32) * 8); |
| |
| /* Clear pending Tx done interrupt */ |
| prHifInfo->prSDIOCtrl->u4WHISR &= ~WHISR_TX_DONE_INT; |
| } else |
| HAL_READ_TX_RELEASED_COUNT(prAdapter, au4WTSR); |
| |
| if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { |
| u4Status = WLAN_STATUS_FAILURE; |
| } else if (halTxReleaseResource(prAdapter, (PUINT_16) au4WTSR)) { |
| if (prTxCtrl->rTc.au4FreeBufferCount[ucTC] > 0) |
| u4Status = WLAN_STATUS_SUCCESS; |
| } |
| |
| return u4Status; |
| } |
| |
| VOID halTxInterruptSanityCheck(IN P_ADAPTER_T prAdapter, IN PUINT_16 au2TxRlsCnt) |
| { |
| UINT_8 ucIdx; |
| BOOLEAN fgError = FALSE; |
| |
| if (prAdapter->rWifiVar.ucTxDbg & BIT(1)) { |
| for (ucIdx = HIF_TX_AC0_INDEX; ucIdx < HIF_TX_NUM; ucIdx++) { |
| if (au2TxRlsCnt[ucIdx] > prAdapter->rTxCtrl.u4TotalPageNum) |
| fgError = TRUE; |
| } |
| |
| if (fgError) |
| DBGLOG(TX, ERROR, "Tx Done INT result, FFA[%u] AC[%u:%u:%u:%u] CPU[%u]\n", |
| au2TxRlsCnt[HIF_TX_FFA_INDEX], au2TxRlsCnt[HIF_TX_AC0_INDEX], |
| au2TxRlsCnt[HIF_TX_AC1_INDEX], au2TxRlsCnt[HIF_TX_AC2_INDEX], |
| au2TxRlsCnt[HIF_TX_AC3_INDEX], au2TxRlsCnt[HIF_TX_CPU_INDEX]); |
| } |
| } |
| |
| #if CFG_SDIO_INTR_ENHANCE |
| VOID halProcessEnhanceInterruptStatus(IN P_ADAPTER_T prAdapter) |
| { |
| P_SDIO_CTRL_T prSDIOCtrl = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl; |
| |
| /* Set Tx done interrupt if there are Tx done count */ |
| if ((prSDIOCtrl->u4WHISR & WHISR_TX_DONE_INT) == 0 && |
| (prSDIOCtrl->rTxInfo.au4WTSR[0] | prSDIOCtrl->rTxInfo.au4WTSR[1] | |
| prSDIOCtrl->rTxInfo.au4WTSR[2] | prSDIOCtrl->rTxInfo.au4WTSR[3] | |
| prSDIOCtrl->rTxInfo.au4WTSR[4] | prSDIOCtrl->rTxInfo.au4WTSR[5] | |
| prSDIOCtrl->rTxInfo.au4WTSR[6] | prSDIOCtrl->rTxInfo.au4WTSR[7])) { |
| |
| prSDIOCtrl->u4WHISR |= WHISR_TX_DONE_INT; |
| } |
| |
| /* Set SW ASSERT INFO interrupt if there are pending mail box */ |
| if (((prSDIOCtrl->u4WHISR & WHISR_D2H_SW_ASSERT_INFO_INT) == 0) && |
| HAL_GET_MAILBOX_READ_CLEAR(prAdapter) && |
| (prSDIOCtrl->u4RcvMailbox0 || prSDIOCtrl->u4RcvMailbox1)) { |
| |
| prSDIOCtrl->u4WHISR |= WHISR_D2H_SW_ASSERT_INFO_INT; |
| } |
| } |
| #endif |
| |
| VOID halProcessTxInterrupt(IN P_ADAPTER_T prAdapter) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| #if CFG_SDIO_INTR_ENHANCE |
| P_SDIO_CTRL_T prSDIOCtrl; |
| #else |
| UINT_32 au4TxCount[2]; |
| #endif /* CFG_SDIO_INTR_ENHANCE */ |
| SDIO_TIME_INTERVAL_DEC(); |
| |
| ASSERT(prAdapter); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| ASSERT(prTxCtrl); |
| |
| SDIO_REC_TIME_START(); |
| |
| /* Get the TX STATUS */ |
| #if CFG_SDIO_INTR_ENHANCE |
| |
| prSDIOCtrl = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl; |
| #if DBG |
| /* DBGLOG_MEM8(RX, TRACE, (PUINT_8)prSDIOCtrl, sizeof(SDIO_CTRL_T)); */ |
| #endif |
| |
| halTxInterruptSanityCheck(prAdapter, (PUINT_16)&prSDIOCtrl->rTxInfo); |
| halTxReleaseResource(prAdapter, (PUINT_16)&prSDIOCtrl->rTxInfo); |
| kalMemZero(&prSDIOCtrl->rTxInfo, sizeof(prSDIOCtrl->rTxInfo)); |
| |
| #else |
| |
| HAL_MCR_RD(prAdapter, MCR_WTSR0, &au4TxCount[0]); |
| HAL_MCR_RD(prAdapter, MCR_WTSR1, &au4TxCount[1]); |
| DBGLOG(EMU, TRACE, "MCR_WTSR0: 0x%x, MCR_WTSR1: 0x%x\n", au4TxCount[0], au4TxCount[1]); |
| |
| halTxReleaseResource(prAdapter, (PUINT_8) au4TxCount); |
| |
| #endif /* CFG_SDIO_INTR_ENHANCE */ |
| |
| nicTxAdjustTcq(prAdapter); |
| |
| SDIO_REC_TIME_END(); |
| SDIO_ADD_TIME_INTERVAL(prAdapter->prGlueInfo->rHifInfo.rStatCounter.u4TxDoneIntTime); |
| |
| } /* end of nicProcessTxInterrupt() */ |
| |
| #if !CFG_SDIO_INTR_ENHANCE |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Read the rx data from data port and setup RFB |
| * |
| * @param prAdapter pointer to the Adapter handler |
| * @param prSWRfb the RFB to receive rx data |
| * |
| * @retval WLAN_STATUS_SUCCESS: SUCCESS |
| * @retval WLAN_STATUS_FAILURE: FAILURE |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS halRxReadBuffer(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) |
| { |
| P_RX_CTRL_T prRxCtrl; |
| PUINT_8 pucBuf; |
| P_HW_MAC_RX_DESC_T prRxStatus; |
| UINT_32 u4PktLen = 0, u4ReadBytes; |
| WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; |
| BOOL fgResult = TRUE; |
| UINT_32 u4RegValue; |
| UINT_32 rxNum; |
| |
| DEBUGFUNC("halRxReadBuffer"); |
| |
| ASSERT(prAdapter); |
| ASSERT(prSwRfb); |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| ASSERT(prRxCtrl); |
| |
| pucBuf = prSwRfb->pucRecvBuff; |
| prRxStatus = prSwRfb->prRxStatus; |
| |
| ASSERT(prRxStatus); |
| ASSERT(pucBuf); |
| DBGLOG(RX, TRACE, "pucBuf= 0x%x, prRxStatus= 0x%x\n", pucBuf, prRxStatus); |
| |
| do { |
| /* Read the RFB DW length and packet length */ |
| HAL_MCR_RD(prAdapter, MCR_WRPLR, &u4RegValue); |
| if (!fgResult) { |
| DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); |
| return WLAN_STATUS_FAILURE; |
| } |
| /* 20091021 move the line to get the HIF RX header (for RX0/1) */ |
| if (u4RegValue == 0) { |
| DBGLOG(RX, ERROR, "No RX packet\n"); |
| return WLAN_STATUS_FAILURE; |
| } |
| |
| u4PktLen = u4RegValue & BITS(0, 15); |
| if (u4PktLen != 0) { |
| rxNum = 0; |
| } else { |
| rxNum = 1; |
| u4PktLen = (u4RegValue & BITS(16, 31)) >> 16; |
| } |
| |
| DBGLOG(RX, TRACE, "RX%d: u4PktLen = %d\n", rxNum, u4PktLen); |
| |
| /* 4 <4> Read Entire RFB and packet, include HW appended DW (Checksum Status) */ |
| u4ReadBytes = ALIGN_4(u4PktLen) + 4; |
| HAL_READ_RX_PORT(prAdapter, rxNum, u4ReadBytes, pucBuf, CFG_RX_MAX_PKT_SIZE); |
| |
| /* 20091021 move the line to get the HIF RX header */ |
| /* u4PktLen = (UINT_32)prHifRxHdr->u2PacketLen; */ |
| if (u4PktLen != (UINT_32) HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)) { |
| DBGLOG(RX, ERROR, "Read u4PktLen = %d, prHifRxHdr->u2PacketLen: %d\n", |
| u4PktLen, HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)); |
| #if DBG |
| DBGLOG_MEM8(RX, TRACE, (PUINT_8) prRxStatus, |
| (HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus) > |
| 4096) ? 4096 : prRxStatus->u2RxByteCount); |
| #endif |
| ASSERT(0); |
| } |
| /* u4PktLen is byte unit, not inlude HW appended DW */ |
| |
| prSwRfb->ucPacketType = (UINT_8) HAL_RX_STATUS_GET_PKT_TYPE(prRxStatus); |
| DBGLOG(RX, TRACE, "ucPacketType = %d\n", prSwRfb->ucPacketType); |
| |
| prSwRfb->ucStaRecIdx = |
| secGetStaIdxByWlanIdx(prAdapter, (UINT_8) HAL_RX_STATUS_GET_WLAN_IDX(prRxStatus)); |
| |
| /* fgResult will be updated in MACRO */ |
| if (!fgResult) |
| return WLAN_STATUS_FAILURE; |
| |
| DBGLOG(RX, TRACE, "Dump RX buffer, length = 0x%x\n", u4ReadBytes); |
| DBGLOG_MEM8(RX, TRACE, pucBuf, u4ReadBytes); |
| } while (FALSE); |
| |
| return u4Status; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Read frames from the data port, fill RFB |
| * and put each frame into the rReceivedRFBList queue. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID halRxSDIOReceiveRFBs(IN P_ADAPTER_T prAdapter) |
| { |
| P_RX_CTRL_T prRxCtrl; |
| P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; |
| P_HW_MAC_RX_DESC_T prRxStatus; |
| UINT_32 u4HwAppendDW; |
| PUINT_32 pu4Temp; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| DEBUGFUNC("halRxSDIOReceiveRFBs"); |
| |
| ASSERT(prAdapter); |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| ASSERT(prRxCtrl); |
| |
| do { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); |
| QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); |
| |
| if (!prSwRfb) { |
| DBGLOG(RX, TRACE, "No More RFB\n"); |
| break; |
| } |
| /* need to consider */ |
| if (halRxReadBuffer(prAdapter, prSwRfb) == WLAN_STATUS_FAILURE) { |
| DBGLOG(RX, TRACE, "halRxFillRFB failed\n"); |
| nicRxReturnRFB(prAdapter, prSwRfb); |
| break; |
| } |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); |
| QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); |
| RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); |
| |
| prRxStatus = prSwRfb->prRxStatus; |
| ASSERT(prRxStatus); |
| |
| pu4Temp = (PUINT_32) prRxStatus; |
| u4HwAppendDW = *(pu4Temp + (ALIGN_4(prRxStatus->u2RxByteCount) >> 2)); |
| DBGLOG(RX, TRACE, "u4HwAppendDW = 0x%x\n", u4HwAppendDW); |
| DBGLOG(RX, TRACE, "u2PacketLen = 0x%x\n", HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)); |
| } while (FALSE); |
| |
| } /* end of nicReceiveRFBs() */ |
| |
| #else |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Read frames from the data port, fill RFB |
| * and put each frame into the rReceivedRFBList queue. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param u4DataPort Specify which port to read |
| * @param u2RxLength Specify to the the rx packet length in Byte. |
| * @param prSwRfb the RFB to receive rx data. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| WLAN_STATUS |
| halRxEnhanceReadBuffer(IN P_ADAPTER_T prAdapter, |
| IN UINT_32 u4DataPort, IN UINT_16 u2RxLength, IN OUT P_SW_RFB_T prSwRfb) |
| { |
| P_RX_CTRL_T prRxCtrl; |
| PUINT_8 pucBuf; |
| P_HW_MAC_RX_DESC_T prRxStatus; |
| UINT_32 u4PktLen = 0; |
| WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; |
| BOOL fgResult = TRUE; |
| |
| DEBUGFUNC("halRxEnhanceReadBuffer"); |
| |
| ASSERT(prAdapter); |
| ASSERT(prSwRfb); |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| ASSERT(prRxCtrl); |
| |
| pucBuf = prSwRfb->pucRecvBuff; |
| ASSERT(pucBuf); |
| |
| prRxStatus = prSwRfb->prRxStatus; |
| ASSERT(prRxStatus); |
| |
| /* DBGLOG(RX, TRACE, ("u2RxLength = %d\n", u2RxLength)); */ |
| |
| do { |
| /* 4 <1> Read RFB frame from MCR_WRDR0, include HW appended DW */ |
| HAL_READ_RX_PORT(prAdapter, |
| u4DataPort, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN), pucBuf, CFG_RX_MAX_PKT_SIZE); |
| |
| if (!fgResult) { |
| DBGLOG(RX, ERROR, "Read RX Packet Lentgh Error\n"); |
| break; |
| } |
| |
| u4PktLen = (UINT_32) (HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)); |
| /* DBGLOG(RX, TRACE, ("u4PktLen = %d\n", u4PktLen)); */ |
| |
| prSwRfb->ucPacketType = (UINT_8) HAL_RX_STATUS_GET_PKT_TYPE(prRxStatus); |
| /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */ |
| |
| prSwRfb->ucStaRecIdx = |
| secGetStaIdxByWlanIdx(prAdapter, (UINT_8) HAL_RX_STATUS_GET_WLAN_IDX(prRxStatus)); |
| |
| /* 4 <2> if the RFB dw size or packet size is zero */ |
| if (u4PktLen == 0) { |
| DBGLOG(RX, ERROR, "Packet Length = %lu\n", u4PktLen); |
| ASSERT(0); |
| break; |
| } |
| /* 4 <3> if the packet is too large or too small */ |
| /* ToDo[6630]: adjust CFG_RX_MAX_PKT_SIZE */ |
| if (u4PktLen > CFG_RX_MAX_PKT_SIZE) { |
| DBGLOG(RX, TRACE, "Read RX Packet Lentgh Error (%lu)\n", u4PktLen); |
| ASSERT(0); |
| break; |
| } |
| |
| u4Status = WLAN_STATUS_SUCCESS; |
| } while (FALSE); |
| |
| DBGLOG_MEM8(RX, TRACE, pucBuf, ALIGN_4(u2RxLength + HIF_RX_HW_APPENDED_LEN)); |
| return u4Status; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Read frames from the data port for SDIO |
| * I/F, fill RFB and put each frame into the rReceivedRFBList queue. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID halRxSDIOEnhanceReceiveRFBs(IN P_ADAPTER_T prAdapter) |
| { |
| P_SDIO_CTRL_T prSDIOCtrl; |
| P_RX_CTRL_T prRxCtrl; |
| P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; |
| UINT_32 i, rxNum; |
| UINT_16 u2RxPktNum, u2RxLength = 0, u2Tmp = 0; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| DEBUGFUNC("halRxSDIOEnhanceReceiveRFBs"); |
| |
| ASSERT(prAdapter); |
| |
| prSDIOCtrl = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl; |
| ASSERT(prSDIOCtrl); |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| ASSERT(prRxCtrl); |
| |
| for (rxNum = 0; rxNum < 2; rxNum++) { |
| u2RxPktNum = |
| (rxNum == 0 ? prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len : prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len); |
| |
| if (u2RxPktNum == 0) |
| continue; |
| |
| for (i = 0; i < u2RxPktNum; i++) { |
| if (rxNum == 0) { |
| /* HAL_READ_RX_LENGTH */ |
| HAL_READ_RX_LENGTH(prAdapter, &u2RxLength, &u2Tmp); |
| } else if (rxNum == 1) { |
| /* HAL_READ_RX_LENGTH */ |
| HAL_READ_RX_LENGTH(prAdapter, &u2Tmp, &u2RxLength); |
| } |
| |
| if (!u2RxLength) |
| break; |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); |
| QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); |
| |
| if (!prSwRfb) { |
| DBGLOG(RX, TRACE, "No More RFB\n"); |
| break; |
| } |
| ASSERT(prSwRfb); |
| |
| if (halRxEnhanceReadBuffer(prAdapter, rxNum, u2RxLength, prSwRfb) == WLAN_STATUS_FAILURE) { |
| DBGLOG(RX, TRACE, "nicRxEnhanceRxReadBuffer failed\n"); |
| nicRxReturnRFB(prAdapter, prSwRfb); |
| break; |
| } |
| /* prSDIOCtrl->au4RxLength[i] = 0; */ |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); |
| QUEUE_INSERT_TAIL(&prRxCtrl->rReceivedRfbList, &prSwRfb->rQueEntry); |
| RX_INC_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); |
| } |
| } |
| |
| prSDIOCtrl->rRxInfo.u.u2NumValidRx0Len = 0; |
| prSDIOCtrl->rRxInfo.u.u2NumValidRx1Len = 0; |
| |
| } /* end of nicRxSDIOReceiveRFBs() */ |
| |
| #endif /* CFG_SDIO_INTR_ENHANCE */ |
| |
| #if CFG_SDIO_RX_AGG |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Read frames from the data port for SDIO with Rx aggregation enabled |
| * I/F, fill RFB and put each frame into the rReceivedRFBList queue. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID halRxSDIOAggReceiveRFBs(IN P_ADAPTER_T prAdapter) |
| { |
| P_ENHANCE_MODE_DATA_STRUCT_T prEnhDataStr; |
| P_RX_CTRL_T prRxCtrl; |
| UINT_32 u4RxLength; |
| UINT_32 i, rxNum; |
| UINT_32 u4RxAggCount = 0, u4RxAggLength = 0; |
| UINT_32 u4RxAvailAggLen; |
| PUINT_8 pucSrcAddr; |
| UINT_16 u2RxPktNum; |
| P_GL_HIF_INFO_T prHifInfo; |
| P_SDIO_RX_COALESCING_BUF_T prRxBuf; |
| BOOLEAN fgNoFreeBuf = FALSE; |
| |
| SDIO_TIME_INTERVAL_DEC(); |
| |
| DEBUGFUNC("halRxSDIOAggReceiveRFBs"); |
| |
| ASSERT(prAdapter); |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| prEnhDataStr = prHifInfo->prSDIOCtrl; |
| |
| if (prEnhDataStr->rRxInfo.u.u2NumValidRx0Len == 0 && prEnhDataStr->rRxInfo.u.u2NumValidRx1Len == 0) |
| return; |
| |
| for (rxNum = 0; rxNum < 2; rxNum++) { |
| u2RxPktNum = (rxNum == 0 ? prEnhDataStr->rRxInfo.u.u2NumValidRx0Len : |
| prEnhDataStr->rRxInfo.u.u2NumValidRx1Len); |
| |
| /* if this assertion happened, it is most likely a F/W bug */ |
| ASSERT(u2RxPktNum <= HIF_RX_MAX_AGG_NUM); |
| |
| if (u2RxPktNum > HIF_RX_MAX_AGG_NUM) |
| continue; |
| |
| if (u2RxPktNum == 0) |
| continue; |
| |
| #if CFG_HIF_STATISTICS |
| prRxCtrl->u4TotalRxAccessNum++; |
| prRxCtrl->u4TotalRxPacketNum += u2RxPktNum; |
| #endif |
| |
| mutex_lock(&prHifInfo->rRxFreeBufQueMutex); |
| fgNoFreeBuf = QUEUE_IS_EMPTY(&prHifInfo->rRxFreeBufQueue); |
| mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); |
| |
| if (fgNoFreeBuf) { |
| DBGLOG(RX, TRACE, "[%s] No free Rx buffer\n", __func__); |
| prHifInfo->rStatCounter.u4RxBufUnderFlowCnt++; |
| |
| if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| QUE_T rTempQue; |
| P_QUE_T prTempQue = &rTempQue; |
| |
| /* During halt state, move all pending Rx buffer to free queue */ |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| QUEUE_MOVE_ALL(prTempQue, &prHifInfo->rRxDeAggQueue); |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| |
| mutex_lock(&prHifInfo->rRxFreeBufQueMutex); |
| QUEUE_CONCATENATE_QUEUES(&prHifInfo->rRxFreeBufQueue, prTempQue); |
| mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); |
| } |
| |
| continue; |
| } |
| |
| u4RxAvailAggLen = HIF_RX_COALESCING_BUFFER_SIZE; |
| #if CFG_SDIO_RX_ENHANCE |
| u4RxAvailAggLen -= (sizeof(ENHANCE_MODE_DATA_STRUCT_T) + HIF_RX_ENHANCE_MODE_PAD_LEN); |
| #endif |
| u4RxAggCount = 0; |
| |
| for (i = 0; i < u2RxPktNum; i++) { |
| u4RxLength = (rxNum == 0 ? (UINT_32) prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : |
| (UINT_32) prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); |
| |
| if (!u4RxLength) { |
| ASSERT(0); |
| DBGLOG(RX, ERROR, "[%s] RxLength == 0\n", __func__); |
| break; |
| } |
| |
| if (ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN) < u4RxAvailAggLen) { |
| u4RxAvailAggLen -= ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN); |
| u4RxAggCount++; |
| } else { |
| /* CFG_RX_COALESCING_BUFFER_SIZE is not large enough */ |
| DBGLOG(RX, ERROR, "[%s] Request_len(%d) >= Available_len(%d)\n", |
| __func__, (ALIGN_4(u4RxLength + HIF_RX_HW_APPENDED_LEN)), u4RxAvailAggLen); |
| ASSERT(0); |
| break; |
| } |
| } |
| |
| mutex_lock(&prHifInfo->rRxFreeBufQueMutex); |
| QUEUE_REMOVE_HEAD(&prHifInfo->rRxFreeBufQueue, prRxBuf, P_SDIO_RX_COALESCING_BUF_T); |
| mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); |
| |
| prRxBuf->u4PktCount = u4RxAggCount; |
| |
| u4RxAggLength = (HIF_RX_COALESCING_BUFFER_SIZE - u4RxAvailAggLen); |
| |
| SDIO_REC_TIME_START(); |
| HAL_READ_RX_PORT(prAdapter, rxNum, u4RxAggLength, |
| prRxBuf->pvRxCoalescingBuf, HIF_RX_COALESCING_BUFFER_SIZE); |
| SDIO_REC_TIME_END(); |
| SDIO_ADD_TIME_INTERVAL(prHifInfo->rStatCounter.u4PortReadTime); |
| |
| #if CFG_SDIO_RX_ENHANCE |
| pucSrcAddr = prRxBuf->pvRxCoalescingBuf + u4RxAggLength - sizeof(ENHANCE_MODE_DATA_STRUCT_T); |
| kalMemCopy(prHifInfo->prSDIOCtrl, pucSrcAddr, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); |
| |
| halProcessEnhanceInterruptStatus(prAdapter); |
| |
| if (prHifInfo->prSDIOCtrl->u4WHISR) { |
| /* Interrupt status without Rx done */ |
| /* Mask Rx done interrupt to avoid recurrsion */ |
| UINT_32 u4IntStatus = prHifInfo->prSDIOCtrl->u4WHISR & |
| (~(WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT)); |
| |
| if ((rxNum == 0) && prEnhDataStr->rRxInfo.u.u2NumValidRx1Len && u4IntStatus) { |
| /* Handle interrupt here if there are pending Rx port1 */ |
| |
| nicProcessIST_impl(prAdapter, u4IntStatus); |
| } else { |
| prAdapter->prGlueInfo->rHifInfo.fgIsPendingInt = TRUE; |
| } |
| } |
| #endif |
| halDeAggRxPkt(prAdapter, prRxBuf); |
| |
| /* Update statistic counter */ |
| prHifInfo->rStatCounter.u4PktReadCnt[rxNum] += u4RxAggCount; |
| prHifInfo->rStatCounter.u4PortReadCnt[rxNum]++; |
| } |
| |
| } |
| #endif /* CFG_SDIO_RX_AGG */ |
| |
| |
| VOID halProcessRxInterrupt(IN P_ADAPTER_T prAdapter) |
| { |
| #if CFG_SDIO_INTR_ENHANCE |
| #if CFG_SDIO_RX_AGG |
| halRxSDIOAggReceiveRFBs(prAdapter); |
| #else |
| halRxSDIOEnhanceReceiveRFBs(prAdapter); |
| #endif |
| #else |
| halRxSDIOReceiveRFBs(prAdapter); |
| #endif /* CFG_SDIO_INTR_ENHANCE */ |
| } |
| |
| VOID halHifSwInfoInit(IN P_ADAPTER_T prAdapter) |
| { |
| |
| } |
| |
| VOID halRxProcessMsduReport(IN P_ADAPTER_T prAdapter, IN OUT P_SW_RFB_T prSwRfb) |
| { |
| |
| } |
| |
| UINT_32 halTxGetPageCount(IN UINT_32 u4FrameLength, IN BOOLEAN fgIncludeDesc) |
| { |
| return 1; |
| } |
| |
| UINT_32 halDumpHifStatus(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucBuf, IN UINT_32 u4Max) |
| { |
| P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; |
| P_GL_HIF_INFO_T prHifInfo = &prGlueInfo->rHifInfo; |
| P_SDIO_STAT_COUNTER_T prStatCnt = &prHifInfo->rStatCounter; |
| UINT_32 u4Len = 0; |
| |
| /* Print out counter */ |
| LOGBUF(pucBuf, u4Max, u4Len, "\n"); |
| LOGBUF(pucBuf, u4Max, u4Len, "------<Dump SDIO Status>------\n"); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Coalescing buffer size[%u] Rx Cnt[%u/%u] DeAgg[%u] UF Cnt[%u]\n", |
| prAdapter->u4CoalescingBufCachedSize, prHifInfo->rRxFreeBufQueue.u4NumElem, |
| HIF_RX_COALESCING_BUF_COUNT, prHifInfo->rRxDeAggQueue.u4NumElem, |
| prStatCnt->u4RxBufUnderFlowCnt); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Pkt cnt Tx[%u] RxP0[%u] RxP1[%u] Tx/Rx ratio[%u.%u]\n", |
| prStatCnt->u4DataPktWriteCnt, prStatCnt->u4PktReadCnt[0], prStatCnt->u4PktReadCnt[1], |
| DIV2INT(prStatCnt->u4DataPktWriteCnt, prStatCnt->u4PktReadCnt[0]), |
| DIV2DEC(prStatCnt->u4DataPktWriteCnt, prStatCnt->u4PktReadCnt[0])); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Tx pkt/wt[%u.%u] pkt/kick[%u.%u] cmd/wt[%u.%u]\n", |
| DIV2INT(prStatCnt->u4DataPktWriteCnt, prStatCnt->u4DataPortWriteCnt), |
| DIV2DEC(prStatCnt->u4DataPktWriteCnt, prStatCnt->u4DataPortWriteCnt), |
| DIV2INT(prStatCnt->u4DataPktWriteCnt, prStatCnt->u4DataPortKickCnt), |
| DIV2DEC(prStatCnt->u4DataPktWriteCnt, prStatCnt->u4DataPortKickCnt), |
| DIV2INT(prStatCnt->u4CmdPktWriteCnt, prStatCnt->u4CmdPortWriteCnt), |
| DIV2DEC(prStatCnt->u4CmdPktWriteCnt, prStatCnt->u4CmdPortWriteCnt)); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Rx P0 pkt/rd[%u.%u] P1 pkt/rd[%u.%u]\n", |
| DIV2INT(prStatCnt->u4PktReadCnt[0], prStatCnt->u4PortReadCnt[0]), |
| DIV2DEC(prStatCnt->u4PktReadCnt[0], prStatCnt->u4PortReadCnt[0]), |
| DIV2INT(prStatCnt->u4PktReadCnt[1], prStatCnt->u4PortReadCnt[1]), |
| DIV2DEC(prStatCnt->u4PktReadCnt[1], prStatCnt->u4PortReadCnt[1])); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Tx done pending cnt TC00~05[%u, %u, %u, %u, %u, %u]\n", |
| prHifInfo->au4PendingTxDoneCount[TC0_INDEX], |
| prHifInfo->au4PendingTxDoneCount[TC1_INDEX], |
| prHifInfo->au4PendingTxDoneCount[TC2_INDEX], |
| prHifInfo->au4PendingTxDoneCount[TC3_INDEX], |
| prHifInfo->au4PendingTxDoneCount[TC4_INDEX], |
| prHifInfo->au4PendingTxDoneCount[TC5_INDEX]); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Tx done counter/int:\n"); |
| LOGBUF(pucBuf, u4Max, u4Len, "AC00~03[%u.%u, %u.%u, %u.%u, %u.%u]\n", |
| DIV2INT(prStatCnt->u4TxDoneCnt[0], prStatCnt->u4TxDoneIntCnt[0]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[0], prStatCnt->u4TxDoneIntCnt[0]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[1], prStatCnt->u4TxDoneIntCnt[1]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[1], prStatCnt->u4TxDoneIntCnt[1]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[2], prStatCnt->u4TxDoneIntCnt[2]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[2], prStatCnt->u4TxDoneIntCnt[2]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[3], prStatCnt->u4TxDoneIntCnt[3]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[3], prStatCnt->u4TxDoneIntCnt[3])); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "AC10~13[%u.%u, %u.%u, %u.%u, %u.%u]\n", |
| DIV2INT(prStatCnt->u4TxDoneCnt[4], prStatCnt->u4TxDoneIntCnt[4]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[4], prStatCnt->u4TxDoneIntCnt[4]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[5], prStatCnt->u4TxDoneIntCnt[5]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[5], prStatCnt->u4TxDoneIntCnt[5]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[6], prStatCnt->u4TxDoneIntCnt[6]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[5], prStatCnt->u4TxDoneIntCnt[5]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[7], prStatCnt->u4TxDoneIntCnt[7]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[7], prStatCnt->u4TxDoneIntCnt[7])); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "AC20~23[%u.%u, %u.%u, %u.%u, %u.%u] FFA,CPU[%u.%u, %u.%u]\n", |
| DIV2INT(prStatCnt->u4TxDoneCnt[8], prStatCnt->u4TxDoneIntCnt[8]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[8], prStatCnt->u4TxDoneIntCnt[8]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[9], prStatCnt->u4TxDoneIntCnt[9]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[9], prStatCnt->u4TxDoneIntCnt[9]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[10], prStatCnt->u4TxDoneIntCnt[10]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[10], prStatCnt->u4TxDoneIntCnt[10]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[11], prStatCnt->u4TxDoneIntCnt[11]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[11], prStatCnt->u4TxDoneIntCnt[11]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[14], prStatCnt->u4TxDoneIntCnt[14]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[14], prStatCnt->u4TxDoneIntCnt[14]), |
| DIV2INT(prStatCnt->u4TxDoneCnt[15], prStatCnt->u4TxDoneIntCnt[15]), |
| DIV2DEC(prStatCnt->u4TxDoneCnt[15], prStatCnt->u4TxDoneIntCnt[15])); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Pending pkt/int[%u.%u] kick/int[%u.%u] rx_enh/sts[%u.%u]\n", |
| DIV2INT(prStatCnt->u4TxDonePendingPktCnt, prStatCnt->u4TxDoneIntTotCnt), |
| DIV2DEC(prStatCnt->u4TxDonePendingPktCnt, prStatCnt->u4TxDoneIntTotCnt), |
| DIV2INT(prStatCnt->u4DataPortKickCnt, prStatCnt->u4TxDoneIntTotCnt), |
| DIV2DEC(prStatCnt->u4DataPortKickCnt, prStatCnt->u4TxDoneIntTotCnt), |
| DIV2INT((prStatCnt->u4IntCnt - prStatCnt->u4IntReadCnt), prStatCnt->u4IntCnt), |
| DIV2DEC((prStatCnt->u4IntCnt - prStatCnt->u4IntReadCnt), prStatCnt->u4IntCnt)); |
| |
| #if CFG_SDIO_TIMING_PROFILING |
| LOGBUF(pucBuf, u4Max, u4Len, "Tx cp_t/pkt[%u.%uus] free/pkt[%u.%uus]\n", |
| DIV2INT(prStatCnt->u4TxDataCpTime, prStatCnt->u4DataPktWriteCnt), |
| DIV2DEC(prStatCnt->u4TxDataCpTime, prStatCnt->u4DataPktWriteCnt), |
| DIV2INT(prStatCnt->u4TxDataFreeTime, prStatCnt->u4DataPktWriteCnt), |
| DIV2DEC(prStatCnt->u4TxDataFreeTime, prStatCnt->u4DataPktWriteCnt)); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Rx P0 cp_t/pkt[%u.%uus] avg read[%u.%uus]\n", |
| DIV2INT(prStatCnt->u4RxDataCpTime, prStatCnt->u4PktReadCnt[0]), |
| DIV2DEC(prStatCnt->u4RxDataCpTime, prStatCnt->u4PktReadCnt[0]), |
| DIV2INT(prStatCnt->u4PortReadTime, prStatCnt->u4PortReadCnt[0]), |
| DIV2DEC(prStatCnt->u4PortReadTime, prStatCnt->u4PortReadCnt[0])); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "INT rd_sts/sts[%u.%uus] tx_sts/sts[%u.%uus]\n", |
| DIV2INT(prStatCnt->u4IntReadTime, prStatCnt->u4IntReadCnt), |
| DIV2DEC(prStatCnt->u4IntReadTime, prStatCnt->u4IntReadCnt), |
| DIV2INT(prStatCnt->u4TxDoneIntTime, prStatCnt->u4TxDoneIntTotCnt), |
| DIV2DEC(prStatCnt->u4TxDoneIntTime, prStatCnt->u4TxDoneIntTotCnt)); |
| #endif |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "---------------------------------\n"); |
| |
| /* Reset statistic counter */ |
| kalMemZero(prStatCnt, sizeof(SDIO_STAT_COUNTER_T)); |
| |
| return u4Len; |
| } |
| |
| #if (CFG_SDIO_ACCESS_N9_REGISTER_BY_MAILBOX == 1) |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief |
| * This routine is used to get the value of N9 register |
| * by SDIO SW interrupt and mailbox. |
| * |
| * \param[in] |
| * pvAdapter: Pointer to the Adapter structure. |
| * addr: the interested address to be read |
| * prresult: to stored the value of the addr |
| * |
| * \return |
| * the error of the reading operation |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| BOOL halReadN9RegisterByMailBox(IN P_ADAPTER_T prAdapter, IN UINT_32 addr, IN UINT_32 *prresult) |
| { |
| UINT_32 ori_whlpcr, temp, counter = 0; |
| BOOL err = TRUE, stop = FALSE; |
| |
| /* use polling mode */ |
| HAL_MCR_RD(prAdapter, MCR_WHLPCR, &ori_whlpcr); /* backup the original setting of W_INT_EN */ |
| ori_whlpcr &= WHLPCR_INT_EN_SET; |
| HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); /* disabel interrupt */ |
| |
| /* progrqm h2d mailbox0 as interested register address */ |
| HAL_MCR_WR(prAdapter, MCR_H2DSM0R, addr); |
| |
| /* set h2d interrupt to notify firmware (bit16) */ |
| HAL_MCR_WR(prAdapter, MCR_WSICR, SDIO_MAILBOX_FUNC_READ_REG_IDX); |
| |
| /* polling interrupt status for the returned result */ |
| while (!stop) { |
| HAL_MCR_RD(prAdapter, MCR_WHISR, &temp); /* read clear mode */ |
| if (temp & SDIO_MAILBOX_FUNC_READ_REG_IDX) { |
| /* get the result */ |
| |
| /* read d2h mailbox0 for interested register address */ |
| HAL_MCR_RD(prAdapter, MCR_D2HRM0R, &temp); |
| if (temp == addr) { |
| /* read d2h mailbox1 for the value of the register */ |
| HAL_MCR_RD(prAdapter, MCR_D2HRM1R, prresult); |
| err = FALSE; |
| } else { |
| DBGLOG(HAL, ERROR, "halReadN9RegisterByMailBox >> interested address is not correct.\n"); |
| } |
| stop = TRUE; |
| } else { |
| counter++; |
| |
| if (counter > 300000) { |
| DBGLOG(HAL, ERROR, "halReadN9RegisterByMailBox >> get response failure.\n"); |
| ASSERT(0); |
| break; |
| } |
| } |
| } |
| |
| HAL_MCR_WR(prAdapter, MCR_WHLPCR, ori_whlpcr); /* restore the W_INT_EN */ |
| |
| return err; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief |
| * This routine is used to write the value of N9 register by SDIO SW interrupt and mailbox. |
| * |
| * \param[in] |
| * pvAdapter: Pointer to the Adapter structure. |
| * addr: the interested address to be write |
| * value: the value to write into the addr |
| * |
| * \return |
| * the error of the write operation |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| BOOL halWriteN9RegisterByMailBox(IN P_ADAPTER_T prAdapter, IN UINT_32 addr, IN UINT_32 value) |
| { |
| UINT_32 ori_whlpcr, temp, counter = 0; |
| BOOL err = TRUE, stop = FALSE; |
| |
| /* use polling mode */ |
| HAL_MCR_RD(prAdapter, MCR_WHLPCR, &ori_whlpcr); /* backup the original setting of W_INT_EN */ |
| ori_whlpcr &= WHLPCR_INT_EN_SET; |
| HAL_MCR_WR(prAdapter, MCR_WHLPCR, WHLPCR_INT_EN_CLR); /* disabel interrupt */ |
| |
| /* progrqm h2d mailbox0 as interested register address */ |
| HAL_MCR_WR(prAdapter, MCR_H2DSM0R, addr); |
| |
| /* progrqm h2d mailbox1 as the value to write */ |
| HAL_MCR_WR(prAdapter, MCR_H2DSM1R, value); |
| |
| /* set h2d interrupt to notify firmware (bit17) */ |
| HAL_MCR_WR(prAdapter, MCR_WSICR, SDIO_MAILBOX_FUNC_WRITE_REG_IDX); |
| |
| /* polling interrupt status for the returned result */ |
| while (!stop) { |
| HAL_MCR_RD(prAdapter, MCR_WHISR, &temp); /* read clear mode */ |
| |
| if (temp & SDIO_MAILBOX_FUNC_WRITE_REG_IDX) { |
| /* get the result */ |
| |
| /* read d2h mailbox0 for interested register address */ |
| HAL_MCR_RD(prAdapter, MCR_D2HRM0R, &temp); |
| if (temp == addr) |
| err = FALSE; |
| else { |
| DBGLOG(HAL, ERROR, "halWriteN9RegisterByMailBox >> "); |
| DBGLOG(HAL, ERROR, "interested address is not correct.\n"); |
| } |
| stop = TRUE; |
| } else { |
| counter++; |
| |
| if (counter > 300000) { |
| DBGLOG(HAL, ERROR, "halWriteN9RegisterByMailBox >> get response failure.\n"); |
| ASSERT(0); |
| break; |
| } |
| } |
| } |
| |
| HAL_MCR_WR(prAdapter, MCR_WHLPCR, ori_whlpcr); /* restore the W_INT_EN */ |
| |
| return err; |
| } |
| #endif |
| |
| BOOLEAN halIsPendingRx(IN P_ADAPTER_T prAdapter) |
| { |
| return FALSE; |
| } |
| |
| WLAN_STATUS halAllocateIOBuffer(IN P_ADAPTER_T prAdapter) |
| { |
| P_GL_HIF_INFO_T prHifInfo; |
| UINT_8 ucIdx; |
| P_SDIO_RX_COALESCING_BUF_T prRxBuf; |
| |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| /* 4 <5> Memory for enhanced interrupt response */ |
| prHifInfo->prSDIOCtrl = (P_SDIO_CTRL_T) |
| kalAllocateIOBuffer(sizeof(ENHANCE_MODE_DATA_STRUCT_T)); |
| |
| if (prHifInfo->prSDIOCtrl == NULL) { |
| DBGLOG(HAL, ERROR, "Could not allocate %d bytes for interrupt response.\n", |
| sizeof(ENHANCE_MODE_DATA_STRUCT_T)); |
| |
| return WLAN_STATUS_RESOURCES; |
| } |
| |
| /* Alloc coalescing buffer */ |
| for (ucIdx = 0; ucIdx < HIF_RX_COALESCING_BUF_COUNT; ucIdx++) { |
| prRxBuf = &prHifInfo->rRxCoalesingBuf[ucIdx]; |
| |
| prRxBuf->u4PktCount = 0; |
| |
| prRxBuf->u4BufSize = HIF_RX_COALESCING_BUFFER_SIZE; |
| prRxBuf->pvRxCoalescingBuf = kalAllocateIOBuffer(prRxBuf->u4BufSize); |
| if (!prRxBuf->pvRxCoalescingBuf) { |
| DBGLOG(HAL, ERROR, "Rx coalescing alloc failed!\n"); |
| continue; |
| } |
| |
| QUEUE_INSERT_TAIL(&prHifInfo->rRxFreeBufQueue, &prRxBuf->rQueEntry); |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| WLAN_STATUS halReleaseIOBuffer(IN P_ADAPTER_T prAdapter) |
| { |
| P_GL_HIF_INFO_T prHifInfo; |
| UINT_8 ucIdx; |
| P_SDIO_RX_COALESCING_BUF_T prRxBuf; |
| |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| /* Release coalescing buffer */ |
| for (ucIdx = 0; ucIdx < HIF_RX_COALESCING_BUF_COUNT; ucIdx++) { |
| prRxBuf = &prHifInfo->rRxCoalesingBuf[ucIdx]; |
| kalReleaseIOBuffer(prRxBuf->pvRxCoalescingBuf, prRxBuf->u4BufSize); |
| prRxBuf->pvRxCoalescingBuf = NULL; |
| } |
| |
| /* 4 <5> Memory for enhanced interrupt response */ |
| if (prHifInfo->prSDIOCtrl) { |
| kalReleaseIOBuffer((PVOID) prHifInfo->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); |
| prHifInfo->prSDIOCtrl = (P_SDIO_CTRL_T) NULL; |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief dump firmware Assert message |
| * |
| * \param[in] |
| * prAdapter |
| * |
| * \return |
| * TRUE |
| * FALSE |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID halPrintFirmwareAssertInfo(IN P_ADAPTER_T prAdapter) |
| { |
| UINT_32 u4MailBox0, u4MailBox1; |
| UINT_32 line = 0; |
| UINT_8 aucAssertFile[7]; |
| /* UINT_32 u4ChipId; */ |
| |
| #if CFG_SDIO_INTR_ENHANCE |
| u4MailBox0 = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl->u4RcvMailbox0; |
| u4MailBox1 = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl->u4RcvMailbox1; |
| #else |
| halGetMailbox(prAdapter, 0, &u4MailBox0); |
| halGetMailbox(prAdapter, 1, &u4MailBox1); |
| #endif |
| |
| line = u4MailBox0 & 0x0000FFFF; |
| |
| u4MailBox0 = ((u4MailBox0 >> 16) & 0x0000FFFF); |
| |
| kalMemCopy(&aucAssertFile[0], &u4MailBox0, 2); |
| kalMemCopy(&aucAssertFile[2], &u4MailBox1, 4); |
| |
| aucAssertFile[6] = '\0'; |
| |
| LOG_FUNC("[%s][wifi][Firmware] Assert at \"%s\" #%ld\n\n", NIC_NAME, aucAssertFile, line); |
| |
| } |
| |
| VOID halPrintMailbox(IN P_ADAPTER_T prAdapter) |
| { |
| UINT_32 u4MailBoxStatus0, u4MailBoxStatus1; |
| |
| halGetMailbox(prAdapter, 0, &u4MailBoxStatus0); |
| halGetMailbox(prAdapter, 1, &u4MailBoxStatus1); |
| DBGLOG(INIT, ERROR, "MailBox Status = 0x%08X, 0x%08X\n", u4MailBoxStatus0, u4MailBoxStatus1); |
| } |
| |
| VOID halProcessSoftwareInterrupt(IN P_ADAPTER_T prAdapter) |
| { |
| UINT_32 u4IntrBits; |
| |
| ASSERT(prAdapter); |
| |
| u4IntrBits = prAdapter->u4IntStatus & BITS(8, 31); |
| |
| if ((u4IntrBits & WHISR_D2H_SW_ASSERT_INFO_INT) != 0) { |
| halPrintFirmwareAssertInfo(prAdapter); |
| #if CFG_CHIP_RESET_SUPPORT |
| glSendResetRequest(); |
| #endif |
| } |
| |
| if (u4IntrBits & WHISR_D2H_WKUP_BY_RX_PACKET) |
| DBGLOG(RX, INFO, "Wake up by Rx\n"); |
| |
| if (u4IntrBits & WHISR_D2H_SW_RD_MAILBOX_INT) |
| halPrintMailbox(prAdapter); |
| |
| if (u4IntrBits & SER_SDIO_N9_HOST_STOP_TX_OP) { |
| halPrintMailbox(prAdapter); |
| /* Stop HIF Tx operation */ |
| nicSerStopTx(prAdapter); |
| } |
| |
| if (u4IntrBits & SER_SDIO_N9_HOST_STOP_TX_RX_OP) { |
| halPrintMailbox(prAdapter); |
| /* Stop HIF Tx/Rx operation */ |
| nicSerStopTxRx(prAdapter); |
| } |
| |
| if ((u4IntrBits & ~WHISR_D2H_WKUP_BY_RX_PACKET) != 0) |
| DBGLOG(SW4, WARN, "u4IntrBits: 0x%lx\n", u4IntrBits); |
| |
| } /* end of halProcessSoftwareInterrupt() */ |
| |
| VOID halPutMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, IN UINT_32 u4Data) |
| { |
| |
| switch (u4MailboxNum) { |
| case 0: |
| HAL_MCR_WR(prAdapter, MCR_H2DSM0R, u4Data); |
| break; |
| case 1: |
| HAL_MCR_WR(prAdapter, MCR_H2DSM1R, u4Data); |
| break; |
| |
| default: |
| ASSERT(0); |
| } |
| |
| } |
| |
| VOID halGetMailbox(IN P_ADAPTER_T prAdapter, IN UINT_32 u4MailboxNum, OUT PUINT_32 pu4Data) |
| { |
| switch (u4MailboxNum) { |
| case 0: |
| HAL_MCR_RD(prAdapter, MCR_D2HRM0R, pu4Data); |
| break; |
| case 1: |
| HAL_MCR_RD(prAdapter, MCR_D2HRM1R, pu4Data); |
| break; |
| |
| default: |
| ASSERT(0); |
| } |
| } |
| |
| VOID halDeAggRxPktWorker(struct work_struct *work) |
| { |
| P_GLUE_INFO_T prGlueInfo; |
| P_GL_HIF_INFO_T prHifInfo; |
| P_ADAPTER_T prAdapter; |
| P_SDIO_RX_COALESCING_BUF_T prRxBuf; |
| UINT_32 i; |
| QUE_T rTempFreeRfbList, rTempRxRfbList; |
| P_QUE_T prTempFreeRfbList = &rTempFreeRfbList; |
| P_QUE_T prTempRxRfbList = &rTempRxRfbList; |
| P_RX_CTRL_T prRxCtrl; |
| P_SW_RFB_T prSwRfb = (P_SW_RFB_T) NULL; |
| PUINT_8 pucSrcAddr; |
| UINT_16 u2PktLength; |
| BOOLEAN fgReschedule = FALSE; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| SDIO_TIME_INTERVAL_DEC(); |
| |
| if (g_u4HaltFlag) |
| return; |
| |
| prGlueInfo = ENTRY_OF(work, GLUE_INFO_T, rRxPktDeAggWork); |
| prHifInfo = &prGlueInfo->rHifInfo; |
| prAdapter = prGlueInfo->prAdapter; |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) |
| return; |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| QUEUE_INITIALIZE(prTempFreeRfbList); |
| QUEUE_INITIALIZE(prTempRxRfbList); |
| |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| QUEUE_REMOVE_HEAD(&prHifInfo->rRxDeAggQueue, prRxBuf, P_SDIO_RX_COALESCING_BUF_T); |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| while (prRxBuf) { |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); |
| if (prRxCtrl->rFreeSwRfbList.u4NumElem < prRxBuf->u4PktCount) { |
| fgReschedule = TRUE; |
| } else { |
| /* Get enough free SW_RFB to be Rx */ |
| for (i = 0; i < prRxBuf->u4PktCount; i++) { |
| QUEUE_REMOVE_HEAD(&prRxCtrl->rFreeSwRfbList, prSwRfb, P_SW_RFB_T); |
| QUEUE_INSERT_TAIL(prTempFreeRfbList, &prSwRfb->rQueEntry); |
| } |
| fgReschedule = FALSE; |
| } |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); |
| |
| if (fgReschedule) { |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| QUEUE_INSERT_HEAD(&prHifInfo->rRxDeAggQueue, (P_QUE_ENTRY_T)prRxBuf); |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| |
| /* Reschedule this work */ |
| if ((prGlueInfo->ulFlag & GLUE_FLAG_HALT) == 0) |
| schedule_delayed_work(&prAdapter->prGlueInfo->rRxPktDeAggWork, 0); |
| |
| return; |
| } |
| |
| pucSrcAddr = prRxBuf->pvRxCoalescingBuf; |
| |
| SDIO_REC_TIME_START(); |
| for (i = 0; i < prRxBuf->u4PktCount; i++) { |
| u2PktLength = HAL_RX_STATUS_GET_RX_BYTE_CNT((P_HW_MAC_RX_DESC_T)pucSrcAddr); |
| |
| QUEUE_REMOVE_HEAD(prTempFreeRfbList, prSwRfb, P_SW_RFB_T); |
| kalMemCopy(prSwRfb->pucRecvBuff, pucSrcAddr, ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN)); |
| |
| prSwRfb->ucPacketType = (UINT_8)HAL_RX_STATUS_GET_PKT_TYPE(prSwRfb->prRxStatus); |
| |
| QUEUE_INSERT_TAIL(prTempRxRfbList, &prSwRfb->rQueEntry); |
| |
| pucSrcAddr += ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN); |
| } |
| SDIO_REC_TIME_END(); |
| SDIO_ADD_TIME_INTERVAL(prHifInfo->rStatCounter.u4RxDataCpTime); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); |
| RX_ADD_CNT(prRxCtrl, RX_MPDU_TOTAL_COUNT, prTempRxRfbList->u4NumElem); |
| QUEUE_CONCATENATE_QUEUES(&prRxCtrl->rReceivedRfbList, prTempRxRfbList); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_QUE); |
| |
| /* Wake up Rx handling thread */ |
| set_bit(GLUE_FLAG_RX_BIT, &(prAdapter->prGlueInfo->ulFlag)); |
| wake_up_interruptible(&(prAdapter->prGlueInfo->waitq)); |
| |
| if (prTempFreeRfbList->u4NumElem) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); |
| QUEUE_CONCATENATE_QUEUES(&prRxCtrl->rFreeSwRfbList, prTempFreeRfbList); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_RX_FREE_QUE); |
| } |
| |
| prRxBuf->u4PktCount = 0; |
| mutex_lock(&prHifInfo->rRxFreeBufQueMutex); |
| QUEUE_INSERT_TAIL(&prHifInfo->rRxFreeBufQueue, (P_QUE_ENTRY_T)prRxBuf); |
| mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) |
| return; |
| |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| QUEUE_REMOVE_HEAD(&prHifInfo->rRxDeAggQueue, prRxBuf, P_SDIO_RX_COALESCING_BUF_T); |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| } |
| } |
| |
| VOID halDeAggRxPkt(P_ADAPTER_T prAdapter, P_SDIO_RX_COALESCING_BUF_T prRxBuf) |
| { |
| P_GL_HIF_INFO_T prHifInfo; |
| |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| /* Avoid to schedule DeAggWorker during uninit flow */ |
| if (prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) { |
| mutex_lock(&prHifInfo->rRxFreeBufQueMutex); |
| QUEUE_INSERT_TAIL(&prHifInfo->rRxFreeBufQueue, (P_QUE_ENTRY_T)prRxBuf); |
| mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); |
| |
| return; |
| } |
| |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| QUEUE_INSERT_TAIL(&prHifInfo->rRxDeAggQueue, (P_QUE_ENTRY_T)prRxBuf); |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| |
| schedule_delayed_work(&prAdapter->prGlueInfo->rRxPktDeAggWork, 0); |
| } |
| |
| VOID halRxTasklet(unsigned long data) |
| { |
| |
| } |
| |
| VOID halTxCompleteTasklet(unsigned long data) |
| { |
| |
| } |
| |
| /* Hif power off wifi */ |
| WLAN_STATUS halHifPowerOffWifi(IN P_ADAPTER_T prAdapter) |
| { |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| |
| 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 */ |
| rStatus = 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); |
| } |
| return rStatus; |
| } |
| |
| VOID halPollDbgCr(IN P_ADAPTER_T prAdapter, IN UINT_32 u4LoopCount) |
| { |
| UINT_32 u4Data = 0; |
| UINT_32 u4Loop = 0; |
| |
| for (u4Loop = 0; u4Loop < u4LoopCount; u4Loop++) { |
| HAL_MCR_RD(prAdapter, MCR_SWPCDBGR, &u4Data); |
| DBGLOG(INIT, WARN, "SWPCDBGR 0x%08X\n", u4Data); |
| } |
| } |
| |
| VOID halSerHifReset(IN P_ADAPTER_T prAdapter) |
| { |
| P_GL_HIF_INFO_T prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| UINT_32 i; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| /* Restore Tx resource */ |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| for (i = TC0_INDEX; i <= TC5_INDEX; i++) { |
| nicTxReleaseResource(prAdapter, i, prHifInfo->au4PendingTxDoneCount[i], FALSE); |
| prHifInfo->au4PendingTxDoneCount[i] = 0; |
| } |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| /* Clear interrupt status from Rx interrupt enhance mode */ |
| prHifInfo->fgIsPendingInt = FALSE; |
| kalMemZero(prHifInfo->prSDIOCtrl, sizeof(ENHANCE_MODE_DATA_STRUCT_T)); |
| } |
| |
| VOID halPrintHifDbgInfo(IN P_ADAPTER_T prAdapter) |
| { |
| halPrintMailbox(prAdapter); |
| halPollDbgCr(prAdapter, LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND); |
| } |
| |
| BOOLEAN halIsTxResourceControlEn(IN P_ADAPTER_T prAdapter) |
| { |
| return TRUE; |
| } |
| |