blob: 15a44bcec9f0c382a86b3f65e85500c93cc2b2f1 [file] [log] [blame]
/*
* Copyright (c) 2011-2017 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.
*/
/*
* This file was originally distributed by Qualcomm Atheros, Inc.
* under proprietary terms before Copyright ownership was assigned
* to the Linux Foundation.
*/
/**=========================================================================
*
* \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.
*
*/
#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"
#include "vos_utils.h"
#include "vos_api.h"
static WDTS_TransportDriverTrype gTransportDriver = {
WLANDXE_Open,
WLANDXE_Start,
WLANDXE_ClientRegistration,
WLANDXE_TxFrame,
WLANDXE_CompleteTX,
WLANDXE_SetPowerState,
WLANDXE_ChannelDebug,
WLANDXE_KickDxe,
WLANDXE_Stop,
WLANDXE_Close,
WLANDXE_GetFreeTxDataResNumber,
WLANDXE_SetupLogTransfer,
WLANDXE_StartLogTransfer
};
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)
uint32 tputBpus; //unit in Bytes per usec: round off to integral value
}WDTS_RateInfo;
#define WDTS_MAX_NUMBER_OF_RX_PKT 5
#define WDTS_MAX_PAGE_SIZE 4096
#define WDTS_MAX_RXDB_DATA_SIZE 128
#define MAC_ADDR_ARRAY(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
#define MAC_ADDRESS_STR "%02x:%02x:%02x:%02x:%02x:%02x"
struct WDTS_RxPktInfo
{
uint8 rx_bd[WDTS_MAX_RXDB_DATA_SIZE];
void *pFrame_head;
void *pFrame_tail;
uint32 pFrame_len;
};
static struct WDTS_PktInfoBuff
{
struct WDTS_RxPktInfo PktInfo[WDTS_MAX_NUMBER_OF_RX_PKT];
uint32 current_count;
uint8 current_position;
}WDTS_Pkt_Data_Buff = { .current_position = 0, .current_count = 0 };
#define WDTS_MAX_RATE_NUM 137
#define WDTS_MAX_11B_RATE_NUM 8
#define MB_PER_SEC_TO_BYTES_PER_MSEC 13
WDTS_RateInfo g11bRateInfo[WDTS_MAX_11B_RATE_NUM] = {
//11b rates
{ 10, 9, 117, 8}, //index 0
{ 20, 17, 221, 5}, //index 1
{ 55, 41, 533, 2}, //index 2
{ 110, 68, 884, 1}, //index 3
//11b short preamble
{ 10, 10, 130, 8}, //index 4
{ 20, 18, 234, 5}, //index 5
{ 55, 44, 572, 2}, //index 6
{ 110, 77, 1001, 1}, //index 7
};
WDTS_RateInfo gRateInfo[WDTS_MAX_RATE_NUM] = {
//11b rates
{ 10, 9, 117, 0}, //index 0
{ 20, 17, 221, 0}, //index 1
{ 55, 41, 533, 0}, //index 2
{ 110, 68, 884, 0}, //index 3
//11b short preamble
{ 10, 10, 130, 0}, //index 4
{ 20, 18, 234, 0}, //index 5
{ 55, 44, 572, 0}, //index 6
{ 110, 77, 1001, 0}, //index 7
//11ag
{ 60, 50, 650, 1}, //index 8
{ 90, 70, 910, 1}, //index 9
{ 120, 100, 1300, 1}, //index 10
{ 180, 150, 1950, 2}, //index 11
{ 240, 190, 2470, 2}, //index 12
{ 360, 280, 3640, 4}, //index 13
{ 480, 350, 4550, 5}, //index 14
{ 540, 380, 4940, 6}, //index 15
//11n SIMO
{ 65, 54, 702, 1}, //index 16
{ 130, 108, 1404, 1}, //index 17
{ 195, 161, 2093, 2}, //index 18
{ 260, 217, 2821, 3}, //index 19
{ 390, 326, 4238, 4}, //index 20
{ 520, 435, 5655, 6}, //index 21
{ 585, 492, 6396, 6}, //index 22
{ 650, 548, 7124, 7}, //index 23
//11n SIMO SGI
{ 72, 59, 767, 1}, //index 24
{ 144, 118, 1534, 2}, //index 25
{ 217, 180, 2340, 2}, //index 26
{ 289, 243, 3159, 3}, //index 27
{ 434, 363, 4719, 5}, //index 28
{ 578, 486, 6318, 6}, //index 29
{ 650, 548, 7124, 7}, //index 30
{ 722, 606, 7878, 8}, //index 31
//11n GF SIMO
{ 65, 54, 702, 1}, //index 32
{ 130, 108, 1404, 1}, //index 33
{ 195, 161, 2093, 2}, //index 34
{ 260, 217, 2821, 3}, //index 35
{ 390, 326, 4238, 4}, //index 36
{ 520, 435, 5655, 6}, //index 37
{ 585, 492, 6396, 6}, //index 38
{ 650, 548, 7124, 7}, //index 39
//11n SIMO CB MCS 0 - 7
{ 135, 110, 1430, 1}, //index 40
{ 270, 223, 2899, 3}, //index 41
{ 405, 337, 4381, 4}, //index 42
{ 540, 454, 5902, 6}, //index 43
{ 810, 679, 8827, 9}, //index 44
{ 1080, 909, 11817, 12}, //index 45
{ 1215, 1022, 13286, 13}, //index 46
{ 1350, 1137, 14781, 15}, //index 47
//11n SIMO CB SGI MCS 0 - 7
{ 150, 121, 1573, 2}, //index 48
{ 300, 249, 3237, 3}, //index 49
{ 450, 378, 4914, 5}, //index 50
{ 600, 503, 6539, 7}, //index 51
{ 900, 758, 9854, 10}, //index 52
{ 1200, 1010, 13130, 13}, //index 53
{ 1350, 1137, 14781, 15}, //index 54
{ 1500, 1262, 16406, 16}, //index 55
//11n SIMO GF CB MCS 0 - 7
{ 135, 110, 1430, 1}, //index 56
{ 270, 223, 2899, 3}, //index 57
{ 405, 337, 4381, 4}, //index 58
{ 540, 454, 5902, 6}, //index 59
{ 810, 679, 8827, 9}, //index 60
{ 1080, 909, 11817, 12}, //index 61
{ 1215, 1022, 13286, 13}, //index 62
{ 1350, 1137, 14781, 15}, //index 63
//11AC
{ 1350, 675, 8775, 9}, //reserved 64
{ 1350, 675, 8775, 9}, //reserved 65
{ 65, 45, 585, 1}, //index 66
{ 130, 91, 1183, 1}, //index 67
{ 195, 136, 1768, 2}, //index 68
{ 260, 182, 2366, 2}, //index 69
{ 390, 273, 3549, 4}, //index 70
{ 520, 364, 4732, 5}, //index 71
{ 585, 409, 5317, 5}, //index 72
{ 650, 455, 5915, 6}, //index 73
{ 780, 546, 7098, 7}, //index 74
{ 1350, 675, 8775, 9}, //reserved 75
{ 1350, 675, 8775, 9}, //reserved 76
{ 1350, 675, 8775, 9}, //reserved 77
{ 1350, 675, 8775, 9}, //index 78
{ 1350, 675, 8775, 9}, //index 79
{ 1350, 675, 8775, 9}, //index 80
{ 1350, 675, 8775, 9}, //index 81
{ 1350, 675, 8775, 9}, //index 82
{ 1350, 675, 8775, 9}, //index 83
{ 655, 458, 5954, 6}, //index 84
{ 722, 505, 6565, 7}, //index 85
{ 866, 606, 7878, 8}, //index 86
{ 1350, 675, 8775, 9}, //reserved 87
{ 1350, 675, 8775, 9}, //reserved 88
{ 1350, 675, 8775, 9}, //reserved 89
{ 135, 94, 1222, 1}, //index 90
{ 270, 189, 2457, 2}, //index 91
{ 405, 283, 3679, 4}, //index 92
{ 540, 378, 4914, 5}, //index 93
{ 810, 567, 7371, 7}, //index 94
{ 1080, 756, 9828, 10}, //index 95
{ 1215, 850, 11050, 11}, //index 96
{ 1350, 675, 8775, 9}, //index 97
{ 1350, 675, 8775, 9}, //index 98
{ 1620, 810, 10530, 11}, //index 99
{ 1800, 900, 11700, 12}, //index 100
{ 1350, 675, 8775, 9}, //reserved 101
{ 1350, 675, 8775, 9}, //index 102
{ 1350, 675, 8775, 9}, //index 103
{ 1350, 675, 8775, 9}, //index 104
{ 1350, 675, 8775, 9}, //index 105
{ 1350, 675, 8775, 9}, //index 106
{ 1200, 840, 10920, 11}, //index 107
{ 1350, 675, 8775, 9}, //index 108
{ 1500, 750, 9750, 10}, //index 109
{ 1350, 675, 8775, 9}, //index 110
{ 1800, 900, 11700, 12}, //index 111
{ 2000, 1000, 13000, 13}, //index 112
{ 1350, 675, 8775, 9}, //index 113
{ 292, 204, 2652, 3}, //index 114
{ 585, 409, 5317, 5}, //index 115
{ 877, 613, 7969, 8}, //index 116
{ 1170, 819, 10647, 11}, //index 117
{ 1755, 877, 11401, 11}, //index 118
{ 2340, 1170, 15210, 15}, //index 119
{ 2632, 1316, 17108, 17}, //index 120
{ 2925, 1462, 19006, 19}, //index 121
{ 1350, 675, 8775, 9}, //index 122
{ 3510, 1755, 22815, 23}, //index 123
{ 3900, 1950, 25350, 25}, //index 124
{ 1350, 675, 8775, 9}, //reserved 125
{ 1350, 675, 8775, 9}, //index 126
{ 1350, 675, 8775, 9}, //index 127
{ 1350, 675, 8775, 9}, //index 128
{ 1350, 675, 8775, 9}, //index 129
{ 1350, 675, 8775, 9}, //index 130
{ 1350, 675, 8775, 9}, //index 131
{ 2925, 1462, 19006, 19}, //index 132
{ 3250, 1625, 21125, 21}, //index 133
{ 1350, 675, 8775, 9}, //index 134
{ 3900, 1950, 25350, 25}, //index 135
{ 4333, 2166, 28158, 28} //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].tputBpus
#define DTS_11BRATE_TPUT_MULTIPLIER(x) g11bRateInfo[x].tputBpus
/* RX thread frame size threshold to delay frame drain */
#define DTS_RX_DELAY_FRAMESIZE_THRESHOLD 500
/* API to fill Rate Info based on the mac efficiency passed to it
* macEff si used to caclulate mac throughput based on each rate index/PHY rate.
* This is eventually used by MAS to calculate RX stats periodically sent to FW
* The start and end Rate Index are the other arguments to this API - the new mac
* efficiency passed to this API (Arg1) is only applied between startRateIndex (arg2) and endRateIndex (arg3).
*/
void WDTS_FillRateInfo(wpt_uint8 macEff, wpt_int16 startRateIndex, wpt_int16 endRateIndex)
{
int i;
DTI_TRACE( DTI_TRACE_LEVEL_ERROR, "Change only 11ac rates");
for (i=startRateIndex; i<=endRateIndex; i++)
{
// tputRate --> unit in Mega bits per sec X 10
gRateInfo[i].tputRate = ((gRateInfo[i].phyRate * macEff)/100);
// tputBmps --> unit in Bytes per msec = (tputRateX1024x1024)/(8x10X1000) ~= (tputRate*13)
gRateInfo[i].tputBpms = gRateInfo[i].tputRate * MB_PER_SEC_TO_BYTES_PER_MSEC;
// tputBpus --> unit in Bytes per usec: (+ 500) to round off to integral value
gRateInfo[i].tputBpus = ((gRateInfo[i].tputBpms + 500) / 1000);
if (gRateInfo[i].tputBpus == 0)
gRateInfo[i].tputBpus = 1;
DTI_TRACE( DTI_TRACE_LEVEL_ERROR, "%4u, %4u, %5u, %2u",
gRateInfo[i].phyRate,
gRateInfo[i].tputRate,
gRateInfo[i].tputBpms,
gRateInfo[i].tputBpus );
}
}
/* 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_11B_RATE_NUM; rate++)
{
pNetTxRxStats->rxBytesRcvd +=
gDsTrafficStats.rxStats[staIdx][rate].rxBytesRcvd;
pNetTxRxStats->rxPacketsRcvd +=
gDsTrafficStats.rxStats[staIdx][rate].rxPacketsRcvd;
pNetTxRxStats->rxTimeTotal +=
gDsTrafficStats.rxStats[staIdx][rate].rxBytesRcvd*DTS_11BRATE_TPUT_MULTIPLIER(rate);
}
for(rate = WDTS_MAX_11B_RATE_NUM; 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].rxBytesRcvd/DTS_RATE_TPUT(rate);
}
pNetTxRxStats->rxTimeTotal = pNetTxRxStats->rxTimeTotal/1000;
}
*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){
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_WARN,
"%s: Tx complete cannot proceed(%p:%p)",
__func__, pContext, 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
*/
#ifdef FEATURE_WLAN_TDLS
/* I utilizes TDLS mgmt frame always sent at BD_RATE2. (See limProcessTdls.c)
Assumption here is data frame sent by WDA_TxPacket() <- HalTxFrame/HalTxFrameWithComplete()
should take managment path. As of today, only TDLS feature has special data frame
which needs to be treated as mgmt.
*/
if((!pTxMetadata->isEapol) &&
((pTxMetadata->txFlags & WDI_USE_BD_RATE2_FOR_MANAGEMENT_FRAME) != WDI_USE_BD_RATE2_FOR_MANAGEMENT_FRAME))
#else
if(!pTxMetadata->isEapol)
#endif
{
/* 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);
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_INFO,
"%s: Management frame Tx complete status: %d", __func__, status);
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
}
/* Store RXBD, skb lenght, skb head, and skb end offset to global buffer.
* This function should be invoked when MPDU lenght + MPDU herader Offset
* if higher then 3872 bytes.
* Parameters:
* pFrame:Refernce to PAL frame.
* pBDHeader: BD header for PAL Frame.
* Return Value: v_VOID_t
*
*/
v_VOID_t
WDTS_StoreMetaInfo(wpt_packet *pFrame, wpt_uint8 *pBDHeader)
{
wpt_uint8 usMPDUHLen;
wpt_boolean usAsf, usAef, usLsf, usESF;
wpt_uint16 usMPDULen;
wpt_uint32 usPmiCmd24to25;
struct WDTS_RxPktInfo *current_data =
&WDTS_Pkt_Data_Buff.PktInfo[WDTS_Pkt_Data_Buff.current_position];
vos_mem_copy(current_data->rx_bd, (void*)wpalPacketGetRawBuf(pFrame),
WDTS_MAX_RXDB_DATA_SIZE);
usMPDULen = (wpt_uint16)WDI_RX_BD_GET_MPDU_LEN(pBDHeader);
usMPDUHLen = (wpt_uint8)WDI_RX_BD_GET_MPDU_H_LEN(pBDHeader);
usAsf = (wpt_boolean)WDI_RX_BD_GET_ASF(pBDHeader);
usAef = (wpt_boolean)WDI_RX_BD_GET_AEF(pBDHeader);
usLsf = (wpt_boolean)WDI_RX_BD_GET_LSF(pBDHeader);
usESF = (wpt_boolean)WDI_RX_BD_GET_ESF(pBDHeader);
usPmiCmd24to25 = (wpt_uint32)WDI_RX_BD_GET_PMICMD_24TO25(pBDHeader);
current_data->pFrame_head = wpalGetOSPktHead(pFrame);
current_data->pFrame_tail = wpalGetOSPktend(pFrame);
current_data->pFrame_len = wpalPacketGetLength(pFrame);
WDTS_Pkt_Data_Buff.current_count++;
/* Dump packet info */
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"count: %d usMPDULen: 0x%x, usMPDUHLen: 0x%x, usAsf: %x,"
"usAef: %x, usLsf: 0x%x, usESF: 0x%x, usPmiCmd24to25: 0x%x,"
"skb_len: 0x%x",WDTS_Pkt_Data_Buff.current_count, usMPDULen,
usMPDUHLen, usAsf, usAef, usLsf, usESF, usPmiCmd24to25,
current_data->pFrame_len);
WDTS_Pkt_Data_Buff.current_position++;
if(WDTS_Pkt_Data_Buff.current_position >= WDTS_MAX_NUMBER_OF_RX_PKT)
WDTS_Pkt_Data_Buff.current_position = 0;
return;
}
/**
*WDTS_RxPacketDump - Dump Rx packet details
*@pFrame: pointer to first Rx buffer received
*@pRxMetadata: pointer to RX packet Meta Info
*
*DTS utility to dump RX packet details.
*
*Return: None.
*/
static void WDTS_RxPacketDump(vos_pkt_t *pFrame,
WDI_DS_RxMetaInfoType *pRxMetadata)
{
tpSirMacMgmtHdr pHdr;
if (NULL == pRxMetadata) {
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"%s: RX Meta data info is NULL", __func__);
return;
}
pHdr = (tpSirMacMgmtHdr)pRxMetadata->mpduHeaderPtr;
/* RX packet type*/
if (pRxMetadata->bcast)
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"%s RX Data frame is BC", __func__);
else if (pHdr->da[0] & 0x01)
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"%s RX Data frame is MC", __func__);
else
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"%s RX Data frame is UC", __func__);
/* 802.11 packet type, subtype */
if (WDI_MAC_MGMT_FRAME == pRxMetadata->type) {
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"%s: Management subtype:%d SA:"MAC_ADDRESS_STR" DA:"
MAC_ADDRESS_STR, __func__, pRxMetadata->subtype,
MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da));
vos_set_rx_wow_dump(false);
} else if (WDI_MAC_CTRL_FRAME == pRxMetadata->type) {
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"%s: Control subtype:%d SA:"MAC_ADDRESS_STR" DA:"
MAC_ADDRESS_STR, __func__, pRxMetadata->subtype,
MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da));
vos_set_rx_wow_dump(false);
} else if (WDI_MAC_DATA_FRAME == pRxMetadata->type) {
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"%s: Data subtype:%d SA:"MAC_ADDRESS_STR" DA:"
MAC_ADDRESS_STR, __func__, pRxMetadata->subtype,
MAC_ADDR_ARRAY(pHdr->sa), MAC_ADDR_ARRAY(pHdr->da));
} else
VOS_TRACE(VOS_MODULE_ID_WDI, VOS_TRACE_LEVEL_ERROR,
"%s: Unknown frame SA:"MAC_ADDRESS_STR,
__func__, MAC_ADDR_ARRAY(pHdr->sa));
}
/* 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;
WDI_DS_LoggingSessionType *pLoggingSession;
tPerPacketStats rxStats = {0};
wpt_uint8 indType = 0;
tpSirMacFrameCtl pMacFrameCtl;
// Do Sanity checks
if(NULL == pContext || NULL == pFrame){
return eWLAN_PAL_STATUS_E_FAILURE;
}
// Normal DMA transfer does not contain RxBD
if (WDTS_CHANNEL_RX_FW_LOG == channel)
{
pLoggingSession = (WDI_DS_LoggingSessionType *)
WDI_DS_GetLoggingSession(pContext);
wpalFwLogPktSerialize(pFrame, pLoggingSession->logType);
return eWLAN_PAL_STATUS_SUCCESS;
}
/*------------------------------------------------------------------------
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);
/* If RX thread drain small size of frame from HW too fast
* Sometimes HW cannot handle interrupt fast enough
* And system crash might happen
* To avoid system crash, input 1usec delay each frame draining
* within host side, if frame size is smaller that threshold.
* This is SW work around, to fix HW problem
* Throughput and SnS test done successfully */
if (usMPDULen < DTS_RX_DELAY_FRAMESIZE_THRESHOLD)
{
wpalBusyWait(1);
}
/*------------------------------------------------------------------------
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);
indType = WDI_RX_BD_GET_PER_SAPOFFLOAD(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);
pRxMetadata = WDI_DS_ExtractRxMetaData(pFrame);
if (WDTS_CHANNEL_RX_LOG == channel)
{
if (VPKT_SIZE_BUFFER_ALIGNED < (usMPDULen+ucMPDUHOffset))
{
/* Size of the packet tranferred by the DMA engine is
* greater than the the memory allocated for the skb
* Recover the SKB case of length is in same memory page
*/
WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
"Invalid Frame size, might memory corrupted(%d+%d/%d)",
usMPDULen, ucMPDUHOffset, VPKT_SIZE_BUFFER_ALIGNED);
// Store RXBD, skb head, tail and skb lenght in circular buffer
WDTS_StoreMetaInfo(pFrame, pBDHeader);
if ((usMPDULen+ucMPDUHOffset) <= WDTS_MAX_PAGE_SIZE)
{
wpalRecoverTail(pFrame);
wpalPacketFree(pFrame);
} else {
//Recovery may cause adjoining buffer corruption
WPAL_BUG(0);
}
return eWLAN_PAL_STATUS_SUCCESS;
}
/* Firmware should send the Header offset as length
* of RxBd and data length should be populated to
* the length of total data being sent
*/
wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset);
wpalPacketRawTrimHead(pFrame, ucMPDUHOffset);
if(indType) {
DTI_TRACE(DTI_TRACE_LEVEL_INFO, "indtype is %d size of pacekt is %lu",
indType, sizeof(WDI_RxBdType));
if (WDI_RXBD_SAP_TX_STATS == indType) {
pRxMetadata->fc = 1;
pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame);
return eWLAN_PAL_STATUS_SUCCESS;
}
}
else {
// Invoke Rx complete callback
wpalLogPktSerialize(pFrame);
return eWLAN_PAL_STATUS_SUCCESS;
}
}
else
{
pRxMetadata->loggingData = 0;
}
if(!isFcBd)
{
/* When channel is WDTS_CHANNEL_RX_LOG firmware doesn't send MPDU header*/
if ((usMPDUDOffset <= ucMPDUHOffset || usMPDULen < ucMPDUHLen) &&
(WDTS_CHANNEL_RX_LOG != channel)) {
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_ALIGNED < (usMPDULen+ucMPDUHOffset))
{
/* Size of the packet tranferred by the DMA engine is
* greater than the the memory allocated for the skb
* Recover the SKB case of length is in same memory page
*/
WPAL_TRACE(eWLAN_MODULE_DAL_DATA, eWLAN_PAL_TRACE_LEVEL_FATAL,
"Invalid Frame size, might memory corrupted(%d+%d/%d)",
usMPDULen, ucMPDUHOffset, VPKT_SIZE_BUFFER_ALIGNED);
// Store RXBD, skb head, tail and skb lenght in circular buffer
WDTS_StoreMetaInfo(pFrame, pBDHeader);
if ((usMPDULen+ucMPDUHOffset) <= WDTS_MAX_PAGE_SIZE)
{
wpalRecoverTail(pFrame);
wpalPacketFree(pFrame);
} else {
//Recovery may cause adjoining buffer corruption
WPAL_BUG(0);
}
return eWLAN_PAL_STATUS_SUCCESS;
}
if(eWLAN_PAL_STATUS_SUCCESS != wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset))
{
DTI_TRACE( DTI_TRACE_LEVEL_ERROR, "Invalid Frame Length, Frame dropped..");
wpalPacketFree(pFrame);
return eWLAN_PAL_STATUS_SUCCESS;
}
if(eWLAN_PAL_STATUS_SUCCESS != wpalPacketRawTrimHead(pFrame, ucMPDUHOffset))
{
DTI_TRACE( DTI_TRACE_LEVEL_ERROR, "Failed to trim Raw Packet Head, Frame dropped..");
wpalPacketFree(pFrame);
return eWLAN_PAL_STATUS_SUCCESS;
}
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->rfBand = WDI_RX_BD_GET_RFBAND(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);
#ifdef WLAN_FEATURE_11W
pRxMetadata->rmf = WDI_RX_BD_GET_RMF(pBDHeader);
#endif
#ifdef WLAN_FEATURE_ROAM_SCAN_OFFLOAD
pRxMetadata->offloadScanLearn = WDI_RX_BD_GET_OFFLOADSCANLEARN(pBDHeader);
pRxMetadata->roamCandidateInd = WDI_RX_BD_GET_ROAMCANDIDATEIND(pBDHeader);
pRxMetadata->perRoamCndInd = WDI_RX_BD_GET_PER_ROAMCANDIDATEIND(pBDHeader);
#endif
#ifdef SAP_AUTH_OFFLOAD
/* Currently firmware use WDTS_CHANNEL_RX_LOG channel for two purpose.
* 1) For firmare logging information: driver will do special handling
* for those message.
* 2) When SAP offload is enabled: In this case, indication type is stored
* in pRxMetadata which will be used by LIM later.
*/
if (WDTS_CHANNEL_RX_LOG == channel)
{
pRxMetadata->indType =
(wpt_uint32)WDI_RX_BD_GET_PER_SAPOFFLOAD(pBDHeader);
if (pRxMetadata->indType == WDI_RXBD_MLME_STA_STATUS)
{
DTI_TRACE( DTI_TRACE_LEVEL_INFO, "%s: Indtype is %d\n",
__func__, pRxMetadata->indType);
pRxMetadata->type = WDI_MAC_MGMT_FRAME;
}
}
else
{
pRxMetadata->indType = 0;
}
#endif
#ifdef WLAN_FEATURE_EXTSCAN
pRxMetadata->extscanBuffer = WDI_RX_BD_GET_EXTSCANFULLSCANRESIND(pBDHeader);
#endif
/* 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_uint16)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));
if (((WDI_ControlBlockType *)pClientData->pcontext)->roamDelayStatsEnabled)
{
vos_record_roam_event(e_DXE_RX_PKT_TIME, (void *)pFrame, pRxMetadata->type);
}
if ((WLAN_LOG_LEVEL_ACTIVE ==
vos_get_ring_log_level(RING_ID_PER_PACKET_STATS)) &&
!(WDI_MAC_CTRL_FRAME == pRxMetadata->type))
{
vos_mem_zero(&rxStats,sizeof(tPerPacketStats));
/* Peer tx packet and it is an Rx packet for us */
rxStats.is_rx= VOS_TRUE;
rxStats.tid = ucTid;
rxStats.rssi = (pRxMetadata->rssi0 > pRxMetadata->rssi1)?
pRxMetadata->rssi0 : pRxMetadata->rssi1;
rxStats.rate_idx = pRxMetadata->rateIndex;
rxStats.seq_num = pRxMetadata->currentPktSeqNo;
rxStats.dxe_timestamp = vos_timer_get_system_ticks();
rxStats.data_len =
vos_copy_80211_data(pFrame, rxStats.data, pRxMetadata->type);
wpalPerPktSerialize(&rxStats);
}
/* Dump first Rx packet after host wakeup */
if (vos_get_rx_wow_dump())
WDTS_RxPacketDump((vos_pkt_t*)pFrame, pRxMetadata);
/* Invoke Rx complete callback */
pClientData->receiveFrameCB(pClientData->pCallbackContext, pFrame);
}
else
{
wpalPacketSetRxLength(pFrame, usMPDULen+ucMPDUHOffset);
wpalPacketRawTrimHead(pFrame, ucMPDUHOffset);
/* flow control related */
pRxMetadata->fc = isFcBd;
pRxMetadata->mclkRxTimestamp = WDI_RX_BD_GET_TIMESTAMP(pBDHeader);
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)
{
if(pRxMetadata->type == WDI_MAC_DATA_FRAME)
{
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;
}
void WDTS_LogRxDone(void *pContext)
{
WDI_DS_LoggingSessionType *pLoggingSession;
pLoggingSession = (WDI_DS_LoggingSessionType *)
WDI_DS_GetLoggingSession(pContext);
if (NULL == pContext || pLoggingSession == NULL)
{
return;
}
/* check for done and Log type Mgmt frame = 0, QXDM = 1, FW Mem dump = 2 */
if (pLoggingSession->done && pLoggingSession->logType <= VALID_FW_LOG_TYPES)
vos_process_done_indication(pLoggingSession->logType,
pLoggingSession->reasonCode);
if (pLoggingSession->logType == QXDM_LOGGING &&
pLoggingSession->reasonCode)
pLoggingSession->logType = FATAL_EVENT;
((WDI_DS_ClientDataType *)(pContext))->rxLogCB(pLoggingSession->logType);
pLoggingSession->done = 0;
pLoggingSession->logType = 0;
pLoggingSession->reasonCode = 0;
return;
}
void WDTS_MbReceiveMsg(void *pContext)
{
tpLoggingMailBox pLoggingMb;
WDI_DS_LoggingSessionType *pLoggingSession;
wpt_int8 i, noMem = 0;
wpt_uint32 totalLen = 0;
pLoggingMb = (tpLoggingMailBox)WDI_DS_GetLoggingMbAddr(pContext);
pLoggingSession = (WDI_DS_LoggingSessionType *)
WDI_DS_GetLoggingSession(pContext);
for(i = 0; i < MAX_NUM_OF_BUFFER; i++)
{
totalLen += pLoggingMb->logBuffLength[i];
// Send done indication when the logbuffer size exceeds 128KB.
if (totalLen > MAX_LOG_BUFFER_LENGTH || pLoggingMb->logBuffLength[i] > MAX_LOG_BUFFER_LENGTH)
{
DTI_TRACE( DTI_TRACE_LEVEL_ERROR, " %d received invalid log buffer length",
totalLen);
// Done using Mailbox, zero out the memory.
wpalMemoryZero(pLoggingMb, sizeof(tLoggingMailBox));
wpalMemoryZero(pLoggingSession, sizeof(WDI_DS_LoggingSessionType));
//Set Status as Failure
pLoggingSession->status = WDTS_LOGGING_STATUS_ERROR;
WDTS_LogRxDone(pContext);
return;
}
}
totalLen = 0;
for(i = 0; i < MAX_NUM_OF_BUFFER; i++)
{
pLoggingSession->logBuffAddress[i] = pLoggingMb->logBuffAddress[i];
if (!noMem)
{
pLoggingSession->logBuffLength[i] = gTransportDriver.setupLogTransfer(
pLoggingMb->logBuffAddress[i],
pLoggingMb->logBuffLength[i]);
}
else
{
pLoggingSession->logBuffLength[i] = 0;
continue;
}
totalLen += pLoggingSession->logBuffLength[i];
if (pLoggingSession->logBuffLength[i] < pLoggingMb->logBuffLength[i])
{
noMem = 1;
}
}
pLoggingSession->done = pLoggingMb->done;
pLoggingSession->logType = pLoggingMb->logType;
pLoggingSession->reasonCode = pLoggingMb->reasonCode;
pLoggingSession->status = WDTS_LOGGING_STATUS_SUCCESS;
// Done using Mailbox, zero out the memory.
wpalMemoryZero(pLoggingMb, sizeof(tLoggingMailBox));
if (totalLen)
{
if (gTransportDriver.startLogTransfer() == eWLAN_PAL_STATUS_SUCCESS)
return;
}
// Send Done event to upper layers, since we wont be getting any from DXE
}
/* 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;
WDTS_ClientCallbacks WDTSCb;
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);
WDTSCb.rxFrameReadyCB = WDTS_RxPacket;
WDTSCb.txCompleteCB = WDTS_TxPacketComplete;
WDTSCb.lowResourceCB = WDTS_OOResourceNotification;
WDTSCb.receiveMbMsgCB = WDTS_MbReceiveMsg;
WDTSCb.receiveLogCompleteCB = WDTS_LogRxDone;
gTransportDriver.register_client(pDTDriverContext, WDTSCb, (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));
sWdiStatus = WDI_DS_LoggingMbCreate(&pClientData->loggingMbContext, sizeof(tLoggingMailBox));
if (WDI_STATUS_SUCCESS != sWdiStatus)
return eWLAN_PAL_STATUS_E_NOMEM;
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;
tPerPacketStats txPktStat = {0};
// extract metadata from PAL packet
pTxMetadata = WDI_DS_ExtractTxMetaData(pFrame);
//Log the TX Stats
if(gDsTrafficStats.running && pTxMetadata->staIdx < HAL_NUM_STA)
{
if(pTxMetadata->frmType & WDI_MAC_DATA_FRAME)
{
gDsTrafficStats.txStats[pTxMetadata->staIdx].txBytesPushed +=
pTxMetadata->fPktlen;
gDsTrafficStats.txStats[pTxMetadata->staIdx].txPacketsPushed += 1;
}
}
// 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
*/
#ifdef FEATURE_WLAN_TDLS
/* I utilizes TDLS mgmt frame always sent at BD_RATE2. (See limProcessTdls.c)
Assumption here is data frame sent by WDA_TxPacket() <- HalTxFrame/HalTxFrameWithComplete()
should take managment path. As of today, only TDLS feature has special data frame
which needs to be treated as mgmt.
*/
(((pTxMetadata->isEapol) || (pTxMetadata->txFlags & WDI_USE_BD_RATE2_FOR_MANAGEMENT_FRAME))? WDTS_CHANNEL_TX_HIGH_PRI : WDTS_CHANNEL_TX_LOW_PRI) : WDTS_CHANNEL_TX_HIGH_PRI;
#else
((pTxMetadata->isEapol) ? WDTS_CHANNEL_TX_HIGH_PRI : WDTS_CHANNEL_TX_LOW_PRI) : WDTS_CHANNEL_TX_HIGH_PRI;
#endif
if (pTxMetadata->isArp)
{
VOS_TRACE(VOS_MODULE_ID_HDD, VOS_TRACE_LEVEL_INFO,
"%s :Transmitting ARP packet", __func__);
}
// Send packet to Transport Driver.
status = gTransportDriver.xmit(pDTDriverContext, pFrame, channel);
if ((WLAN_LOG_LEVEL_ACTIVE ==
vos_get_ring_log_level(RING_ID_PER_PACKET_STATS)) &&
!(pTxMetadata->frmType & WDI_MAC_CTRL_FRAME)){
vos_mem_zero(&txPktStat,sizeof(tPerPacketStats));
txPktStat.tid = pTxMetadata->fUP;
txPktStat.dxe_timestamp = vos_timer_get_system_ticks();
/*HW limitation cant get the seq number*/
txPktStat.seq_num = 0;
txPktStat.data_len =
vos_copy_80211_data((void *)pFrame, txPktStat.data,
pTxMetadata->frmType);
wpalPerPktSerialize(&txPktStat);
}
if (((WDI_ControlBlockType *)pContext)->roamDelayStatsEnabled)
{
vos_record_roam_event(e_DXE_FIRST_XMIT_TIME, (void *)pFrame, pTxMetadata->frmType);
}
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_uint8 debugFlags)
{
gTransportDriver.channelDebug(displaySnapshot, debugFlags);
return;
}
/* DTS Transport Channel Kick Dxe
* Request Kick DXE when HDD TX time out happen
*
* Parameters : NONE
* Return Value: NONE
*
*/
void WDTS_ChannelKickDxe()
{
gTransportDriver.kickDxe();
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);
WDI_DS_LoggingMbDestroy(&pClientData->loggingMbContext);
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));
}