| /****************************************************************************** |
| * |
| * 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. |
| * |
| *****************************************************************************/ |
| /* |
| ** Id: //Department/DaVinci/BRANCHES/MT6620_WIFI_DRIVER_V2_3/nic/nic_tx.c#2 |
| */ |
| |
| /*! \file nic_tx.c |
| * \brief Functions that provide TX operation in NIC Layer. |
| * |
| * This file provides TX functions which are responsible for both Hardware and |
| * Software Resource Management and keep their Synchronization. |
| */ |
| |
| |
| /******************************************************************************* |
| * C O M P I L E R F L A G S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * E X T E R N A L R E F E R E N C E S |
| ******************************************************************************** |
| */ |
| #include "precomp.h" |
| #include "que_mgt.h" |
| |
| #ifdef UDP_SKT_WIFI |
| #include <linux/ftrace_event.h> |
| #endif |
| |
| /******************************************************************************* |
| * C O N S T A N T S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * D A T A T Y P E S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * P U B L I C D A T A |
| ******************************************************************************** |
| */ |
| |
| PFN_TX_DATA_DONE_CB g_pfTxDataDoneCb = nicTxMsduDoneCb; |
| |
| static const TX_RESOURCE_CONTROL_T arTcResourceControl[TC_NUM] = { |
| /* dest port index, dest queue index, HIF TX queue index */ |
| /* First HW queue */ |
| {PORT_INDEX_LMAC, MAC_TXQ_AC0_INDEX, HIF_TX_AC0_INDEX}, |
| {PORT_INDEX_LMAC, MAC_TXQ_AC1_INDEX, HIF_TX_AC1_INDEX}, |
| {PORT_INDEX_LMAC, MAC_TXQ_AC2_INDEX, HIF_TX_AC2_INDEX}, |
| {PORT_INDEX_LMAC, MAC_TXQ_AC3_INDEX, HIF_TX_AC3_INDEX}, |
| {PORT_INDEX_MCU, MCU_Q1_INDEX, HIF_TX_CPU_INDEX}, |
| {PORT_INDEX_LMAC, MAC_TXQ_AC1_INDEX, HIF_TX_AC1_INDEX}, |
| |
| /* Second HW queue */ |
| #if NIC_TX_ENABLE_SECOND_HW_QUEUE |
| {PORT_INDEX_LMAC, MAC_TXQ_AC10_INDEX, HIF_TX_AC10_INDEX}, |
| {PORT_INDEX_LMAC, MAC_TXQ_AC11_INDEX, HIF_TX_AC11_INDEX}, |
| {PORT_INDEX_LMAC, MAC_TXQ_AC12_INDEX, HIF_TX_AC12_INDEX}, |
| {PORT_INDEX_LMAC, MAC_TXQ_AC13_INDEX, HIF_TX_AC13_INDEX}, |
| {PORT_INDEX_LMAC, MAC_TXQ_AC11_INDEX, HIF_TX_AC11_INDEX}, |
| #endif |
| }; |
| |
| /* Traffic settings per TC */ |
| static const TX_TC_TRAFFIC_SETTING_T arTcTrafficSettings[NET_TC_NUM] = { |
| /* Tx desc template format, Remaining Tx time, Retry count */ |
| /* For Data frame with StaRec, set Long Format to enable the following settings */ |
| {NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_AC_BE_REMAINING_TX_TIME, |
| NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT}, |
| {NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_AC_BK_REMAINING_TX_TIME, |
| NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT}, |
| {NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_AC_VI_REMAINING_TX_TIME, |
| NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT}, |
| {NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_AC_VO_REMAINING_TX_TIME, |
| NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT}, |
| |
| /* MGMT frame */ |
| {NIC_TX_DESC_LONG_FORMAT_LENGTH, NIC_TX_MGMT_REMAINING_TX_TIME, |
| NIC_TX_MGMT_DEFAULT_RETRY_COUNT_LIMIT}, |
| |
| /* non-StaRec frame (BMC, etc...) */ |
| {NIC_TX_DESC_LONG_FORMAT_LENGTH, TX_DESC_TX_TIME_NO_LIMIT, |
| NIC_TX_DATA_DEFAULT_RETRY_COUNT_LIMIT}, |
| }; |
| |
| /******************************************************************************* |
| * P R I V A T E D A T A |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * M A C R O S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * F U N C T I O N D E C L A R A T I O N S |
| ******************************************************************************** |
| */ |
| |
| /******************************************************************************* |
| * F U N C T I O N S |
| ******************************************************************************** |
| */ |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief This function will initial all variables in regard to SW TX Queues and |
| * all free lists of MSDU_INFO_T and SW_TFCB_T. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxInitialize(IN P_ADAPTER_T prAdapter) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| PUINT_8 pucMemHandle; |
| P_MSDU_INFO_T prMsduInfo; |
| UINT_32 i; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| DEBUGFUNC("nicTxInitialize"); |
| |
| ASSERT(prAdapter); |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| /* 4 <1> Initialization of Traffic Class Queue Parameters */ |
| nicTxResetResource(prAdapter); |
| |
| prTxCtrl->pucTxCoalescingBufPtr = prAdapter->pucCoalescingBufCached; |
| |
| prTxCtrl->u4WrIdx = 0; |
| |
| /* allocate MSDU_INFO_T and link it into rFreeMsduInfoList */ |
| QUEUE_INITIALIZE(&prTxCtrl->rFreeMsduInfoList); |
| |
| pucMemHandle = prTxCtrl->pucTxCached; |
| for (i = 0; i < CFG_TX_MAX_PKT_NUM; i++) { |
| prMsduInfo = (P_MSDU_INFO_T) pucMemHandle; |
| kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); |
| QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T) prMsduInfo); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); |
| |
| pucMemHandle += ALIGN_4(sizeof(MSDU_INFO_T)); |
| } |
| |
| ASSERT(prTxCtrl->rFreeMsduInfoList.u4NumElem == CFG_TX_MAX_PKT_NUM); |
| /* Check if the memory allocation consist with this initialization function */ |
| ASSERT((UINT_32) (pucMemHandle - prTxCtrl->pucTxCached) == prTxCtrl->u4TxCachedSize); |
| |
| QUEUE_INITIALIZE(&prTxCtrl->rTxMgmtTxingQueue); |
| prTxCtrl->i4TxMgmtPendingNum = 0; |
| |
| #if CFG_HIF_STATISTICS |
| prTxCtrl->u4TotalTxAccessNum = 0; |
| prTxCtrl->u4TotalTxPacketNum = 0; |
| #endif |
| |
| prTxCtrl->i4PendingFwdFrameCount = 0; |
| |
| /* Assign init value */ |
| /* Tx sequence number */ |
| prAdapter->ucTxSeqNum = 0; |
| /* PID pool */ |
| for (i = 0; i < WTBL_SIZE; i++) |
| prAdapter->aucPidPool[i] = NIC_TX_DESC_DRIVER_PID_MIN; |
| |
| prTxCtrl->u4PageSize = NIC_TX_PAGE_SIZE; |
| |
| /* enable/disable TX resource control */ |
| prTxCtrl->fgIsTxResourceCtrl = NIC_TX_RESOURCE_CTRL; |
| |
| qmInit(prAdapter, halIsTxResourceControlEn(prAdapter)); |
| |
| TX_RESET_ALL_CNTS(prTxCtrl); |
| |
| } /* end of nicTxInitialize() */ |
| |
| BOOLEAN nicTxSanityCheckResource(IN P_ADAPTER_T prAdapter) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| UINT_8 ucTC; |
| UINT_32 ucTotalMaxResource = 0; |
| UINT_32 ucTotalFreeResource = 0; |
| BOOLEAN fgError = FALSE; |
| |
| if (prAdapter->rWifiVar.ucTxDbg & BIT(0)) { |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| for (ucTC = TC0_INDEX; ucTC < TC_NUM; ucTC++) { |
| ucTotalMaxResource += prTxCtrl->rTc.au4MaxNumOfPage[ucTC]; |
| ucTotalFreeResource += prTxCtrl->rTc.au4FreePageCount[ucTC]; |
| |
| if (prTxCtrl->rTc.au4FreePageCount[ucTC] > prTxCtrl->u4TotalPageNum) { |
| DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, __LINE__); |
| fgError = TRUE; |
| } |
| |
| if (prTxCtrl->rTc.au4MaxNumOfPage[ucTC] > prTxCtrl->u4TotalPageNum) { |
| DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, __LINE__); |
| fgError = TRUE; |
| } |
| |
| if (prTxCtrl->rTc.au4FreePageCount[ucTC] > prTxCtrl->rTc.au4MaxNumOfPage[ucTC]) { |
| DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, __LINE__); |
| fgError = TRUE; |
| } |
| } |
| |
| if (ucTotalMaxResource != prTxCtrl->u4TotalPageNum) { |
| DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, __LINE__); |
| fgError = TRUE; |
| } |
| |
| if (ucTotalMaxResource < ucTotalFreeResource) { |
| DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, __LINE__); |
| fgError = TRUE; |
| } |
| |
| if (ucTotalFreeResource > prTxCtrl->u4TotalPageNum) { |
| DBGLOG(TX, ERROR, "%s:%u\n error\n", __func__, __LINE__); |
| fgError = TRUE; |
| } |
| |
| if (fgError) { |
| DBGLOG(TX, ERROR, "Total resource[%u]\n", prTxCtrl->u4TotalPageNum); |
| qmDumpQueueStatus(prAdapter, NULL, 0); |
| } |
| } |
| |
| return !fgError; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Driver maintain a variable that is synchronous with the usage of individual |
| * TC Buffer Count. This function will check if has enough TC Buffer for incoming |
| * packet and then update the value after promise to provide the resources. |
| * |
| * \param[in] prAdapter Pointer to the Adapter structure. |
| * \param[in] ucTC Specify the resource of TC |
| * |
| * \retval WLAN_STATUS_SUCCESS Resource is available and been assigned. |
| * \retval WLAN_STATUS_RESOURCES Resource is not available. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxAcquireResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC, IN UINT_32 u4PageCount, |
| IN BOOLEAN fgReqLock) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| P_TX_TCQ_STATUS_T prTc; |
| WLAN_STATUS u4Status = WLAN_STATUS_RESOURCES; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| /* enable/disable TX resource control */ |
| if (!prAdapter->rTxCtrl.fgIsTxResourceCtrl) |
| return WLAN_STATUS_SUCCESS; |
| |
| ASSERT(prAdapter); |
| prTxCtrl = &prAdapter->rTxCtrl; |
| prTc = &prTxCtrl->rTc; |
| |
| if (fgReqLock) |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| #if 1 |
| if (prTc->au4FreePageCount[ucTC] >= u4PageCount) { |
| prTc->au4FreePageCount[ucTC] -= u4PageCount; |
| prTc->au4FreeBufferCount[ucTC] = (prTc->au4FreePageCount[ucTC] / NIC_TX_MAX_PAGE_PER_FRAME); |
| |
| DBGLOG(TX, LOUD, "Acquire: TC%d AcquirePageCnt[%u] FreeBufferCnt[%u] FreePageCnt[%u]\n", |
| ucTC, u4PageCount, prTc->au4FreeBufferCount[ucTC], prTc->au4FreePageCount[ucTC]); |
| |
| u4Status = WLAN_STATUS_SUCCESS; |
| } |
| #else |
| if (prTxCtrl->rTc.au4FreePageCount[ucTC] > 0) { |
| |
| prTxCtrl->rTc.au4FreePageCount[ucTC] -= 1; |
| |
| u4Status = WLAN_STATUS_SUCCESS; |
| } |
| #endif |
| if (fgReqLock) |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| return u4Status; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Driver maintain a variable that is synchronous with the usage of individual |
| * TC Buffer Count. This function will do polling if FW has return the resource. |
| * Used when driver start up before enable interrupt. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param ucTC Specify the resource of TC |
| * |
| * @retval WLAN_STATUS_SUCCESS Resource is available. |
| * @retval WLAN_STATUS_FAILURE Resource is not available. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxPollingResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| WLAN_STATUS u4Status = WLAN_STATUS_FAILURE; |
| INT_32 i = NIC_TX_RESOURCE_POLLING_TIMEOUT; |
| /*UINT_32 au4WTSR[8];*/ |
| |
| ASSERT(prAdapter); |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| if (ucTC >= TC_NUM) |
| return WLAN_STATUS_FAILURE; |
| |
| if (prTxCtrl->rTc.au4FreeBufferCount[ucTC] > 0) |
| return WLAN_STATUS_SUCCESS; |
| |
| while (i-- > 0) { |
| #if 1 |
| u4Status = halTxPollingResource(prAdapter, ucTC); |
| if (u4Status == WLAN_STATUS_RESOURCES) |
| kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); |
| else |
| break; |
| #else |
| HAL_READ_TX_RELEASED_COUNT(prAdapter, au4WTSR); |
| |
| if (kalIsCardRemoved(prAdapter->prGlueInfo) == TRUE || fgIsBusAccessFailed == TRUE) { |
| u4Status = WLAN_STATUS_FAILURE; |
| break; |
| } else if (halTxReleaseResource(prAdapter, (PUINT_16) au4WTSR)) { |
| if (prTxCtrl->rTc.au4FreeBufferCount[ucTC] > 0) { |
| u4Status = WLAN_STATUS_SUCCESS; |
| break; |
| } |
| kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); |
| } else { |
| kalMsleep(NIC_TX_RESOURCE_POLLING_DELAY_MSEC); |
| } |
| #endif |
| } |
| |
| #if DBG |
| { |
| INT_32 i4Times = NIC_TX_RESOURCE_POLLING_TIMEOUT - (i + 1); |
| |
| if (i4Times) { |
| DBGLOG(TX, TRACE, "Polling MCR_WTSR delay %ld times, %ld msec\n", |
| i4Times, (i4Times * NIC_TX_RESOURCE_POLLING_DELAY_MSEC)); |
| } |
| } |
| #endif /* DBG */ |
| |
| return u4Status; |
| |
| } /* end of nicTxPollingResource() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Driver maintain a variable that is synchronous with the usage of individual |
| * TC Buffer Count. This function will release TC Buffer count according to |
| * the given TX_STATUS COUNTER after TX Done. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN nicTxReleaseResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTc, IN UINT_32 u4PageCount, |
| IN BOOLEAN fgReqLock) |
| { |
| P_TX_TCQ_STATUS_T prTcqStatus; |
| BOOLEAN bStatus = FALSE; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| /* enable/disable TX resource control */ |
| if (!prAdapter->rTxCtrl.fgIsTxResourceCtrl) |
| return TRUE; |
| |
| ASSERT(prAdapter); |
| prTcqStatus = &prAdapter->rTxCtrl.rTc; |
| |
| /* Return free Tc page count */ |
| if (fgReqLock) |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| prTcqStatus->au4FreePageCount[ucTc] += u4PageCount; |
| prTcqStatus->au4FreeBufferCount[ucTc] = (prTcqStatus->au4FreePageCount[ucTc] / NIC_TX_MAX_PAGE_PER_FRAME); |
| |
| if (fgReqLock) |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| bStatus = TRUE; |
| |
| return bStatus; |
| } /* end of nicTxReleaseResource() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Driver maintain a variable that is synchronous with the usage of individual |
| * TC Buffer Count. This function will release TC Buffer count for resource |
| * allocated but un-Tx MSDU_INFO |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxReleaseMsduResource(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) |
| { |
| P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| while (prMsduInfo) { |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); |
| |
| nicTxReleaseResource(prAdapter, prMsduInfo->ucTC, |
| nicTxGetPageCount(prMsduInfo->u2FrameLength, FALSE), FALSE); |
| |
| prMsduInfo = prNextMsduInfo; |
| }; |
| |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Reset TC Buffer Count to initialized value |
| * |
| * \param[in] prAdapter Pointer to the Adapter structure. |
| * |
| * @return WLAN_STATUS_SUCCESS |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxResetResource(IN P_ADAPTER_T prAdapter) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| UINT_8 ucIdx; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| DEBUGFUNC("nicTxResetResource"); |
| |
| ASSERT(prAdapter); |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| /* Delta page count */ |
| kalMemZero(prTxCtrl->rTc.au4TxDonePageCount, sizeof(prTxCtrl->rTc.au4TxDonePageCount)); |
| kalMemZero(prTxCtrl->rTc.au4PreUsedPageCount, sizeof(prTxCtrl->rTc.au4PreUsedPageCount)); |
| |
| prTxCtrl->rTc.ucNextTcIdx = TC0_INDEX; |
| prTxCtrl->rTc.u4AvaliablePageCount = 0; |
| |
| DBGLOG(TX, TRACE, "Default TCQ free resource [%u %u %u %u %u %u]\n", |
| prAdapter->rWifiVar.au4TcPageCount[TC0_INDEX], |
| prAdapter->rWifiVar.au4TcPageCount[TC1_INDEX], |
| prAdapter->rWifiVar.au4TcPageCount[TC2_INDEX], |
| prAdapter->rWifiVar.au4TcPageCount[TC3_INDEX], |
| prAdapter->rWifiVar.au4TcPageCount[TC4_INDEX], prAdapter->rWifiVar.au4TcPageCount[TC5_INDEX]); |
| |
| prAdapter->rTxCtrl.u4TotalPageNum = 0; |
| prAdapter->rTxCtrl.u4TotalTxRsvPageNum = 0; |
| |
| for (ucIdx = TC0_INDEX; ucIdx < TC_NUM; ucIdx++) { |
| /* Page Count */ |
| prTxCtrl->rTc.au4MaxNumOfPage[ucIdx] = prAdapter->rWifiVar.au4TcPageCount[ucIdx]; |
| prTxCtrl->rTc.au4FreePageCount[ucIdx] = prAdapter->rWifiVar.au4TcPageCount[ucIdx]; |
| |
| DBGLOG(TX, TRACE, "Set TC%u Default[%u] Max[%u] Free[%u]\n", |
| ucIdx, |
| prAdapter->rWifiVar.au4TcPageCount[ucIdx], |
| prTxCtrl->rTc.au4MaxNumOfPage[ucIdx], prTxCtrl->rTc.au4FreePageCount[ucIdx]); |
| |
| /* Buffer count */ |
| prTxCtrl->rTc.au4MaxNumOfBuffer[ucIdx] = |
| (prTxCtrl->rTc.au4MaxNumOfPage[ucIdx] / NIC_TX_MAX_PAGE_PER_FRAME); |
| prTxCtrl->rTc.au4FreeBufferCount[ucIdx] = |
| (prTxCtrl->rTc.au4FreePageCount[ucIdx] / NIC_TX_MAX_PAGE_PER_FRAME); |
| |
| DBGLOG(TX, TRACE, "Set TC%u Default[%u] Buffer Max[%u] Free[%u]\n", |
| ucIdx, |
| prAdapter->rWifiVar.au4TcPageCount[ucIdx], |
| prTxCtrl->rTc.au4MaxNumOfBuffer[ucIdx], prTxCtrl->rTc.au4FreeBufferCount[ucIdx]); |
| |
| prAdapter->rTxCtrl.u4TotalPageNum += prTxCtrl->rTc.au4MaxNumOfPage[ucIdx]; |
| } |
| |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| DBGLOG(TX, TRACE, "Reset TCQ free resource to Page:Buf [%u:%u %u:%u %u:%u %u:%u %u:%u %u:%u ]\n", |
| prTxCtrl->rTc.au4FreePageCount[TC0_INDEX], |
| prTxCtrl->rTc.au4FreeBufferCount[TC0_INDEX], |
| prTxCtrl->rTc.au4FreePageCount[TC1_INDEX], |
| prTxCtrl->rTc.au4FreeBufferCount[TC1_INDEX], |
| prTxCtrl->rTc.au4FreePageCount[TC2_INDEX], |
| prTxCtrl->rTc.au4FreeBufferCount[TC2_INDEX], |
| prTxCtrl->rTc.au4FreePageCount[TC3_INDEX], |
| prTxCtrl->rTc.au4FreeBufferCount[TC3_INDEX], |
| prTxCtrl->rTc.au4FreePageCount[TC4_INDEX], |
| prTxCtrl->rTc.au4FreeBufferCount[TC4_INDEX], |
| prTxCtrl->rTc.au4FreePageCount[TC5_INDEX], prTxCtrl->rTc.au4FreeBufferCount[TC5_INDEX]); |
| |
| DBGLOG(TX, TRACE, "Reset TCQ MAX resource to Page:Buf [%u:%u %u:%u %u:%u %u:%u %u:%u %u:%u]\n", |
| prTxCtrl->rTc.au4MaxNumOfPage[TC0_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfBuffer[TC0_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfPage[TC1_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfBuffer[TC1_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfPage[TC2_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfBuffer[TC2_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfPage[TC3_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfBuffer[TC3_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfPage[TC4_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfBuffer[TC4_INDEX], |
| prTxCtrl->rTc.au4MaxNumOfPage[TC5_INDEX], prTxCtrl->rTc.au4MaxNumOfBuffer[TC5_INDEX]); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| |
| #if QM_FAST_TC_RESOURCE_CTRL |
| UINT_32 |
| nicTxGetAdjustableResourceCnt(IN P_ADAPTER_T prAdapter) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| UINT_8 ucIdx; |
| UINT_32 u4TotAdjCnt = 0; |
| UINT_32 u4AdjCnt; |
| P_QUE_MGT_T prQm = NULL; |
| |
| prQm = &prAdapter->rQM; |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| for (ucIdx = TC0_INDEX; ucIdx < TC_NUM; ucIdx++) { |
| if (ucIdx == TC4_INDEX) |
| continue; |
| |
| if (prTxCtrl->rTc.au4FreeBufferCount[ucIdx] > prQm->au4MinReservedTcResource[ucIdx]) |
| u4AdjCnt = prTxCtrl->rTc.au4FreeBufferCount[ucIdx] - prQm->au4MinReservedTcResource[ucIdx]; |
| else |
| u4AdjCnt = 0; |
| |
| u4TotAdjCnt += u4AdjCnt; |
| } |
| |
| return u4TotAdjCnt; |
| } |
| #endif |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Driver maintain a variable that is synchronous with the usage of individual |
| * TC Buffer Count. This function will return the value for other component |
| * which needs this information for making decisions |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param ucTC Specify the resource of TC |
| * |
| * @retval UINT_8 The number of corresponding TC number |
| */ |
| /*----------------------------------------------------------------------------*/ |
| UINT_16 nicTxGetResource(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTC) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| |
| ASSERT(prAdapter); |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| ASSERT(prTxCtrl); |
| |
| if (ucTC >= TC_NUM) |
| return 0; |
| else |
| return prTxCtrl->rTc.au4FreePageCount[ucTC]; |
| } |
| |
| UINT_8 nicTxGetFrameResourceType(IN UINT_8 eFrameType, IN P_MSDU_INFO_T prMsduInfo) |
| { |
| UINT_8 ucTC; |
| |
| switch (eFrameType) { |
| case FRAME_TYPE_802_1X: |
| ucTC = TC4_INDEX; |
| break; |
| |
| case FRAME_TYPE_MMPDU: |
| if (prMsduInfo) |
| ucTC = prMsduInfo->ucTC; |
| else |
| ucTC = TC4_INDEX; |
| break; |
| |
| default: |
| DBGLOG(INIT, WARN, "Undefined Frame Type(%u)\n", eFrameType); |
| ucTC = TC4_INDEX; |
| break; |
| } |
| |
| return ucTC; |
| } |
| |
| UINT_8 nicTxGetCmdResourceType(IN P_CMD_INFO_T prCmdInfo) |
| { |
| UINT_8 ucTC; |
| |
| switch (prCmdInfo->eCmdType) { |
| case COMMAND_TYPE_NETWORK_IOCTL: |
| case COMMAND_TYPE_GENERAL_IOCTL: |
| ucTC = TC4_INDEX; |
| break; |
| |
| case COMMAND_TYPE_SECURITY_FRAME: |
| ucTC = nicTxGetFrameResourceType(FRAME_TYPE_802_1X, NULL); |
| break; |
| |
| case COMMAND_TYPE_MANAGEMENT_FRAME: |
| ucTC = nicTxGetFrameResourceType(FRAME_TYPE_MMPDU, prCmdInfo->prMsduInfo); |
| break; |
| |
| default: |
| DBGLOG(INIT, WARN, "Undefined CMD Type(%u)\n", prCmdInfo->eCmdType); |
| ucTC = TC4_INDEX; |
| break; |
| } |
| |
| return ucTC; |
| } |
| |
| UINT_8 nicTxGetTxQByTc(IN P_ADAPTER_T prAdapter, IN UINT_8 ucTc) |
| { |
| return arTcResourceControl[ucTc].ucHifTxQIndex; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief In this function, we'll aggregate frame(PACKET_INFO_T) |
| * corresponding to HIF TX port |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prMsduInfoListHead a link list of P_MSDU_INFO_T |
| * |
| * @retval WLAN_STATUS_SUCCESS Bus access ok. |
| * @retval WLAN_STATUS_FAILURE Bus access fail. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxMsduInfoList(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) |
| { |
| P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; |
| QUE_T qDataPort0, qDataPort1; |
| P_QUE_T prDataPort0, prDataPort1; |
| WLAN_STATUS status; |
| |
| ASSERT(prAdapter); |
| ASSERT(prMsduInfoListHead); |
| |
| prMsduInfo = prMsduInfoListHead; |
| |
| prDataPort0 = &qDataPort0; |
| prDataPort1 = &qDataPort1; |
| |
| QUEUE_INITIALIZE(prDataPort0); |
| QUEUE_INITIALIZE(prDataPort1); |
| |
| /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ |
| while (prMsduInfo) { |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); |
| |
| switch (prMsduInfo->ucTC) { |
| case TC0_INDEX: |
| case TC1_INDEX: |
| case TC2_INDEX: |
| case TC3_INDEX: |
| case TC5_INDEX: /* Broadcast/multicast data packets */ |
| QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; |
| QUEUE_INSERT_TAIL(prDataPort0, (P_QUE_ENTRY_T) prMsduInfo); |
| status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, |
| nicTxGetPageCount(prMsduInfo->u2FrameLength, FALSE), TRUE); |
| ASSERT(status == WLAN_STATUS_SUCCESS); |
| |
| break; |
| |
| case TC4_INDEX: /* Management packets */ |
| QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; |
| QUEUE_INSERT_TAIL(prDataPort1, (P_QUE_ENTRY_T) prMsduInfo); |
| |
| status = nicTxAcquireResource(prAdapter, prMsduInfo->ucTC, |
| nicTxGetPageCount(prMsduInfo->u2FrameLength, FALSE), TRUE); |
| ASSERT(status == WLAN_STATUS_SUCCESS); |
| |
| break; |
| |
| default: |
| ASSERT(0); |
| break; |
| } |
| |
| prMsduInfo = prNextMsduInfo; |
| } |
| |
| if (prDataPort0->u4NumElem > 0) |
| nicTxMsduQueue(prAdapter, 0, prDataPort0); |
| |
| if (prDataPort1->u4NumElem > 0) |
| nicTxMsduQueue(prAdapter, 1, prDataPort1); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| #if CFG_SUPPORT_MULTITHREAD |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief In this function, we'll aggregate frame(PACKET_INFO_T) |
| * corresponding to HIF TX port |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prMsduInfoListHead a link list of P_MSDU_INFO_T |
| * |
| * @retval WLAN_STATUS_SUCCESS Bus access ok. |
| * @retval WLAN_STATUS_FAILURE Bus access fail. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxMsduInfoListMthread(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) |
| { |
| #if CFG_FIX_2_TX_PORT |
| P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; |
| QUE_T qDataPort0, qDataPort1; |
| P_QUE_T prDataPort0, prDataPort1; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| ASSERT(prMsduInfoListHead); |
| |
| prMsduInfo = prMsduInfoListHead; |
| |
| prDataPort0 = &qDataPort0; |
| prDataPort1 = &qDataPort1; |
| |
| QUEUE_INITIALIZE(prDataPort0); |
| QUEUE_INITIALIZE(prDataPort1); |
| |
| /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ |
| while (prMsduInfo) { |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); |
| |
| switch (prMsduInfo->ucTC) { |
| case TC0_INDEX: |
| case TC1_INDEX: |
| case TC2_INDEX: |
| case TC3_INDEX: |
| case TC5_INDEX: /* Broadcast/multicast data packets */ |
| QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; |
| QUEUE_INSERT_TAIL(prDataPort0, (P_QUE_ENTRY_T) prMsduInfo); |
| break; |
| |
| case TC4_INDEX: /* Management packets */ |
| QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; |
| QUEUE_INSERT_TAIL(prDataPort1, (P_QUE_ENTRY_T) prMsduInfo); |
| break; |
| |
| default: |
| ASSERT(0); |
| break; |
| } |
| |
| nicTxFillDataDesc(prAdapter, prMsduInfo); |
| |
| prMsduInfo = prNextMsduInfo; |
| } |
| |
| if (prDataPort0->u4NumElem > 0 || prDataPort1->u4NumElem > 0) { |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| QUEUE_CONCATENATE_QUEUES((&(prAdapter->rTxP0Queue)), (prDataPort0)); |
| QUEUE_CONCATENATE_QUEUES((&(prAdapter->rTxP1Queue)), (prDataPort1)); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| |
| kalSetTxEvent2Hif(prAdapter->prGlueInfo); |
| } |
| #else |
| |
| P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; |
| QUE_T qDataPort[TX_PORT_NUM]; |
| P_QUE_T prDataPort[TX_PORT_NUM]; |
| INT_32 i; |
| BOOLEAN fgSetTx2Hif = FALSE; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| ASSERT(prMsduInfoListHead); |
| |
| prMsduInfo = prMsduInfoListHead; |
| |
| for (i = 0; i < TX_PORT_NUM; i++) { |
| prDataPort[i] = &qDataPort[i]; |
| QUEUE_INITIALIZE(prDataPort[i]); |
| } |
| |
| /* Separate MSDU_INFO_T lists into 2 categories: for Port#0 & Port#1 */ |
| while (prMsduInfo) { |
| |
| fgSetTx2Hif = TRUE; |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); |
| |
| if (prMsduInfo->ucWmmQueSet != DBDC_5G_WMM_INDEX) { |
| QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; |
| QUEUE_INSERT_TAIL(prDataPort[TX_2G_WMM_PORT_NUM], (P_QUE_ENTRY_T) prMsduInfo); |
| } else { |
| if (prMsduInfo->ucTC >= 0 && |
| prMsduInfo->ucTC < TC_NUM) { |
| QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; |
| QUEUE_INSERT_TAIL(prDataPort[prMsduInfo->ucTC], (P_QUE_ENTRY_T) prMsduInfo); |
| } else |
| ASSERT(0); |
| } |
| nicTxFillDataDesc(prAdapter, prMsduInfo); |
| |
| prMsduInfo = prNextMsduInfo; |
| } |
| |
| if (fgSetTx2Hif) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| for (i = 0; i < TX_PORT_NUM; i++) |
| QUEUE_CONCATENATE_QUEUES((&(prAdapter->rTxPQueue[i])), (prDataPort[i])); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| kalSetTxEvent2Hif(prAdapter->prGlueInfo); |
| } |
| |
| #endif |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief In this function, we'll write frame(PACKET_INFO_T) into HIF when apply multithread. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @retval WLAN_STATUS_SUCCESS Bus access ok. |
| * @retval WLAN_STATUS_FAILURE Bus access fail. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| UINT_32 nicTxMsduQueueMthread(IN P_ADAPTER_T prAdapter) |
| { |
| #if CFG_FIX_2_TX_PORT |
| QUE_T qDataPort0, qDataPort1; |
| P_QUE_T prDataPort0, prDataPort1; |
| UINT_32 u4TxLoopCount; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| prDataPort0 = &qDataPort0; |
| prDataPort1 = &qDataPort1; |
| |
| QUEUE_INITIALIZE(prDataPort0); |
| QUEUE_INITIALIZE(prDataPort1); |
| |
| u4TxLoopCount = prAdapter->rWifiVar.u4HifTxloopCount; |
| |
| while (u4TxLoopCount--) { |
| while (QUEUE_IS_NOT_EMPTY(&(prAdapter->rTxP0Queue))) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| QUEUE_MOVE_ALL(prDataPort0, &(prAdapter->rTxP0Queue)); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| |
| nicTxMsduQueue(prAdapter, 0, prDataPort0); |
| |
| if (QUEUE_IS_NOT_EMPTY(prDataPort0)) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| QUEUE_CONCATENATE_QUEUES_HEAD(&(prAdapter->rTxP0Queue), prDataPort0); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| |
| break; |
| } |
| } |
| |
| while (QUEUE_IS_NOT_EMPTY(&(prAdapter->rTxP1Queue))) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| QUEUE_MOVE_ALL(prDataPort1, &(prAdapter->rTxP1Queue)); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| |
| nicTxMsduQueue(prAdapter, 1, prDataPort1); |
| |
| if (QUEUE_IS_NOT_EMPTY(prDataPort1)) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| QUEUE_CONCATENATE_QUEUES_HEAD(&(prAdapter->rTxP1Queue), prDataPort1); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| |
| break; |
| } |
| } |
| } |
| #else |
| |
| UINT_32 u4TxLoopCount; |
| QUE_T qDataPort[TX_PORT_NUM]; |
| P_QUE_T prDataPort[TX_PORT_NUM]; |
| INT_32 i; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| for (i = 0; i < TX_PORT_NUM; i++) { |
| prDataPort[i] = &qDataPort[i]; |
| QUEUE_INITIALIZE(prDataPort[i]); |
| } |
| |
| u4TxLoopCount = prAdapter->rWifiVar.u4HifTxloopCount; |
| |
| while (u4TxLoopCount--) { |
| for (i = TC_NUM; i >= 0; i--) { |
| while (QUEUE_IS_NOT_EMPTY(&(prAdapter->rTxPQueue[i]))) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| QUEUE_MOVE_ALL(prDataPort[i], &(prAdapter->rTxPQueue[i])); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| |
| nicTxMsduQueue(prAdapter, 0, prDataPort[i]); |
| |
| if (QUEUE_IS_NOT_EMPTY(prDataPort[i])) { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| QUEUE_CONCATENATE_QUEUES_HEAD(&(prAdapter->rTxPQueue[i]), prDataPort[i]); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_PORT_QUE); |
| |
| break; |
| } |
| } |
| } |
| } |
| #endif |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| UINT_32 nicTxGetMsduPendingCnt(IN P_ADAPTER_T prAdapter) |
| { |
| #if CFG_FIX_2_TX_PORT |
| return prAdapter->rTxP0Queue.u4NumElem + prAdapter->rTxP1Queue.u4NumElem; |
| #else |
| INT_32 i; |
| UINT_32 retValue = 0; |
| |
| for (i = 0; i < TX_PORT_NUM; i++) |
| retValue += prAdapter->rTxPQueue[i].u4NumElem; |
| return retValue; |
| #endif |
| } |
| |
| #endif |
| |
| VOID nicTxComposeDescAppend(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, |
| OUT PUINT_8 prTxDescBuffer) |
| { |
| P_HW_MAC_TX_DESC_APPEND_T prHwTxDescAppend; |
| |
| /* Fill TxD append */ |
| prHwTxDescAppend = (P_HW_MAC_TX_DESC_APPEND_T)prTxDescBuffer; |
| kalMemZero(prHwTxDescAppend, HW_MAC_TX_DESC_APPEND_T_LENGTH); |
| prHwTxDescAppend->u2PktFlags = HIT_PKT_FLAGS_CT_WITH_TXD; |
| prHwTxDescAppend->ucBssIndex = prMsduInfo->ucBssIndex; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief In this function, we'll compose the Tx descriptor of the MSDU. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prMsduInfo Pointer to the Msdu info |
| * @param prTxDesc Pointer to the Tx descriptor buffer |
| * |
| * @retval VOID |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID |
| nicTxComposeDesc(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, |
| IN UINT_32 u4TxDescLength, IN BOOLEAN fgIsTemplate, OUT PUINT_8 prTxDescBuffer) |
| { |
| P_HW_MAC_TX_DESC_T prTxDesc; |
| P_STA_RECORD_T prStaRec; |
| P_BSS_INFO_T prBssInfo; |
| UINT_8 ucEtherTypeOffsetInWord; |
| UINT_32 u4TxDescAndPaddingLength; |
| UINT_8 ucTarPort, ucTarQueue; |
| #if ((CFG_SISO_SW_DEVELOP == 1) || (CFG_SUPPORT_ANT_SELECT == 1)) |
| enum ENUM_WF_PATH_FAVOR_T eWfPathFavor; |
| #endif |
| |
| prTxDesc = (P_HW_MAC_TX_DESC_T) prTxDescBuffer; |
| prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); |
| prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); |
| |
| u4TxDescAndPaddingLength = u4TxDescLength + NIC_TX_DESC_PADDING_LENGTH; |
| |
| kalMemZero(prTxDesc, u4TxDescAndPaddingLength); |
| |
| /* Move to nicTxFillDesc */ |
| /* Tx byte count */ |
| /* HAL_MAC_TX_DESC_SET_TX_BYTE_COUNT(prTxDesc, ucTxDescAndPaddingLength + prMsduInfo->u2FrameLength); */ |
| |
| /* Ether-type offset */ |
| if (prMsduInfo->fgIs802_11) { |
| ucEtherTypeOffsetInWord = |
| (NIC_TX_PSE_HEADER_LENGTH + prMsduInfo->ucMacHeaderLength + prMsduInfo->ucLlcLength) >> 1; |
| } else { |
| ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + NIC_TX_PSE_HEADER_LENGTH) >> 1; |
| } |
| HAL_MAC_TX_DESC_SET_ETHER_TYPE_OFFSET(prTxDesc, ucEtherTypeOffsetInWord); |
| |
| /* Port index / queue index */ |
| ucTarPort = arTcResourceControl[prMsduInfo->ucTC].ucDestPortIndex; |
| HAL_MAC_TX_DESC_SET_PORT_INDEX(prTxDesc, ucTarPort); |
| |
| ucTarQueue = arTcResourceControl[prMsduInfo->ucTC].ucDestQueueIndex; |
| if (ucTarPort == PORT_INDEX_LMAC) |
| ucTarQueue += (prBssInfo->ucWmmQueSet * WMM_AC_INDEX_NUM); |
| |
| HAL_MAC_TX_DESC_SET_QUEUE_INDEX(prTxDesc, ucTarQueue); |
| |
| /* BMC packet */ |
| if (prMsduInfo->ucStaRecIndex == STA_REC_INDEX_BMCAST) { |
| HAL_MAC_TX_DESC_SET_BMC(prTxDesc); |
| |
| /* Must set No ACK to mask retry bit in FC */ |
| HAL_MAC_TX_DESC_SET_NO_ACK(prTxDesc); |
| } |
| /* WLAN index */ |
| prMsduInfo->ucWlanIndex = nicTxGetWlanIdx(prAdapter, prMsduInfo->ucBssIndex, prMsduInfo->ucStaRecIndex); |
| |
| #if 0 /* DBG */ |
| DBGLOG(RSN, INFO, |
| "Tx WlanIndex = %d eAuthMode = %d\n", prMsduInfo->ucWlanIndex, |
| prAdapter->rWifiVar.rConnSettings.eAuthMode); |
| #endif |
| HAL_MAC_TX_DESC_SET_WLAN_INDEX(prTxDesc, prMsduInfo->ucWlanIndex); |
| |
| /* Header format */ |
| if (prMsduInfo->fgIs802_11) { |
| HAL_MAC_TX_DESC_SET_HEADER_FORMAT(prTxDesc, HEADER_FORMAT_802_11_NORMAL_MODE); |
| HAL_MAC_TX_DESC_SET_802_11_HEADER_LENGTH(prTxDesc, (prMsduInfo->ucMacHeaderLength >> 1)); |
| } else { |
| HAL_MAC_TX_DESC_SET_HEADER_FORMAT(prTxDesc, HEADER_FORMAT_NON_802_11); |
| HAL_MAC_TX_DESC_SET_ETHERNET_II(prTxDesc); |
| } |
| |
| /* Header Padding */ |
| HAL_MAC_TX_DESC_SET_HEADER_PADDING(prTxDesc, NIC_TX_DESC_HEADER_PADDING_LENGTH); |
| |
| /* TID */ |
| HAL_MAC_TX_DESC_SET_TID(prTxDesc, prMsduInfo->ucUserPriority); |
| |
| /* Protection */ |
| if (secIsProtectedFrame(prAdapter, prMsduInfo, prStaRec)) { |
| /* Update Packet option, PF bit will be set in nicTxFillDescByPktOption() */ |
| if ((prStaRec && prStaRec->fgTransmitKeyExist) || fgIsTemplate) { |
| nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE); |
| |
| if (prMsduInfo->fgIs802_1x_NonProtected) { |
| nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, FALSE); |
| DBGLOG(RSN, LOUD, "Pairwise EAPoL not protect!\n"); |
| } |
| } else if (prMsduInfo->ucStaRecIndex == STA_REC_INDEX_BMCAST) {/* BMC packet */ |
| nicTxConfigPktOption(prMsduInfo, MSDU_OPT_PROTECTED_FRAME, TRUE); |
| DBGLOG(RSN, LOUD, "Protect BMC frame!\n"); |
| } |
| } |
| #if (UNIFIED_MAC_TX_FORMAT == 1) |
| /* Packet Format */ |
| if (prMsduInfo->eSrc == TX_PACKET_MGMT) |
| HAL_MAC_TX_DESC_SET_PKT_FORMAT(prTxDesc, TXD_PKT_FORMAT_COMMAND); |
| |
| #endif |
| |
| /* Own MAC */ |
| HAL_MAC_TX_DESC_SET_OWN_MAC_INDEX(prTxDesc, prBssInfo->ucOwnMacIndex); |
| |
| if (u4TxDescLength == NIC_TX_DESC_SHORT_FORMAT_LENGTH) { |
| HAL_MAC_TX_DESC_SET_SHORT_FORMAT(prTxDesc); |
| |
| /* Update Packet option */ |
| nicTxFillDescByPktOption(prMsduInfo, prTxDesc); |
| |
| /* Short format, Skip DW 2~6 */ |
| return; |
| } |
| HAL_MAC_TX_DESC_SET_LONG_FORMAT(prTxDesc); |
| |
| /* Update Packet option */ |
| nicTxFillDescByPktOption(prMsduInfo, prTxDesc); |
| |
| nicTxFillDescByPktControl(prMsduInfo, prTxDesc); |
| |
| /* Type */ |
| if (prMsduInfo->fgIs802_11) { |
| P_WLAN_MAC_HEADER_T prWlanHeader = |
| (P_WLAN_MAC_HEADER_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); |
| |
| HAL_MAC_TX_DESC_SET_TYPE(prTxDesc, (prWlanHeader->u2FrameCtrl & MASK_FC_TYPE) >> 2); |
| HAL_MAC_TX_DESC_SET_SUB_TYPE(prTxDesc, |
| (prWlanHeader->u2FrameCtrl & MASK_FC_SUBTYPE) >> OFFSET_OF_FC_SUBTYPE); |
| } |
| /* PID */ |
| if (prMsduInfo->pfTxDoneHandler) { |
| prMsduInfo->ucPID = nicTxAssignPID(prAdapter, prMsduInfo->ucWlanIndex); |
| HAL_MAC_TX_DESC_SET_PID(prTxDesc, prMsduInfo->ucPID); |
| HAL_MAC_TX_DESC_SET_TXS_TO_MCU(prTxDesc); |
| } else if (prAdapter->rWifiVar.ucDataTxDone == 2) { |
| /* Log mode: only TxS to FW, no event to driver */ |
| HAL_MAC_TX_DESC_SET_PID(prTxDesc, NIC_TX_DESC_PID_RESERVED); |
| HAL_MAC_TX_DESC_SET_TXS_TO_MCU(prTxDesc); |
| } |
| |
| /* Remaining TX time */ |
| if (!(prMsduInfo->u4Option & MSDU_OPT_MANUAL_LIFE_TIME)) |
| prMsduInfo->u4RemainingLifetime = arTcTrafficSettings[prMsduInfo->ucTC].u4RemainingTxTime; |
| HAL_MAC_TX_DESC_SET_REMAINING_LIFE_TIME_IN_MS(prTxDesc, prMsduInfo->u4RemainingLifetime); |
| |
| /* Tx count limit */ |
| if (!(prMsduInfo->u4Option & MSDU_OPT_MANUAL_RETRY_LIMIT)) { |
| /* Note: BMC packet retry limit is set to unlimited */ |
| prMsduInfo->ucRetryLimit = arTcTrafficSettings[prMsduInfo->ucTC].ucTxCountLimit; |
| } |
| HAL_MAC_TX_DESC_SET_REMAINING_TX_COUNT(prTxDesc, prMsduInfo->ucRetryLimit); |
| |
| /* Power Offset */ |
| HAL_MAC_TX_DESC_SET_POWER_OFFSET(prTxDesc, prMsduInfo->cPowerOffset); |
| |
| /* Fix rate */ |
| switch (prMsduInfo->ucRateMode) { |
| case MSDU_RATE_MODE_MANUAL_DESC: |
| HAL_MAC_TX_DESC_SET_DW(prTxDesc, 6, 1, &prMsduInfo->u4FixedRateOption); |
| #if ((CFG_SISO_SW_DEVELOP == 1) || (CFG_SUPPORT_ANT_SELECT == 1)) |
| /* Update spatial extension index setting */ |
| eWfPathFavor = wlanGetAntPathType(prAdapter, ENUM_WF_NON_FAVOR); |
| HAL_MAC_TX_DESC_SET_SPE_IDX(prTxDesc, wlanGetSpeIdx(prAdapter, prBssInfo->ucBssIndex, eWfPathFavor)); |
| #endif |
| HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_DESC(prTxDesc); |
| HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); |
| break; |
| |
| case MSDU_RATE_MODE_MANUAL_CR: |
| |
| #if ((CFG_SISO_SW_DEVELOP == 1) || (CFG_SUPPORT_ANT_SELECT == 1)) |
| /* Update spatial extension index setting */ |
| eWfPathFavor = wlanGetAntPathType(prAdapter, ENUM_WF_NON_FAVOR); |
| HAL_MAC_TX_DESC_SET_SPE_IDX(prTxDesc, wlanGetSpeIdx(prAdapter, prBssInfo->ucBssIndex, eWfPathFavor)); |
| #endif |
| HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_CR(prTxDesc); |
| HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); |
| break; |
| |
| case MSDU_RATE_MODE_AUTO: |
| default: |
| break; |
| } |
| |
| } |
| |
| VOID |
| nicTxComposeSecurityFrameDesc(IN P_ADAPTER_T prAdapter, |
| IN P_CMD_INFO_T prCmdInfo, OUT PUINT_8 prTxDescBuffer, OUT PUINT_8 pucTxDescLength) |
| { |
| P_HW_MAC_TX_DESC_T prTxDesc = (P_HW_MAC_TX_DESC_T) prTxDescBuffer; |
| UINT_8 ucTxDescAndPaddingLength = NIC_TX_DESC_LONG_FORMAT_LENGTH + NIC_TX_DESC_PADDING_LENGTH; |
| /* P_STA_RECORD_T prStaRec = cnmGetStaRecByIndex(prAdapter, prCmdInfo->ucStaRecIndex); */ |
| P_BSS_INFO_T prBssInfo; |
| UINT_8 ucTid = 0; |
| UINT_8 ucTempTC = TC4_INDEX; |
| P_NATIVE_PACKET prNativePacket; |
| UINT_8 ucEtherTypeOffsetInWord; |
| P_MSDU_INFO_T prMsduInfo; |
| |
| prMsduInfo = prCmdInfo->prMsduInfo; |
| prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); |
| prNativePacket = prMsduInfo->prPacket; |
| |
| ASSERT(prNativePacket); |
| |
| kalMemZero(prTxDesc, ucTxDescAndPaddingLength); |
| |
| /* WLAN index */ |
| prMsduInfo->ucWlanIndex = nicTxGetWlanIdx(prAdapter, prMsduInfo->ucBssIndex, prMsduInfo->ucStaRecIndex); |
| |
| /* UC to a connected peer */ |
| HAL_MAC_TX_DESC_SET_WLAN_INDEX(prTxDesc, prMsduInfo->ucWlanIndex); |
| /* Redirect Security frame to TID0 */ |
| /* ucTempTC = arNetwork2TcResource[prStaRec->ucBssIndex][aucTid2ACI[ucTid]]; */ |
| |
| /* Tx byte count */ |
| HAL_MAC_TX_DESC_SET_TX_BYTE_COUNT(prTxDesc, ucTxDescAndPaddingLength + prCmdInfo->u2InfoBufLen); |
| |
| /* Ether-type offset */ |
| ucEtherTypeOffsetInWord = ((ETHER_HEADER_LEN - ETHER_TYPE_LEN) + NIC_TX_PSE_HEADER_LENGTH) >> 1; |
| HAL_MAC_TX_DESC_SET_ETHER_TYPE_OFFSET(prTxDesc, ucEtherTypeOffsetInWord); |
| |
| /* Port index / queue index */ |
| HAL_MAC_TX_DESC_SET_PORT_INDEX(prTxDesc, arTcResourceControl[ucTempTC].ucDestPortIndex); |
| HAL_MAC_TX_DESC_SET_QUEUE_INDEX(prTxDesc, arTcResourceControl[ucTempTC].ucDestQueueIndex); |
| |
| /* Header format */ |
| HAL_MAC_TX_DESC_SET_HEADER_FORMAT(prTxDesc, HEADER_FORMAT_NON_802_11); |
| |
| /* Long Format */ |
| HAL_MAC_TX_DESC_SET_LONG_FORMAT(prTxDesc); |
| |
| /* Update Packet option */ |
| nicTxFillDescByPktOption(prMsduInfo, prTxDesc); |
| |
| if (!GLUE_TEST_PKT_FLAG(prNativePacket, ENUM_PKT_802_3)) { |
| /* Set EthernetII */ |
| HAL_MAC_TX_DESC_SET_ETHERNET_II(prTxDesc); |
| } |
| /* Header Padding */ |
| HAL_MAC_TX_DESC_SET_HEADER_PADDING(prTxDesc, NIC_TX_DESC_HEADER_PADDING_LENGTH); |
| |
| /* TID */ |
| HAL_MAC_TX_DESC_SET_TID(prTxDesc, ucTid); |
| |
| /* Remaining TX time */ |
| HAL_MAC_TX_DESC_SET_REMAINING_LIFE_TIME_IN_MS(prTxDesc, arTcTrafficSettings[ucTempTC].u4RemainingTxTime); |
| |
| /* Tx count limit */ |
| HAL_MAC_TX_DESC_SET_REMAINING_TX_COUNT(prTxDesc, arTcTrafficSettings[ucTempTC].ucTxCountLimit); |
| |
| /* Set lowest BSS basic rate */ |
| HAL_MAC_TX_DESC_SET_FR_RATE(prTxDesc, prBssInfo->u2HwDefaultFixedRateCode); |
| HAL_MAC_TX_DESC_SET_FIXED_RATE_MODE_TO_DESC(prTxDesc); |
| HAL_MAC_TX_DESC_SET_FIXED_RATE_ENABLE(prTxDesc); |
| |
| /* Packet Format */ |
| HAL_MAC_TX_DESC_SET_PKT_FORMAT(prTxDesc, TXD_PKT_FORMAT_COMMAND); |
| |
| /* Own MAC */ |
| HAL_MAC_TX_DESC_SET_OWN_MAC_INDEX(prTxDesc, prBssInfo->ucOwnMacIndex); |
| |
| /* PID */ |
| if (prMsduInfo->pfTxDoneHandler) { |
| prMsduInfo->ucPID = nicTxAssignPID(prAdapter, prMsduInfo->ucWlanIndex); |
| HAL_MAC_TX_DESC_SET_PID(prTxDesc, prMsduInfo->ucPID); |
| HAL_MAC_TX_DESC_SET_TXS_TO_MCU(prTxDesc); |
| } |
| |
| if (pucTxDescLength) |
| *pucTxDescLength = ucTxDescAndPaddingLength; |
| } |
| |
| BOOLEAN nicTxIsTXDTemplateAllowed(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_STA_RECORD_T prStaRec) |
| { |
| if (prMsduInfo->fgIsTXDTemplateValid) { |
| if (prMsduInfo->fgIs802_1x) |
| return FALSE; |
| |
| if (prMsduInfo->ucRateMode != MSDU_RATE_MODE_AUTO) |
| return FALSE; |
| |
| if (!prStaRec) |
| return FALSE; |
| |
| if (prMsduInfo->ucControlFlag) |
| return FALSE; |
| |
| if (prMsduInfo->pfTxDoneHandler) |
| return FALSE; |
| |
| if (prAdapter->rWifiVar.ucDataTxRateMode) |
| return FALSE; |
| |
| return TRUE; |
| } |
| return FALSE; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief In this function, we'll compose the Tx descriptor of the MSDU. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prMsduInfo Pointer to the Msdu info |
| * @param prTxDesc Pointer to the Tx descriptor buffer |
| * |
| * @retval VOID |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID |
| nicTxFillDesc(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, |
| OUT PUINT_8 prTxDescBuffer, OUT PUINT_32 pu4TxDescLength) |
| { |
| P_HW_MAC_TX_DESC_T prTxDesc = (P_HW_MAC_TX_DESC_T) prTxDescBuffer; |
| P_HW_MAC_TX_DESC_T prTxDescTemplate = NULL; |
| P_STA_RECORD_T prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); |
| UINT_32 u4TxDescLength, u4TxDescAppendLength; |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| UINT_8 ucChksumFlag = 0; |
| #endif |
| |
| /* |
| *------------------------------------------------------------------------------ |
| * Fill up common fileds |
| *------------------------------------------------------------------------------ |
| */ |
| /* Decide TxD append length */ |
| if (prMsduInfo->ucPacketType == TX_PACKET_TYPE_DATA) |
| u4TxDescAppendLength = HW_MAC_TX_DESC_APPEND_T_LENGTH; |
| else |
| u4TxDescAppendLength = 0; |
| |
| /* Get TXD from pre-allocated template */ |
| if (nicTxIsTXDTemplateAllowed(prAdapter, prMsduInfo, prStaRec)) { |
| prTxDescTemplate = prStaRec->aprTxDescTemplate[prMsduInfo->ucUserPriority]; |
| #if 1 |
| u4TxDescLength = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| #else |
| if (HAL_MAC_TX_DESC_IS_LONG_FORMAT(prTxDescTemplate)) |
| u4TxDescLength = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| else |
| u4TxDescLength = NIC_TX_DESC_SHORT_FORMAT_LENGTH; |
| #endif |
| |
| kalMemCopy(prTxDesc, prTxDescTemplate, u4TxDescLength + u4TxDescAppendLength); |
| |
| /* Overwrite fields for EOSP or More data */ |
| nicTxFillDescByPktOption(prMsduInfo, prTxDesc); |
| } |
| /* Compose TXD by Msdu info */ |
| else { |
| u4TxDescLength = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| nicTxComposeDesc(prAdapter, prMsduInfo, u4TxDescLength, FALSE, prTxDescBuffer); |
| |
| /* Compose TxD append */ |
| if (prMsduInfo->ucPacketType == TX_PACKET_TYPE_DATA) |
| nicTxComposeDescAppend(prAdapter, prMsduInfo, prTxDescBuffer + u4TxDescLength); |
| } |
| |
| /* |
| *------------------------------------------------------------------------------ |
| * Fill up remaining parts, per-packet variant fields |
| *------------------------------------------------------------------------------ |
| */ |
| /* Calculate Tx byte count */ |
| HAL_MAC_TX_DESC_SET_TX_BYTE_COUNT(prTxDesc, u4TxDescLength + u4TxDescAppendLength + prMsduInfo->u2FrameLength); |
| |
| /* Checksum offload */ |
| #if CFG_TCP_IP_CHKSUM_OFFLOAD |
| if (prAdapter->fgIsSupportCsumOffload && prMsduInfo->eSrc == TX_PACKET_OS) { |
| if (prAdapter->u4CSUMFlags & |
| (CSUM_OFFLOAD_EN_TX_TCP | CSUM_OFFLOAD_EN_TX_UDP | CSUM_OFFLOAD_EN_TX_IP)) { |
| ASSERT(prMsduInfo->prPacket); |
| kalQueryTxChksumOffloadParam(prMsduInfo->prPacket, &ucChksumFlag); |
| if ((ucChksumFlag & TX_CS_IP_GEN)) |
| HAL_MAC_TX_DESC_SET_IP_CHKSUM(prTxDesc); |
| if ((ucChksumFlag & TX_CS_TCP_UDP_GEN)) |
| HAL_MAC_TX_DESC_SET_TCP_UDP_CHKSUM(prTxDesc); |
| } |
| } |
| #endif /* CFG_TCP_IP_CHKSUM_OFFLOAD */ |
| |
| /* Set EtherType & VLAN for non 802.11 frame */ |
| if (!prMsduInfo->fgIs802_11) { |
| if (prMsduInfo->fgIs802_3) |
| HAL_MAC_TX_DESC_UNSET_ETHERNET_II(prTxDesc); |
| if (prMsduInfo->fgIsVlanExists) |
| HAL_MAC_TX_DESC_SET_VLAN(prTxDesc); |
| } |
| |
| if (pu4TxDescLength) |
| *pu4TxDescLength = u4TxDescLength; |
| } |
| |
| VOID |
| nicTxFillDataDesc(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) |
| { |
| PUINT_8 pucOutputBuf; |
| |
| pucOutputBuf = skb_push((struct sk_buff *)prMsduInfo->prPacket, NIC_TX_HEAD_ROOM); |
| |
| nicTxFillDesc(prAdapter, prMsduInfo, pucOutputBuf, NULL); |
| } |
| |
| VOID |
| nicTxCopyDesc(IN P_ADAPTER_T prAdapter, IN PUINT_8 pucTarTxDesc, IN PUINT_8 pucSrcTxDesc, OUT PUINT_8 pucTxDescLength) |
| { |
| UINT_8 ucTxDescLength; |
| |
| if (HAL_MAC_TX_DESC_IS_LONG_FORMAT((P_HW_MAC_TX_DESC_T) pucSrcTxDesc)) |
| ucTxDescLength = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| else |
| ucTxDescLength = NIC_TX_DESC_SHORT_FORMAT_LENGTH; |
| |
| kalMemCopy(pucTarTxDesc, pucSrcTxDesc, ucTxDescLength); |
| |
| if (pucTxDescLength) |
| *pucTxDescLength = ucTxDescLength; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief In this function, we'll generate Tx descriptor template for each TID. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prStaRec Pointer to the StaRec structure. |
| * |
| * @retval VOID |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxGenerateDescTemplate(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) |
| { |
| UINT_8 ucTid; |
| UINT_8 ucTc; |
| UINT_32 u4TxDescSize, u4TxDescAppendSize; |
| P_HW_MAC_TX_DESC_T prTxDesc; |
| P_MSDU_INFO_T prMsduInfo; |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| |
| ASSERT(prAdapter); |
| |
| /* Free previous template, first */ |
| /* nicTxFreeDescTemplate(prAdapter, prStaRec); */ |
| for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) |
| prStaRec->aprTxDescTemplate[ucTid] = NULL; |
| |
| prMsduInfo = cnmPktAlloc(prAdapter, 0); |
| |
| if (!prMsduInfo) |
| return WLAN_STATUS_RESOURCES; |
| |
| /* Fill up MsduInfo template */ |
| prMsduInfo->eSrc = TX_PACKET_OS; |
| prMsduInfo->fgIs802_11 = FALSE; |
| prMsduInfo->fgIs802_1x = FALSE; |
| prMsduInfo->fgIs802_1x_NonProtected = FALSE; |
| prMsduInfo->fgIs802_3 = FALSE; |
| prMsduInfo->fgIsVlanExists = FALSE; |
| prMsduInfo->pfTxDoneHandler = NULL; |
| prMsduInfo->prPacket = NULL; |
| prMsduInfo->u2FrameLength = 0; |
| prMsduInfo->u4Option = 0; |
| prMsduInfo->u4FixedRateOption = 0; |
| prMsduInfo->ucRateMode = MSDU_RATE_MODE_AUTO; |
| prMsduInfo->ucBssIndex = prStaRec->ucBssIndex; |
| prMsduInfo->ucPacketType = TX_PACKET_TYPE_DATA; |
| prMsduInfo->ucStaRecIndex = prStaRec->ucIndex; |
| prMsduInfo->ucPID = NIC_TX_DESC_PID_RESERVED; |
| |
| u4TxDescSize = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| u4TxDescAppendSize = HW_MAC_TX_DESC_APPEND_T_LENGTH; |
| |
| DBGLOG(QM, INFO, "Generate TXD template for STA[%u] QoS[%u]\n", prStaRec->ucIndex, prStaRec->fgIsQoS); |
| |
| /* Generate new template */ |
| if (prStaRec->fgIsQoS) { |
| /* For QoS STA, generate 8 TXD template (TID0~TID7) */ |
| for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) { |
| |
| if (prAdapter->rWifiVar.ucTcRestrict < TC_NUM) |
| ucTc = prAdapter->rWifiVar.ucTcRestrict; |
| else |
| ucTc = arNetwork2TcResource[prStaRec->ucBssIndex][aucTid2ACI[ucTid]]; |
| u4TxDescSize = arTcTrafficSettings[ucTc].u4TxDescLength; |
| |
| /* Include TxD append */ |
| prTxDesc = kalMemAlloc(u4TxDescSize + u4TxDescAppendSize, VIR_MEM_TYPE); |
| DBGLOG(QM, TRACE, "STA[%u] TID[%u] TxDTemp[0x%p]\n", prStaRec->ucIndex, ucTid, prTxDesc); |
| if (!prTxDesc) { |
| rStatus = WLAN_STATUS_RESOURCES; |
| break; |
| } |
| |
| /* Update MsduInfo TID & TC */ |
| prMsduInfo->ucUserPriority = ucTid; |
| prMsduInfo->ucTC = ucTc; |
| |
| /* Compose Tx desc template */ |
| nicTxComposeDesc(prAdapter, prMsduInfo, u4TxDescSize, TRUE, (PUINT_8) prTxDesc); |
| |
| /* Fill TxD append */ |
| nicTxComposeDescAppend(prAdapter, prMsduInfo, ((PUINT_8)prTxDesc + u4TxDescSize)); |
| |
| prStaRec->aprTxDescTemplate[ucTid] = prTxDesc; |
| } |
| } else { |
| /* For non-QoS STA, generate 1 TXD template (TID0) */ |
| do { |
| if (prAdapter->rWifiVar.ucTcRestrict < TC_NUM) |
| ucTc = prAdapter->rWifiVar.ucTcRestrict; |
| else |
| ucTc = arNetwork2TcResource[prStaRec->ucBssIndex][NET_TC_WMM_AC_BE_INDEX]; |
| |
| /* ucTxDescSize = arTcTrafficSettings[ucTc].ucTxDescLength; */ |
| u4TxDescSize = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| |
| prTxDesc = kalMemAlloc(u4TxDescSize + u4TxDescAppendSize, VIR_MEM_TYPE); |
| if (!prTxDesc) { |
| rStatus = WLAN_STATUS_RESOURCES; |
| break; |
| } |
| /* Update MsduInfo TID & TC */ |
| prMsduInfo->ucUserPriority = 0; |
| prMsduInfo->ucTC = ucTc; |
| |
| /* Compose Tx desc template */ |
| nicTxComposeDesc(prAdapter, prMsduInfo, u4TxDescSize, TRUE, (PUINT_8) prTxDesc); |
| |
| /* Fill TxD append */ |
| nicTxComposeDescAppend(prAdapter, prMsduInfo, ((PUINT_8)prTxDesc + u4TxDescSize)); |
| |
| for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) { |
| prStaRec->aprTxDescTemplate[ucTid] = prTxDesc; |
| DBGLOG(QM, TRACE, "TXD template: TID[%u] Ptr[0x%x]\n", ucTid, (ULONG) prTxDesc); |
| } |
| } while (FALSE); |
| } |
| |
| nicTxReturnMsduInfo(prAdapter, prMsduInfo); |
| |
| return rStatus; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief In this function, we'll free Tx descriptor template for each TID. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prStaRec Pointer to the StaRec structure. |
| * |
| * @retval VOID |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxFreeDescTemplate(IN P_ADAPTER_T prAdapter, IN P_STA_RECORD_T prStaRec) |
| { |
| UINT_8 ucTid; |
| UINT_8 ucTxDescSize; |
| P_HW_MAC_TX_DESC_T prTxDesc; |
| |
| DBGLOG(QM, INFO, "Free TXD template for STA[%u] QoS[%u]\n", prStaRec->ucIndex, prStaRec->fgIsQoS); |
| |
| if (prStaRec->fgIsQoS) { |
| for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) { |
| prTxDesc = (P_HW_MAC_TX_DESC_T) prStaRec->aprTxDescTemplate[ucTid]; |
| |
| if (prTxDesc) { |
| if (HAL_MAC_TX_DESC_IS_LONG_FORMAT(prTxDesc)) |
| ucTxDescSize = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| else |
| ucTxDescSize = NIC_TX_DESC_SHORT_FORMAT_LENGTH; |
| |
| kalMemFree(prTxDesc, VIR_MEM_TYPE, ucTxDescSize); |
| |
| prTxDesc = prStaRec->aprTxDescTemplate[ucTid] = NULL; |
| } |
| } |
| } else { |
| prTxDesc = (P_HW_MAC_TX_DESC_T) prStaRec->aprTxDescTemplate[0]; |
| if (prTxDesc) { |
| if (HAL_MAC_TX_DESC_IS_LONG_FORMAT(prTxDesc)) |
| ucTxDescSize = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| else |
| ucTxDescSize = NIC_TX_DESC_SHORT_FORMAT_LENGTH; |
| |
| kalMemFree(prTxDesc, VIR_MEM_TYPE, ucTxDescSize); |
| prTxDesc = NULL; |
| } |
| for (ucTid = 0; ucTid < TX_DESC_TID_NUM; ucTid++) |
| prStaRec->aprTxDescTemplate[ucTid] = NULL; |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief Write data to device done |
| * |
| * \param[in] prGlueInfo Pointer to the GLUE_INFO_T structure. |
| * \param[in] prQue msdu info que to be free |
| * |
| * \retval TRUE operation success |
| * \retval FALSE operation fail |
| */ |
| /*----------------------------------------------------------------------------*/ |
| void nicTxMsduDoneCb(IN P_GLUE_INFO_T prGlueInfo, IN P_QUE_T prQue) |
| { |
| P_MSDU_INFO_T prMsduInfo, prNextMsduInfo; |
| QUE_T rFreeQueue; |
| P_QUE_T prFreeQueue; |
| /* P_NATIVE_PACKET prNativePacket; */ |
| P_TX_CTRL_T prTxCtrl; |
| P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; |
| |
| ASSERT(prAdapter); |
| prTxCtrl = &prAdapter->rTxCtrl; |
| ASSERT(prTxCtrl); |
| |
| prFreeQueue = &rFreeQueue; |
| QUEUE_INITIALIZE(prFreeQueue); |
| |
| if (prQue && prQue->u4NumElem > 0) { |
| prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_HEAD(prQue); |
| |
| while (prMsduInfo) { |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfo->rQueEntry); |
| |
| #if 1 |
| nicTxFreePacket(prAdapter, prMsduInfo, FALSE); |
| #else |
| prNativePacket = prMsduInfo->prPacket; |
| |
| /* Free MSDU_INFO */ |
| if (prMsduInfo->eSrc == TX_PACKET_OS) { |
| wlanTxProfilingTagMsdu(prAdapter, prMsduInfo, TX_PROF_TAG_DRV_TX_DONE); |
| kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_SUCCESS); |
| prMsduInfo->prPacket = NULL; |
| } else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) { |
| GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); |
| } |
| #endif |
| |
| if (!prMsduInfo->pfTxDoneHandler) |
| QUEUE_INSERT_TAIL(prFreeQueue, (P_QUE_ENTRY_T) prMsduInfo); |
| |
| prMsduInfo = prNextMsduInfo; |
| } |
| nicTxReturnMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(&rFreeQueue)); |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief In this function, we'll write frame(PACKET_INFO_T) into HIF. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param ucPortIdx Port Number |
| * @param prQue a link list of P_MSDU_INFO_T |
| * |
| * @retval WLAN_STATUS_SUCCESS Bus access ok. |
| * @retval WLAN_STATUS_FAILURE Bus access fail. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxMsduQueue(IN P_ADAPTER_T prAdapter, UINT_8 ucPortIdx, P_QUE_T prQue) |
| { |
| P_MSDU_INFO_T prMsduInfo; |
| P_TX_CTRL_T prTxCtrl; |
| |
| ASSERT(prAdapter); |
| ASSERT(prQue); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| #if CFG_HIF_STATISTICS |
| prTxCtrl->u4TotalTxAccessNum++; |
| prTxCtrl->u4TotalTxPacketNum += prQue->u4NumElem; |
| #endif |
| |
| while (QUEUE_IS_NOT_EMPTY(prQue)) { |
| QUEUE_REMOVE_HEAD(prQue, prMsduInfo, P_MSDU_INFO_T); |
| |
| if (!halTxIsDataBufEnough(prAdapter, prMsduInfo)) { |
| QUEUE_INSERT_HEAD(prQue, (P_QUE_ENTRY_T) prMsduInfo); |
| break; |
| } |
| |
| #if !CFG_SUPPORT_MULTITHREAD |
| nicTxFillDataDesc(prAdapter, prMsduInfo); |
| #endif |
| |
| if (prMsduInfo->pfTxDoneHandler) { |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| /* Record native packet pointer for Tx done log */ |
| WLAN_GET_FIELD_32(&prMsduInfo->prPacket, &prMsduInfo->u4TxDoneTag); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| } |
| |
| HAL_WRITE_TX_DATA(prAdapter, prMsduInfo); |
| } |
| |
| HAL_KICK_TX_DATA(prAdapter); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief In this function, we'll write Command(CMD_INFO_T) into HIF. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prPacketInfo Pointer of CMD_INFO_T |
| * @param ucTC Specify the resource of TC |
| * |
| * @retval WLAN_STATUS_SUCCESS Bus access ok. |
| * @retval WLAN_STATUS_FAILURE Bus access fail. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo, IN UINT_8 ucTC) |
| { |
| P_WIFI_CMD_T prWifiCmd; |
| P_MSDU_INFO_T prMsduInfo; |
| P_TX_CTRL_T prTxCtrl; |
| struct sk_buff *skb; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| ASSERT(prCmdInfo); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| if (prCmdInfo->eCmdType == COMMAND_TYPE_SECURITY_FRAME) { |
| prMsduInfo = prCmdInfo->prMsduInfo; |
| |
| prCmdInfo->pucTxd = prMsduInfo->aucTxDescBuffer; |
| if (HAL_MAC_TX_DESC_IS_LONG_FORMAT((P_HW_MAC_TX_DESC_T) prMsduInfo->aucTxDescBuffer)) |
| prCmdInfo->u4TxdLen = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| else |
| prCmdInfo->u4TxdLen = NIC_TX_DESC_SHORT_FORMAT_LENGTH; |
| |
| skb = (struct sk_buff *)prMsduInfo->prPacket; |
| prCmdInfo->pucTxp = skb->data; |
| prCmdInfo->u4TxpLen = skb->len; |
| |
| HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); |
| |
| prMsduInfo->prPacket = NULL; |
| |
| if (prMsduInfo->pfTxDoneHandler) { |
| /* DBGLOG(INIT, TRACE,("Wait Cmd TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum)); */ |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| } else { |
| /* Only return MSDU_INFO */ |
| /* NativePacket will be freed at SEC frame CMD callback */ |
| nicTxReturnMsduInfo(prAdapter, prMsduInfo); |
| } |
| |
| } else if (prCmdInfo->eCmdType == COMMAND_TYPE_MANAGEMENT_FRAME) { |
| prMsduInfo = prCmdInfo->prMsduInfo; |
| |
| ASSERT(prMsduInfo->fgIs802_11 == TRUE); |
| ASSERT(prMsduInfo->eSrc == TX_PACKET_MGMT); |
| |
| prCmdInfo->pucTxd = prMsduInfo->aucTxDescBuffer; |
| if (HAL_MAC_TX_DESC_IS_LONG_FORMAT((P_HW_MAC_TX_DESC_T) prMsduInfo->aucTxDescBuffer)) |
| prCmdInfo->u4TxdLen = NIC_TX_DESC_LONG_FORMAT_LENGTH; |
| else |
| prCmdInfo->u4TxdLen = NIC_TX_DESC_SHORT_FORMAT_LENGTH; |
| |
| prCmdInfo->pucTxp = prMsduInfo->prPacket; |
| prCmdInfo->u4TxpLen = prMsduInfo->u2FrameLength; |
| |
| HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); |
| /* <4> Management Frame Post-Processing */ |
| GLUE_DEC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); |
| |
| DBGLOG(INIT, INFO, "TX MGMT Frame: BSS[%u] WIDX:PID[%u:%u] SEQ[%u] STA[%u] RSP[%u]\n", |
| prMsduInfo->ucBssIndex, prMsduInfo->ucWlanIndex, prMsduInfo->ucPID, |
| prMsduInfo->ucTxSeqNum, prMsduInfo->ucStaRecIndex, prMsduInfo->pfTxDoneHandler ? TRUE : FALSE); |
| |
| if (prMsduInfo->pfTxDoneHandler) { |
| /* DBGLOG(INIT, TRACE,("Wait Cmd TxSeqNum:%d\n", prMsduInfo->ucTxSeqNum)); */ |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| QUEUE_INSERT_TAIL(&(prTxCtrl->rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| } else { |
| cnmMgtPktFree(prAdapter, prMsduInfo); |
| } |
| |
| } else { |
| P_PSE_CMD_HDR_T prPseCmdHdr; |
| |
| prWifiCmd = (P_WIFI_CMD_T) prCmdInfo->pucInfoBuffer; |
| |
| prPseCmdHdr = (P_PSE_CMD_HDR_T) (prCmdInfo->pucInfoBuffer); |
| prPseCmdHdr->u2Qidx = TXD_Q_IDX_MCU_RQ0; |
| prPseCmdHdr->u2Pidx = TXD_P_IDX_MCU; |
| prPseCmdHdr->u2Hf = TXD_HF_CMD; |
| prPseCmdHdr->u2Ft = TXD_FT_LONG_FORMAT; |
| prPseCmdHdr->u2PktFt = TXD_PKT_FT_CMD; |
| |
| prWifiCmd->u2Length = prWifiCmd->u2TxByteCount - sizeof(PSE_CMD_HDR_T); |
| |
| #if (CFG_UMAC_GENERATION >= 0x20) |
| /* TODO ? */ |
| /* prWifiCmd->prPseCmd.u2TxByteCount = u2OverallBufferLength; */ |
| /* prWifiCmd->u2TxByteCount = u2OverallBufferLength - sizeof(PSE_CMD_HDR_T); */ |
| #else |
| prWifiCmd->u2TxByteCount = |
| TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen) & (UINT_16) HIF_TX_HDR_TX_BYTE_COUNT_MASK); |
| #endif |
| prWifiCmd->u2PQ_ID = CMD_PQ_ID; |
| prWifiCmd->ucPktTypeID = CMD_PACKET_TYPE_ID; |
| prWifiCmd->ucS2DIndex = S2D_INDEX_CMD_H2N_H2C; |
| prCmdInfo->pucTxd = prCmdInfo->pucInfoBuffer; |
| prCmdInfo->u4TxdLen = prCmdInfo->u2InfoBufLen; |
| prCmdInfo->pucTxp = NULL; |
| prCmdInfo->u4TxpLen = 0; |
| |
| HAL_WRITE_TX_CMD(prAdapter, prCmdInfo, ucTC); |
| |
| DBGLOG(INIT, INFO, "TX CMD: ID[0x%02X] SEQ[%u] SET[%u] LEN[%u]\n", |
| prWifiCmd->ucCID, prWifiCmd->ucSeqNum, prWifiCmd->ucSetQuery, prWifiCmd->u2Length); |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| } /* end of nicTxCmd() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief This function will clean up all the pending frames in internal SW Queues |
| * by return the pending TX packet to the system. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxRelease(IN P_ADAPTER_T prAdapter, IN BOOLEAN fgProcTxDoneHandler) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| P_MSDU_INFO_T prMsduInfo; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| nicTxFlush(prAdapter); |
| |
| /* free MSDU_INFO_T from rTxMgmtMsduInfoList */ |
| do { |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| QUEUE_REMOVE_HEAD(&prTxCtrl->rTxMgmtTxingQueue, prMsduInfo, P_MSDU_INFO_T); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| |
| if (prMsduInfo) { |
| DBGLOG(TX, TRACE, "%s: Get Msdu WIDX:PID[%u:%u] SEQ[%u] from Pending Q\n", |
| __func__, prMsduInfo->ucWlanIndex, prMsduInfo->ucPID, prMsduInfo->ucTxSeqNum); |
| |
| /* invoke done handler */ |
| if (prMsduInfo->pfTxDoneHandler && fgProcTxDoneHandler) |
| prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); |
| |
| nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo); |
| nicTxReturnMsduInfo(prAdapter, prMsduInfo); |
| } else { |
| break; |
| } |
| } while (TRUE); |
| |
| } /* end of nicTxRelease() */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Process the TX Done interrupt and pull in more pending frames in SW |
| * Queues for transmission. |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicProcessTxInterrupt(IN P_ADAPTER_T prAdapter) |
| { |
| P_WIFI_VAR_T prWifiVar = &prAdapter->rWifiVar; |
| |
| halProcessTxInterrupt(prAdapter); |
| |
| /* Indicate Service Thread */ |
| if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo) > 0 || wlanGetTxPendingFrameCount(prAdapter) > 0) |
| kalSetEvent(prAdapter->prGlueInfo); |
| |
| /* SER break point */ |
| if (nicSerIsTxStop(prAdapter)) { |
| /* Skip following Tx handling */ |
| return; |
| } |
| |
| /* TX Commands */ |
| if (kalGetTxPendingCmdCount(prAdapter->prGlueInfo)) |
| wlanTxCmdMthread(prAdapter); |
| |
| /* Process TX data packet to HIF */ |
| if (nicTxGetMsduPendingCnt(prAdapter) >= prWifiVar->u4TxIntThCount) |
| nicTxMsduQueueMthread(prAdapter); |
| } /* end of nicProcessTxInterrupt() */ |
| |
| VOID nicTxFreePacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN BOOLEAN fgDrop) |
| { |
| P_NATIVE_PACKET prNativePacket; |
| P_TX_CTRL_T prTxCtrl; |
| WLAN_STATUS rStatus = WLAN_STATUS_SUCCESS; |
| |
| ASSERT(prAdapter); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| prNativePacket = prMsduInfo->prPacket; |
| |
| if (fgDrop) |
| rStatus = WLAN_STATUS_FAILURE; |
| |
| if (prMsduInfo->eSrc == TX_PACKET_OS) { |
| if (prNativePacket) |
| kalSendComplete(prAdapter->prGlueInfo, prNativePacket, rStatus); |
| if (fgDrop) |
| wlanUpdateTxStatistics(prAdapter, prMsduInfo, TRUE); /*get per-AC Tx drop packets */ |
| } else if (prMsduInfo->eSrc == TX_PACKET_MGMT) { |
| if (prMsduInfo->pfTxDoneHandler) |
| prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); |
| if (prNativePacket) |
| cnmMemFree(prAdapter, prNativePacket); |
| } else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) { |
| GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief this function frees packet of P_MSDU_INFO_T linked-list |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prMsduInfoList a link list of P_MSDU_INFO_T |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxFreeMsduInfoPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) |
| { |
| P_NATIVE_PACKET prNativePacket; |
| P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead; |
| P_TX_CTRL_T prTxCtrl; |
| |
| ASSERT(prAdapter); |
| ASSERT(prMsduInfoListHead); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| while (prMsduInfo) { |
| prNativePacket = prMsduInfo->prPacket; |
| |
| #if 1 |
| nicTxFreePacket(prAdapter, prMsduInfo, TRUE); |
| #else |
| if (prMsduInfo->eSrc == TX_PACKET_OS) { |
| if (prNativePacket) |
| kalSendComplete(prAdapter->prGlueInfo, prNativePacket, WLAN_STATUS_FAILURE); |
| /*get per-AC Tx drop packets */ |
| wlanUpdateTxStatistics(prAdapter, prMsduInfo, TRUE); |
| } else if (prMsduInfo->eSrc == TX_PACKET_MGMT) { |
| if (prMsduInfo->pfTxDoneHandler) |
| prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, TX_RESULT_DROPPED_IN_DRIVER); |
| if (prNativePacket) |
| cnmMemFree(prAdapter, prNativePacket); |
| } else if (prMsduInfo->eSrc == TX_PACKET_FORWARDING) { |
| GLUE_DEC_REF_CNT(prTxCtrl->i4PendingFwdFrameCount); |
| } |
| #endif |
| prMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); |
| } |
| |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief this function returns P_MSDU_INFO_T of MsduInfoList to TxCtrl->rfreeMsduInfoList |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prMsduInfoList a link list of P_MSDU_INFO_T |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxReturnMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfoListHead) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| P_MSDU_INFO_T prMsduInfo = prMsduInfoListHead, prNextMsduInfo; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| ASSERT(prTxCtrl); |
| |
| while (prMsduInfo) { |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); |
| |
| switch (prMsduInfo->eSrc) { |
| case TX_PACKET_FORWARDING: |
| wlanReturnPacket(prAdapter, prMsduInfo->prPacket); |
| break; |
| case TX_PACKET_OS: |
| case TX_PACKET_OS_OID: |
| case TX_PACKET_MGMT: |
| default: |
| break; |
| } |
| |
| /* Reset MSDU_INFO fields */ |
| kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); |
| QUEUE_INSERT_TAIL(&prTxCtrl->rFreeMsduInfoList, (P_QUE_ENTRY_T) prMsduInfo); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_MSDU_INFO_LIST); |
| prMsduInfo = prNextMsduInfo; |
| }; |
| |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief this function fills packet information to P_MSDU_INFO_T |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prMsduInfo P_MSDU_INFO_T |
| * @param prPacket P_NATIVE_PACKET |
| * |
| * @retval TRUE Success to extract information |
| * @retval FALSE Fail to extract correct information |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN nicTxFillMsduInfo(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN P_NATIVE_PACKET prPacket) |
| { |
| P_GLUE_INFO_T prGlueInfo; |
| |
| ASSERT(prAdapter); |
| |
| kalMemZero(prMsduInfo, sizeof(MSDU_INFO_T)); |
| |
| prGlueInfo = prAdapter->prGlueInfo; |
| ASSERT(prGlueInfo); |
| |
| kalGetEthDestAddr(prAdapter->prGlueInfo, prPacket, prMsduInfo->aucEthDestAddr); |
| |
| prMsduInfo->prPacket = prPacket; |
| prMsduInfo->ucBssIndex = GLUE_GET_PKT_BSS_IDX(prPacket); |
| prMsduInfo->ucUserPriority = GLUE_GET_PKT_TID(prPacket); |
| prMsduInfo->ucMacHeaderLength = GLUE_GET_PKT_HEADER_LEN(prPacket); |
| prMsduInfo->u2FrameLength = (UINT_16) GLUE_GET_PKT_FRAME_LEN(prPacket); |
| prMsduInfo->u4PageCount = nicTxGetPageCount(prMsduInfo->u2FrameLength, FALSE); |
| |
| if (GLUE_IS_PKT_FLAG_SET(prPacket)) { |
| prMsduInfo->fgIs802_1x = GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_1X) ? TRUE:FALSE; |
| prMsduInfo->fgIs802_1x_NonProtected = |
| GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_NON_PROTECTED_1X) ? TRUE:FALSE; |
| prMsduInfo->fgIs802_3 = GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_802_3) ? TRUE:FALSE; |
| prMsduInfo->fgIsVlanExists = GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_VLAN_EXIST) ? TRUE:FALSE; |
| |
| if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_DHCP) && prAdapter->rWifiVar.ucDhcpTxDone) |
| prMsduInfo->pfTxDoneHandler = wlanDhcpTxDone; |
| else if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_ARP) && prAdapter->rWifiVar.ucArpTxDone) |
| prMsduInfo->pfTxDoneHandler = wlanArpTxDone; |
| else if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_1X)) |
| prMsduInfo->pfTxDoneHandler = wlan1xTxDone; |
| |
| if (GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_DHCP) || |
| GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_ARP) || |
| GLUE_TEST_PKT_FLAG(prPacket, ENUM_PKT_1X)) { |
| /* Set BSS/STA lowest basic rate */ |
| prMsduInfo->ucRateMode = MSDU_RATE_MODE_LOWEST_RATE; |
| |
| /* Set higher priority */ |
| prMsduInfo->ucUserPriority = NIC_TX_CRITICAL_DATA_TID; |
| } |
| } |
| |
| /* Add dummy Tx done */ |
| if ((prAdapter->rWifiVar.ucDataTxDone == 1) && (prMsduInfo->pfTxDoneHandler == NULL)) |
| prMsduInfo->pfTxDoneHandler = nicTxDummyTxDone; |
| |
| return TRUE; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief this function update TCQ values by passing current status to txAdjustTcQuotas |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @retval WLAN_STATUS_SUCCESS Updated successfully |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxAdjustTcq(IN P_ADAPTER_T prAdapter) |
| { |
| #if CFG_SUPPORT_MULTITHREAD |
| TX_TCQ_ADJUST_T rTcqAdjust; |
| P_TX_CTRL_T prTxCtrl; |
| |
| ASSERT(prAdapter); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| ASSERT(prTxCtrl); |
| |
| qmAdjustTcQuotasMthread(prAdapter, &rTcqAdjust, &prTxCtrl->rTc); |
| |
| #else |
| |
| UINT_32 u4Num; |
| TX_TCQ_ADJUST_T rTcqAdjust; |
| P_TX_CTRL_T prTxCtrl; |
| P_TX_TCQ_STATUS_T prTcqStatus; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| prTcqStatus = &prAdapter->rTxCtrl.rTc; |
| ASSERT(prTxCtrl); |
| |
| if (qmAdjustTcQuotas(prAdapter, &rTcqAdjust, &prTxCtrl->rTc)) { |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| |
| for (u4Num = 0; u4Num < TC_NUM; u4Num++) { |
| /* Page count */ |
| prTxCtrl->rTc.au4FreePageCount[u4Num] += |
| (rTcqAdjust.ai4Variation[u4Num] * NIC_TX_MAX_PAGE_PER_FRAME); |
| prTxCtrl->rTc.au4MaxNumOfPage[u4Num] += |
| (rTcqAdjust.ai4Variation[u4Num] * NIC_TX_MAX_PAGE_PER_FRAME); |
| |
| /* Buffer count */ |
| prTxCtrl->rTc.au4FreeBufferCount[u4Num] += rTcqAdjust.ai4Variation[u4Num]; |
| prTxCtrl->rTc.au4MaxNumOfBuffer[u4Num] += rTcqAdjust.ai4Variation[u4Num]; |
| |
| ASSERT(prTxCtrl->rTc.au4FreeBufferCount[u4Num] >= 0); |
| ASSERT(prTxCtrl->rTc.au4MaxNumOfBuffer[u4Num] >= 0); |
| } |
| |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| #if 0 |
| DBGLOG(TX, LOUD, |
| "TCQ Status Free Page:Buf[%03u:%02u, %03u:%02u, %03u:%02u, %03u:%02u, %03u:%02u, %03u:%02u]\n", |
| prTcqStatus->au4FreePageCount[TC0_INDEX], |
| prTcqStatus->au4FreeBufferCount[TC0_INDEX], |
| prTcqStatus->au4FreePageCount[TC1_INDEX], |
| prTcqStatus->au4FreeBufferCount[TC1_INDEX], |
| prTcqStatus->au4FreePageCount[TC2_INDEX], |
| prTcqStatus->au4FreeBufferCount[TC2_INDEX], |
| prTcqStatus->au4FreePageCount[TC3_INDEX], |
| prTcqStatus->au4FreeBufferCount[TC3_INDEX], |
| prTcqStatus->au4FreePageCount[TC4_INDEX], |
| prTcqStatus->au4FreeBufferCount[TC4_INDEX], |
| prTcqStatus->au4FreePageCount[TC5_INDEX], prTcqStatus->au4FreeBufferCount[TC5_INDEX]); |
| #endif |
| DBGLOG(TX, LOUD, |
| "TCQ Status Max Page:Buf[%03u:%02u, %03u:%02u, %03u:%02u, %03u:%02u, %03u:%02u, %03u:%02u]\n", |
| prTcqStatus->au4MaxNumOfPage[TC0_INDEX], |
| prTcqStatus->au4MaxNumOfBuffer[TC0_INDEX], |
| prTcqStatus->au4MaxNumOfPage[TC1_INDEX], |
| prTcqStatus->au4MaxNumOfBuffer[TC1_INDEX], |
| prTcqStatus->au4MaxNumOfPage[TC2_INDEX], |
| prTcqStatus->au4MaxNumOfBuffer[TC2_INDEX], |
| prTcqStatus->au4MaxNumOfPage[TC3_INDEX], |
| prTcqStatus->au4MaxNumOfBuffer[TC3_INDEX], |
| prTcqStatus->au4MaxNumOfPage[TC4_INDEX], |
| prTcqStatus->au4MaxNumOfBuffer[TC4_INDEX], |
| prTcqStatus->au4MaxNumOfPage[TC5_INDEX], prTcqStatus->au4MaxNumOfBuffer[TC5_INDEX]); |
| |
| } |
| #endif |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief this function flushes all packets queued in STA/AC queue |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @retval WLAN_STATUS_SUCCESS Flushed successfully |
| */ |
| /*----------------------------------------------------------------------------*/ |
| |
| WLAN_STATUS nicTxFlush(IN P_ADAPTER_T prAdapter) |
| { |
| P_MSDU_INFO_T prMsduInfo; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| |
| if (HAL_IS_TX_DIRECT(prAdapter)) { |
| nicTxDirectClearAllStaPsQ(prAdapter); |
| } else { |
| /* ask Per STA/AC queue to be fllushed and return all queued packets */ |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); |
| prMsduInfo = qmFlushTxQueues(prAdapter); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); |
| |
| if (prMsduInfo != NULL) { |
| nicTxFreeMsduInfoPacket(prAdapter, prMsduInfo); |
| nicTxReturnMsduInfo(prAdapter, prMsduInfo); |
| } |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| #if CFG_ENABLE_FW_DOWNLOAD |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief In this function, we'll write Command(CMD_INFO_T) into HIF. |
| * However this function is used for INIT_CMD. |
| * |
| * In order to avoid further maintenance issues, these 2 functions are separated |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * @param prPacketInfo Pointer of CMD_INFO_T |
| * @param ucTC Specify the resource of TC |
| * |
| * @retval WLAN_STATUS_SUCCESS Bus access ok. |
| * @retval WLAN_STATUS_FAILURE Bus access fail. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxInitCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) |
| { |
| UINT_16 u2OverallBufferLength; |
| PUINT_8 pucOutputBuf = (PUINT_8) NULL; /* Pointer to Transmit Data Structure Frame */ |
| P_TX_CTRL_T prTxCtrl; |
| |
| ASSERT(prAdapter); |
| ASSERT(prCmdInfo); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| pucOutputBuf = prTxCtrl->pucTxCoalescingBufPtr; |
| u2OverallBufferLength = TFCB_FRAME_PAD_TO_DW((prCmdInfo->u2InfoBufLen) & (UINT_16) |
| HIF_TX_HDR_TX_BYTE_COUNT_MASK); |
| |
| /* <1> Copy CMD Header to command buffer (by using pucCoalescingBufCached) */ |
| kalMemCopy((PVOID)&pucOutputBuf[0], (PVOID) prCmdInfo->pucInfoBuffer, prCmdInfo->u2InfoBufLen); |
| |
| ASSERT(u2OverallBufferLength <= prAdapter->u4CoalescingBufCachedSize); |
| |
| /* <2> Write frame to data port */ |
| HAL_WRITE_TX_PORT(prAdapter, NIC_TX_INIT_CMD_PORT, |
| (UINT_32) u2OverallBufferLength, |
| (PUINT_8) pucOutputBuf, (UINT_32) prAdapter->u4CoalescingBufCachedSize); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief In this function, we'll reset TX resource counter to initial value used |
| * in F/W download state |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @retval WLAN_STATUS_SUCCESS Reset is done successfully. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxInitResetResource(IN P_ADAPTER_T prAdapter) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| UINT_8 ucIdx; |
| |
| DEBUGFUNC("nicTxInitResetResource"); |
| |
| ASSERT(prAdapter); |
| prTxCtrl = &prAdapter->rTxCtrl; |
| |
| /* Delta page count */ |
| kalMemZero(prTxCtrl->rTc.au4TxDonePageCount, sizeof(prTxCtrl->rTc.au4TxDonePageCount)); |
| kalMemZero(prTxCtrl->rTc.au4PreUsedPageCount, sizeof(prTxCtrl->rTc.au4PreUsedPageCount)); |
| prTxCtrl->rTc.ucNextTcIdx = TC0_INDEX; |
| prTxCtrl->rTc.u4AvaliablePageCount = 0; |
| |
| /* Page count */ |
| prTxCtrl->rTc.au4MaxNumOfPage[TC0_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC0; |
| prTxCtrl->rTc.au4FreePageCount[TC0_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC0; |
| |
| prTxCtrl->rTc.au4MaxNumOfPage[TC1_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC1; |
| prTxCtrl->rTc.au4FreePageCount[TC1_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC1; |
| |
| prTxCtrl->rTc.au4MaxNumOfPage[TC2_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC2; |
| prTxCtrl->rTc.au4FreePageCount[TC2_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC2; |
| |
| prTxCtrl->rTc.au4MaxNumOfPage[TC3_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC3; |
| prTxCtrl->rTc.au4FreePageCount[TC3_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC3; |
| |
| prTxCtrl->rTc.au4MaxNumOfPage[TC4_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC4; |
| prTxCtrl->rTc.au4FreePageCount[TC4_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC4; |
| |
| prTxCtrl->rTc.au4MaxNumOfPage[TC5_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC5; |
| prTxCtrl->rTc.au4FreePageCount[TC5_INDEX] = NIC_TX_INIT_PAGE_COUNT_TC5; |
| |
| /* Buffer count */ |
| for (ucIdx = TC0_INDEX; ucIdx < TC_NUM; ucIdx++) { |
| prTxCtrl->rTc.au4MaxNumOfBuffer[ucIdx] = |
| prTxCtrl->rTc.au4MaxNumOfPage[ucIdx] / NIC_TX_MAX_PAGE_PER_FRAME; |
| prTxCtrl->rTc.au4FreeBufferCount[ucIdx] = |
| prTxCtrl->rTc.au4FreePageCount[ucIdx] / NIC_TX_MAX_PAGE_PER_FRAME; |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| |
| } |
| |
| #endif |
| |
| BOOLEAN nicTxProcessMngPacket(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) |
| { |
| #if 0 |
| UINT_16 u2RateCode; |
| #endif |
| P_BSS_INFO_T prBssInfo; |
| P_STA_RECORD_T prStaRec; |
| |
| if (prMsduInfo->eSrc != TX_PACKET_MGMT) |
| return FALSE; |
| |
| /* Sanity check */ |
| if (!prMsduInfo->prPacket) |
| return FALSE; |
| |
| if (!prMsduInfo->u2FrameLength) |
| return FALSE; |
| |
| if (!prMsduInfo->ucMacHeaderLength) |
| return FALSE; |
| |
| prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); |
| prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); |
| |
| /* MMPDU: force stick to TC4 */ |
| prMsduInfo->ucTC = TC4_INDEX; |
| |
| /* No Tx descriptor template for MMPDU */ |
| prMsduInfo->fgIsTXDTemplateValid = FALSE; |
| |
| /* Fixed Rate */ |
| if (prMsduInfo->ucRateMode == MSDU_RATE_MODE_AUTO) { |
| #if 0 |
| prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; |
| |
| if (prStaRec) |
| u2RateCode = prStaRec->u2HwDefaultFixedRateCode; |
| else |
| u2RateCode = prBssInfo->u2HwDefaultFixedRateCode; |
| |
| nicTxSetPktFixedRateOption(prMsduInfo, u2RateCode, FIX_BW_NO_FIXED, FALSE, FALSE); |
| #else |
| nicTxSetPktLowestFixedRate(prAdapter, prMsduInfo); |
| #endif |
| } |
| #if CFG_SUPPORT_MULTITHREAD |
| nicTxFillDesc(prAdapter, prMsduInfo, prMsduInfo->aucTxDescBuffer, NULL); |
| #endif |
| |
| return TRUE; |
| } |
| |
| VOID nicTxProcessTxDoneEvent(IN P_ADAPTER_T prAdapter, IN P_WIFI_EVENT_T prEvent) |
| { |
| P_EVENT_TX_DONE_T prTxDone; |
| P_MSDU_INFO_T prMsduInfo; |
| PUINT_8 apucBandwidt[4] = {(PUINT_8)"20", (PUINT_8)"40", (PUINT_8)"80", (PUINT_8)"160/80+80"}; |
| |
| prTxDone = (P_EVENT_TX_DONE_T) (prEvent->aucBuffer); |
| |
| if (prTxDone->ucFlag & BIT(TXS_WITH_ADVANCED_INFO)) { |
| /* Tx Done with advanced info */ |
| DBGLOG(NIC, INFO, "EVENT_ID_TX_DONE WIDX:PID[%u:%u] Status[%u] TID[%u] SN[%u] CNT[%u] RATE[0x%04x]\n", |
| prTxDone->ucWlanIndex, prTxDone->ucPacketSeq, prTxDone->ucStatus, prTxDone->ucTid, |
| prTxDone->u2SequenceNumber, prTxDone->ucTxCount, prTxDone->u2TxRate); |
| |
| if (prTxDone->ucFlag & BIT(TXS_IS_EXIST)) { |
| UINT_8 ucNss, ucStbc; |
| INT_8 icTxPwr; |
| |
| ucNss = (prTxDone->u2TxRate & TX_DESC_NSTS_MASK) >> TX_DESC_NSTS_OFFSET; |
| ucNss += 1; |
| ucStbc = (prTxDone->u2TxRate & TX_DESC_STBC) ? TRUE:FALSE; |
| |
| if (ucStbc) |
| ucNss /= 2; |
| |
| DBGLOG(NIC, INFO, "||BW[%s] NSS[%u] ArIdx[%u] RspRate[0x%02x]\n", |
| apucBandwidt[prTxDone->ucBandwidth], ucNss, prTxDone->ucRateTableIdx, |
| prTxDone->ucRspRate); |
| |
| icTxPwr = (INT_8)prTxDone->ucTxPower; |
| if (icTxPwr & BIT(6)) |
| icTxPwr |= BIT(7); |
| |
| DBGLOG(NIC, INFO, "||AMPDU[%u] PS[%u] IBF[%u] EBF[%u] TxPwr[%d%sdBm] TSF[%u] TxDelay[%uus]\n", |
| prTxDone->u4AppliedFlag & BIT(TX_FRAME_IN_AMPDU_FORMAT) ? TRUE:FALSE, |
| prTxDone->u4AppliedFlag & BIT(TX_FRAME_PS_BIT) ? TRUE:FALSE, |
| prTxDone->u4AppliedFlag & BIT(TX_FRAME_IMP_BF) ? TRUE:FALSE, |
| prTxDone->u4AppliedFlag & BIT(TX_FRAME_EXP_BF) ? TRUE:FALSE, |
| icTxPwr / 2, icTxPwr & BIT(0) ? ".5" : "", |
| prTxDone->u4Timestamp, prTxDone->u4TxDelay); |
| } |
| } else { |
| DBGLOG(NIC, INFO, "EVENT_ID_TX_DONE WIDX:PID[%u:%u] Status[%u] SN[%u]\n", |
| prTxDone->ucWlanIndex, prTxDone->ucPacketSeq, prTxDone->ucStatus, prTxDone->u2SequenceNumber); |
| } |
| |
| /* call related TX Done Handler */ |
| prMsduInfo = nicGetPendingTxMsduInfo(prAdapter, prTxDone->ucWlanIndex, prTxDone->ucPacketSeq); |
| |
| #if CFG_SUPPORT_802_11V_TIMING_MEASUREMENT |
| DBGLOG(NIC, TRACE, "EVENT_ID_TX_DONE u4TimeStamp = %x u2AirDelay = %x\n", |
| prTxDone->au4Reserved1, prTxDone->au4Reserved2); |
| |
| wnmReportTimingMeas(prAdapter, prMsduInfo->ucStaRecIndex, |
| prTxDone->au4Reserved1, prTxDone->au4Reserved1 + prTxDone->au4Reserved2); |
| #endif |
| |
| if (prMsduInfo) { |
| prMsduInfo->pfTxDoneHandler(prAdapter, prMsduInfo, (ENUM_TX_RESULT_CODE_T) (prTxDone->ucStatus)); |
| |
| if (prMsduInfo->eSrc == TX_PACKET_MGMT) |
| cnmMgtPktFree(prAdapter, prMsduInfo); |
| #if defined(_HIF_PCIE) |
| else if (prMsduInfo->prToken) |
| prMsduInfo->pfTxDoneHandler = NULL; |
| #endif |
| else { |
| nicTxFreePacket(prAdapter, prMsduInfo, FALSE); |
| nicTxReturnMsduInfo(prAdapter, prMsduInfo); |
| } |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief this function enqueues MSDU_INFO_T into queue management, |
| * or command queue |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * prMsduInfo Pointer to MSDU |
| * |
| * @retval WLAN_STATUS_SUCCESS Reset is done successfully. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxEnqueueMsdu(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) |
| { |
| P_TX_CTRL_T prTxCtrl; |
| P_MSDU_INFO_T prNextMsduInfo, prRetMsduInfo, prMsduInfoHead; |
| QUE_T qDataPort0, qDataPort1; |
| P_QUE_T prDataPort0, prDataPort1; |
| P_CMD_INFO_T prCmdInfo; |
| WLAN_STATUS u4Status = WLAN_STATUS_SUCCESS; |
| |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| ASSERT(prAdapter); |
| ASSERT(prMsduInfo); |
| |
| prTxCtrl = &prAdapter->rTxCtrl; |
| ASSERT(prTxCtrl); |
| |
| prDataPort0 = &qDataPort0; |
| prDataPort1 = &qDataPort1; |
| |
| QUEUE_INITIALIZE(prDataPort0); |
| QUEUE_INITIALIZE(prDataPort1); |
| |
| /* check how many management frame are being queued */ |
| while (prMsduInfo) { |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo); |
| |
| QUEUE_GET_NEXT_ENTRY((P_QUE_ENTRY_T) prMsduInfo) = NULL; |
| |
| if (prMsduInfo->eSrc == TX_PACKET_MGMT) { |
| if (nicTxProcessMngPacket(prAdapter, prMsduInfo)) { |
| /* Valid MGMT */ |
| QUEUE_INSERT_TAIL(prDataPort1, (P_QUE_ENTRY_T) prMsduInfo); |
| } else { |
| /* Invalid MGMT */ |
| DBGLOG(TX, WARN, "Invalid MGMT[0x%p] BSS[%u] STA[%u],free it\n", |
| prMsduInfo, prMsduInfo->ucBssIndex, prMsduInfo->ucStaRecIndex); |
| |
| cnmMgtPktFree(prAdapter, prMsduInfo); |
| } |
| } else { |
| QUEUE_INSERT_TAIL(prDataPort0, (P_QUE_ENTRY_T) prMsduInfo); |
| } |
| |
| prMsduInfo = prNextMsduInfo; |
| } |
| |
| if (prDataPort0->u4NumElem) { |
| /* send to QM */ |
| KAL_SPIN_LOCK_DECLARATION(); |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); |
| prRetMsduInfo = qmEnqueueTxPackets(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prDataPort0)); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_QM_TX_QUEUE); |
| |
| /* post-process for dropped packets */ |
| if (prRetMsduInfo) { /* unable to enqueue */ |
| nicTxFreeMsduInfoPacket(prAdapter, prRetMsduInfo); |
| nicTxReturnMsduInfo(prAdapter, prRetMsduInfo); |
| } |
| } |
| |
| if (prDataPort1->u4NumElem) { |
| prMsduInfoHead = (P_MSDU_INFO_T) QUEUE_GET_HEAD(prDataPort1); |
| |
| if (nicTxGetFreeCmdCount(prAdapter) < NIC_TX_CMD_INFO_RESERVED_COUNT) { |
| /* not enough descriptors for sending */ |
| u4Status = WLAN_STATUS_FAILURE; |
| |
| /* free all MSDUs */ |
| while (prMsduInfoHead) { |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); |
| |
| if (prMsduInfoHead->pfTxDoneHandler != NULL) { |
| prMsduInfoHead->pfTxDoneHandler(prAdapter, prMsduInfoHead, |
| TX_RESULT_DROPPED_IN_DRIVER); |
| } |
| |
| cnmMgtPktFree(prAdapter, prMsduInfoHead); |
| |
| prMsduInfoHead = prNextMsduInfo; |
| } |
| } else { |
| /* send to command queue */ |
| while (prMsduInfoHead) { |
| prNextMsduInfo = (P_MSDU_INFO_T) QUEUE_GET_NEXT_ENTRY(&prMsduInfoHead->rQueEntry); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); |
| QUEUE_REMOVE_HEAD(&prAdapter->rFreeCmdList, prCmdInfo, P_CMD_INFO_T); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_CMD_RESOURCE); |
| |
| if (prCmdInfo) { |
| GLUE_INC_REF_CNT(prTxCtrl->i4TxMgmtPendingNum); |
| |
| kalMemZero(prCmdInfo, sizeof(CMD_INFO_T)); |
| |
| #if CFG_ENABLE_PKT_LIFETIME_PROFILE |
| /* Tag MGMT enqueue time */ |
| GET_CURRENT_SYSTIME(&prMsduInfoHead->rPktProfile.rEnqueueTimestamp); |
| #endif |
| prCmdInfo->eCmdType = COMMAND_TYPE_MANAGEMENT_FRAME; |
| prCmdInfo->u2InfoBufLen = prMsduInfoHead->u2FrameLength; |
| prCmdInfo->pucInfoBuffer = NULL; |
| prCmdInfo->prMsduInfo = prMsduInfoHead; |
| prCmdInfo->pfCmdDoneHandler = NULL; |
| prCmdInfo->pfCmdTimeoutHandler = NULL; |
| prCmdInfo->fgIsOid = FALSE; |
| prCmdInfo->fgSetQuery = TRUE; |
| prCmdInfo->fgNeedResp = FALSE; |
| prCmdInfo->ucCmdSeqNum = prMsduInfoHead->ucTxSeqNum; |
| |
| DBGLOG(TX, TRACE, "%s: EN-Q MSDU[0x%p] SEQ[%u] BSS[%u] STA[%u] to CMD Q\n", |
| __func__, prMsduInfoHead, |
| prMsduInfoHead->ucTxSeqNum, prMsduInfoHead->ucBssIndex, |
| prMsduInfoHead->ucStaRecIndex); |
| |
| kalEnqueueCommand(prAdapter->prGlueInfo, (P_QUE_ENTRY_T) prCmdInfo); |
| } else { |
| /* Cmd free count is larger than expected, but allocation fail. */ |
| u4Status = WLAN_STATUS_FAILURE; |
| |
| if (prMsduInfoHead->pfTxDoneHandler != NULL) { |
| prMsduInfoHead->pfTxDoneHandler(prAdapter, |
| prMsduInfoHead, |
| TX_RESULT_DROPPED_IN_DRIVER); |
| } |
| |
| cnmMgtPktFree(prAdapter, prMsduInfoHead); |
| } |
| |
| prMsduInfoHead = prNextMsduInfo; |
| } |
| } |
| } |
| |
| /* indicate service thread for sending */ |
| if (prTxCtrl->i4TxMgmtPendingNum > 0 || kalGetTxPendingFrameCount(prAdapter->prGlueInfo) > 0) |
| kalSetEvent(prAdapter->prGlueInfo); |
| |
| return u4Status; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief this function returns WLAN index |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @retval |
| */ |
| /*----------------------------------------------------------------------------*/ |
| UINT_8 nicTxGetWlanIdx(P_ADAPTER_T prAdapter, UINT_8 ucBssIdx, UINT_8 ucStaRecIdx) |
| { |
| P_STA_RECORD_T prStaRec; |
| P_BSS_INFO_T prBssInfo; |
| UINT_8 ucWlanIndex = NIC_TX_DEFAULT_WLAN_INDEX; |
| |
| prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIdx); |
| prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIdx); |
| |
| if (prStaRec) |
| ucWlanIndex = prStaRec->ucWlanIndex; |
| else if ((ucStaRecIdx == STA_REC_INDEX_BMCAST) && prBssInfo->fgIsInUse) { |
| if (prBssInfo->fgBcDefaultKeyExist) { |
| if (prBssInfo->wepkeyUsed[prBssInfo->ucBcDefaultKeyIdx] && |
| prBssInfo->wepkeyWlanIdx < NIC_TX_DEFAULT_WLAN_INDEX) |
| ucWlanIndex = prBssInfo->wepkeyWlanIdx; |
| else if (prBssInfo->ucBMCWlanIndexSUsed[prBssInfo->ucBcDefaultKeyIdx]) |
| ucWlanIndex = prBssInfo->ucBMCWlanIndexS[prBssInfo->ucBcDefaultKeyIdx]; |
| } else |
| ucWlanIndex = prBssInfo->ucBMCWlanIndex; |
| } |
| |
| if (ucWlanIndex >= WTBL_SIZE) { |
| DBGLOG(TX, WARN, "%s: Unexpected WIDX[%u] BSS[%u] STA[%u], set WIDX to default value[%u]\n", |
| ucWlanIndex, ucBssIdx, ucStaRecIdx, NIC_TX_DEFAULT_WLAN_INDEX); |
| |
| ucWlanIndex = NIC_TX_DEFAULT_WLAN_INDEX; |
| } |
| |
| return ucWlanIndex; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @retval |
| */ |
| /*----------------------------------------------------------------------------*/ |
| BOOLEAN nicTxIsMgmtResourceEnough(IN P_ADAPTER_T prAdapter) |
| { |
| if (nicTxGetFreeCmdCount(prAdapter) > (CFG_TX_MAX_CMD_PKT_NUM / 2)) |
| return TRUE; |
| else |
| return FALSE; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief this function returns available count in command queue |
| * |
| * @param prAdapter Pointer to the Adapter structure. |
| * |
| * @retval |
| */ |
| /*----------------------------------------------------------------------------*/ |
| UINT_32 nicTxGetFreeCmdCount(IN P_ADAPTER_T prAdapter) |
| { |
| ASSERT(prAdapter); |
| |
| return prAdapter->rFreeCmdList.u4NumElem; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * \brief this function returns page count of frame |
| * |
| * @param u4FrameLength frame length |
| * |
| * @retval page count of this frame |
| */ |
| /*----------------------------------------------------------------------------*/ |
| UINT_32 nicTxGetPageCount(IN UINT_32 u4FrameLength, IN BOOLEAN fgIncludeDesc) |
| { |
| return halTxGetPageCount(u4FrameLength, fgIncludeDesc); |
| } |
| |
| UINT_32 nicTxGetCmdPageCount(IN P_CMD_INFO_T prCmdInfo) |
| { |
| UINT_32 u4PageCount; |
| |
| switch (prCmdInfo->eCmdType) { |
| case COMMAND_TYPE_NETWORK_IOCTL: |
| case COMMAND_TYPE_GENERAL_IOCTL: |
| u4PageCount = nicTxGetPageCount(prCmdInfo->u2InfoBufLen, TRUE); |
| break; |
| |
| case COMMAND_TYPE_SECURITY_FRAME: |
| case COMMAND_TYPE_MANAGEMENT_FRAME: |
| /* No TxD append field for management packet */ |
| u4PageCount = nicTxGetPageCount(prCmdInfo->u2InfoBufLen + NIC_TX_DESC_LONG_FORMAT_LENGTH, TRUE); |
| break; |
| |
| default: |
| DBGLOG(INIT, WARN, "Undefined CMD Type(%u)\n", prCmdInfo->eCmdType); |
| u4PageCount = nicTxGetPageCount(prCmdInfo->u2InfoBufLen, FALSE); |
| break; |
| } |
| |
| return u4PageCount; |
| } |
| |
| VOID nicTxSetMngPacket(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo, |
| UINT_8 ucBssIndex, UINT_8 ucStaRecIndex, UINT_8 ucMacHeaderLength, |
| UINT_16 u2FrameLength, PFN_TX_DONE_HANDLER pfTxDoneHandler, UINT_8 ucRateMode) |
| { |
| ASSERT(prMsduInfo); |
| |
| prMsduInfo->ucBssIndex = ucBssIndex; |
| prMsduInfo->ucStaRecIndex = ucStaRecIndex; |
| prMsduInfo->ucMacHeaderLength = ucMacHeaderLength; |
| prMsduInfo->u2FrameLength = u2FrameLength; |
| prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; |
| prMsduInfo->ucRateMode = ucRateMode; |
| |
| /* Reset default value for MMPDU */ |
| prMsduInfo->fgIs802_11 = TRUE; |
| prMsduInfo->fgIs802_1x = FALSE; |
| prMsduInfo->fgIs802_1x_NonProtected = TRUE; /*For data frame only, no sense for management frame*/ |
| prMsduInfo->u4FixedRateOption = 0; |
| prMsduInfo->cPowerOffset = 0; |
| prMsduInfo->u4Option = 0; |
| prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); |
| prMsduInfo->ucPID = NIC_TX_DESC_PID_RESERVED; |
| prMsduInfo->ucPacketType = TX_PACKET_TYPE_MGMT; |
| prMsduInfo->ucUserPriority = 0; |
| prMsduInfo->eSrc = TX_PACKET_MGMT; |
| } |
| |
| VOID nicTxSetDataPacket(P_ADAPTER_T prAdapter, P_MSDU_INFO_T prMsduInfo, |
| UINT_8 ucBssIndex, UINT_8 ucStaRecIndex, UINT_8 ucMacHeaderLength, |
| UINT_16 u2FrameLength, PFN_TX_DONE_HANDLER pfTxDoneHandler, |
| UINT_8 ucRateMode, ENUM_TX_PACKET_SRC_T eSrc, UINT_8 ucTID, |
| BOOLEAN fgIs802_11Frame, BOOLEAN fgIs1xFrame) |
| { |
| ASSERT(prMsduInfo); |
| |
| prMsduInfo->ucBssIndex = ucBssIndex; |
| prMsduInfo->ucStaRecIndex = ucStaRecIndex; |
| prMsduInfo->ucMacHeaderLength = ucMacHeaderLength; |
| prMsduInfo->u2FrameLength = u2FrameLength; |
| prMsduInfo->pfTxDoneHandler = pfTxDoneHandler; |
| prMsduInfo->ucRateMode = ucRateMode; |
| prMsduInfo->ucUserPriority = ucTID; |
| prMsduInfo->fgIs802_11 = fgIs802_11Frame; |
| prMsduInfo->eSrc = eSrc; |
| prMsduInfo->fgIs802_1x = fgIs1xFrame; |
| |
| /* Reset default value for data packet */ |
| prMsduInfo->u4FixedRateOption = 0; |
| prMsduInfo->cPowerOffset = 0; |
| prMsduInfo->u4Option = 0; |
| prMsduInfo->ucTxSeqNum = nicIncreaseTxSeqNum(prAdapter); |
| prMsduInfo->ucPID = NIC_TX_DESC_PID_RESERVED; |
| prMsduInfo->ucPacketType = TX_PACKET_TYPE_DATA; |
| } |
| |
| VOID nicTxFillDescByPktOption(P_MSDU_INFO_T prMsduInfo, P_HW_MAC_TX_DESC_T prTxDesc) |
| { |
| UINT_32 u4PktOption = prMsduInfo->u4Option; |
| BOOLEAN fgIsLongFormat; |
| BOOLEAN fgProtected = FALSE; |
| |
| /* Skip this function if no options is set */ |
| if (!u4PktOption) |
| return; |
| |
| fgIsLongFormat = HAL_MAC_TX_DESC_IS_LONG_FORMAT(prTxDesc); |
| |
| /* Fields in DW0 and DW1 (Short Format) */ |
| if (u4PktOption & MSDU_OPT_NO_ACK) |
| HAL_MAC_TX_DESC_SET_NO_ACK(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_PROTECTED_FRAME) { |
| /* DBGLOG(RSN, INFO, "MSDU_OPT_PROTECTED_FRAME\n"); */ |
| HAL_MAC_TX_DESC_SET_PROTECTION(prTxDesc); |
| fgProtected = TRUE; |
| } |
| |
| switch (HAL_MAC_TX_DESC_GET_HEADER_FORMAT(prTxDesc)) { |
| case HEADER_FORMAT_802_11_ENHANCE_MODE: |
| if (u4PktOption & MSDU_OPT_EOSP) |
| HAL_MAC_TX_DESC_SET_EOSP(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_AMSDU) |
| HAL_MAC_TX_DESC_SET_AMSDU(prTxDesc); |
| break; |
| |
| case HEADER_FORMAT_NON_802_11: |
| if (u4PktOption & MSDU_OPT_EOSP) |
| HAL_MAC_TX_DESC_SET_EOSP(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_MORE_DATA) |
| HAL_MAC_TX_DESC_SET_MORE_DATA(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_REMOVE_VLAN) |
| HAL_MAC_TX_DESC_SET_REMOVE_VLAN(prTxDesc); |
| break; |
| |
| case HEADER_FORMAT_802_11_NORMAL_MODE: |
| if (fgProtected && prMsduInfo->prPacket) { |
| P_WLAN_MAC_HEADER_T prWlanHeader = |
| (P_WLAN_MAC_HEADER_T) ((ULONG) (prMsduInfo->prPacket) + MAC_TX_RESERVED_FIELD); |
| |
| prWlanHeader->u2FrameCtrl |= MASK_FC_PROTECTED_FRAME; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| |
| if (!fgIsLongFormat) |
| return; |
| |
| /* Fields in DW2~6 (Long Format) */ |
| if (u4PktOption & MSDU_OPT_NO_AGGREGATE) |
| HAL_MAC_TX_DESC_SET_BA_DISABLE(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_TIMING_MEASURE) |
| HAL_MAC_TX_DESC_SET_TIMING_MEASUREMENT(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_NDP) |
| HAL_MAC_TX_DESC_SET_NDP(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_NDPA) |
| HAL_MAC_TX_DESC_SET_NDPA(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_SOUNDING) |
| HAL_MAC_TX_DESC_SET_SOUNDING_FRAME(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_FORCE_RTS) |
| HAL_MAC_TX_DESC_SET_FORCE_RTS_CTS(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_BIP) |
| HAL_MAC_TX_DESC_SET_BIP(prTxDesc); |
| |
| /* SW field */ |
| if (u4PktOption & MSDU_OPT_SW_DURATION) |
| HAL_MAC_TX_DESC_SET_DURATION_CONTROL_BY_SW(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_SW_PS_BIT) |
| HAL_MAC_TX_DESC_SET_SW_PM_CONTROL(prTxDesc); |
| |
| if (u4PktOption & MSDU_OPT_SW_HTC) |
| HAL_MAC_TX_DESC_SET_HTC_EXIST(prTxDesc); |
| #if 0 |
| if (u4PktOption & MSDU_OPT_SW_BAR_SN) |
| HAL_MAC_TX_DESC_SET_SW_BAR_SSN(prTxDesc); |
| #endif |
| if (u4PktOption & MSDU_OPT_MANUAL_SN) { |
| HAL_MAC_TX_DESC_SET_TXD_SN_VALID(prTxDesc); |
| HAL_MAC_TX_DESC_SET_SEQUENCE_NUMBER(prTxDesc, prMsduInfo->u2SwSN); |
| } |
| |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Extra configuration for Tx packet |
| * |
| * @retval |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxConfigPktOption(P_MSDU_INFO_T prMsduInfo, UINT_32 u4OptionMask, BOOLEAN fgSetOption) |
| { |
| if (fgSetOption) |
| prMsduInfo->u4Option |= u4OptionMask; |
| else |
| prMsduInfo->u4Option &= ~u4OptionMask; |
| } |
| |
| VOID nicTxFillDescByPktControl(P_MSDU_INFO_T prMsduInfo, P_HW_MAC_TX_DESC_T prTxDesc) |
| { |
| UINT_8 ucPktControl = prMsduInfo->ucControlFlag; |
| UINT_8 ucSwReserved; |
| |
| /* Skip this function if no options is set */ |
| if (!ucPktControl) |
| return; |
| |
| if (HAL_MAC_TX_DESC_IS_LONG_FORMAT(prTxDesc)) { |
| ucSwReserved = HAL_MAC_TX_DESC_GET_SW_RESERVED(prTxDesc); |
| |
| if (ucPktControl & MSDU_CONTROL_FLAG_FORCE_TX) |
| ucSwReserved |= MSDU_CONTROL_FLAG_FORCE_TX; |
| |
| HAL_MAC_TX_DESC_SET_SW_RESERVED(prTxDesc, ucSwReserved); |
| } |
| } |
| |
| VOID nicTxConfigPktControlFlag(P_MSDU_INFO_T prMsduInfo, UINT_8 ucControlFlagMask, BOOLEAN fgSetFlag) |
| { |
| /* Set control flag */ |
| if (fgSetFlag) |
| prMsduInfo->ucControlFlag |= ucControlFlagMask; |
| else |
| prMsduInfo->ucControlFlag &= ~ucControlFlagMask; /* Clear control flag */ |
| } |
| |
| VOID nicTxSetPktLifeTime(P_MSDU_INFO_T prMsduInfo, UINT_32 u4TxLifeTimeInMs) |
| { |
| prMsduInfo->u4RemainingLifetime = u4TxLifeTimeInMs; |
| prMsduInfo->u4Option |= MSDU_OPT_MANUAL_LIFE_TIME; |
| } |
| |
| VOID nicTxSetPktRetryLimit(P_MSDU_INFO_T prMsduInfo, UINT_8 ucRetryLimit) |
| { |
| prMsduInfo->ucRetryLimit = ucRetryLimit; |
| prMsduInfo->u4Option |= MSDU_OPT_MANUAL_RETRY_LIMIT; |
| } |
| |
| VOID nicTxSetPktPowerOffset(P_MSDU_INFO_T prMsduInfo, INT_8 cPowerOffset) |
| { |
| prMsduInfo->cPowerOffset = cPowerOffset; |
| prMsduInfo->u4Option |= MSDU_OPT_MANUAL_POWER_OFFSET; |
| } |
| |
| VOID nicTxSetPktSequenceNumber(P_MSDU_INFO_T prMsduInfo, UINT_16 u2SN) |
| { |
| prMsduInfo->u2SwSN = u2SN; |
| prMsduInfo->u4Option |= MSDU_OPT_MANUAL_SN; |
| } |
| |
| VOID nicTxSetPktMacTxQue(P_MSDU_INFO_T prMsduInfo, UINT_8 ucMacTxQue) |
| { |
| UINT_8 ucTcIdx; |
| |
| for (ucTcIdx = TC0_INDEX; ucTcIdx < TC_NUM; ucTcIdx++) { |
| if (arTcResourceControl[ucTcIdx].ucDestQueueIndex == ucMacTxQue) |
| break; |
| } |
| |
| if (ucTcIdx < TC_NUM) { |
| prMsduInfo->ucTC = ucTcIdx; |
| prMsduInfo->u4Option |= MSDU_OPT_MANUAL_TX_QUE; |
| } |
| } |
| |
| VOID nicTxSetPktFixedRateOptionFull(P_MSDU_INFO_T prMsduInfo, |
| UINT_16 u2RateCode, |
| UINT_8 ucBandwidth, |
| BOOLEAN fgShortGI, |
| BOOLEAN fgLDPC, |
| BOOLEAN fgDynamicBwRts, BOOLEAN fgBeamforming, UINT_8 ucAntennaIndex) |
| { |
| HW_MAC_TX_DESC_T rTxDesc; |
| P_HW_MAC_TX_DESC_T prTxDesc = &rTxDesc; |
| |
| kalMemZero(prTxDesc, NIC_TX_DESC_LONG_FORMAT_LENGTH); |
| |
| /* Follow the format of Tx descriptor DW 6 */ |
| HAL_MAC_TX_DESC_SET_FR_RATE(prTxDesc, u2RateCode); |
| |
| if (ucBandwidth) |
| HAL_MAC_TX_DESC_SET_FR_BW(prTxDesc, ucBandwidth); |
| |
| if (fgBeamforming) |
| HAL_MAC_TX_DESC_SET_FR_BF(prTxDesc); |
| |
| if (fgShortGI) |
| HAL_MAC_TX_DESC_SET_FR_SHORT_GI(prTxDesc); |
| |
| if (fgLDPC) |
| HAL_MAC_TX_DESC_SET_FR_LDPC(prTxDesc); |
| |
| if (fgDynamicBwRts) |
| HAL_MAC_TX_DESC_SET_FR_DYNAMIC_BW_RTS(prTxDesc); |
| |
| HAL_MAC_TX_DESC_SET_FR_ANTENNA_ID(prTxDesc, ucAntennaIndex); |
| |
| /* Write back to RateOption of MSDU_INFO */ |
| HAL_MAC_TX_DESC_GET_DW(prTxDesc, 6, 1, &prMsduInfo->u4FixedRateOption); |
| |
| prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; |
| |
| } |
| |
| VOID nicTxSetPktFixedRateOption(P_MSDU_INFO_T prMsduInfo, |
| UINT_16 u2RateCode, UINT_8 ucBandwidth, BOOLEAN fgShortGI, BOOLEAN fgDynamicBwRts) |
| { |
| HW_MAC_TX_DESC_T rTxDesc; |
| P_HW_MAC_TX_DESC_T prTxDesc = &rTxDesc; |
| |
| kalMemZero(prTxDesc, NIC_TX_DESC_LONG_FORMAT_LENGTH); |
| |
| /* Follow the format of Tx descriptor DW 6 */ |
| HAL_MAC_TX_DESC_SET_FR_RATE(prTxDesc, u2RateCode); |
| |
| if (ucBandwidth) |
| HAL_MAC_TX_DESC_SET_FR_BW(prTxDesc, ucBandwidth); |
| |
| if (fgShortGI) |
| HAL_MAC_TX_DESC_SET_FR_SHORT_GI(prTxDesc); |
| |
| if (fgDynamicBwRts) |
| HAL_MAC_TX_DESC_SET_FR_DYNAMIC_BW_RTS(prTxDesc); |
| |
| /* Write back to RateOption of MSDU_INFO */ |
| HAL_MAC_TX_DESC_GET_DW(prTxDesc, 6, 1, &prMsduInfo->u4FixedRateOption); |
| |
| prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; |
| |
| } |
| |
| VOID nicTxSetPktLowestFixedRate(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo) |
| { |
| P_BSS_INFO_T prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); |
| P_STA_RECORD_T prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); |
| UINT_8 ucRateSwIndex, ucRateIndex, ucRatePreamble; |
| UINT_16 u2RateCode, u2RateCodeLimit, u2OperationalRateSet; |
| UINT_32 u4CurrentPhyRate, u4Status; |
| |
| /* Not to use TxD template for fixed rate */ |
| prMsduInfo->fgIsTXDTemplateValid = FALSE; |
| |
| /* Fixed Rate */ |
| prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; |
| |
| if (prStaRec) { |
| u2RateCode = prStaRec->u2HwDefaultFixedRateCode; |
| u2OperationalRateSet = prStaRec->u2OperationalRateSet; |
| } else { |
| u2RateCode = prBssInfo->u2HwDefaultFixedRateCode; |
| u2OperationalRateSet = prBssInfo->u2OperationalRateSet; |
| } |
| |
| /* CoexPhyRateLimit is 0 means phy rate is unlimited */ |
| if (prBssInfo->u4CoexPhyRateLimit != 0) { |
| |
| u4CurrentPhyRate = nicRateCode2PhyRate(u2RateCode, FIX_BW_NO_FIXED, MAC_GI_NORMAL, AR_SS_NULL); |
| |
| if (prBssInfo->u4CoexPhyRateLimit > u4CurrentPhyRate) { |
| nicGetRateIndexFromRateSetWithLimit( |
| u2OperationalRateSet, |
| prBssInfo->u4CoexPhyRateLimit, TRUE, &ucRateSwIndex); |
| |
| /* Convert SW rate index to rate code */ |
| nicSwIndex2RateIndex(ucRateSwIndex, &ucRateIndex, &ucRatePreamble); |
| u4Status = nicRateIndex2RateCode(ucRatePreamble, ucRateIndex, &u2RateCodeLimit); |
| if (u4Status == WLAN_STATUS_SUCCESS) { |
| /* Replace by limitation rate */ |
| u2RateCode = u2RateCodeLimit; |
| DBGLOG(NIC, INFO, "Coex RatePreamble=%d, R_SW_IDX:%d, R_CODE:0x%x\n", |
| ucRatePreamble, ucRateIndex, u2RateCode); |
| } |
| } |
| } |
| nicTxSetPktFixedRateOption(prMsduInfo, u2RateCode, FIX_BW_NO_FIXED, FALSE, FALSE); |
| } |
| |
| VOID nicTxSetPktMoreData(P_MSDU_INFO_T prCurrentMsduInfo, BOOLEAN fgSetMoreDataBit) |
| { |
| P_WLAN_MAC_HEADER_T prWlanMacHeader = NULL; |
| |
| if (prCurrentMsduInfo->fgIs802_11) { |
| prWlanMacHeader = |
| (P_WLAN_MAC_HEADER_T) (((PUINT_8) (prCurrentMsduInfo->prPacket)) + MAC_TX_RESERVED_FIELD); |
| } |
| |
| if (fgSetMoreDataBit) { |
| if (!prCurrentMsduInfo->fgIs802_11) |
| prCurrentMsduInfo->u4Option |= MSDU_OPT_MORE_DATA; |
| else |
| prWlanMacHeader->u2FrameCtrl |= MASK_FC_MORE_DATA; |
| } else { |
| if (!prCurrentMsduInfo->fgIs802_11) |
| prCurrentMsduInfo->u4Option &= ~MSDU_OPT_MORE_DATA; |
| else |
| prWlanMacHeader->u2FrameCtrl &= ~MASK_FC_MORE_DATA; |
| } |
| } |
| |
| UINT_8 nicTxAssignPID(IN P_ADAPTER_T prAdapter, IN UINT_8 ucWlanIndex) |
| { |
| UINT_8 ucRetval; |
| PUINT_8 pucPidPool; |
| |
| ASSERT(prAdapter); |
| |
| pucPidPool = &prAdapter->aucPidPool[ucWlanIndex]; |
| |
| ucRetval = *pucPidPool; |
| |
| /* Driver side Tx Sequence number: 1~127 */ |
| (*pucPidPool)++; |
| |
| if (*pucPidPool > NIC_TX_DESC_DRIVER_PID_MAX) |
| *pucPidPool = NIC_TX_DESC_DRIVER_PID_MIN; |
| |
| return ucRetval; |
| } |
| |
| VOID nicTxSetPktEOSP(P_MSDU_INFO_T prCurrentMsduInfo, BOOLEAN fgSetEOSPBit) |
| { |
| P_WLAN_MAC_HEADER_QOS_T prWlanMacHeader = NULL; |
| BOOLEAN fgWriteToDesc = TRUE; |
| |
| if (prCurrentMsduInfo->fgIs802_11) { |
| prWlanMacHeader = |
| (P_WLAN_MAC_HEADER_QOS_T) (((PUINT_8) (prCurrentMsduInfo->prPacket)) + MAC_TX_RESERVED_FIELD); |
| fgWriteToDesc = FALSE; |
| } |
| |
| if (fgSetEOSPBit) { |
| if (fgWriteToDesc) |
| prCurrentMsduInfo->u4Option |= MSDU_OPT_EOSP; |
| else |
| prWlanMacHeader->u2QosCtrl |= MASK_QC_EOSP; |
| } else { |
| if (fgWriteToDesc) |
| prCurrentMsduInfo->u4Option &= ~MSDU_OPT_EOSP; |
| else |
| prWlanMacHeader->u2QosCtrl &= ~MASK_QC_EOSP; |
| } |
| } |
| |
| WLAN_STATUS |
| nicTxDummyTxDone(IN P_ADAPTER_T prAdapter, IN P_MSDU_INFO_T prMsduInfo, IN ENUM_TX_RESULT_CODE_T rTxDoneStatus) |
| { |
| DBGLOG(TX, TRACE, "Msdu WIDX:PID[%u:%u] SEQ[%u] Tx Status[%u]\n", |
| prMsduInfo->ucWlanIndex, prMsduInfo->ucPID, prMsduInfo->ucTxSeqNum, rTxDoneStatus); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Update BSS Tx Params |
| * |
| * @param prStaRec The peer |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxUpdateBssDefaultRate(P_BSS_INFO_T prBssInfo) |
| { |
| UINT_8 ucLowestBasicRateIndex; |
| |
| prBssInfo->u2HwDefaultFixedRateCode = RATE_OFDM_6M; |
| |
| /* 4 <1> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ |
| if (rateGetLowestRateIndexFromRateSet(prBssInfo->u2BSSBasicRateSet, &ucLowestBasicRateIndex)) { |
| nicRateIndex2RateCode(PREAMBLE_DEFAULT_LONG_NONE, ucLowestBasicRateIndex, |
| &prBssInfo->u2HwDefaultFixedRateCode); |
| } else { |
| switch (prBssInfo->ucNonHTBasicPhyType) { |
| case PHY_TYPE_ERP_INDEX: |
| case PHY_TYPE_OFDM_INDEX: |
| prBssInfo->u2HwDefaultFixedRateCode = RATE_OFDM_6M; |
| break; |
| |
| default: |
| prBssInfo->u2HwDefaultFixedRateCode = RATE_CCK_1M_LONG; |
| break; |
| } |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /*! |
| * @brief Update StaRec Tx parameters |
| * |
| * @param prStaRec The peer |
| * |
| * @return (none) |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxUpdateStaRecDefaultRate(P_STA_RECORD_T prStaRec) |
| { |
| UINT_8 ucLowestBasicRateIndex; |
| |
| prStaRec->u2HwDefaultFixedRateCode = RATE_OFDM_6M; |
| |
| /* 4 <1> Find Lowest Basic Rate Index for default TX Rate of MMPDU */ |
| if (rateGetLowestRateIndexFromRateSet(prStaRec->u2BSSBasicRateSet, &ucLowestBasicRateIndex)) { |
| nicRateIndex2RateCode(PREAMBLE_DEFAULT_LONG_NONE, |
| ucLowestBasicRateIndex, &prStaRec->u2HwDefaultFixedRateCode); |
| } else { |
| if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11B) |
| prStaRec->u2HwDefaultFixedRateCode = RATE_CCK_1M_LONG; |
| else if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11G) |
| prStaRec->u2HwDefaultFixedRateCode = RATE_OFDM_6M; |
| else if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11A) |
| prStaRec->u2HwDefaultFixedRateCode = RATE_OFDM_6M; |
| else if (prStaRec->ucDesiredPhyTypeSet & PHY_TYPE_SET_802_11N) |
| prStaRec->u2HwDefaultFixedRateCode = RATE_MM_MCS_0; |
| } |
| } |
| |
| VOID nicTxCancelSendingCmd(IN P_ADAPTER_T prAdapter, IN P_CMD_INFO_T prCmdInfo) |
| { |
| halTxCancelSendingCmd(prAdapter, prCmdInfo); |
| } |
| |
| /* TX Direct functions : BEGIN */ |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is to start rTxDirectHifTimer to try to send out packets in |
| * rStaPsQueue[], rBssAbsentQueue[], rTxDirectHifQueue[]. |
| * |
| * \param[in] prAdapter Pointer of Adapter |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| VOID nicTxDirectStartCheckQTimer(IN P_ADAPTER_T prAdapter) |
| { |
| mod_timer(&prAdapter->rTxDirectHifTimer, jiffies + 1); |
| } |
| |
| VOID nicTxDirectClearSkbQ(IN P_ADAPTER_T prAdapter) |
| { |
| P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; |
| struct sk_buff *prSkb; |
| |
| while (TRUE) { |
| spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| prSkb = skb_dequeue(&prAdapter->rTxDirectSkbQueue); |
| spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| if (prSkb == NULL) |
| break; |
| |
| kalSendComplete(prGlueInfo, prSkb, WLAN_STATUS_NOT_ACCEPTED); |
| } |
| } |
| |
| VOID nicTxDirectClearHifQ(IN P_ADAPTER_T prAdapter) |
| { |
| P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; |
| UINT_8 ucHifTc = 0; |
| QUE_T rNeedToFreeQue; |
| P_QUE_T prNeedToFreeQue = &rNeedToFreeQue; |
| |
| QUEUE_INITIALIZE(prNeedToFreeQue); |
| |
| for (ucHifTc = 0; ucHifTc < TX_PORT_NUM; ucHifTc++) { |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rTxDirectHifQueue[ucHifTc])) { |
| spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| QUEUE_MOVE_ALL(prNeedToFreeQue, &prAdapter->rTxDirectHifQueue[ucHifTc]); |
| spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| |
| wlanProcessQueuedMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prNeedToFreeQue)); |
| } |
| } |
| } |
| |
| VOID nicTxDirectClearStaPsQ(IN P_ADAPTER_T prAdapter, UINT_8 ucStaRecIndex) |
| { |
| P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; |
| QUE_T rNeedToFreeQue; |
| P_QUE_T prNeedToFreeQue = &rNeedToFreeQue; |
| |
| QUEUE_INITIALIZE(prNeedToFreeQue); |
| |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rStaPsQueue[ucStaRecIndex])) { |
| spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| QUEUE_MOVE_ALL(prNeedToFreeQue, &prAdapter->rStaPsQueue[ucStaRecIndex]); |
| spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| |
| wlanProcessQueuedMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prNeedToFreeQue)); |
| } |
| } |
| |
| VOID nicTxDirectClearBssAbsentQ(IN P_ADAPTER_T prAdapter, UINT_8 ucBssIndex) |
| { |
| P_GLUE_INFO_T prGlueInfo = prAdapter->prGlueInfo; |
| QUE_T rNeedToFreeQue; |
| P_QUE_T prNeedToFreeQue = &rNeedToFreeQue; |
| |
| QUEUE_INITIALIZE(prNeedToFreeQue); |
| |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rBssAbsentQueue[ucBssIndex])) { |
| spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| QUEUE_MOVE_ALL(prNeedToFreeQue, &prAdapter->rBssAbsentQueue[ucBssIndex]); |
| spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| |
| wlanProcessQueuedMsduInfo(prAdapter, (P_MSDU_INFO_T) QUEUE_GET_HEAD(prNeedToFreeQue)); |
| } |
| } |
| |
| VOID nicTxDirectClearAllStaPsQ(IN P_ADAPTER_T prAdapter) |
| { |
| UINT_8 ucStaRecIndex; |
| UINT_32 u4StaPsBitmap; |
| |
| u4StaPsBitmap = prAdapter->u4StaPsBitmap; |
| if (!u4StaPsBitmap) |
| return; |
| |
| for (ucStaRecIndex = 0; ucStaRecIndex < CFG_STA_REC_NUM; ++ucStaRecIndex) { |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rStaPsQueue[ucStaRecIndex])) { |
| nicTxDirectClearStaPsQ(prAdapter, ucStaRecIndex); |
| u4StaPsBitmap &= ~BIT(ucStaRecIndex); |
| } |
| if (u4StaPsBitmap == 0) |
| break; |
| } |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is to check the StaRec is in Ps or not, |
| * and store MsduInfo(s) or sent MsduInfo(s) to the next stage respectively. |
| * |
| * \param[in] prAdapter Pointer of Adapter |
| * \param[in] ucStaRecIndex Indictate which StaRec to be checked |
| * \param[in] prQue Pointer of MsduInfo queue which to be processed |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| static VOID nicTxDirectCheckStaPsQ(IN P_ADAPTER_T prAdapter, UINT_8 ucStaRecIndex, P_QUE_T prQue) |
| { |
| P_STA_RECORD_T prStaRec; /* The current focused STA */ |
| P_MSDU_INFO_T prMsduInfo; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| BOOLEAN fgReturnStaPsQ = FALSE; |
| |
| if (ucStaRecIndex >= CFG_STA_REC_NUM) |
| return; |
| |
| prStaRec = cnmGetStaRecByIndex(prAdapter, ucStaRecIndex); |
| if (!prStaRec) { |
| DBGLOG(TX, WARN, "prStaRec is NULL!\n"); |
| return; |
| } |
| |
| QUEUE_CONCATENATE_QUEUES(&prAdapter->rStaPsQueue[ucStaRecIndex], prQue); |
| QUEUE_REMOVE_HEAD(&prAdapter->rStaPsQueue[ucStaRecIndex], prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| |
| if (prMsduInfo == NULL) { |
| DBGLOG(TX, INFO, "prMsduInfo empty\n"); |
| return; |
| } |
| |
| if (prStaRec->fgIsInPS) { |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| DBGLOG(TX, INFO, "fgIsInPS!\n"); |
| while (1) { |
| if (prStaRec->fgIsQoS && prStaRec->fgIsUapsdSupported && |
| (prStaRec->ucBmpTriggerAC & BIT(prMsduInfo->ucTC))) { |
| if (prStaRec->ucFreeQuotaForDelivery > 0) { |
| prStaRec->ucFreeQuotaForDelivery--; |
| QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo); |
| } else { |
| fgReturnStaPsQ = TRUE; |
| break; |
| } |
| } else { |
| if (prStaRec->ucFreeQuotaForNonDelivery > 0) { |
| prStaRec->ucFreeQuotaForNonDelivery--; |
| QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo); |
| } else { |
| fgReturnStaPsQ = TRUE; |
| break; |
| } |
| } |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rStaPsQueue[ucStaRecIndex])) { |
| QUEUE_REMOVE_HEAD(&prAdapter->rStaPsQueue[ucStaRecIndex], prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| } else { |
| break; |
| } |
| } |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| if (fgReturnStaPsQ) { |
| QUEUE_INSERT_HEAD(&prAdapter->rStaPsQueue[ucStaRecIndex], (P_QUE_ENTRY_T) prMsduInfo); |
| prAdapter->u4StaPsBitmap |= BIT(ucStaRecIndex); |
| return; |
| } |
| } else { |
| QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo); |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rStaPsQueue[ucStaRecIndex])) |
| QUEUE_CONCATENATE_QUEUES(prQue, &prAdapter->rStaPsQueue[ucStaRecIndex]); |
| } |
| prAdapter->u4StaPsBitmap &= ~BIT(ucStaRecIndex); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is to check the Bss is net absent or not, |
| * and store MsduInfo(s) or sent MsduInfo(s) to the next stage respectively. |
| * |
| * \param[in] prAdapter Pointer of Adapter |
| * \param[in] ucBssIndex Indictate which Bss to be checked |
| * \param[in] prQue Pointer of MsduInfo queue which to be processed |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| static VOID nicTxDirectCheckBssAbsentQ(IN P_ADAPTER_T prAdapter, UINT_8 ucBssIndex, P_QUE_T prQue) |
| { |
| P_BSS_INFO_T prBssInfo; |
| P_MSDU_INFO_T prMsduInfo; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| BOOLEAN fgReturnBssAbsentQ = FALSE; |
| |
| prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, ucBssIndex); |
| |
| QUEUE_CONCATENATE_QUEUES(&prAdapter->rBssAbsentQueue[ucBssIndex], prQue); |
| QUEUE_REMOVE_HEAD(&prAdapter->rBssAbsentQueue[ucBssIndex], prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| |
| if (prMsduInfo == NULL) { |
| DBGLOG(TX, INFO, "prMsduInfo empty\n"); |
| return; |
| } |
| |
| if (prBssInfo->fgIsNetAbsent) { |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| DBGLOG(TX, INFO, "fgIsNetAbsent!\n"); |
| while (1) { |
| if (prBssInfo->ucBssFreeQuota > 0) { |
| prBssInfo->ucBssFreeQuota--; |
| QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo); |
| DBGLOG(TX, INFO, "fgIsNetAbsent Quota Availalbe\n"); |
| } else { |
| fgReturnBssAbsentQ = TRUE; |
| DBGLOG(TX, INFO, "fgIsNetAbsent NoQuota\n"); |
| break; |
| } |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rBssAbsentQueue[ucBssIndex])) { |
| QUEUE_REMOVE_HEAD(&prAdapter->rBssAbsentQueue[ucBssIndex], |
| prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| } else { |
| break; |
| } |
| } |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TX_RESOURCE); |
| if (fgReturnBssAbsentQ) { |
| QUEUE_INSERT_HEAD(&prAdapter->rBssAbsentQueue[ucBssIndex], (P_QUE_ENTRY_T) prMsduInfo); |
| prAdapter->u4BssAbsentBitmap |= BIT(ucBssIndex); |
| return; |
| } |
| } else { |
| if (prAdapter->u4BssAbsentBitmap) |
| DBGLOG(TX, INFO, "fgIsNetAbsent END!\n"); |
| QUEUE_INSERT_TAIL(prQue, (P_QUE_ENTRY_T) prMsduInfo); |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rBssAbsentQueue[prMsduInfo->ucStaRecIndex])) |
| QUEUE_CONCATENATE_QUEUES(prQue, &prAdapter->rBssAbsentQueue[ucBssIndex]); |
| } |
| prAdapter->u4BssAbsentBitmap &= ~BIT(ucBssIndex); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief Get Tc for hif port mapping. |
| * |
| * \param[in] prMsduInfo Pointer of the MsduInfo |
| * |
| * \retval Tc which maps to hif port. |
| */ |
| /*----------------------------------------------------------------------------*/ |
| static UINT_8 nicTxDirectGetHifTc(P_MSDU_INFO_T prMsduInfo) |
| { |
| UINT_8 ucHifTc = 0; |
| |
| if (prMsduInfo->ucWmmQueSet != DBDC_5G_WMM_INDEX) { |
| ucHifTc = TX_2G_WMM_PORT_NUM; |
| } else { |
| if (prMsduInfo->ucTC >= 0 && prMsduInfo->ucTC < TC_NUM) |
| ucHifTc = prMsduInfo->ucTC; |
| else |
| ASSERT(0); |
| } |
| return ucHifTc; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is called by nicTxDirectStartXmit() and nicTxDirectTimerCheckHifQ(). |
| * It is the main function to send skb out on HIF bus. |
| * |
| * \param[in] prSkb Pointer of the sk_buff to be sent |
| * \param[in] prMsduInfo Pointer of the MsduInfo |
| * \param[in] prAdapter Pointer of Adapter |
| * \param[in] ucCheckTc Indictate which Tc HifQ to be checked |
| * \param[in] ucStaRecIndex Indictate which StaPsQ to be checked |
| * \param[in] ucBssIndex Indictate which BssAbsentQ to be checked |
| * |
| * \retval WLAN_STATUS |
| */ |
| /*----------------------------------------------------------------------------*/ |
| static WLAN_STATUS nicTxDirectStartXmitMain(struct sk_buff *prSkb, P_MSDU_INFO_T prMsduInfo, P_ADAPTER_T prAdapter, |
| UINT_8 ucCheckTc, UINT_8 ucStaRecIndex, UINT_8 ucBssIndex) |
| { |
| P_STA_RECORD_T prStaRec; /* The current focused STA */ |
| P_BSS_INFO_T prBssInfo; |
| UINT_8 ucTC = 0, ucHifTc = 0; |
| P_QUE_T prTxQue; |
| BOOLEAN fgDropPacket = FALSE; |
| P_QUE_ENTRY_T prQueueEntry = (P_QUE_ENTRY_T) NULL; |
| QUE_T rProcessingQue; |
| P_QUE_T prProcessingQue = &rProcessingQue; |
| |
| QUEUE_INITIALIZE(prProcessingQue); |
| |
| if (prSkb) { |
| nicTxFillMsduInfo(prAdapter, prMsduInfo, prSkb); |
| |
| /* Tx profiling */ |
| wlanTxProfilingTagMsdu(prAdapter, prMsduInfo, TX_PROF_TAG_DRV_ENQUE); |
| |
| prBssInfo = GET_BSS_INFO_BY_INDEX(prAdapter, prMsduInfo->ucBssIndex); |
| |
| if (!prBssInfo) { |
| /* No BSS_INFO */ |
| fgDropPacket = TRUE; |
| } else if (IS_BSS_ACTIVE(prBssInfo)) { |
| /* BSS active */ |
| fgDropPacket = FALSE; |
| } else { |
| /* BSS inactive */ |
| fgDropPacket = TRUE; |
| } |
| |
| if (fgDropPacket) { |
| DBGLOG(QM, TRACE, "Drop the Packet for inactive Bss %u\n", prMsduInfo->ucBssIndex); |
| QM_DBG_CNT_INC(prQM, QM_DBG_CNT_31); |
| TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_BSS_DROP); |
| |
| wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); |
| return WLAN_STATUS_FAILURE; |
| } |
| |
| qmDetermineStaRecIndex(prAdapter, prMsduInfo); |
| |
| wlanUpdateTxStatistics(prAdapter, prMsduInfo, FALSE); /*get per-AC Tx packets */ |
| |
| switch (prMsduInfo->ucStaRecIndex) { |
| case STA_REC_INDEX_BMCAST: |
| ucTC = arNetwork2TcResource[prMsduInfo->ucBssIndex][NET_TC_BMC_INDEX]; |
| |
| /* Always set BMC packet retry limit to unlimited */ |
| if (!(prMsduInfo->u4Option & MSDU_OPT_MANUAL_RETRY_LIMIT)) |
| nicTxSetPktRetryLimit(prMsduInfo, TX_DESC_TX_COUNT_NO_LIMIT); |
| |
| QM_DBG_CNT_INC(prQM, QM_DBG_CNT_23); |
| break; |
| case STA_REC_INDEX_NOT_FOUND: |
| /* Drop packet if no STA_REC is found */ |
| DBGLOG(QM, TRACE, "Drop the Packet for no STA_REC\n"); |
| |
| TX_INC_CNT(&prAdapter->rTxCtrl, TX_INACTIVE_STA_DROP); |
| QM_DBG_CNT_INC(prQM, QM_DBG_CNT_24); |
| wlanProcessQueuedMsduInfo(prAdapter, prMsduInfo); |
| return WLAN_STATUS_FAILURE; |
| default: |
| prTxQue = qmDetermineStaTxQueue(prAdapter, prMsduInfo, &ucTC); |
| break; /*default */ |
| } /* switch (prMsduInfo->ucStaRecIndex) */ |
| |
| prMsduInfo->ucTC = ucTC; |
| prMsduInfo->ucWmmQueSet = prBssInfo->ucWmmQueSet; /* to record WMM Set */ |
| |
| /* Check the Tx descriptor template is valid */ |
| qmSetTxPacketDescTemplate(prAdapter, prMsduInfo); |
| |
| /* Set Tx rate */ |
| switch (prAdapter->rWifiVar.ucDataTxRateMode) { |
| case DATA_RATE_MODE_BSS_LOWEST: |
| nicTxSetPktLowestFixedRate(prAdapter, prMsduInfo); |
| break; |
| |
| case DATA_RATE_MODE_MANUAL: |
| prMsduInfo->u4FixedRateOption = prAdapter->rWifiVar.u4DataTxRateCode; |
| |
| prMsduInfo->ucRateMode = MSDU_RATE_MODE_MANUAL_DESC; |
| break; |
| |
| case DATA_RATE_MODE_AUTO: |
| default: |
| if (prMsduInfo->ucRateMode == MSDU_RATE_MODE_LOWEST_RATE) |
| nicTxSetPktLowestFixedRate(prAdapter, prMsduInfo); |
| break; |
| } |
| |
| nicTxFillDataDesc(prAdapter, prMsduInfo); |
| |
| prStaRec = cnmGetStaRecByIndex(prAdapter, prMsduInfo->ucStaRecIndex); |
| |
| QUEUE_INSERT_TAIL(prProcessingQue, (P_QUE_ENTRY_T) prMsduInfo); |
| |
| /* Power-save STA handling */ |
| nicTxDirectCheckStaPsQ(prAdapter, prMsduInfo->ucStaRecIndex, prProcessingQue); |
| |
| /* Absent BSS handling */ |
| nicTxDirectCheckBssAbsentQ(prAdapter, prMsduInfo->ucBssIndex, prProcessingQue); |
| |
| if (QUEUE_IS_EMPTY(prProcessingQue)) |
| return WLAN_STATUS_SUCCESS; |
| |
| if (prProcessingQue->u4NumElem != 1) { |
| while (1) { |
| QUEUE_REMOVE_HEAD(prProcessingQue, prQueueEntry, P_QUE_ENTRY_T); |
| if (prQueueEntry == NULL) |
| break; |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| ucHifTc = nicTxDirectGetHifTc(prMsduInfo); |
| QUEUE_INSERT_TAIL(&prAdapter->rTxDirectHifQueue[ucHifTc], (P_QUE_ENTRY_T) prMsduInfo); |
| } |
| nicTxDirectStartCheckQTimer(prAdapter); |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| QUEUE_REMOVE_HEAD(prProcessingQue, prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| ucHifTc = nicTxDirectGetHifTc(prMsduInfo); |
| |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rTxDirectHifQueue[ucHifTc])) { |
| QUEUE_INSERT_TAIL(&prAdapter->rTxDirectHifQueue[ucHifTc], (P_QUE_ENTRY_T) prMsduInfo); |
| QUEUE_REMOVE_HEAD(&prAdapter->rTxDirectHifQueue[ucHifTc], prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| } |
| } else { |
| if (ucStaRecIndex != 0xff || ucBssIndex != 0xff) { |
| /* Power-save STA handling */ |
| if (ucStaRecIndex != 0xff) |
| nicTxDirectCheckStaPsQ(prAdapter, ucStaRecIndex, prProcessingQue); |
| |
| /* Absent BSS handling */ |
| if (ucBssIndex != 0xff) |
| nicTxDirectCheckBssAbsentQ(prAdapter, ucBssIndex, prProcessingQue); |
| |
| if (QUEUE_IS_EMPTY(prProcessingQue)) |
| return WLAN_STATUS_SUCCESS; |
| |
| if (prProcessingQue->u4NumElem != 1) { |
| while (1) { |
| QUEUE_REMOVE_HEAD(prProcessingQue, prQueueEntry, P_QUE_ENTRY_T); |
| if (prQueueEntry == NULL) |
| break; |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| ucHifTc = nicTxDirectGetHifTc(prMsduInfo); |
| QUEUE_INSERT_TAIL(&prAdapter->rTxDirectHifQueue[ucHifTc], |
| (P_QUE_ENTRY_T) prMsduInfo); |
| } |
| nicTxDirectStartCheckQTimer(prAdapter); |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| QUEUE_REMOVE_HEAD(prProcessingQue, prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| ucHifTc = nicTxDirectGetHifTc(prMsduInfo); |
| } else { |
| if (ucCheckTc != 0xff) |
| ucHifTc = ucCheckTc; |
| |
| if (QUEUE_IS_EMPTY(&prAdapter->rTxDirectHifQueue[ucHifTc])) { |
| DBGLOG(TX, INFO, "ERROR: no rTxDirectHifQueue (%u)\n", ucHifTc); |
| return WLAN_STATUS_FAILURE; |
| } |
| QUEUE_REMOVE_HEAD(&prAdapter->rTxDirectHifQueue[ucHifTc], prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| } |
| } |
| |
| while (1) { |
| if (!halTxIsDataBufEnough(prAdapter, prMsduInfo)) { |
| QUEUE_INSERT_HEAD(&prAdapter->rTxDirectHifQueue[ucHifTc], |
| (P_QUE_ENTRY_T) prMsduInfo); |
| mod_timer(&prAdapter->rTxDirectHifTimer, jiffies + TX_DIRECT_CHECK_INTERVAL); |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| if (prMsduInfo->pfTxDoneHandler) { |
| KAL_SPIN_LOCK_DECLARATION(); |
| |
| /* Record native packet pointer for Tx done log */ |
| WLAN_GET_FIELD_32(&prMsduInfo->prPacket, &prMsduInfo->u4TxDoneTag); |
| |
| KAL_ACQUIRE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| QUEUE_INSERT_TAIL(&(prAdapter->rTxCtrl.rTxMgmtTxingQueue), (P_QUE_ENTRY_T) prMsduInfo); |
| KAL_RELEASE_SPIN_LOCK(prAdapter, SPIN_LOCK_TXING_MGMT_LIST); |
| } |
| HAL_WRITE_TX_DATA(prAdapter, prMsduInfo); |
| |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rTxDirectHifQueue[ucHifTc])) { |
| QUEUE_REMOVE_HEAD(&prAdapter->rTxDirectHifQueue[ucHifTc], prQueueEntry, P_QUE_ENTRY_T); |
| prMsduInfo = (P_MSDU_INFO_T) prQueueEntry; |
| } else { |
| break; |
| } |
| } |
| |
| return WLAN_STATUS_SUCCESS; |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is the timeout function of timer rTxDirectSkbTimer. |
| * The purpose is to check if rTxDirectSkbQueue has any skb to be sent. |
| * |
| * \param[in] data Pointer of GlueInfo |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| void nicTxDirectTimerCheckSkbQ(unsigned long data) |
| { |
| P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)data; |
| P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; |
| |
| if (skb_queue_len(&prAdapter->rTxDirectSkbQueue)) |
| nicTxDirectStartXmit(NULL, prGlueInfo); |
| else |
| DBGLOG(TX, INFO, "fgHasNoMsdu FALSE\n"); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is the timeout function of timer rTxDirectHifTimer. |
| * The purpose is to check if rStaPsQueue, rBssAbsentQueue, and rTxDirectHifQueue has any MsduInfo to be sent. |
| * |
| * \param[in] data Pointer of GlueInfo |
| * |
| * \retval none |
| */ |
| /*----------------------------------------------------------------------------*/ |
| void nicTxDirectTimerCheckHifQ(unsigned long data) |
| { |
| P_GLUE_INFO_T prGlueInfo = (P_GLUE_INFO_T)data; |
| P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; |
| UINT_8 ucHifTc = 0; |
| UINT_32 u4StaPsBitmap, u4BssAbsentBitmap; |
| UINT_8 ucStaRecIndex, ucBssIndex; |
| |
| spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| |
| u4StaPsBitmap = prAdapter->u4StaPsBitmap; |
| u4BssAbsentBitmap = prAdapter->u4BssAbsentBitmap; |
| |
| if (u4StaPsBitmap) |
| for (ucStaRecIndex = 0; ucStaRecIndex < CFG_STA_REC_NUM; ++ucStaRecIndex) { |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rStaPsQueue[ucStaRecIndex])) { |
| nicTxDirectStartXmitMain(NULL, NULL, prAdapter, 0xff, ucStaRecIndex, 0xff); |
| u4StaPsBitmap &= ~BIT(ucStaRecIndex); |
| DBGLOG(TX, INFO, "ucStaRecIndex: %u\n", ucStaRecIndex); |
| } |
| if (u4StaPsBitmap == 0) |
| break; |
| } |
| |
| if (u4BssAbsentBitmap) |
| for (ucBssIndex = 0; ucBssIndex < HW_BSSID_NUM + 1; ++ucBssIndex) { |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rBssAbsentQueue[ucBssIndex])) { |
| nicTxDirectStartXmitMain(NULL, NULL, prAdapter, 0xff, 0xff, ucBssIndex); |
| u4BssAbsentBitmap &= ~BIT(ucBssIndex); |
| DBGLOG(TX, INFO, "ucBssIndex: %u\n", ucBssIndex); |
| } |
| if (u4BssAbsentBitmap == 0) |
| break; |
| } |
| |
| |
| for (ucHifTc = 0; ucHifTc < TX_PORT_NUM; ucHifTc++) |
| if (QUEUE_IS_NOT_EMPTY(&prAdapter->rTxDirectHifQueue[ucHifTc])) |
| nicTxDirectStartXmitMain(NULL, NULL, prAdapter, ucHifTc, 0xff, 0xff); |
| |
| spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| } |
| |
| /*----------------------------------------------------------------------------*/ |
| /* |
| * \brief This function is have to called by kalHardStartXmit(). The purpose is |
| * to let as many as possible TX processing in softirq instead of in |
| * kernel thread to reduce TX CPU usage. |
| * NOTE: Currently only USB interface can use this function. |
| * |
| * \param[in] prSkb Pointer of the sk_buff to be sent |
| * \param[in] prGlueInfo Pointer of prGlueInfo |
| * |
| * \retval WLAN_STATUS |
| */ |
| /*----------------------------------------------------------------------------*/ |
| WLAN_STATUS nicTxDirectStartXmit(struct sk_buff *prSkb, P_GLUE_INFO_T prGlueInfo) |
| { |
| P_ADAPTER_T prAdapter = prGlueInfo->prAdapter; |
| P_MSDU_INFO_T prMsduInfo; |
| WLAN_STATUS ret = WLAN_STATUS_SUCCESS; |
| |
| spin_lock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| |
| if (prSkb) { |
| prMsduInfo = cnmPktAlloc(prAdapter, 0); |
| |
| if (prMsduInfo == NULL) { |
| DBGLOG(TX, INFO, "cnmPktAlloc NULL\n"); |
| skb_queue_tail(&prAdapter->rTxDirectSkbQueue, prSkb); |
| |
| ret = WLAN_STATUS_SUCCESS; |
| goto end; |
| } |
| if (skb_queue_len(&prAdapter->rTxDirectSkbQueue)) { |
| skb_queue_tail(&prAdapter->rTxDirectSkbQueue, prSkb); |
| prSkb = skb_dequeue(&prAdapter->rTxDirectSkbQueue); |
| } |
| } else { |
| prMsduInfo = cnmPktAlloc(prAdapter, 0); |
| if (prMsduInfo != NULL) { |
| prSkb = skb_dequeue(&prAdapter->rTxDirectSkbQueue); |
| if (prSkb == NULL) { |
| DBGLOG(TX, INFO, "ERROR: no rTxDirectSkbQueue\n"); |
| nicTxReturnMsduInfo(prAdapter, prMsduInfo); |
| ret = WLAN_STATUS_FAILURE; |
| goto end; |
| } |
| } else { |
| ret = WLAN_STATUS_FAILURE; |
| goto end; |
| } |
| } |
| |
| while (1) { |
| nicTxDirectStartXmitMain(prSkb, prMsduInfo, prAdapter, 0xff, 0xff, 0xff); |
| prSkb = skb_dequeue(&prAdapter->rTxDirectSkbQueue); |
| if (prSkb != NULL) { |
| prMsduInfo = cnmPktAlloc(prAdapter, 0); |
| if (prMsduInfo == NULL) { |
| skb_queue_head(&prAdapter->rTxDirectSkbQueue, prSkb); |
| break; |
| } |
| } else { |
| break; |
| } |
| } |
| |
| end: |
| if (skb_queue_len(&prAdapter->rTxDirectSkbQueue)) |
| mod_timer(&prAdapter->rTxDirectSkbTimer, jiffies + TX_DIRECT_CHECK_INTERVAL); |
| spin_unlock_bh(&prGlueInfo->rSpinLock[SPIN_LOCK_TX_DIRECT]); |
| return ret; |
| } |
| /* TX Direct functions : END */ |