| /* |
| * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| /* |
| * Copyright (c) 2012, The Linux Foundation. All rights reserved. |
| * |
| * Previously licensed under the ISC license by Qualcomm Atheros, Inc. |
| * |
| * |
| * Permission to use, copy, modify, and/or distribute this software for |
| * any purpose with or without fee is hereby granted, provided that the |
| * above copyright notice and this permission notice appear in all |
| * copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| * PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| /**========================================================================= |
| * |
| * \file wlan_qct_wdi_dts.c |
| * |
| * \brief Data Transport Service API |
| * |
| * WLAN Device Abstraction layer External API for Dataservice |
| * DESCRIPTION |
| * This file contains the external API implemntation exposed by the |
| * wlan device abstarction layer module. |
| * |
| * Copyright (c) 2008 QUALCOMM Incorporated. All Rights Reserved. |
| * Qualcomm Confidential and Proprietary |
| */ |
| |
| |
| #include "wlan_qct_wdi.h" |
| #include "wlan_qct_dxe.h" |
| #include "wlan_qct_wdi_ds.h" |
| #include "wlan_qct_wdi_ds_i.h" |
| #include "wlan_qct_wdi_dts.h" |
| #include "wlan_qct_wdi_dp.h" |
| #include "wlan_qct_wdi_sta.h" |
| |
| static WDTS_TransportDriverTrype gTransportDriver = { |
| WLANDXE_Open, |
| WLANDXE_Start, |
| WLANDXE_ClientRegistration, |
| WLANDXE_TxFrame, |
| WLANDXE_CompleteTX, |
| WLANDXE_SetPowerState, |
| WLANDXE_ChannelDebug, |
| WLANDXE_Stop, |
| WLANDXE_Close, |
| WLANDXE_GetFreeTxDataResNumber |
| }; |
| |
| static WDTS_SetPowerStateCbInfoType gSetPowerStateCbInfo; |
| |
| typedef struct |
| { |
| uint32 phyRate; //unit in Mega bits per sec X 10 |
| uint32 tputRate; //unit in Mega bits per sec X 10 |
| uint32 tputBpms; //unit in Bytes per msec = (tputRateX1024x1024)/(8x10X1000) ~= (tputRate*13) |
| float tputBpus; //unit in Bytes per usec |
| }WDTS_RateInfo; |
| |
| #define WDTS_MAX_RATE_NUM 137 |
| |
| WDTS_RateInfo gRateInfo[WDTS_MAX_RATE_NUM] = { |
| //11b rates |
| { 10, 9, 117, 0.12}, //index 0 |
| { 20, 17, 221, 0.22}, //index 1 |
| { 55, 41, 533, 0.53}, //index 2 |
| { 110, 68, 884, 0.88}, //index 3 |
| |
| //11b short preamble |
| { 10, 10, 130, 0.13}, //index 4 |
| { 20, 18, 234, 0.23}, //index 5 |
| { 55, 44, 572, 0.57}, //index 6 |
| { 110, 77, 1001, 1.00}, //index 7 |
| |
| //11ag |
| { 60, 50, 650, 0.65}, //index 8 |
| { 90, 70, 910, 0.91}, //index 9 |
| { 120, 100, 1300, 1.30}, //index 10 |
| { 180, 150, 1950, 1.95}, //index 11 |
| { 240, 190, 2470, 2.47}, //index 12 |
| { 360, 280, 3640, 3.64}, //index 13 |
| { 480, 350, 4550, 4.55}, //index 14 |
| { 540, 380, 4940, 4.94}, //index 15 |
| |
| //11n SIMO |
| { 65, 54, 702, 0.70}, //index 16 |
| { 130, 108, 1404, 1.40}, //index 17 |
| { 195, 161, 2093, 2.09}, //index 18 |
| { 260, 217, 2821, 2.82}, //index 19 |
| { 390, 326, 4238, 4.24}, //index 20 |
| { 520, 435, 5655, 5.66}, //index 21 |
| { 585, 492, 6396, 6.40}, //index 22 |
| { 650, 548, 7124, 7.12}, //index 23 |
| |
| //11n SIMO SGI |
| { 72, 59, 767, 0.77}, //index 24 |
| { 144, 118, 1534, 1.53}, //index 25 |
| { 217, 180, 2340, 2.34}, //index 26 |
| { 289, 243, 3159, 3.16}, //index 27 |
| { 434, 363, 4719, 4.72}, //index 28 |
| { 578, 486, 6318, 6.32}, //index 29 |
| { 650, 548, 7124, 7.12}, //index 30 |
| { 722, 606, 7878, 7.88}, //index 31 |
| |
| //11n GF SIMO |
| { 65, 54, 702, 0.70}, //index 32 |
| { 130, 108, 1404, 1.40}, //index 33 |
| { 195, 161, 2093, 2.09}, //index 34 |
| { 260, 217, 2821, 2.82}, //index 35 |
| { 390, 326, 4238, 4.23}, //index 36 |
| { 520, 435, 5655, 5.66}, //index 37 |
| { 585, 492, 6396, 6.40}, //index 38 |
| { 650, 548, 7124, 7.12}, //index 39 |
| |
| //11n SIMO CB MCS 0 - 7 |
| { 135, 110, 1430, 1.43}, //index 40 |
| { 270, 223, 2899, 2.90}, //index 41 |
| { 405, 337, 4381, 4.38}, //index 42 |
| { 540, 454, 5902, 5.90}, //index 43 |
| { 810, 679, 8827, 8.83}, //index 44 |
| { 1080, 909, 11817, 11.81}, //index 45 |
| { 1215, 1022, 13286, 13.29}, //index 46 |
| { 1350, 1137, 14781, 14.78}, //index 47 |
| |
| //11n SIMO CB SGI MCS 0 - 7 |
| { 150, 121, 1573, 1.57}, //index 48 |
| { 300, 249, 3237, 3.24}, //index 49 |
| { 450, 378, 4914, 4.91}, //index 50 |
| { 600, 503, 6539, 6.54}, //index 51 |
| { 900, 758, 9854, 9.85}, //index 52 |
| { 1200, 1010, 13130, 13.13}, //index 53 |
| { 1350, 1137, 14781, 14.78}, //index 54 |
| { 1500, 1262, 16406, 16.41}, //index 55 |
| |
| //11n SIMO GF CB MCS 0 - 7 |
| { 135, 110, 1430, 1.43}, //index 56 |
| { 270, 223, 2899, 2.90}, //index 57 |
| { 405, 337, 4381, 4.38}, //index 58 |
| { 540, 454, 5902, 5.90}, //index 59 |
| { 810, 679, 8827, 8.83}, //index 60 |
| { 1080, 909, 11817, 11.81}, //index 61 |
| { 1215, 1022, 13286, 13.29}, //index 62 |
| { 1350, 1137, 14781, 14.79}, //index 63 |
| |
| //11AC |
| { 1350, 1137, 14781, 14.78}, //reserved 64 |
| { 1350, 1137, 14781, 14.78}, //reserved 65 |
| { 65, 65, 845, 0.85}, //index 66 |
| { 130, 130, 1690, 1.69}, //index 67 |
| { 195, 195, 2535, 2.54}, //index 68 |
| { 260, 260, 3380, 3.38}, //index 69 |
| { 390, 390, 5070, 5.07}, //index 70 |
| { 520, 520, 6760, 6.76}, //index 71 |
| { 585, 585, 7605, 7.61}, //index 72 |
| { 650, 650, 8450, 8.45}, //index 73 |
| { 780, 780, 2340, 2.34}, //index 74 |
| { 1350, 1137, 14781, 14.78}, //reserved 75 |
| { 1350, 1137, 14781, 14.78}, //reserved 76 |
| { 1350, 1137, 14781, 14.78}, //reserved 77 |
| { 1350, 1137, 14781, 14.78}, //index 78 |
| { 1350, 1137, 14781, 14.78}, //index 79 |
| { 1350, 1137, 14781, 14.78}, //index 80 |
| { 1350, 1137, 14781, 14.78}, //index 81 |
| { 1350, 1137, 14781, 14.78}, //index 82 |
| { 1350, 1137, 14781, 14.78}, //index 83 |
| { 655, 655, 8515, 8.52}, //index 84 |
| { 722, 722, 9386, 9.39}, //index 85 |
| { 866, 866, 11258, 11.26}, //index 86 |
| { 1350, 1137, 14781, 14.78}, //reserved 87 |
| { 1350, 1137, 14781, 14.78}, //reserved 88 |
| { 1350, 1137, 14781, 14.78}, //reserved 89 |
| { 135, 135, 1755, 1.76}, //index 90 |
| { 270, 270, 3510, 3.51}, //index 91 |
| { 405, 405, 5265, 5.27}, //index 92 |
| { 540, 540, 7020, 7.02}, //index 93 |
| { 810, 810, 10530, 10.53}, //index 94 |
| { 1080, 1080, 14040, 14.04}, //index 95 |
| { 1215, 1215, 15795, 15.80}, //index 96 |
| { 1350, 1350, 17550, 17.55}, //index 97 |
| { 1350, 1137, 14781, 14.78}, //index 98 |
| { 1620, 1620, 21060, 21.06}, //index 99 |
| { 1800, 1800, 23400, 23.40}, //index 100 |
| { 1350, 1137, 14781, 14.78}, //reserved 101 |
| { 1350, 1137, 14781, 14.78}, //index 102 |
| { 1350, 1137, 14781, 14.78}, //index 103 |
| { 1350, 1137, 14781, 14.78}, //index 104 |
| { 1350, 1137, 14781, 14.78}, //index 105 |
| { 1350, 1137, 14781, 14.78}, //index 106 |
| { 1200, 1200, 15600, 15.60}, //index 107 |
| { 1350, 1350, 17550, 17.55}, //index 108 |
| { 1500, 1500, 19500, 19.50}, //index 109 |
| { 1350, 1137, 14781, 14.78}, //index 110 |
| { 1800, 1800, 23400, 23.40}, //index 111 |
| { 2000, 2000, 26000, 26.00}, //index 112 |
| { 1350, 1137, 14781, 14.78}, //index 113 |
| { 292, 292, 3796, 3.80}, //index 114 |
| { 585, 585, 7605, 7.61}, //index 115 |
| { 877, 877, 11401, 11.40}, //index 116 |
| { 1170, 1170, 15210, 15.21}, //index 117 |
| { 1755, 1755, 22815, 22.82}, //index 118 |
| { 2340, 2340, 30420, 30.42}, //index 119 |
| { 2632, 2632, 34216, 34.22}, //index 120 |
| { 2925, 2925, 38025, 38.03}, //index 121 |
| { 1350, 1137, 14781, 14.78}, //index 122 |
| { 3510, 3510, 45630, 45.63}, //index 123 |
| { 3900, 3900, 50700, 50.70}, //index 124 |
| { 1350, 1137, 14781, 14.78}, //reserved 125 |
| { 1350, 1137, 14781, 14.78}, //index 126 |
| { 1350, 1137, 14781, 14.78}, //index 127 |
| { 1350, 1137, 14781, 14.78}, //index 128 |
| { 1350, 1137, 14781, 14.78}, //index 129 |
| { 1350, 1137, 14781, 14.78}, //index 130 |
| { 1350, 1137, 14781, 14.78}, //index 131 |
| { 2925, 2925, 38025, 38.03}, //index 132 |
| { 3250, 3250, 42250, 42.25}, //index 133 |
| { 1350, 1137, 14781, 14.78}, //index 134 |
| { 3900, 3900, 50700, 50.70}, //index 135 |
| { 4333, 4333, 56329, 56.33} //index 136 |
| }; |
| |
| /* TX stats */ |
| typedef struct |
| { |
| wpt_uint32 txBytesPushed; |
| wpt_uint32 txPacketsPushed; //Can be removed to optimize memory |
| }WDI_DTS_TX_TrafficStatsType; |
| |
| /* RX stats */ |
| typedef struct |
| { |
| wpt_uint32 rxBytesRcvd; |
| wpt_uint32 rxPacketsRcvd; //Can be removed to optimize memory |
| }WDI_DTS_RX_TrafficStatsType; |
| |
| typedef struct { |
| wpt_uint8 running; |
| WDI_DTS_RX_TrafficStatsType rxStats[HAL_NUM_STA][WDTS_MAX_RATE_NUM]; |
| WDI_DTS_TX_TrafficStatsType txStats[HAL_NUM_STA]; |
| WDI_TrafficStatsType netTxRxStats[HAL_NUM_STA]; |
| }WDI_DTS_TrafficStatsType; |
| |
| static WDI_DTS_TrafficStatsType gDsTrafficStats; |
| |
| #define DTS_RATE_TPUT(x) gRateInfo[x].tputBpms |
| |
| /* Tx/Rx stats function |
| * This function should be invoked to fetch the current stats |
| * Parameters: |
| * pStats:Pointer to the collected stats |
| * len: length of buffer pointed to by pStats |
| * Return Status: None |
| */ |
| void WDTS_GetTrafficStats(WDI_TrafficStatsType** pStats, wpt_uint32 *len) |
| { |
| if(gDsTrafficStats.running) |
| { |
| uint8 staIdx, rate; |
| WDI_TrafficStatsType *pNetTxRxStats = gDsTrafficStats.netTxRxStats; |
| wpalMemoryZero(pNetTxRxStats, sizeof(gDsTrafficStats.netTxRxStats)); |
| |
| for(staIdx = 0; staIdx < HAL_NUM_STA; staIdx++, pNetTxRxStats++) |
| { |
| pNetTxRxStats->txBytesPushed += gDsTrafficStats.txStats[staIdx].txBytesPushed; |
| pNetTxRxStats->txPacketsPushed+= gDsTrafficStats.txStats[staIdx].txPacketsPushed; |
| for (rate = 0; rate < WDTS_MAX_RATE_NUM; rate++) |
| { |
| pNetTxRxStats->rxBytesRcvd += |
| gDsTrafficStats.rxStats[staIdx][rate].rxBytesRcvd; |
| pNetTxRxStats->rxPacketsRcvd += |
| gDsTrafficStats.rxStats[staIdx][rate].rxPacketsRcvd; |
| pNetTxRxStats->rxTimeTotal += |
| gDsTrafficStats.rxStats[staIdx][rate].rxPacketsRcvd/DTS_RATE_TPUT(rate); |
| } |
| } |
| *pStats = gDsTrafficStats.netTxRxStats; |
| *len = sizeof(gDsTrafficStats.netTxRxStats); |
| } |
| else |
| { |
| *pStats = NULL; |
| *len = 0; |
| } |
| } |
| |
| /* WDTS_DeactivateTrafficStats |
| * This function should be invoked to deactivate traffic stats collection |
| * Parameters: None |
| * Return Status: None |
| */ |
| void WDTS_DeactivateTrafficStats(void) |
| { |
| gDsTrafficStats.running = eWLAN_PAL_FALSE; |
| } |
| |
| /* WDTS_ActivateTrafficStats |
| * This function should be invoked to activate traffic stats collection |
| * Parameters: None |
| * Return Status: None |
| */ |
| void WDTS_ActivateTrafficStats(void) |
| { |
| gDsTrafficStats.running = eWLAN_PAL_TRUE; |
| } |
| |
| /* WDTS_ClearTrafficStats |
| * This function should be invoked to clear traffic stats |
| * Parameters: None |
| * Return Status: None |
| */ |
| void WDTS_ClearTrafficStats(void) |
| { |
| wpalMemoryZero(gDsTrafficStats.rxStats, sizeof(gDsTrafficStats.rxStats)); |
| wpalMemoryZero(gDsTrafficStats.txStats, sizeof(gDsTrafficStats.txStats)); |
| } |
| |
| /* DTS Tx packet complete function. |
| * This function should be invoked by the transport device to indicate |
| * transmit complete for a frame. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller |
| * pFrame:Refernce to PAL frame. |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_TxPacketComplete(void *pContext, wpt_packet *pFrame, wpt_status status) |
| { |
| WDI_DS_ClientDataType *pClientData = (WDI_DS_ClientDataType*)(pContext); |
| WDI_DS_TxMetaInfoType *pTxMetadata; |
| void *pvBDHeader, *physBDHeader; |
| wpt_uint8 staIndex; |
| |
| // Do Sanity checks |
| if(NULL == pContext || NULL == pFrame){ |
| return eWLAN_PAL_STATUS_E_FAILURE; |
| } |
| |
| |
| // extract metadata from PAL packet |
| pTxMetadata = WDI_DS_ExtractTxMetaData(pFrame); |
| pTxMetadata->txCompleteStatus = status; |
| |
| // Free BD header from pool |
| WDI_GetBDPointers(pFrame, &pvBDHeader, &physBDHeader); |
| switch(pTxMetadata->frmType) |
| { |
| case WDI_MAC_DATA_FRAME: |
| /* note that EAPOL frame hasn't incremented ReserveCount. see |
| WDI_DS_TxPacket() in wlan_qct_wdi_ds.c |
| */ |
| if(!pTxMetadata->isEapol) |
| { |
| /* SWAP BD header to get STA index for completed frame */ |
| WDI_SwapTxBd(pvBDHeader); |
| staIndex = (wpt_uint8)WDI_TX_BD_GET_STA_ID(pvBDHeader); |
| WDI_DS_MemPoolFree(&(pClientData->dataMemPool), pvBDHeader, physBDHeader); |
| WDI_DS_MemPoolDecreaseReserveCount(&(pClientData->dataMemPool), staIndex); |
| break; |
| } |
| // intentional fall-through to handle eapol packet as mgmt |
| case WDI_MAC_MGMT_FRAME: |
| WDI_DS_MemPoolFree(&(pClientData->mgmtMemPool), pvBDHeader, physBDHeader); |
| break; |
| } |
| WDI_SetBDPointers(pFrame, 0, 0); |
| |
| // Invoke Tx complete callback |
| pClientData->txCompleteCB(pClientData->pCallbackContext, pFrame); |
| return eWLAN_PAL_STATUS_SUCCESS; |
| |
| } |
| |
| |
| /*=============================================================================== |
| FUNCTION WLANTL_GetReplayCounterFromRxBD |
| |
| DESCRIPTION This function extracts 48-bit replay packet number from RX BD |
| |
| DEPENDENCIES Validity of replay check must be done before the function |
| is called |
| |
| PARAMETERS pucRxHeader pointer to RX BD header |
| |
| RETRUN v_U64_t Packet number extarcted from RX BD |
| |
| SIDE EFFECTS none |
| ===============================================================================*/ |
| v_U64_t |
| WDTS_GetReplayCounterFromRxBD |
| ( |
| v_U8_t *pucRxBDHeader |
| ) |
| { |
| v_U64_t ullcurrentReplayCounter = 0; |
| /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ |
| /* 48-bit replay counter is created as follows |
| from RX BD 6 byte PMI command: |
| Addr : AES/TKIP |
| 0x38 : pn3/tsc3 |
| 0x39 : pn2/tsc2 |
| 0x3a : pn1/tsc1 |
| 0x3b : pn0/tsc0 |
| |
| 0x3c : pn5/tsc5 |
| 0x3d : pn4/tsc4 */ |
| |
| #ifdef ANI_BIG_BYTE_ENDIAN |
| /* Getting 48-bit replay counter from the RX BD */ |
| ullcurrentReplayCounter = WDI_RX_BD_GET_PMICMD_20TO23(pucRxBDHeader); |
| ullcurrentReplayCounter <<= 16; |
| ullcurrentReplayCounter |= (( WDI_RX_BD_GET_PMICMD_24TO25(pucRxBDHeader) & 0xFFFF0000) >> 16); |
| return ullcurrentReplayCounter; |
| #else |
| /* Getting 48-bit replay counter from the RX BD */ |
| ullcurrentReplayCounter = (WDI_RX_BD_GET_PMICMD_24TO25(pucRxBDHeader) & 0x0000FFFF); |
| ullcurrentReplayCounter <<= 32; |
| ullcurrentReplayCounter |= WDI_RX_BD_GET_PMICMD_20TO23(pucRxBDHeader); |
| return ullcurrentReplayCounter; |
| #endif |
| } |
| |
| |
| /* DTS Rx packet function. |
| * This function should be invoked by the transport device to indicate |
| * reception of a frame. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller |
| * pFrame:Refernce to PAL frame. |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_RxPacket (void *pContext, wpt_packet *pFrame, WDTS_ChannelType channel) |
| { |
| WDI_DS_ClientDataType *pClientData = |
| (WDI_DS_ClientDataType*)(pContext); |
| wpt_boolean bASF, bFSF, bLSF, bAEF; |
| wpt_uint8 ucMPDUHOffset, ucMPDUHLen, ucTid; |
| wpt_uint8 *pBDHeader; |
| wpt_uint16 usMPDUDOffset, usMPDULen; |
| WDI_DS_RxMetaInfoType *pRxMetadata; |
| wpt_uint8 isFcBd = 0; |
| |
| tpSirMacFrameCtl pMacFrameCtl; |
| // Do Sanity checks |
| if(NULL == pContext || NULL == pFrame){ |
| return eWLAN_PAL_STATUS_E_FAILURE; |
| } |
| |
| /*------------------------------------------------------------------------ |
| Extract BD header and check if valid |
| ------------------------------------------------------------------------*/ |
| pBDHeader = (wpt_uint8*)wpalPacketGetRawBuf(pFrame); |
| if(NULL == pBDHeader) |
| { |
| DTI_TRACE( DTI_TRACE_LEVEL_ERROR, |
| "WLAN TL:BD header received NULL - dropping packet"); |
| wpalPacketFree(pFrame); |
| return eWLAN_PAL_STATUS_E_FAILURE; |
| } |
| WDI_SwapRxBd(pBDHeader); |
| |
| ucMPDUHOffset = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_OFFSET(pBDHeader); |
| usMPDUDOffset = (wpt_uint16)WDI_RX_BD_GET_MPDU_D_OFFSET(pBDHeader); |
| usMPDULen = (wpt_uint16)WDI_RX_BD_GET_MPDU_LEN(pBDHeader); |
| ucMPDUHLen = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_LEN(pBDHeader); |
| ucTid = (wpt_uint8)WDI_RX_BD_GET_TID(pBDHeader); |
| |
| /*------------------------------------------------------------------------ |
| Gather AMSDU information |
| ------------------------------------------------------------------------*/ |
| bASF = WDI_RX_BD_GET_ASF(pBDHeader); |
| bAEF = WDI_RX_BD_GET_AEF(pBDHeader); |
| bFSF = WDI_RX_BD_GET_ESF(pBDHeader); |
| bLSF = WDI_RX_BD_GET_LSF(pBDHeader); |
| isFcBd = WDI_RX_FC_BD_GET_FC(pBDHeader); |
| |
| DTI_TRACE( DTI_TRACE_LEVEL_INFO, |
| "WLAN TL:BD header processing data: HO %d DO %d Len %d HLen %d" |
| " Tid %d BD %d", |
| ucMPDUHOffset, usMPDUDOffset, usMPDULen, ucMPDUHLen, ucTid, |
| WDI_RX_BD_HEADER_SIZE); |
| |
| if(!isFcBd) |
| { |
| if(usMPDUDOffset <= ucMPDUHOffset || usMPDULen < ucMPDUHLen) { |
| DTI_TRACE( DTI_TRACE_LEVEL_ERROR, |
| "WLAN TL:BD header corrupted - dropping packet"); |
| /* Drop packet ???? */ |
| wpalPacketFree(pFrame); |
| return eWLAN_PAL_STATUS_SUCCESS; |
| } |
| |
| if((ucMPDUHOffset < WDI_RX_BD_HEADER_SIZE) && (!(bASF && !bFSF))){ |
| /* AMSDU case, ucMPDUHOffset = 0 it should be hancdled seperatly */ |
| /* Drop packet ???? */ |
| wpalPacketFree(pFrame); |
| return eWLAN_PAL_STATUS_SUCCESS; |
| } |
| |
| /* AMSDU frame, but not first sub-frame |
| * No MPDU header, MPDU header offset is 0 |
| * Total frame size is actual frame size + MPDU data offset */ |
| if((ucMPDUHOffset < WDI_RX_BD_HEADER_SIZE) && (bASF && !bFSF)){ |
| ucMPDUHOffset = usMPDUDOffset; |
| } |
| |
| if(VPKT_SIZE_BUFFER < (usMPDULen+ucMPDUHOffset)){ |
| DTI_TRACE( DTI_TRACE_LEVEL_FATAL, |
| "Invalid Frame size, might memory corrupted"); |
| wpalPacketFree(pFrame); |
| return eWLAN_PAL_STATUS_SUCCESS; |
| } |
| wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset); |
| wpalPacketRawTrimHead(pFrame, ucMPDUHOffset); |
| |
| |
| |
| pRxMetadata = WDI_DS_ExtractRxMetaData(pFrame); |
| |
| pRxMetadata->fc = isFcBd; |
| pRxMetadata->staId = WDI_RX_BD_GET_STA_ID(pBDHeader); |
| pRxMetadata->addr3Idx = WDI_RX_BD_GET_ADDR3_IDX(pBDHeader); |
| pRxMetadata->rxChannel = WDI_RX_BD_GET_RX_CHANNEL(pBDHeader); |
| pRxMetadata->rtsf = WDI_RX_BD_GET_RTSF(pBDHeader); |
| pRxMetadata->bsf = WDI_RX_BD_GET_BSF(pBDHeader); |
| pRxMetadata->scan = WDI_RX_BD_GET_SCAN(pBDHeader); |
| pRxMetadata->dpuSig = WDI_RX_BD_GET_DPU_SIG(pBDHeader); |
| pRxMetadata->ft = WDI_RX_BD_GET_FT(pBDHeader); |
| pRxMetadata->ne = WDI_RX_BD_GET_NE(pBDHeader); |
| pRxMetadata->llcr = WDI_RX_BD_GET_LLCR(pBDHeader); |
| pRxMetadata->bcast = WDI_RX_BD_GET_UB(pBDHeader); |
| pRxMetadata->tid = ucTid; |
| pRxMetadata->dpuFeedback = WDI_RX_BD_GET_DPU_FEEDBACK(pBDHeader); |
| pRxMetadata->rateIndex = WDI_RX_BD_GET_RATEINDEX(pBDHeader); |
| pRxMetadata->rxpFlags = WDI_RX_BD_GET_RXPFLAGS(pBDHeader); |
| pRxMetadata->mclkRxTimestamp = WDI_RX_BD_GET_TIMESTAMP(pBDHeader); |
| |
| /* typeSubtype in BD doesn't look like correct. Fill from frame ctrl |
| TL does it for Volans but TL does not know BD for Prima. WDI should do it */ |
| if ( 0 == WDI_RX_BD_GET_FT(pBDHeader) ) { |
| if ( bASF ) { |
| pRxMetadata->subtype = WDI_MAC_DATA_QOS_DATA; |
| pRxMetadata->type = WDI_MAC_DATA_FRAME; |
| } else { |
| pMacFrameCtl = (tpSirMacFrameCtl)(((wpt_uint8*)pBDHeader) + ucMPDUHOffset); |
| pRxMetadata->subtype = pMacFrameCtl->subType; |
| pRxMetadata->type = pMacFrameCtl->type; |
| } |
| } else { |
| pMacFrameCtl = (tpSirMacFrameCtl)(((wpt_uint8*)pBDHeader) + WDI_RX_BD_HEADER_SIZE); |
| pRxMetadata->subtype = pMacFrameCtl->subType; |
| pRxMetadata->type = pMacFrameCtl->type; |
| } |
| |
| pRxMetadata->mpduHeaderPtr = pBDHeader + ucMPDUHOffset; |
| pRxMetadata->mpduDataPtr = pBDHeader + usMPDUDOffset; |
| pRxMetadata->mpduLength = usMPDULen; |
| pRxMetadata->mpduHeaderLength = ucMPDUHLen; |
| |
| /*------------------------------------------------------------------------ |
| Gather AMPDU information |
| ------------------------------------------------------------------------*/ |
| pRxMetadata->ampdu_reorderOpcode = (wpt_uint8)WDI_RX_BD_GET_BA_OPCODE(pBDHeader); |
| pRxMetadata->ampdu_reorderSlotIdx = (wpt_uint8)WDI_RX_BD_GET_BA_SI(pBDHeader); |
| pRxMetadata->ampdu_reorderFwdIdx = (wpt_uint8)WDI_RX_BD_GET_BA_FI(pBDHeader); |
| pRxMetadata->currentPktSeqNo = (wpt_uint8)WDI_RX_BD_GET_BA_CSN(pBDHeader); |
| |
| |
| /*------------------------------------------------------------------------ |
| Gather AMSDU information |
| ------------------------------------------------------------------------*/ |
| pRxMetadata->amsdu_asf = bASF; |
| pRxMetadata->amsdu_aef = bAEF; |
| pRxMetadata->amsdu_esf = bFSF; |
| pRxMetadata->amsdu_lsf = bLSF; |
| pRxMetadata->amsdu_size = WDI_RX_BD_GET_AMSDU_SIZE(pBDHeader); |
| |
| pRxMetadata->rssi0 = WDI_RX_BD_GET_RSSI0(pBDHeader); |
| pRxMetadata->rssi1 = WDI_RX_BD_GET_RSSI1(pBDHeader); |
| |
| |
| /* Missing: |
| wpt_uint32 fcSTATxQStatus:8; |
| wpt_uint32 fcSTAThreshIndMask:8; |
| wpt_uint32 fcSTAPwrSaveStateMask:8; |
| wpt_uint32 fcSTAValidMask:8; |
| |
| wpt_uint8 fcSTATxQLen[8]; // one byte per STA. |
| wpt_uint8 fcSTACurTxRate[8]; // current Tx rate for each sta. |
| unknownUcastPkt |
| */ |
| |
| pRxMetadata->replayCount = WDTS_GetReplayCounterFromRxBD(pBDHeader); |
| pRxMetadata->snr = WDI_RX_BD_GET_SNR(pBDHeader); |
| |
| /* |
| * PAL BD pointer information needs to be populated |
| */ |
| WPAL_PACKET_SET_BD_POINTER(pFrame, pBDHeader); |
| WPAL_PACKET_SET_BD_LENGTH(pFrame, sizeof(WDI_RxBdType)); |
| |
| // Invoke Rx complete callback |
| pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame); |
| } |
| else |
| { |
| wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset); |
| wpalPacketRawTrimHead(pFrame, ucMPDUHOffset); |
| |
| pRxMetadata = WDI_DS_ExtractRxMetaData(pFrame); |
| //flow control related |
| pRxMetadata->fc = isFcBd; |
| pRxMetadata->fcStaTxDisabledBitmap = WDI_RX_FC_BD_GET_STA_TX_DISABLED_BITMAP(pBDHeader); |
| pRxMetadata->fcSTAValidMask = WDI_RX_FC_BD_GET_STA_VALID_MASK(pBDHeader); |
| // Invoke Rx complete callback |
| pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame); |
| } |
| |
| //Log the RX Stats |
| if(gDsTrafficStats.running && pRxMetadata->staId < HAL_NUM_STA) |
| { |
| if(pRxMetadata->rateIndex < WDTS_MAX_RATE_NUM) |
| { |
| gDsTrafficStats.rxStats[pRxMetadata->staId][pRxMetadata->rateIndex].rxBytesRcvd += pRxMetadata->mpduLength; |
| gDsTrafficStats.rxStats[pRxMetadata->staId][pRxMetadata->rateIndex].rxPacketsRcvd++; |
| } |
| } |
| return eWLAN_PAL_STATUS_SUCCESS; |
| |
| } |
| |
| |
| |
| /* DTS Out of Resource packet function. |
| * This function should be invoked by the transport device to indicate |
| * the device is out of resources. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller |
| * priority: indicates which channel is out of resource. |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| */ |
| wpt_status WDTS_OOResourceNotification(void *pContext, WDTS_ChannelType channel, wpt_boolean on) |
| { |
| WDI_DS_ClientDataType *pClientData = |
| (WDI_DS_ClientDataType *) pContext; |
| static wpt_uint8 ac_mask = 0x1f; |
| |
| // Do Sanity checks |
| if(NULL == pContext){ |
| return eWLAN_PAL_STATUS_E_FAILURE; |
| } |
| |
| if(on){ |
| ac_mask |= channel == WDTS_CHANNEL_TX_LOW_PRI? 0x0f : 0x10; |
| } else { |
| ac_mask &= channel == WDTS_CHANNEL_TX_LOW_PRI? 0x10 : 0x0f; |
| } |
| |
| |
| // Invoke OOR callback |
| pClientData->txResourceCB(pClientData->pCallbackContext, ac_mask); |
| return eWLAN_PAL_STATUS_SUCCESS; |
| |
| } |
| |
| /* DTS open function. |
| * On open the transport device should initialize itself. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along |
| * with the callback. |
| * |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_openTransport( void *pContext) |
| { |
| void *pDTDriverContext; |
| WDI_DS_ClientDataType *pClientData; |
| WDI_Status sWdiStatus = WDI_STATUS_SUCCESS; |
| |
| pClientData = (WDI_DS_ClientDataType*) wpalMemoryAllocate(sizeof(WDI_DS_ClientDataType)); |
| if (!pClientData){ |
| return eWLAN_PAL_STATUS_E_NOMEM; |
| } |
| |
| pClientData->suspend = 0; |
| WDI_DS_AssignDatapathContext(pContext, (void*)pClientData); |
| |
| pDTDriverContext = gTransportDriver.open(); |
| if( NULL == pDTDriverContext ) |
| { |
| DTI_TRACE( DTI_TRACE_LEVEL_ERROR, " %s fail from transport open", __func__); |
| return eWLAN_PAL_STATUS_E_FAILURE; |
| } |
| WDT_AssignTransportDriverContext(pContext, pDTDriverContext); |
| gTransportDriver.register_client(pDTDriverContext, WDTS_RxPacket, WDTS_TxPacketComplete, |
| WDTS_OOResourceNotification, (void*)pClientData); |
| |
| /* Create a memory pool for Mgmt BDheaders.*/ |
| sWdiStatus = WDI_DS_MemPoolCreate(&pClientData->mgmtMemPool, WDI_DS_MAX_CHUNK_SIZE, |
| WDI_DS_HI_PRI_RES_NUM); |
| if (WDI_STATUS_SUCCESS != sWdiStatus){ |
| return eWLAN_PAL_STATUS_E_NOMEM; |
| } |
| |
| /* Create a memory pool for Data BDheaders.*/ |
| sWdiStatus = WDI_DS_MemPoolCreate(&pClientData->dataMemPool, WDI_DS_MAX_CHUNK_SIZE, |
| WDI_DS_LO_PRI_RES_NUM); |
| if (WDI_STATUS_SUCCESS != sWdiStatus){ |
| return eWLAN_PAL_STATUS_E_NOMEM; |
| } |
| |
| wpalMemoryZero(&gDsTrafficStats, sizeof(gDsTrafficStats)); |
| |
| return eWLAN_PAL_STATUS_SUCCESS; |
| |
| } |
| |
| |
| |
| /* DTS start function. |
| * On start the transport device should start running. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along |
| * with the callback. |
| * |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_startTransport( void *pContext) |
| { |
| void *pDTDriverContext = WDT_GetTransportDriverContext(pContext); |
| gTransportDriver.start(pDTDriverContext); |
| return eWLAN_PAL_STATUS_SUCCESS; |
| |
| } |
| |
| |
| /* DTS Tx packet function. |
| * This function should be invoked by the DAL Dataservice to schedule transmit frame through DXE/SDIO. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * pFrame:Refernce to PAL frame. |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_TxPacket(void *pContext, wpt_packet *pFrame) |
| { |
| void *pDTDriverContext = WDT_GetTransportDriverContext(pContext); |
| WDI_DS_TxMetaInfoType *pTxMetadata; |
| WDTS_ChannelType channel = WDTS_CHANNEL_TX_LOW_PRI; |
| wpt_status status = eWLAN_PAL_STATUS_SUCCESS; |
| WDI_TxBdType *pvBDHeader; |
| |
| // extract metadata from PAL packet |
| pTxMetadata = WDI_DS_ExtractTxMetaData(pFrame); |
| pvBDHeader = (WDI_TxBdType*)WPAL_PACKET_GET_BD_POINTER(pFrame); |
| |
| //Log the TX Stats |
| if(gDsTrafficStats.running && pvBDHeader->staIndex < HAL_NUM_STA) |
| { |
| gDsTrafficStats.txStats[pvBDHeader->staIndex].txBytesPushed += |
| pvBDHeader->mpduLength; |
| } |
| |
| // assign MDPU to correct channel?? |
| channel = (pTxMetadata->frmType & WDI_MAC_DATA_FRAME)? |
| /* EAPOL frame uses TX_HIGH_PRIORITY DXE channel |
| To make sure EAPOL (for second session) is pushed even if TX_LO channel |
| already reached to low resource condition |
| This can happen especially in MCC, high data traffic TX in first session |
| */ |
| ((pTxMetadata->isEapol) ? WDTS_CHANNEL_TX_HIGH_PRI : WDTS_CHANNEL_TX_LOW_PRI) : WDTS_CHANNEL_TX_HIGH_PRI; |
| // Send packet to Transport Driver. |
| status = gTransportDriver.xmit(pDTDriverContext, pFrame, channel); |
| return status; |
| } |
| |
| /* DTS Tx Complete function. |
| * This function should be invoked by the DAL Dataservice to notify tx completion to DXE/SDIO. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * ucTxResReq:TX resource number required by TL |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_CompleteTx(void *pContext, wpt_uint32 ucTxResReq) |
| { |
| void *pDTDriverContext = WDT_GetTransportDriverContext(pContext); |
| |
| // Notify completion to Transport Driver. |
| return gTransportDriver.txComplete(pDTDriverContext, ucTxResReq); |
| } |
| |
| /* DXE Set power state ACK callback. |
| * This callback function should be invoked by the DXE to notify WDI that set |
| * power state request is complete. |
| * Parameters: |
| * status: status of the set operation |
| * Return Value: None. |
| * |
| */ |
| void WDTS_SetPowerStateCb(wpt_status status, unsigned int dxePhyAddr) |
| { |
| //print a msg |
| if(NULL != gSetPowerStateCbInfo.cback) |
| { |
| gSetPowerStateCbInfo.cback(status, dxePhyAddr, gSetPowerStateCbInfo.pUserData); |
| } |
| } |
| |
| |
| /* DTS Set power state function. |
| * This function should be invoked by the DAL to notify the WLAN device power state. |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * powerState:Power state of the WLAN device. |
| * Return Value: SUCCESS Set successfully in DXE control blk. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_SetPowerState(void *pContext, WDTS_PowerStateType powerState, |
| WDTS_SetPowerStateCbType cback) |
| { |
| void *pDTDriverContext = WDT_GetTransportDriverContext(pContext); |
| wpt_status status = eWLAN_PAL_STATUS_SUCCESS; |
| |
| if( cback ) |
| { |
| //save the cback & cookie |
| gSetPowerStateCbInfo.pUserData = pContext; |
| gSetPowerStateCbInfo.cback = cback; |
| status = gTransportDriver.setPowerState(pDTDriverContext, powerState, |
| WDTS_SetPowerStateCb); |
| } |
| else |
| { |
| status = gTransportDriver.setPowerState(pDTDriverContext, powerState, |
| NULL); |
| } |
| |
| return status; |
| } |
| |
| /* DTS Transport Channel Debug |
| * Display DXE Channel debugging information |
| * User may request to display DXE channel snapshot |
| * Or if host driver detects any abnormal stcuk may display |
| * Parameters: |
| * displaySnapshot : Display DXE snapshot option |
| * enableStallDetect : Enable stall detect feature |
| This feature will take effect to data performance |
| Not integrate till fully verification |
| * Return Value: NONE |
| * |
| */ |
| void WDTS_ChannelDebug(wpt_boolean displaySnapshot, wpt_boolean toggleStallDetect) |
| { |
| gTransportDriver.channelDebug(displaySnapshot, toggleStallDetect); |
| return; |
| } |
| |
| /* DTS Stop function. |
| * Stop Transport driver, ie DXE, SDIO |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_Stop(void *pContext) |
| { |
| void *pDTDriverContext = WDT_GetTransportDriverContext(pContext); |
| wpt_status status = eWLAN_PAL_STATUS_SUCCESS; |
| |
| status = gTransportDriver.stop(pDTDriverContext); |
| |
| wpalMemoryZero(&gDsTrafficStats, sizeof(gDsTrafficStats)); |
| |
| return status; |
| } |
| |
| /* DTS Stop function. |
| * Stop Transport driver, ie DXE, SDIO |
| * Parameters: |
| * pContext:Cookie that should be passed back to the caller along with the callback. |
| * Return Value: SUCCESS Completed successfully. |
| * FAILURE_XXX Request was rejected due XXX Reason. |
| * |
| */ |
| wpt_status WDTS_Close(void *pContext) |
| { |
| void *pDTDriverContext = WDT_GetTransportDriverContext(pContext); |
| WDI_DS_ClientDataType *pClientData = WDI_DS_GetDatapathContext(pContext); |
| wpt_status status = eWLAN_PAL_STATUS_SUCCESS; |
| |
| /*Destroy the mem pool for mgmt BD headers*/ |
| WDI_DS_MemPoolDestroy(&pClientData->mgmtMemPool); |
| |
| /*Destroy the mem pool for mgmt BD headers*/ |
| WDI_DS_MemPoolDestroy(&pClientData->dataMemPool); |
| |
| status = gTransportDriver.close(pDTDriverContext); |
| |
| wpalMemoryFree(pClientData); |
| |
| return status; |
| } |
| |
| /* Get free TX data descriptor number from DXE |
| * Parameters: |
| * pContext: Cookie that should be passed back to the caller along with the callback. |
| * Return Value: number of free descriptors for TX data channel |
| * |
| */ |
| wpt_uint32 WDTS_GetFreeTxDataResNumber(void *pContext) |
| { |
| return |
| gTransportDriver.getFreeTxDataResNumber(WDT_GetTransportDriverContext(pContext)); |
| } |