| /****************************************************************************** |
| * |
| * 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 (3000) |
| |
| /******************************************************************************* |
| * 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 |
| ******************************************************************************** |
| */ |
| /* |
| *TX Done Counter Layout |
| * |
| * enum HIF_TX_COUNT_IDX_T { |
| * |
| * /==== First WMM ====/ |
| * |
| * HIF_TXC_IDX_0, ==>AC0 PSE |
| * HIF_TXC_IDX_1, ==>AC1 PSE |
| * HIF_TXC_IDX_2, ==>AC2 PSE |
| * HIF_TXC_IDX_3, ==>AC3 PLE |
| * HIF_TXC_IDX_4, ==>CPU PSE |
| * HIF_TXC_IDX_5, ==>AC0 PLE |
| * HIF_TXC_IDX_6, ==>AC1 PLE |
| * HIF_TXC_IDX_7, ==>AC2 PLE |
| * HIF_TXC_IDX_8, ==>AC3 PLE |
| * |
| * /==== Second WMM ====/ |
| * |
| * HIF_TXC_IDX_9, ==>AC10, AC11 PSE |
| * HIF_TXC_IDX_10, ==> AC12 PSE |
| * HIF_TXC_IDX_11, ==>AC13 PSE |
| * HIF_TXC_IDX_12, ==>AC10, AC11 PLE |
| * HIF_TXC_IDX_13, ==>AC12 PLE |
| * HIF_TXC_IDX_14, ==>Reservec |
| * HIF_TXC_IDX_15, ==>AC13 PLE |
| * }; |
| */ |
| #define HIF_TXC_IDX_2_TC_IDX_PSE(hif_idx) (hif_idx) |
| #define HIF_TXC_IDX_2_TC_IDX_PLE(hif_idx) (hif_idx - HIF_TXC_IDX_5) |
| #define TC_IDX_PSE_2_HIF_TXC_IDX(ucTc) (ucTc) |
| #define TC_IDX_PLE_2_HIF_TXC_IDX(ucTc) (ucTc + HIF_TXC_IDX_5) |
| |
| /******************************************************************************* |
| * 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 |
| */ |
| /*----------------------------------------------------------------------------*/ |
| u_int8_t halVerifyChipID(IN struct ADAPTER *prAdapter) |
| { |
| uint32_t 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 = (uint8_t) (((u4CIR & WCIR_REVISION_ID) >> 16) & 0xF); |
| prAdapter->fgIsReadRevID = TRUE; |
| |
| return TRUE; |
| } |
| |
| uint32_t |
| halRxWaitResponse(IN struct ADAPTER *prAdapter, IN uint8_t ucPortIdx, OUT uint8_t *pucRspBuffer, |
| IN uint32_t u4MaxRespBufferLen, OUT uint32_t *pu4Length) |
| { |
| struct mt66xx_chip_info *prChipInfo; |
| uint32_t u4Value = 0, u4PktLen = 0, i = 0, u4CpyLen; |
| uint32_t u4Status = WLAN_STATUS_SUCCESS; |
| uint32_t u4Time, u4Current; |
| struct RX_CTRL *prRxCtrl; |
| struct WIFI_EVENT *prEvent; |
| |
| DEBUGFUNC("halRxWaitResponse"); |
| |
| ASSERT(prAdapter); |
| ASSERT(pucRspBuffer); |
| prChipInfo = prAdapter->chip_info; |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| |
| u4Time = (uint32_t) kalGetTimeTick(); |
| |
| do { |
| HAL_MCR_RD(prAdapter, MCR_WHISR, &u4Value); |
| if (!(u4Value & (WHISR_RX0_DONE_INT | WHISR_RX1_DONE_INT))) { |
| /* timeout exceeding check */ |
| u4Current = (uint32_t) kalGetTimeTick(); |
| |
| if ((u4Current > u4Time) && ((u4Current - u4Time) |
| > RX_RESPONSE_TIMEOUT)) { |
| |
| DBGLOG(RX, ERROR, "Timeout! %d - %d = %d\n", |
| u4Current, u4Time, (u4Current-u4Time)); |
| return WLAN_STATUS_FAILURE; |
| } else if (u4Current < u4Time && |
| ((u4Current + (0xFFFFFFFF - u4Time)) |
| > RX_RESPONSE_TIMEOUT)) { |
| |
| DBGLOG(RX, ERROR, "Timeout! %d - %d = %d\n", |
| u4Current, u4Time, |
| (u4Current + (0xFFFFFFFF - u4Time))); |
| return WLAN_STATUS_FAILURE; |
| } |
| /* Response packet is not ready */ |
| kalUdelay(50); |
| |
| continue; |
| } |
| /* 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 > u4MaxRespBufferLen) { |
| DBGLOG(RX, ERROR, "Packet length over buffer! Dump Response buffer, length = 0x%x\n", |
| *pu4Length); |
| prEvent = (struct WIFI_EVENT *) |
| (pucRspBuffer + prChipInfo->rxd_size); |
| DBGLOG(RX, ERROR, "RX EVENT: ID[0x%02X] SEQ[%u] LEN[%u]\n", |
| prEvent->ucEID, prEvent->ucSeqNum, prEvent->u2PacketLength); |
| DBGLOG_MEM8(RX, ERROR, pucRspBuffer, u4MaxRespBufferLen); |
| return WLAN_STATUS_FAILURE; |
| } |
| if (u4PktLen == 0) { |
| DBGLOG(RX, ERROR, "Packet length is 0!!\n"); |
| return WLAN_STATUS_FAILURE; |
| } else { |
| |
| #if (CFG_ENABLE_READ_EXTRA_4_BYTES == 1) |
| #if CFG_SDIO_RX_AGG |
| /* If rx enhanced mode is enabled, need to read |
| * enhanced mode information even if don't need this, |
| * because hw will error. |
| */ |
| #if CFG_SDIO_RX_ENHANCE |
| u4PktLen += sizeof(struct ENHANCE_MODE_DATA_STRUCT); |
| #endif |
| /* 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 struct ADAPTER *prAdapter) |
| { |
| u_int8_t 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 struct ADAPTER *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) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| u_int8_t halSetDriverOwn(IN struct ADAPTER *prAdapter) |
| { |
| u_int8_t fgStatus = TRUE; |
| uint32_t i, j, u4CurrTick = 0, u4WriteTick, u4WriteTickTemp; |
| u_int8_t fgTimeout; |
| u_int8_t fgResult; |
| uint32_t u4DriverOwnTime = 0, u4Cr4ReadyTime = 0; |
| struct GL_HIF_INFO *prHifInfo; |
| u_int8_t fgWmtCoreDump = FALSE; |
| |
| ASSERT(prAdapter); |
| |
| KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_SET_OWN); |
| |
| GLUE_INC_REF_CNT(prAdapter->u4PwrCtrlBlockCnt); |
| |
| if (prAdapter->fgIsFwOwn == FALSE) |
| goto unlock; |
| |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| DBGLOG(INIT, TRACE, "DRIVER OWN\n"); |
| |
| u4WriteTick = 0; |
| u4CurrTick = kalGetTimeTick(); |
| i = 0; |
| j = 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)) { |
| DBGLOG(INIT, WARN, |
| "[SER][L1] driver own pass\n"); |
| |
| /* SER is done, start Tx/Rx */ |
| nicSerStartTxRx(prAdapter); |
| nicTxRelease(prAdapter, 0x0); |
| } |
| break; |
| } else if ((i > LP_OWN_BACK_FAILED_RETRY_CNT) && |
| (kalIsCardRemoved(prAdapter->prGlueInfo) || fgIsBusAccessFailed || fgTimeout |
| || wlanIsChipNoAck(prAdapter))) { |
| |
| /* For driver own back fail debug, get current PC value */ |
| halPrintMailbox(prAdapter); |
| halPollDbgCr(prAdapter, LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND); |
| |
| 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] fgCoreDump[%u]\n", |
| kalIsResetting(), |
| kalIsCardRemoved(prAdapter->prGlueInfo), wlanIsChipNoAck(prAdapter), |
| prAdapter->u4OwnFailedCount, fgWmtCoreDump); |
| |
| 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 */ |
| glGetRstReason(RST_DRV_OWN_FAIL); |
| GL_RESET_TRIGGER(prAdapter, |
| RST_FLAG_DO_CORE_DUMP); |
| } |
| GET_CURRENT_SYSTIME(&prAdapter->rLastOwnFailedLogTime); |
| } |
| |
| prAdapter->u4OwnFailedCount++; |
| fgStatus = FALSE; |
| break; |
| } |
| |
| u4WriteTickTemp = kalGetTimeTick(); |
| if ((i == 0) || TIME_AFTER(u4WriteTickTemp, (u4WriteTick + LP_OWN_REQ_CLR_INTERVAL_MS))) { |
| /* Driver get LP ownership per 200 ms, to avoid iteration time not accurate */ |
| HAL_LP_OWN_CLR(prAdapter, &fgResult); |
| u4WriteTick = u4WriteTickTemp; |
| } |
| |
| /* Delay for LP engine to complete its operation. */ |
| kalUsleep_range(LP_OWN_BACK_LOOP_DELAY_MIN_US, LP_OWN_BACK_LOOP_DELAY_MAX_US); |
| i++; |
| } |
| u4DriverOwnTime = ((kalGetTimeTick() >= u4CurrTick) ? |
| (kalGetTimeTick() - u4CurrTick) : (kalGetTimeTick() + (~u4CurrTick))); |
| |
| /* 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 (prAdapter->fgIsCr4FwDownloaded && prAdapter->fgIsFwDownloaded) { |
| const uint32_t ready_bits = prAdapter->chip_info->sw_ready_bits; |
| u_int8_t fgReady = FALSE; |
| |
| DBGLOG(INIT, INFO, "halSetDriverOwn:: Check ready_bits(=0x%x)\n", ready_bits); |
| u4CurrTick = kalGetTimeTick(); |
| while (1) { |
| HAL_WIFI_FUNC_READY_CHECK(prAdapter, ready_bits/*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)) { |
| |
| /* For driver own back fail debug, get current PC value */ |
| halPrintMailbox(prAdapter); |
| halPollDbgCr(prAdapter, LP_OWN_BACK_FAILED_DBGCR_POLL_ROUND); |
| |
| DBGLOG(INIT, ERROR, |
| "Resetting[%u], CardRemoved[%u] NoAck[%u] Timeout[%u](%u - %u)ms, fgCoreDump[%u]\n", |
| kalIsResetting(), |
| kalIsCardRemoved(prAdapter->prGlueInfo), wlanIsChipNoAck(prAdapter), |
| fgTimeout, kalGetTimeTick(), u4CurrTick, fgWmtCoreDump); |
| |
| |
| DBGLOG(INIT, INFO, |
| "Skip waiting CR4 ready for next %ums\n", LP_OWN_BACK_FAILED_LOG_SKIP_MS); |
| fgStatus = FALSE; |
| |
| if (fgTimeout) { |
| /* Trigger RESET */ |
| glGetRstReason(RST_DRV_OWN_FAIL); |
| GL_RESET_TRIGGER(prAdapter, |
| RST_FLAG_DO_CORE_DUMP); |
| } |
| |
| break; |
| } |
| /* Delay for CR4 to complete its operation. */ |
| kalUsleep_range(LP_OWN_BACK_LOOP_DELAY_MIN_US, LP_OWN_BACK_LOOP_DELAY_MAX_US); |
| } |
| |
| halTagIntLog(prAdapter, SDIO_INT_DRV_OWN); |
| HAL_MCR_RD(prAdapter, MCR_D2HRM1R, &j); |
| |
| if (j == 0x77889901) { |
| |
| struct mt66xx_chip_info *prChipInfo = prAdapter->chip_info; |
| |
| if (halIsPendingTxDone(prAdapter)) { |
| /* Workaround for missing Tx done */ |
| halSerHifReset(prAdapter); |
| } |
| |
| /* fgIsWakeupFromDeepSleep */ |
| wlanSendDummyCmd(prAdapter, FALSE); |
| |
| /* Workaround for dummy command which is not count in Tx done count */ |
| if (prChipInfo->is_support_cr4) |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[TC4_INDEX]--; |
| halTagIntLog(prAdapter, SDIO_INT_WAKEUP_DSLP); |
| } |
| u4Cr4ReadyTime = ((kalGetTimeTick() >= u4CurrTick) ? |
| (kalGetTimeTick() - u4CurrTick) : (kalGetTimeTick() + (~u4CurrTick))); |
| } |
| |
| DBGLOG(NIC, TRACE, "DRIVER OWN %d, %d, DSLP %s, count %d\n", |
| u4DriverOwnTime, u4Cr4ReadyTime, ((j == 0x77889901)?"1":"0"), i); |
| unlock: |
| KAL_RELEASE_MUTEX(prAdapter, MUTEX_SET_OWN); |
| 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 struct ADAPTER *prAdapter, IN u_int8_t fgEnableGlobalInt) |
| { |
| |
| u_int8_t fgResult; |
| |
| ASSERT(prAdapter); |
| ASSERT(prAdapter->u4PwrCtrlBlockCnt != 0); |
| |
| KAL_ACQUIRE_MUTEX(prAdapter, MUTEX_SET_OWN); |
| |
| /* Decrease Block to Enter Low Power Semaphore count */ |
| GLUE_DEC_REF_CNT(prAdapter->u4PwrCtrlBlockCnt); |
| |
| if (prAdapter->u4PwrCtrlBlockCnt != 0) { |
| DBGLOG(INIT, TRACE, "prAdapter->u4PwrCtrlBlockCnt = %d\n", |
| prAdapter->u4PwrCtrlBlockCnt); |
| goto unlock; |
| } |
| |
| if (prAdapter->fgForceFwOwn == FALSE |
| && prAdapter->fgWiFiInSleepyState == FALSE) |
| goto unlock; |
| |
| if (prAdapter->fgIsFwOwn == TRUE) |
| goto unlock; |
| |
| if ((nicProcessIST(prAdapter) != WLAN_STATUS_NOT_INDICATING) && |
| !nicSerIsWaitingReset(prAdapter)) { |
| DBGLOG(INIT, INFO, "FW OWN Skipped due to pending INT\n"); |
| /* pending interrupts */ |
| goto unlock; |
| } |
| |
| if (fgEnableGlobalInt) { |
| prAdapter->fgIsIntEnableWithLPOwnSet = TRUE; |
| } else { |
| if (nicSerIsWaitingReset(prAdapter)) |
| DBGLOG(INIT, WARN, "[SER][L1] set fw own\n"); |
| |
| 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); |
| } else { |
| prAdapter->fgIsFwOwn = TRUE; |
| |
| DBGLOG(INIT, TRACE, "FW OWN\n"); |
| |
| if (nicSerIsWaitingReset(prAdapter)) |
| DBGLOG(INIT, WARN, "[SER][L1] set fw pass\n"); |
| } |
| } |
| |
| unlock: |
| KAL_RELEASE_MUTEX(prAdapter, MUTEX_SET_OWN); |
| } |
| |
| void halWakeUpWiFi(IN struct ADAPTER *prAdapter) |
| { |
| |
| u_int8_t fgResult; |
| |
| ASSERT(prAdapter); |
| |
| HAL_LP_OWN_RD(prAdapter, &fgResult); |
| |
| if (fgResult) |
| prAdapter->fgIsFwOwn = FALSE; |
| else |
| HAL_LP_OWN_CLR(prAdapter, &fgResult); |
| } |
| |
| void halDevInit(IN struct ADAPTER *prAdapter) |
| { |
| uint32_t u4Value = 0; |
| |
| ASSERT(prAdapter); |
| |
| #if CFG_SDIO_INTR_ENHANCE |
| /* 4 <1> Check STATUS Buffer is DW alignment. */ |
| ASSERT(IS_ALIGN_4((unsigned long)&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 struct ADAPTER *prAdapter, IN struct CMD_INFO *prCmdInfo) |
| { |
| } |
| |
| #ifdef _SDIO_RING |
| u_int8_t halTxIsDataBufEnough(IN struct ADAPTER *prAdapter, |
| IN struct MSDU_INFO *prMsduInfo) |
| { |
| |
| struct GLUE_INFO *prGlueInfo = NULL; |
| struct GL_HIF_INFO *prHif = NULL; |
| struct sk_buff *skb; |
| uint32_t u4Length; |
| uint32_t head; |
| uint32_t tail; |
| uint32_t data_len; |
| |
| if (!prAdapter) { |
| DBGLOG(TX, ERROR, "prAdapter is NULL!\n"); |
| return FALSE; |
| } |
| prGlueInfo = prAdapter->prGlueInfo; |
| if (!prGlueInfo) { |
| DBGLOG(TX, ERROR, "prGlueInfo is NULL!\n"); |
| return FALSE; |
| } |
| prHif = &prGlueInfo->rHifInfo; |
| if (!prHif) { |
| DBGLOG(TX, ERROR, "prHif is NULL!\n"); |
| return FALSE; |
| } |
| head = prHif->ring_head; |
| tail = prHif->ring_tail; |
| data_len = prHif->ring_len[head]; |
| skb = (struct sk_buff *)prMsduInfo->prPacket; |
| u4Length = skb->len; |
| |
| /* gurantee Ring data buffer enough */ |
| if (((data_len + ALIGN_4(u4Length)) > SDIO_RING_BUF_LEN) && |
| (((head + 1) % SDIO_RING_SIZE) == tail)) |
| return FALSE; |
| |
| /* gurantee PLE resource enough */ |
| if ((prHif->ring_PLE[head] == |
| prAdapter->nicTxReousrce.u4DataTotalResourcePle) && |
| (((head + 1) % SDIO_RING_SIZE) == tail)) |
| return FALSE; |
| |
| return TRUE; |
| } |
| #else |
| u_int8_t halTxIsDataBufEnough(IN struct ADAPTER *prAdapter, |
| IN struct MSDU_INFO *prMsduInfo) |
| { |
| return TRUE; |
| } |
| #endif |
| |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \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 |
| */ |
| /*----------------------------------------------------------------------------*/ |
| u_int8_t halTxCalculateResource(IN struct ADAPTER *prAdapter, IN uint16_t *au2TxRlsCnt, OUT uint16_t *au2FreeTcResource) |
| { |
| struct TX_TCQ_STATUS *prTcqStatus; |
| u_int8_t bStatus = FALSE; |
| uint8_t ucTcIdx; |
| uint32_t u4TotalTxDoneCnt = 0; |
| uint32_t u4TotalExtraTxDone = 0; |
| uint32_t au4UsedCnt[TC_NUM]; |
| uint32_t au4ExtraTxDone[TC_NUM]; |
| |
| uint32_t *au4TxDoneCnt; |
| uint32_t *au4PreUsedCnt; |
| uint32_t u4AvaliableCnt; |
| u_int8_t 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]\n", |
| au4TxDoneCnt[TC0_INDEX], au4TxDoneCnt[TC1_INDEX], au4TxDoneCnt[TC2_INDEX], |
| au4TxDoneCnt[TC3_INDEX], au4TxDoneCnt[TC4_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; |
| } |
| u_int8_t halTxReleaseResource(IN struct ADAPTER *prAdapter, IN uint16_t *au2TxRlsCnt) |
| { |
| struct TX_TCQ_STATUS *prTcqStatus; |
| u_int8_t bStatus = FALSE; |
| uint32_t i; |
| struct SDIO_STAT_COUNTER *prStatCnt; |
| uint16_t au2TxDoneCnt[HIF_TX_NUM] = { 0 }; |
| |
| ASSERT(prAdapter); |
| prTcqStatus = &prAdapter->rTxCtrl.rTc; |
| prStatCnt = &prAdapter->prGlueInfo->rHifInfo.rStatCounter; |
| |
| /* Update Free Tc resource counter */ |
| halTxGetFreeResource(prAdapter, au2TxDoneCnt, au2TxRlsCnt); |
| |
| /* Return free Tc page count */ |
| halTxReturnFreeResource(prAdapter, au2TxDoneCnt); |
| bStatus = TRUE; |
| |
| /* Update Statistic counter */ |
| prStatCnt->u4TxDonePendingPktCnt += nicTxGetMsduPendingCnt(prAdapter); |
| prStatCnt->u4TxDoneIntTotCnt++; |
| |
| for (i = HIF_TXC_IDX_0; i < HIF_TXC_IDX_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 <<PSE>>:Buf[%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]); |
| |
| |
| if (prAdapter->rTxCtrl.rTc.fgNeedPleCtrl) |
| DBGLOG(TX, LOUD, "TCQ Status Free Page <<PLE>>:Buf[%u:%u, %u:%u, %u:%u, %u:%u, %u:%u]\n", |
| prTcqStatus->au4FreePageCount_PLE[TC0_INDEX], prTcqStatus->au4FreePageCount_PLE[TC0_INDEX], |
| prTcqStatus->au4FreePageCount_PLE[TC1_INDEX], prTcqStatus->au4FreePageCount_PLE[TC1_INDEX], |
| prTcqStatus->au4FreePageCount_PLE[TC2_INDEX], prTcqStatus->au4FreePageCount_PLE[TC2_INDEX], |
| prTcqStatus->au4FreePageCount_PLE[TC3_INDEX], prTcqStatus->au4FreePageCount_PLE[TC3_INDEX], |
| prTcqStatus->au4FreePageCount_PLE[TC4_INDEX], prTcqStatus->au4FreePageCount_PLE[TC4_INDEX]); |
| |
| return bStatus; |
| } |
| |
| uint32_t halTxPollingResource(IN struct ADAPTER *prAdapter, IN uint8_t ucTC) |
| { |
| struct TX_CTRL *prTxCtrl; |
| uint32_t u4Status = WLAN_STATUS_RESOURCES; |
| uint32_t au4WTSR[8]; |
| struct GL_HIF_INFO *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(uint32_t) * 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, (uint16_t *) au4WTSR)) { |
| if (prTxCtrl->rTc.au4FreeBufferCount[ucTC] > 0) |
| u4Status = WLAN_STATUS_SUCCESS; |
| } |
| |
| return u4Status; |
| } |
| |
| void halTxInterruptSanityCheck(IN struct ADAPTER *prAdapter, IN uint16_t *au2TxRlsCnt) |
| { |
| uint8_t ucIdx; |
| u_int8_t 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 struct ADAPTER *prAdapter) |
| { |
| struct ENHANCE_MODE_DATA_STRUCT *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 struct ADAPTER *prAdapter) |
| { |
| struct TX_CTRL *prTxCtrl; |
| #if CFG_SDIO_INTR_ENHANCE |
| struct ENHANCE_MODE_DATA_STRUCT *prSDIOCtrl; |
| #else |
| uint32_t 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, (uint16_t *)&prSDIOCtrl->rTxInfo); |
| halTxReleaseResource(prAdapter, (uint16_t *)&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, (uint8_t *) au4TxCount); |
| |
| #endif /* CFG_SDIO_INTR_ENHANCE */ |
| |
| nicTxAdjustTcq(prAdapter); |
| kalSetTxEvent2Hif(prAdapter->prGlueInfo); |
| |
| 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 |
| * |
| */ |
| /*----------------------------------------------------------------------------*/ |
| uint32_t halRxReadBuffer(IN struct ADAPTER *prAdapter, IN OUT struct SW_RFB *prSwRfb) |
| { |
| struct RX_CTRL *prRxCtrl; |
| uint8_t *pucBuf; |
| struct HW_MAC_RX_DESC *prRxStatus; |
| uint32_t u4PktLen = 0, u4ReadBytes; |
| uint32_t u4Status = WLAN_STATUS_SUCCESS; |
| u_int8_t fgResult = TRUE; |
| uint32_t u4RegValue; |
| uint32_t rxNum; |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| uint32_t *pu4HwAppendDW; |
| #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ |
| |
| 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 != (uint32_t) 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, (uint8_t *) 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 = (uint8_t) HAL_RX_STATUS_GET_PKT_TYPE(prRxStatus); |
| DBGLOG(RX, TRACE, "ucPacketType = %d\n", prSwRfb->ucPacketType); |
| |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| pu4HwAppendDW = (uint32_t *) prRxStatus; |
| pu4HwAppendDW += (ALIGN_4(prRxStatus->u2RxByteCount) >> 2); |
| prSwRfb->u4TcpUdpIpCksStatus = *pu4HwAppendDW; |
| DBGLOG(RX, TRACE, "u4TcpUdpIpCksStatus[0x%02x]\n", prSwRfb->u4TcpUdpIpCksStatus); |
| #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ |
| |
| prSwRfb->ucStaRecIdx = |
| secGetStaIdxByWlanIdx(prAdapter, (uint8_t) 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 struct ADAPTER *prAdapter) |
| { |
| struct RX_CTRL *prRxCtrl; |
| struct SW_RFB *prSwRfb = (struct SW_RFB *) NULL; |
| struct HW_MAC_RX_DESC *prRxStatus; |
| uint32_t u4HwAppendDW; |
| uint32_t *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, struct SW_RFB *); |
| 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 = (uint32_t *) 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) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| uint32_t |
| halRxEnhanceReadBuffer(IN struct ADAPTER *prAdapter, |
| IN uint32_t u4DataPort, IN uint16_t u2RxLength, IN OUT struct SW_RFB *prSwRfb) |
| { |
| struct RX_CTRL *prRxCtrl; |
| uint8_t *pucBuf; |
| struct HW_MAC_RX_DESC *prRxStatus; |
| uint32_t u4PktLen = 0; |
| uint32_t u4Status = WLAN_STATUS_FAILURE; |
| u_int8_t fgResult = TRUE; |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| uint32_t *pu4HwAppendDW; |
| #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ |
| |
| 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 = (uint32_t) (HAL_RX_STATUS_GET_RX_BYTE_CNT(prRxStatus)); |
| /* DBGLOG(RX, TRACE, ("u4PktLen = %d\n", u4PktLen)); */ |
| |
| prSwRfb->ucPacketType = (uint8_t) HAL_RX_STATUS_GET_PKT_TYPE(prRxStatus); |
| /* DBGLOG(RX, TRACE, ("ucPacketType = %d\n", prSwRfb->ucPacketType)); */ |
| |
| prSwRfb->ucStaRecIdx = |
| secGetStaIdxByWlanIdx(prAdapter, (uint8_t) 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 = %u\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 (%u)\n", |
| u4PktLen); |
| ASSERT(0); |
| break; |
| } |
| |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| pu4HwAppendDW = (uint32_t *) prRxStatus; |
| pu4HwAppendDW += (ALIGN_4(prRxStatus->u2RxByteCount) >> 2); |
| prSwRfb->u4TcpUdpIpCksStatus = *pu4HwAppendDW; |
| DBGLOG(RX, TRACE, "u4TcpUdpIpCksStatus[0x%02x]\n", prSwRfb->u4TcpUdpIpCksStatus); |
| #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ |
| |
| 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 struct ADAPTER *prAdapter) |
| { |
| struct ENHANCE_MODE_DATA_STRUCT *prSDIOCtrl; |
| struct RX_CTRL *prRxCtrl; |
| struct SW_RFB *prSwRfb = (struct SW_RFB *) NULL; |
| uint32_t i, rxNum; |
| uint16_t 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, struct SW_RFB *); |
| 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 struct ADAPTER *prAdapter) |
| { |
| struct ENHANCE_MODE_DATA_STRUCT *prEnhDataStr; |
| struct RX_CTRL *prRxCtrl; |
| uint32_t u4RxLength; |
| uint32_t i, rxNum; |
| uint32_t u4RxAggCount = 0, u4RxAggLength = 0; |
| uint32_t u4RxAvailAggLen; |
| uint8_t *pucSrcAddr; |
| uint16_t u2RxPktNum; |
| struct GL_HIF_INFO *prHifInfo; |
| struct SDIO_RX_COALESCING_BUF *prRxBuf; |
| u_int8_t 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 (u2RxPktNum > HIF_RX_MAX_AGG_NUM) { |
| DBGLOG(RX, ERROR, |
| "[%s] u2RxPktNum (%d) > HIF_RX_MAX_AGG_NUM\n", |
| __func__, u2RxPktNum); |
| |
| halProcessAbnormalInterrupt(prAdapter); |
| GL_RESET_TRIGGER(prAdapter, RST_FLAG_DO_CORE_DUMP); |
| return; |
| } |
| |
| 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) { |
| struct QUE rTempQue; |
| struct QUE *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(struct ENHANCE_MODE_DATA_STRUCT) + HIF_RX_ENHANCE_MODE_PAD_LEN); |
| #endif |
| u4RxAggCount = 0; |
| |
| for (i = 0; i < u2RxPktNum; i++) { |
| u4RxLength = (rxNum == 0 ? (uint32_t) prEnhDataStr->rRxInfo.u.au2Rx0Len[i] : |
| (uint32_t) prEnhDataStr->rRxInfo.u.au2Rx1Len[i]); |
| |
| if (!u4RxLength) { |
| DBGLOG(RX, ERROR, "[%s] RxLength == 0\n", __func__); |
| halProcessAbnormalInterrupt(prAdapter); |
| GL_RESET_TRIGGER(prAdapter, RST_FLAG_DO_CORE_DUMP); |
| return; |
| } |
| |
| 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); |
| |
| halProcessAbnormalInterrupt(prAdapter); |
| GL_RESET_TRIGGER(prAdapter, RST_FLAG_DO_CORE_DUMP); |
| return; |
| } |
| } |
| |
| mutex_lock(&prHifInfo->rRxFreeBufQueMutex); |
| QUEUE_REMOVE_HEAD(&prHifInfo->rRxFreeBufQueue, prRxBuf, struct SDIO_RX_COALESCING_BUF *); |
| mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); |
| |
| prRxBuf->u4PktCount = u4RxAggCount; |
| |
| u4RxAggLength = (HIF_RX_COALESCING_BUFFER_SIZE - u4RxAvailAggLen); |
| |
| prRxBuf->u4PktTotalLength = u4RxAggLength - sizeof(struct ENHANCE_MODE_DATA_STRUCT); |
| |
| prRxBuf->u4IntLogIdx = prHifInfo->u4IntLogIdx; |
| |
| 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(struct ENHANCE_MODE_DATA_STRUCT); |
| |
| /* Sanity check of zero padding before interrupt status */ |
| if (((uint32_t)*(pucSrcAddr - HIF_RX_ENHANCE_MODE_PAD_LEN)) == 0) { |
| kalMemCopy(prHifInfo->prSDIOCtrl, pucSrcAddr, sizeof(struct ENHANCE_MODE_DATA_STRUCT)); |
| |
| halProcessEnhanceInterruptStatus(prAdapter); |
| |
| if (prHifInfo->prSDIOCtrl->u4WHISR) { |
| /* Interrupt status without Rx done */ |
| /* Mask Rx done interrupt to avoid recurrsion */ |
| uint32_t 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 struct ADAPTER *prAdapter) |
| { |
| if (prAdapter->prGlueInfo->rHifInfo.fgSkipRx) |
| return; |
| |
| #if CFG_SDIO_INTR_ENHANCE |
| #if CFG_SDIO_RX_AGG |
| halRxSDIOAggReceiveRFBs(prAdapter); |
| #else |
| halRxSDIOEnhanceReceiveRFBs(prAdapter); |
| #endif |
| #else |
| halRxSDIOReceiveRFBs(prAdapter); |
| #endif /* CFG_SDIO_INTR_ENHANCE */ |
| } |
| |
| bool halHifSwInfoInit(IN struct ADAPTER *prAdapter) |
| { |
| return true; |
| } |
| |
| void halRxProcessMsduReport(IN struct ADAPTER *prAdapter, IN OUT struct SW_RFB *prSwRfb) |
| { |
| |
| } |
| |
| uint32_t halTxGetPageCountPSE(IN struct ADAPTER *prAdapter, IN uint32_t u4FrameLength) |
| { |
| uint32_t u4PageSize = prAdapter->rTxCtrl.u4PageSize; |
| |
| return ((u4FrameLength + prAdapter->nicTxReousrce.ucPpTxAddCnt + u4PageSize - 1)/u4PageSize); |
| } |
| |
| uint32_t halTxGetPageCount(IN struct ADAPTER *prAdapter, IN uint32_t u4FrameLength, IN u_int8_t fgIncludeDesc) |
| { |
| struct mt66xx_chip_info *prChipInfo = prAdapter->chip_info; |
| |
| if (prChipInfo->is_support_cr4) |
| return 1; |
| |
| return halTxGetPageCountPSE(prAdapter, u4FrameLength); |
| } |
| |
| uint32_t halDumpHifStatus(IN struct ADAPTER *prAdapter, IN uint8_t *pucBuf, IN uint32_t u4Max) |
| { |
| struct GLUE_INFO *prGlueInfo = prAdapter->prGlueInfo; |
| struct GL_HIF_INFO *prHifInfo = &prGlueInfo->rHifInfo; |
| struct SDIO_STAT_COUNTER *prStatCnt = &prHifInfo->rStatCounter; |
| uint32_t u4Len = 0; |
| uint32_t u4Idx; |
| |
| /* 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 HIF_TXC00~04[%u, %u, %u, %u, %u]\n", |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_0], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_1], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_2], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_3], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_4]); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Tx done pending cnt HIF_TXC05~09[%u, %u, %u, %u, %u]\n", |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_5], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_6], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_7], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_8], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_9]); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "Tx done pending cnt HIF_TXC10~15[%u, %u, %u, %u, %u, %u]\n", |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_10], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_11], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_12], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_13], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_14], |
| prHifInfo->au4PendingTxDoneCount[HIF_TXC_IDX_15]); |
| |
| |
| 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"); |
| |
| for (u4Idx = 0; u4Idx < CFG_SDIO_INT_LOG_CNT; u4Idx++) { |
| struct SDIO_INT_LOG_T *prIntLog = &prHifInfo->arIntLog[u4Idx]; |
| struct ENHANCE_MODE_DATA_STRUCT *prIntSts = (struct ENHANCE_MODE_DATA_STRUCT *)&prIntLog->aucIntSts[0]; |
| uint8_t ucPktIdx; |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "INT IDX[%u] STS[0x%08x] FG[0x%08x] Rx Pkt[%u] Sts0/1[%u:%u]\n", |
| prIntLog->u4Idx, prIntSts->u4WHISR, prIntLog->u4Flag, prIntLog->ucRxPktCnt, |
| prIntSts->rRxInfo.u.u2NumValidRx0Len, prIntSts->rRxInfo.u.u2NumValidRx1Len); |
| |
| if (prIntLog->ucRxPktCnt) { |
| LOGBUF(pucBuf, u4Max, u4Len, "RxDAggLen["); |
| for (ucPktIdx = 0; ucPktIdx < prIntLog->ucRxPktCnt; ucPktIdx++) |
| LOGBUF(pucBuf, u4Max, u4Len, "%4u:", prIntLog->au2RxPktLen[ucPktIdx]); |
| LOGBUF(pucBuf, u4Max, u4Len, "]\n"); |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "RxDAggSn ["); |
| for (ucPktIdx = 0; ucPktIdx < prIntLog->ucRxPktCnt; ucPktIdx++) |
| LOGBUF(pucBuf, u4Max, u4Len, "0x%08x: ", prIntLog->au4RxPktInfo[ucPktIdx]); |
| LOGBUF(pucBuf, u4Max, u4Len, "]\n"); |
| } |
| |
| if (prIntSts->rRxInfo.u.u2NumValidRx0Len) { |
| LOGBUF(pucBuf, u4Max, u4Len, "Rx0StsLen["); |
| for (ucPktIdx = 0; ucPktIdx < prIntSts->rRxInfo.u.u2NumValidRx0Len; ucPktIdx++) |
| LOGBUF(pucBuf, u4Max, u4Len, "%4u:", prIntSts->rRxInfo.u.au2Rx0Len[ucPktIdx]); |
| LOGBUF(pucBuf, u4Max, u4Len, "]\n"); |
| } |
| |
| if (prIntSts->rRxInfo.u.u2NumValidRx1Len) { |
| LOGBUF(pucBuf, u4Max, u4Len, "Rx1StsLen["); |
| for (ucPktIdx = 0; ucPktIdx < HIF_RX_MAX_AGG_NUM; ucPktIdx++) |
| LOGBUF(pucBuf, u4Max, u4Len, "%4u:", prIntSts->rRxInfo.u.au2Rx1Len[ucPktIdx]); |
| LOGBUF(pucBuf, u4Max, u4Len, "]\n"); |
| } |
| } |
| |
| LOGBUF(pucBuf, u4Max, u4Len, "---------------------------------\n"); |
| |
| /* Reset statistic counter */ |
| kalMemZero(prStatCnt, sizeof(struct SDIO_STAT_COUNTER)); |
| |
| halDumpIntLog(prAdapter); |
| |
| 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 |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| u_int8_t halReadN9RegisterByMailBox(IN struct ADAPTER *prAdapter, IN uint32_t addr, IN uint32_t *prresult) |
| { |
| uint32_t ori_whlpcr, temp, counter = 0; |
| u_int8_t 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 |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| u_int8_t halWriteN9RegisterByMailBox(IN struct ADAPTER *prAdapter, IN uint32_t addr, IN uint32_t value) |
| { |
| uint32_t ori_whlpcr, temp, counter = 0; |
| u_int8_t 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 |
| |
| u_int8_t halIsPendingRx(IN struct ADAPTER *prAdapter) |
| { |
| return FALSE; |
| } |
| |
| uint32_t halGetValidCoalescingBufSize(IN struct ADAPTER *prAdapter) |
| { |
| struct GL_HIF_INFO *prHifInfo; |
| uint32_t u4BufSize; |
| #if (MTK_WCN_HIF_SDIO == 0) |
| struct sdio_func *prSdioFunc; |
| uint32_t u4RuntimeMaxBuf; |
| |
| #endif |
| |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| if (HIF_TX_COALESCING_BUFFER_SIZE > HIF_RX_COALESCING_BUFFER_SIZE) |
| u4BufSize = HIF_TX_COALESCING_BUFFER_SIZE; |
| else |
| u4BufSize = HIF_RX_COALESCING_BUFFER_SIZE; |
| |
| #if (MTK_WCN_HIF_SDIO == 0) |
| prSdioFunc = prHifInfo->func; |
| |
| /* Check host capability */ |
| /* 1. Should less than host-max_req_size */ |
| if (u4BufSize > prSdioFunc->card->host->max_req_size) |
| u4BufSize = prSdioFunc->card->host->max_req_size; |
| |
| /* 2. Should less than runtime-blksize * host-blk_count */ |
| u4RuntimeMaxBuf = prSdioFunc->cur_blksize * |
| prSdioFunc->card->host->max_blk_count; |
| if (u4BufSize > u4RuntimeMaxBuf) |
| u4BufSize = u4RuntimeMaxBuf; |
| |
| DBGLOG(INIT, TRACE, "\n" |
| "Final buf : 0x%X\n" |
| "Default TX buf : 0x%X\n" |
| "Default RX buf : 0x%X\n" |
| "Host caps -\n" |
| "max_req_size : 0x%X\n" |
| "max_seg_size : 0x%X\n" |
| "max_segs : 0x%X\n" |
| "max_blk_size : 0x%X\n" |
| "max_blk_count : 0x%X\n" |
| "Runtime -\n" |
| "cur_blksize : 0x%X\n", |
| u4BufSize, |
| HIF_TX_COALESCING_BUFFER_SIZE, |
| HIF_RX_COALESCING_BUFFER_SIZE, |
| prSdioFunc->card->host->max_req_size, |
| prSdioFunc->card->host->max_seg_size, |
| prSdioFunc->card->host->max_segs, |
| prSdioFunc->card->host->max_blk_size, |
| prSdioFunc->card->host->max_blk_count, |
| prSdioFunc->cur_blksize); |
| #endif |
| |
| return u4BufSize; |
| } |
| |
| uint32_t halAllocateIOBuffer(IN struct ADAPTER *prAdapter) |
| { |
| struct GL_HIF_INFO *prHifInfo; |
| uint8_t ucIdx; |
| struct SDIO_RX_COALESCING_BUF *prRxBuf; |
| |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| /* 4 <5> Memory for enhanced interrupt response */ |
| #ifdef CFG_PREALLOC_MEMORY |
| prHifInfo->prSDIOCtrl = (struct ENHANCE_MODE_DATA_STRUCT *) |
| preallocGetMem(MEM_ID_IO_CTRL); |
| #else |
| prHifInfo->prSDIOCtrl = (struct ENHANCE_MODE_DATA_STRUCT *) |
| kalAllocateIOBuffer(sizeof(struct ENHANCE_MODE_DATA_STRUCT)); |
| #endif |
| if (prHifInfo->prSDIOCtrl == NULL) { |
| DBGLOG(HAL, ERROR, |
| "Could not allocate %d bytes for interrupt response.\n", |
| sizeof(struct ENHANCE_MODE_DATA_STRUCT)); |
| |
| 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; |
| #ifdef CFG_PREALLOC_MEMORY |
| prRxBuf->pvRxCoalescingBuf = preallocGetMem(MEM_ID_RX_DATA); |
| #else |
| prRxBuf->pvRxCoalescingBuf = kalAllocateIOBuffer(prRxBuf->u4BufSize); |
| #endif |
| if (!prRxBuf->pvRxCoalescingBuf) { |
| DBGLOG(HAL, ERROR, "Rx coalescing alloc failed!\n"); |
| continue; |
| } |
| |
| QUEUE_INSERT_TAIL(&prHifInfo->rRxFreeBufQueue, &prRxBuf->rQueEntry); |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| uint32_t halReleaseIOBuffer(IN struct ADAPTER *prAdapter) |
| { |
| struct GL_HIF_INFO *prHifInfo; |
| uint8_t ucIdx; |
| struct SDIO_RX_COALESCING_BUF *prRxBuf; |
| |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| /* Release coalescing buffer */ |
| for (ucIdx = 0; ucIdx < HIF_RX_COALESCING_BUF_COUNT; ucIdx++) { |
| prRxBuf = &prHifInfo->rRxCoalesingBuf[ucIdx]; |
| #ifndef CFG_PREALLOC_MEMORY |
| kalReleaseIOBuffer(prRxBuf->pvRxCoalescingBuf, prRxBuf->u4BufSize); |
| #endif |
| prRxBuf->pvRxCoalescingBuf = NULL; |
| } |
| |
| /* 4 <5> Memory for enhanced interrupt response */ |
| if (prHifInfo->prSDIOCtrl) { |
| #ifndef CFG_PREALLOC_MEMORY |
| kalReleaseIOBuffer((void *) prHifInfo->prSDIOCtrl, sizeof(struct ENHANCE_MODE_DATA_STRUCT)); |
| #endif |
| prHifInfo->prSDIOCtrl = (struct ENHANCE_MODE_DATA_STRUCT *) NULL; |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief dump firmware Assert message |
| * |
| * \param[in] |
| * prAdapter |
| * |
| * \return |
| * TRUE |
| * FALSE |
| */ |
| /*----------------------------------------------------------------------------*/ |
| void halPrintFirmwareAssertInfo(IN struct ADAPTER *prAdapter) |
| { |
| uint32_t u4MailBox0, u4MailBox1; |
| uint32_t line = 0; |
| uint8_t 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\" #%u\n\n", |
| NIC_NAME, aucAssertFile, line); |
| |
| } |
| |
| void halPrintMailbox(IN struct ADAPTER *prAdapter) |
| { |
| uint32_t u4MailBoxStatus0, u4MailBoxStatus1; |
| uint8_t fgResult; |
| |
| HAL_LP_OWN_RD(prAdapter, &fgResult); |
| if (fgResult != TRUE) |
| return; |
| |
| halGetMailbox(prAdapter, 0, &u4MailBoxStatus0); |
| halGetMailbox(prAdapter, 1, &u4MailBoxStatus1); |
| DBGFWLOG(INIT, ERROR, "MailBox Status = 0x%08X, 0x%08X\n", u4MailBoxStatus0, u4MailBoxStatus1); |
| } |
| |
| void halPrintIntStatus(IN struct ADAPTER *prAdapter) |
| { |
| #if CFG_SDIO_INTR_ENHANCE |
| struct ENHANCE_MODE_DATA_STRUCT *prSDIOCtrl; |
| |
| prSDIOCtrl = prAdapter->prGlueInfo->rHifInfo.prSDIOCtrl; |
| ASSERT(prSDIOCtrl); |
| |
| DBGLOG_MEM32(REQ, WARN, prSDIOCtrl, sizeof(struct ENHANCE_MODE_DATA_STRUCT)); |
| #else |
| uint32_t u4IntStatus; |
| |
| HAL_MCR_RD(prAdapter, MCR_WHISR, u4IntStatus); |
| |
| DBGLOG(REQ, WARN, "INT status[0x%08x]\n", u4IntStatus); |
| #endif /* CFG_SDIO_INTR_ENHANCE */ |
| } |
| |
| void halDumpIntLog(IN struct ADAPTER *prAdapter) |
| { |
| struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| struct SDIO_INT_LOG_T *prIntLog; |
| struct ENHANCE_MODE_DATA_STRUCT *prIntSts; |
| uint32_t u4Idx; |
| |
| for (u4Idx = 0; u4Idx < CFG_SDIO_INT_LOG_CNT; u4Idx++) { |
| prIntLog = &prHifInfo->arIntLog[u4Idx]; |
| prIntSts = (struct ENHANCE_MODE_DATA_STRUCT *)&prIntLog->aucIntSts[0]; |
| |
| DBGLOG(INTR, ERROR, "INT IDX[%u] STS[0x%08x] FG[0x%08x] Rx Pkt[%u] Sts0/1[%u:%u]\n", |
| prIntLog->u4Idx, prIntSts->u4WHISR, prIntLog->u4Flag, prIntLog->ucRxPktCnt, |
| prIntSts->rRxInfo.u.u2NumValidRx0Len, prIntSts->rRxInfo.u.u2NumValidRx1Len); |
| DBGLOG_MEM32(INTR, ERROR, &prIntLog->au2RxPktLen[0], sizeof(uint16_t) * HIF_RX_MAX_AGG_NUM); |
| DBGLOG_MEM32(INTR, ERROR, &prIntLog->au4RxPktInfo[0], sizeof(uint32_t) * HIF_RX_MAX_AGG_NUM); |
| DBGLOG_MEM32(INTR, ERROR, prIntSts, sizeof(struct ENHANCE_MODE_DATA_STRUCT)); |
| } |
| |
| DBGLOG(INTR, ERROR, "---------------------------------\n"); |
| } |
| |
| void halTagIntLog(IN struct ADAPTER *prAdapter, IN enum HIF_SDIO_INT_STS eTag) |
| { |
| struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| prHifInfo->arIntLog[prHifInfo->ucIntLogEntry].u4Flag |= BIT(eTag); |
| } |
| |
| void halRecIntLog(IN struct ADAPTER *prAdapter, IN struct ENHANCE_MODE_DATA_STRUCT *prSDIOCtrl) |
| { |
| struct SDIO_INT_LOG_T *prIntLog; |
| uint8_t ucLogEntry; |
| struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| prHifInfo->u4IntLogIdx++; |
| ucLogEntry = prHifInfo->u4IntLogIdx % CFG_SDIO_INT_LOG_CNT; |
| prIntLog = &prHifInfo->arIntLog[ucLogEntry]; |
| kalMemZero(prIntLog, sizeof(struct SDIO_INT_LOG_T)); |
| |
| prIntLog->u4Idx = prHifInfo->u4IntLogIdx; |
| prHifInfo->ucIntLogEntry = ucLogEntry; |
| kalMemCopy(&prIntLog->aucIntSts[0], prSDIOCtrl, sizeof(struct ENHANCE_MODE_DATA_STRUCT)); |
| } |
| |
| struct SDIO_INT_LOG_T *halGetIntLog(IN struct ADAPTER *prAdapter, IN uint32_t u4Idx) |
| { |
| struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| return &prHifInfo->arIntLog[u4Idx % CFG_SDIO_INT_LOG_CNT]; |
| } |
| |
| void halProcessAbnormalInterrupt(IN struct ADAPTER *prAdapter) |
| { |
| uint32_t u4Data = 0; |
| uint8_t fgResult; |
| |
| /* dump abnormal status */ |
| |
| /* Need driver own */ |
| HAL_LP_OWN_RD(prAdapter, &fgResult); |
| if (fgResult == TRUE) |
| HAL_MCR_RD(prAdapter, MCR_WASR, &u4Data); |
| |
| halPollDbgCr(prAdapter, 5); |
| |
| halPrintIntStatus(prAdapter); |
| |
| if (u4Data) { |
| DBGLOG(REQ, WARN, "SDIO Abnormal: WASR = 0x%x!\n", |
| u4Data); |
| } |
| |
| if (u4Data & (WASR_RX0_UNDER_FLOW | WASR_RX1_UNDER_FLOW)) { |
| DBGLOG(REQ, ERROR, |
| "Skip all SDIO Rx due to Rx underflow error!\n"); |
| prAdapter->prGlueInfo->rHifInfo.fgSkipRx = TRUE; |
| halDumpHifStatus(prAdapter, NULL, 0); |
| GL_RESET_TRIGGER(prAdapter, RST_FLAG_DO_CORE_DUMP); |
| } |
| |
| halDumpIntLog(prAdapter); |
| } |
| |
| void halProcessSoftwareInterrupt(IN struct ADAPTER *prAdapter) |
| { |
| uint32_t 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, TRACE, "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) { |
| DBGLOG(INIT, WARN, "[SER][L1] fw notify host L1 start\n"); |
| halPrintMailbox(prAdapter); |
| /* Stop HIF Tx/Rx operation */ |
| nicSerStopTxRx(prAdapter); |
| } |
| |
| if (u4IntrBits & SER_SDIO_N9_HOST_RECOVERY_DONE) |
| DBGLOG(INIT, WARN, "[SER][L1] fw L1 rst done\n"); |
| |
| if (u4IntrBits & SDIO_MAILBOX_FUNC_READ_REG_IDX) |
| prAdapter->fgGetMailBoxRWAck = TRUE; |
| |
| if ((u4IntrBits & ~WHISR_D2H_WKUP_BY_RX_PACKET) != 0) |
| DBGLOG(SW4, WARN, "u4IntrBits: 0x%08x\n", u4IntrBits); |
| |
| } /* end of halProcessSoftwareInterrupt() */ |
| |
| void halPutMailbox(IN struct ADAPTER *prAdapter, IN uint32_t u4MailboxNum, IN uint32_t 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 struct ADAPTER *prAdapter, IN uint32_t u4MailboxNum, OUT uint32_t *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); |
| } |
| } |
| |
| u_int8_t halDeAggErrorCheck(struct ADAPTER *prAdapter, |
| struct SDIO_RX_COALESCING_BUF *prRxBuf, |
| uint8_t *pucPktAddr) |
| { |
| struct mt66xx_chip_info *prChipInfo; |
| uint16_t u2PktLength; |
| uint8_t *pucRxBufEnd; |
| |
| ASSERT(prAdapter); |
| prChipInfo = prAdapter->chip_info; |
| |
| pucRxBufEnd = (uint8_t *)prRxBuf->pvRxCoalescingBuf + prRxBuf->u4PktTotalLength; |
| |
| u2PktLength = HAL_RX_STATUS_GET_RX_BYTE_CNT((struct HW_MAC_RX_DESC *)pucPktAddr); |
| |
| /* Rx buffer boundary check */ |
| if ((pucPktAddr + ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN)) >= pucRxBufEnd) |
| return TRUE; |
| |
| /* Rx packet min length check */ |
| if (u2PktLength <= prChipInfo->rxd_size) |
| return TRUE; |
| |
| /* Rx packet max length check */ |
| if (u2PktLength >= CFG_RX_MAX_PKT_SIZE) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| void halDeAggRxPktProc(struct ADAPTER *prAdapter, |
| struct SDIO_RX_COALESCING_BUF *prRxBuf) |
| { |
| struct GL_HIF_INFO *prHifInfo; |
| uint32_t i; |
| struct QUE rTempFreeRfbList, rTempRxRfbList; |
| struct QUE *prTempFreeRfbList = &rTempFreeRfbList; |
| struct QUE *prTempRxRfbList = &rTempRxRfbList; |
| struct RX_CTRL *prRxCtrl; |
| struct SW_RFB *prSwRfb = (struct SW_RFB *) NULL; |
| uint8_t *pucSrcAddr; |
| uint16_t u2PktLength; |
| u_int8_t fgReschedule = FALSE; |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| uint32_t *pu4HwAppendDW; |
| #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ |
| u_int8_t fgDeAggErr = FALSE; |
| struct SDIO_INT_LOG_T *prIntLog; |
| uint64_t u8Current = 0; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| SDIO_TIME_INTERVAL_DEC(); |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| QUEUE_INITIALIZE(prTempFreeRfbList); |
| QUEUE_INITIALIZE(prTempRxRfbList); |
| |
| 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, struct SW_RFB *); |
| |
| 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, |
| (struct QUE_ENTRY *)prRxBuf); |
| |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| |
| /* Reschedule this work */ |
| if ((prAdapter->prGlueInfo->ulFlag & GLUE_FLAG_HALT) == 0) |
| schedule_delayed_work( |
| &prAdapter->prGlueInfo->rRxPktDeAggWork, 0); |
| |
| return; |
| } |
| |
| pucSrcAddr = prRxBuf->pvRxCoalescingBuf; |
| fgDeAggErr = FALSE; |
| |
| prIntLog = halGetIntLog(prAdapter, prRxBuf->u4IntLogIdx); |
| u8Current = sched_clock(); |
| |
| SDIO_REC_TIME_START(); |
| for (i = 0; i < prRxBuf->u4PktCount; i++) { |
| /* Rx de-aggregation check */ |
| if (halDeAggErrorCheck(prAdapter, prRxBuf, pucSrcAddr)) { |
| fgDeAggErr = TRUE; |
| break; |
| } |
| |
| u2PktLength = |
| HAL_RX_STATUS_GET_RX_BYTE_CNT( |
| (struct HW_MAC_RX_DESC *)pucSrcAddr); |
| |
| prIntLog->au2RxPktLen[i] = u2PktLength; |
| |
| QUEUE_REMOVE_HEAD(prTempFreeRfbList, |
| prSwRfb, struct SW_RFB *); |
| |
| kalMemCopy(prSwRfb->pucRecvBuff, pucSrcAddr, |
| ALIGN_4(u2PktLength + HIF_RX_HW_APPENDED_LEN)); |
| |
| prSwRfb->ucPacketType = |
| (uint8_t)HAL_RX_STATUS_GET_PKT_TYPE(prSwRfb->prRxStatus); |
| |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| pu4HwAppendDW = (uint32_t *) prSwRfb->prRxStatus; |
| pu4HwAppendDW += |
| (ALIGN_4(prSwRfb->prRxStatus->u2RxByteCount) >> 2); |
| prSwRfb->u4TcpUdpIpCksStatus = *pu4HwAppendDW; |
| DBGLOG(RX, TRACE, |
| "u4TcpUdpIpCksStatus[0x%02x]\n", |
| prSwRfb->u4TcpUdpIpCksStatus); |
| #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ |
| |
| kalMemCopy(&prIntLog->au4RxPktInfo[i], |
| pucSrcAddr + ALIGN_4(u2PktLength), sizeof(uint32_t)); |
| |
| GLUE_RX_SET_PKT_INT_TIME(prSwRfb->pvPacket, |
| prAdapter->prGlueInfo->u8HifIntTime); |
| |
| GLUE_RX_SET_PKT_RX_TIME(prSwRfb->pvPacket, u8Current); |
| |
| 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); |
| |
| prIntLog->ucRxPktCnt = i; |
| |
| if (fgDeAggErr) { |
| /* Rx de-aggregation error */ |
| /* Dump current Rx buffer */ |
| DBGLOG(RX, ERROR, |
| "Rx de-aggregation error!, INT sts: total len[%u] pkt cnt[%u]\n", |
| prRxBuf->u4PktTotalLength, prRxBuf->u4PktCount); |
| #if 0 |
| /* Sometimes the larger frame is received, and dump |
| * those message will let platform stop application. |
| */ |
| DBGLOG_MEM32(RX, ERROR, |
| prRxBuf->pvRxCoalescingBuf, |
| prRxBuf->u4PktTotalLength); |
| |
| halDumpIntLog(prAdapter); |
| #endif |
| |
| /* Free all de-aggregated SwRfb */ |
| QUEUE_CONCATENATE_QUEUES(prTempFreeRfbList, prTempRxRfbList); |
| } else { |
| 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, |
| (struct QUE_ENTRY *)prRxBuf); |
| mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); |
| } |
| |
| |
| void halDeAggRxPktWorker(struct work_struct *work) |
| { |
| struct GLUE_INFO *prGlueInfo; |
| struct GL_HIF_INFO *prHifInfo; |
| struct ADAPTER *prAdapter; |
| struct SDIO_RX_COALESCING_BUF *prRxBuf; |
| struct RX_CTRL *prRxCtrl; |
| |
| if (g_u4HaltFlag) |
| return; |
| |
| prGlueInfo = ENTRY_OF(work, struct GLUE_INFO, rRxPktDeAggWork); |
| prHifInfo = &prGlueInfo->rHifInfo; |
| prAdapter = prGlueInfo->prAdapter; |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) |
| return; |
| |
| prRxCtrl = &prAdapter->rRxCtrl; |
| prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| |
| QUEUE_REMOVE_HEAD(&prHifInfo->rRxDeAggQueue, |
| prRxBuf, struct SDIO_RX_COALESCING_BUF *); |
| |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| while (prRxBuf) { |
| halDeAggRxPktProc(prAdapter, prRxBuf); |
| |
| if (prGlueInfo->ulFlag & GLUE_FLAG_HALT) |
| return; |
| |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| QUEUE_REMOVE_HEAD(&prHifInfo->rRxDeAggQueue, prRxBuf, struct SDIO_RX_COALESCING_BUF *); |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| } |
| } |
| |
| void halDeAggRxPkt(struct ADAPTER *prAdapter, struct SDIO_RX_COALESCING_BUF *prRxBuf) |
| { |
| struct GL_HIF_INFO *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, (struct QUE_ENTRY *)prRxBuf); |
| mutex_unlock(&prHifInfo->rRxFreeBufQueMutex); |
| |
| return; |
| } |
| |
| #if CFG_SDIO_RX_AGG_WORKQUE && !CFG_SDIO_RX_DE_AGG_IN_THREAD |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| QUEUE_INSERT_TAIL(&prHifInfo->rRxDeAggQueue, (struct QUE_ENTRY *)prRxBuf); |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| |
| schedule_delayed_work(&prAdapter->prGlueInfo->rRxPktDeAggWork, 0); |
| #elif CFG_SDIO_RX_DE_AGG_IN_THREAD |
| mutex_lock(&prHifInfo->rRxDeAggQueMutex); |
| QUEUE_INSERT_TAIL(&prHifInfo->rRxDeAggQueue, |
| (struct QUE_ENTRY *)prRxBuf); |
| mutex_unlock(&prHifInfo->rRxDeAggQueMutex); |
| set_bit(GLUE_FLAG_RX_DE_AGG_IN_THREAD_BIT, |
| &(prAdapter->prGlueInfo->ulFlag)); |
| wake_up_interruptible(&(prAdapter->prGlueInfo->waitq_rxDeAgg)); |
| #else |
| halDeAggRxPktProc(prAdapter, prRxBuf); |
| #endif |
| } |
| |
| void halRxTasklet(unsigned long data) |
| { |
| |
| } |
| |
| void halTxCompleteTasklet(unsigned long data) |
| { |
| |
| } |
| |
| /* Hif power off wifi */ |
| uint32_t halHifPowerOffWifi(IN struct ADAPTER *prAdapter) |
| { |
| uint32_t 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) { |
| uint32_t 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 */ |
| /* Not set mailbox r/w interrupt */ |
| kalDevRegWrite(prAdapter->prGlueInfo, MCR_WSICR, |
| WSICR_H2D_SW_INT_SET & ~ |
| (SDIO_MAILBOX_FUNC_READ_REG_IDX | |
| SDIO_MAILBOX_FUNC_WRITE_REG_IDX)); |
| |
| /* 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 struct ADAPTER *prAdapter, IN uint32_t u4LoopCount) |
| { |
| uint32_t au4Value[] = {MCR_WCIR, MCR_WHLPCR}; |
| uint32_t au4Value1[] = {MCR_WHIER, MCR_D2HRM0R, MCR_D2HRM1R, |
| MCR_D2HRM2R}; |
| uint32_t u4Loop = 0; |
| uint32_t u4Data = 0; |
| uint8_t i = 0, fgResult; |
| #if MTK_WCN_HIF_SDIO |
| uint8_t *pucCCR = (uint8_t *)&au4Value[0]; |
| unsigned long cltCtx = prAdapter->prGlueInfo->rHifInfo.cltCtx; |
| #endif |
| for (; i < sizeof(au4Value)/sizeof(uint32_t); i++) |
| HAL_MCR_RD(prAdapter, au4Value[i], &au4Value[i]); |
| |
| DBGLOG(REQ, WARN, "MCR_WCIR:0x%x, MCR_WHLPCR:0x%x\n", |
| au4Value[0], au4Value[1]); |
| |
| /* Need driver own */ |
| HAL_LP_OWN_RD(prAdapter, &fgResult); |
| if (fgResult == TRUE) { |
| /* dump N9 programming counter */ |
| for (u4Loop = 0; u4Loop < u4LoopCount; u4Loop++) { |
| HAL_MCR_RD(prAdapter, MCR_SWPCDBGR, &u4Data); |
| DBGLOG(INIT, WARN, "SWPCDBGR 0x%08X\n", u4Data); |
| } |
| |
| /* dump others */ |
| for (i = 0; i < sizeof(au4Value1)/sizeof(uint32_t); i++) |
| HAL_MCR_RD(prAdapter, au4Value1[i], &au4Value1[i]); |
| |
| DBGLOG(REQ, WARN, "MCR_WHIER:0x%x, MCR_D2HRM0R:0x%x", |
| au4Value1[0], au4Value1[1]); |
| DBGLOG(REQ, WARN, "MCR_D2HRM1R:0x%x, MCR_D2HRM2R:0x%x\n", |
| au4Value1[2], au4Value1[3]); |
| } |
| |
| #if MTK_WCN_HIF_SDIO |
| for (i = 0; i < 8; i++) |
| mtk_wcn_hif_sdio_f0_readb(cltCtx, 0xf8 + i, &pucCCR[i]); |
| DBGLOG(REQ, WARN, "CCCR %02x %02x %02x %02x %02x %02x %02x %02x\n", |
| pucCCR[0], pucCCR[1], pucCCR[2], pucCCR[3], pucCCR[4], pucCCR[5], pucCCR[6], pucCCR[7]); |
| #endif |
| } |
| |
| void halSerHifReset(IN struct ADAPTER *prAdapter) |
| { |
| struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| /* Restore Tx resource */ |
| halRestoreTxResource(prAdapter); |
| |
| /* Clear interrupt status from Rx interrupt enhance mode */ |
| prHifInfo->fgIsPendingInt = FALSE; |
| kalMemZero(prHifInfo->prSDIOCtrl, sizeof(struct ENHANCE_MODE_DATA_STRUCT)); |
| } |
| |
| u_int8_t halIsPendingTxDone(IN struct ADAPTER *prAdapter) |
| { |
| struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| uint32_t i; |
| u_int8_t fgIsPendingTxDone = FALSE; |
| |
| for (i = TC0_INDEX; i <= TC4_INDEX; i++) { |
| if (prHifInfo->au4PendingTxDoneCount[i]) { |
| fgIsPendingTxDone = TRUE; |
| break; |
| } |
| } |
| |
| if (fgIsPendingTxDone) |
| DBGLOG(NIC, ERROR, "Missing Tx done[%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]); |
| |
| return fgIsPendingTxDone; |
| } |
| |
| void halPrintHifDbgInfo(IN struct ADAPTER *prAdapter) |
| { |
| struct CHIP_DBG_OPS *prDbgOps; |
| |
| if (prAdapter->u4HifDbgFlag & DEG_HIF_ALL || |
| prAdapter->u4HifDbgFlag & DEG_HIF_DEFAULT_DUMP) { |
| halPrintMailbox(prAdapter); |
| halPollDbgCr(prAdapter, LP_DBGCR_POLL_ROUND); |
| } |
| |
| prDbgOps = prAdapter->chip_info->prDebugOps; |
| |
| if (prAdapter->u4HifDbgFlag & (DEG_HIF_ALL | DEG_HIF_PSE)) |
| prDbgOps->showPseInfo(prAdapter); |
| |
| if (prAdapter->u4HifDbgFlag & (DEG_HIF_ALL | DEG_HIF_PLE)) |
| prDbgOps->showPleInfo(prAdapter); |
| |
| prAdapter->u4HifDbgFlag = 0; |
| } |
| |
| u_int8_t halIsTxResourceControlEn(IN struct ADAPTER *prAdapter) |
| { |
| return TRUE; |
| } |
| |
| void halTxResourceResetHwTQCounter(IN struct ADAPTER *prAdapter) |
| { |
| uint32_t *pu4WHISR = NULL; |
| uint16_t au2TxCount[16]; |
| |
| pu4WHISR = (uint32_t *)kalMemAlloc(sizeof(uint32_t), PHY_MEM_TYPE); |
| if (!pu4WHISR) { |
| DBGLOG(INIT, ERROR, "Allocate pu4WHISR fail\n"); |
| return; |
| } |
| |
| HAL_READ_INTR_STATUS(prAdapter, sizeof(uint32_t), (uint8_t *)pu4WHISR); |
| if (HAL_IS_TX_DONE_INTR(*pu4WHISR)) |
| HAL_READ_TX_RELEASED_COUNT(prAdapter, au2TxCount); |
| |
| if (pu4WHISR) |
| kalMemFree(pu4WHISR, PHY_MEM_TYPE, sizeof(uint32_t)); |
| } |
| |
| uint32_t halGetHifTxPageSize(IN struct ADAPTER *prAdapter) |
| { |
| if (!prAdapter->chip_info->is_support_cr4) { |
| if (prAdapter->fgIsNicTxReousrceValid) |
| return prAdapter->nicTxReousrce.u4DataResourceUnit; |
| else |
| return HIF_TX_PAGE_SIZE_STORED_FORWARD; |
| } |
| |
| /*cr4 mode*/ |
| return HIF_TX_PAGE_SIZE; |
| } |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Generic update Tx done counter |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param au2TxDoneCnt Pointer to the final reference table |
| * @param au2TxRlsCnt Pointer to the Tx done counter result got fom interrupt |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| void halTxGetFreeResource(IN struct ADAPTER *prAdapter, IN uint16_t *au2TxDoneCnt, IN uint16_t *au2TxRlsCnt) |
| { |
| uint8_t i; |
| struct BUS_INFO *prBusInfo = prAdapter->chip_info->bus_info; |
| |
| if (prBusInfo->halTxGetFreeResource) |
| return prBusInfo->halTxGetFreeResource(prAdapter, au2TxDoneCnt, au2TxRlsCnt); |
| |
| /* 6632, 7668 ways */ |
| 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]; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Update Tx done counter for mt7663 |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param au2TxDoneCnt Pointer to the final reference table |
| * @param au2TxRlsCnt Pointer to the Tx done counter result got fom interrupt |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| void halTxGetFreeResource_v1(IN struct ADAPTER *prAdapter, IN uint16_t *au2TxDoneCnt, IN uint16_t *au2TxRlsCnt) |
| { |
| uint8_t i; |
| |
| for (i = HIF_TXC_IDX_0; i < HIF_TXC_IDX_NUM; i++) |
| au2TxDoneCnt[i] = au2TxRlsCnt[i]; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Generic return free resource to TCs |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param au2TxDoneCnt Pointer to the final reference table |
| * @param au2TxRlsCnt Pointer to the Tx done counter result got fom interrupt |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| void halTxReturnFreeResource(IN struct ADAPTER *prAdapter, IN uint16_t *au2TxDoneCnt) |
| { |
| uint8_t i; |
| struct BUS_INFO *prBusInfo = prAdapter->chip_info->bus_info; |
| uint16_t u2ReturnCnt; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| |
| if (prBusInfo->halTxReturnFreeResource) |
| prBusInfo->halTxReturnFreeResource(prAdapter, au2TxDoneCnt); |
| else { |
| /* 6632, 7668 ways */ |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| for (i = TC0_INDEX; i < TC_NUM; i++) { |
| u2ReturnCnt = au2TxDoneCnt[nicTxGetTxQByTc(prAdapter, i)]; |
| nicTxReleaseResource_PSE(prAdapter, i, u2ReturnCnt, FALSE); |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[i] -= u2ReturnCnt; |
| } |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Return free resource to TCs for mt7663 |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param au2TxDoneCnt Pointer to the final reference table |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| void halTxReturnFreeResource_v1(IN struct ADAPTER *prAdapter, IN uint16_t *au2TxDoneCnt) |
| { |
| uint8_t i; |
| uint16_t u2ReturnCnt; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| /* WMM 1 */ |
| for (i = HIF_TXC_IDX_0; i <= HIF_TXC_IDX_8; i++) { |
| uint8_t ucTc; |
| |
| u2ReturnCnt = au2TxDoneCnt[i]; |
| |
| if (i < HIF_TXC_IDX_5) { |
| ucTc = HIF_TXC_IDX_2_TC_IDX_PSE(i); |
| nicTxReleaseResource_PSE(prAdapter, ucTc, u2ReturnCnt, FALSE); |
| } else { |
| ucTc = HIF_TXC_IDX_2_TC_IDX_PLE(i); |
| nicTxReleaseResource_PLE(prAdapter, ucTc, u2ReturnCnt, FALSE); |
| } |
| |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[i] -= u2ReturnCnt; |
| } |
| |
| /* WMM 2,3 */ |
| /*TBD*/ |
| |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Generic rollback resource to TCs |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| void halRestoreTxResource(IN struct ADAPTER *prAdapter) |
| { |
| uint8_t i; |
| struct BUS_INFO *prBusInfo = prAdapter->chip_info->bus_info; |
| struct GL_HIF_INFO *prHifInfo = &prAdapter->prGlueInfo->rHifInfo; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| if (prBusInfo->halRestoreTxResource) |
| prBusInfo->halRestoreTxResource(prAdapter); |
| else { |
| /* 6632, 7668 ways */ |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| for (i = TC0_INDEX; i < TC_NUM; i++) { |
| nicTxReleaseResource_PSE(prAdapter, i, prHifInfo->au4PendingTxDoneCount[i], FALSE); |
| prHifInfo->au4PendingTxDoneCount[i] = 0; |
| } |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Rollback resource to TCs for mt7663 |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| void halRestoreTxResource_v1(IN struct ADAPTER *prAdapter) |
| { |
| uint8_t i; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| /* WMM 1 */ |
| /* PSE pages: HIF_TXC_IDX_0- */ |
| for (i = HIF_TXC_IDX_0; i <= HIF_TXC_IDX_4; i++) { |
| nicTxReleaseResource_PSE(prAdapter, HIF_TXC_IDX_2_TC_IDX_PSE(i), |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[i], |
| FALSE); |
| |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[i] = 0; |
| } |
| |
| /* PLE pages */ |
| for (i = HIF_TXC_IDX_5; i <= HIF_TXC_IDX_8; i++) { |
| nicTxReleaseResource_PLE(prAdapter, HIF_TXC_IDX_2_TC_IDX_PLE(i), |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[i], |
| FALSE); |
| |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[i] = 0; |
| } |
| |
| /* WMM 2,3 */ |
| /*TBD*/ |
| |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| } |
| |
| void halUpdateTxDonePendingCount(IN struct ADAPTER *prAdapter, IN u_int8_t isIncr, IN uint8_t ucTc, IN uint32_t u4Len) |
| { |
| uint8_t u2PageCnt; |
| struct BUS_INFO *prBusInfo = prAdapter->chip_info->bus_info; |
| |
| u2PageCnt = halTxGetPageCount(prAdapter, u4Len, FALSE); |
| |
| if (prBusInfo->halUpdateTxDonePendingCount) |
| prBusInfo->halUpdateTxDonePendingCount(prAdapter, isIncr, ucTc, u2PageCnt); |
| else { |
| /* 6632, 7668 ways */ |
| if (isIncr) |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[ucTc] += u2PageCnt; |
| else |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[ucTc] -= u2PageCnt; |
| } |
| } |
| |
| void halUpdateTxDonePendingCount_v1(IN struct ADAPTER *prAdapter, IN u_int8_t isIncr, IN uint8_t ucTc, IN uint16_t u2Cnt) |
| { |
| uint8_t idx; |
| |
| /* Update PSE part */ |
| idx = TC_IDX_PSE_2_HIF_TXC_IDX(ucTc); |
| |
| if (idx >= HIF_TXC_IDX_NUM) |
| ASSERT(0); |
| |
| if (isIncr) |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[idx] += u2Cnt; |
| else |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[idx] -= u2Cnt; |
| |
| /* Update PLE part */ |
| if (!nicTxResourceIsPleCtrlNeeded(prAdapter, ucTc)) |
| return; |
| |
| idx = TC_IDX_PLE_2_HIF_TXC_IDX(ucTc); |
| |
| if (idx >= HIF_TXC_IDX_NUM) |
| ASSERT(0); |
| |
| if (isIncr) |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[idx] += NIX_TX_PLE_PAGE_CNT_PER_FRAME; |
| else |
| prAdapter->prGlueInfo->rHifInfo.au4PendingTxDoneCount[idx] -= NIX_TX_PLE_PAGE_CNT_PER_FRAME; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Send HIF_CTRL command to inform FW stop send packet/event to host |
| * suspend = 1 |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (void) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| void halPreSuspendCmd(IN struct ADAPTER *prAdapter) |
| { |
| struct CMD_HIF_CTRL rCmdHifCtrl; |
| uint32_t rStatus; |
| |
| rCmdHifCtrl.ucHifType = ENUM_HIF_TYPE_SDIO; |
| rCmdHifCtrl.ucHifDirection = ENUM_HIF_TX; |
| rCmdHifCtrl.ucHifStop = 1; |
| rCmdHifCtrl.ucHifSuspend = 1; |
| |
| rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ |
| CMD_ID_HIF_CTRL, /* ucCID */ |
| TRUE, /* fgSetQuery */ |
| FALSE, /* fgNeedResp */ |
| FALSE, /* fgIsOid */ |
| NULL, /* nicEventHifCtrl */ |
| NULL, /* pfCmdTimeoutHandler */ |
| sizeof(struct CMD_HIF_CTRL), |
| (uint8_t *)&rCmdHifCtrl, /* pucInfoBuffer */ |
| NULL, /* pvSetQueryBuffer */ |
| 0 /* u4SetQueryBufferLen */ |
| ); |
| |
| if (kalIsResetting()) |
| return; |
| |
| ASSERT(rStatus == WLAN_STATUS_PENDING); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Send HIF_CTRL command to inform FW allow send packet/event to host |
| * suspend = 0 |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (void) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| void halPreResumeCmd(IN struct ADAPTER *prAdapter) |
| { |
| struct CMD_HIF_CTRL rCmdHifCtrl; |
| uint32_t rStatus; |
| |
| rCmdHifCtrl.ucHifType = ENUM_HIF_TYPE_SDIO; |
| rCmdHifCtrl.ucHifDirection = ENUM_HIF_TX; |
| rCmdHifCtrl.ucHifStop = 0; |
| rCmdHifCtrl.ucHifSuspend = 0; |
| |
| rStatus = wlanSendSetQueryCmd(prAdapter, /* prAdapter */ |
| CMD_ID_HIF_CTRL, /* ucCID */ |
| TRUE, /* fgSetQuery */ |
| FALSE, /* fgNeedResp */ |
| FALSE, /* fgIsOid */ |
| NULL, /* nicEventHifCtrl */ |
| NULL, /* pfCmdTimeoutHandler */ |
| sizeof(struct CMD_HIF_CTRL), |
| (uint8_t *)&rCmdHifCtrl, /* pucInfoBuffer */ |
| NULL, /* pvSetQueryBuffer */ |
| 0 /* u4SetQueryBufferLen */ |
| ); |
| |
| if (kalIsResetting()) |
| return; |
| |
| ASSERT(rStatus == WLAN_STATUS_PENDING); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Check if HIF state is READY for upper layer cfg80211 |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (TRUE: ready, FALSE: not ready) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| bool halIsHifStateReady(IN struct ADAPTER *prAdapter, uint8_t *pucState) |
| { |
| if (!prAdapter) |
| return FALSE; |
| |
| if (!prAdapter->prGlueInfo) |
| return FALSE; |
| |
| if (prAdapter->prGlueInfo->u4ReadyFlag == 0) |
| return FALSE; |
| |
| if (pucState) |
| *pucState = prAdapter->prGlueInfo->rHifInfo.state; |
| |
| if (prAdapter->prGlueInfo->rHifInfo.state != SDIO_STATE_READY) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Check if HIF state is during supend process |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (TRUE: suspend, reject the caller action. FALSE: not suspend) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| bool halIsHifStateSuspend(IN struct ADAPTER *prAdapter) |
| { |
| enum sdio_state state; |
| |
| if (!prAdapter) |
| return FALSE; |
| |
| if (!prAdapter->prGlueInfo) |
| return FALSE; |
| |
| state = prAdapter->prGlueInfo->rHifInfo.state; |
| |
| if (state == SDIO_STATE_SUSPEND) |
| return TRUE; |
| |
| return FALSE; |
| } |
| |
| |