1 /**************************************************************************** 2 **+-----------------------------------------------------------------------+** 3 **| |** 4 **| Copyright(c) 1998 - 2008 Texas Instruments. All rights reserved. |** 5 **| All rights reserved. |** 6 **| |** 7 **| Redistribution and use in source and binary forms, with or without |** 8 **| modification, are permitted provided that the following conditions |** 9 **| are met: |** 10 **| |** 11 **| * Redistributions of source code must retain the above copyright |** 12 **| notice, this list of conditions and the following disclaimer. |** 13 **| * Redistributions in binary form must reproduce the above copyright |** 14 **| notice, this list of conditions and the following disclaimer in |** 15 **| the documentation and/or other materials provided with the |** 16 **| distribution. |** 17 **| * Neither the name Texas Instruments nor the names of its |** 18 **| contributors may be used to endorse or promote products derived |** 19 **| from this software without specific prior written permission. |** 20 **| |** 21 **| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |** 22 **| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |** 23 **| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |** 24 **| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |** 25 **| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |** 26 **| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |** 27 **| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |** 28 **| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |** 29 **| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |** 30 **| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |** 31 **| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |** 32 **| |** 33 **+-----------------------------------------------------------------------+** 34 ****************************************************************************/ 35 36 /**************************************************************************** 37 * 38 * MODULE: txHwQueueCalc.c 39 * 40 * PURPOSE: 41 * Calculates the fragmentation threshold and number of HW memory blocks 42 * required for the transmitted packet. 43 * 44 * DESCRIPTION: 45 * ============ 46 * This is a sub-module of the Tx-HW-Queue module. 47 * When the Tx-HW-Queue is requested to allocate HW resources for a Tx 48 * packet (see txHwQueue_alloc()), it first calls this module to get 49 * the number of HW memory blocks required for the packet. 50 * First the fragmentation threshold is calculated, and then the number 51 * blocks. Both values are written in the provided control block of 52 * the packet (in the descriptor structure to be copied to the FW). 53 * 54 ****************************************************************************/ 55 56 #include "public_types.h" 57 #include "802_11Defs.h" 58 #include "ratesTypes.h" 59 #include "whalCommon.h" 60 #include "whalParams.h" 61 #include "whalCtrl_api.h" 62 #include "txHwQueue_api.h" 63 #include "utils.h" 64 #include "txHwQueue.h" /* Local definitions */ 65 #include "txHwQueueCalc.h" /* Local definitions */ 66 67 68 69 70 /**************************************************************************** 71 * txHwQueueCalc_BlocksNum() 72 **************************************************************************** 73 * DESCRIPTION: 74 * ============ 75 * Calculate the fragmentation threshold and the number of HW blocks 76 * required for the whole FW Tx processing of the packet. 77 * 78 ****************************************************************************/ 79 void txHwQueueCalc_BlocksNum(TI_HANDLE hTxHwQueue, txCtrlBlkEntry_t *pPktCtrlBlk) 80 { 81 TxHwQueueObj_t *pTxHwQueue = (TxHwQueueObj_t *)hTxHwQueue; 82 UINT16 memBlocks; 83 UINT16 numMpdus; 84 UINT16 numMemBlocksPerFullFrag; 85 UINT16 payloadDataLen; 86 UINT16 fragThreshold; 87 88 /* Calculate the fragmentation threshold. */ 89 fragThreshold = CalcFragThreshold(pTxHwQueue, pPktCtrlBlk); 90 91 payloadDataLen = pPktCtrlBlk->txDescriptor.length + MAX_MSDU_SECURITY_LENGTH; 92 93 if (payloadDataLen > fragThreshold) 94 { 95 #ifdef TI_DBG 96 if (fragThreshold == 0) 97 { 98 WLAN_OS_REPORT(("ERROR !!!!!!!!! fragThreshold==0 !!!!!!")); 99 return; 100 } 101 #endif 102 103 numMemBlocksPerFullFrag = ((fragThreshold + MAX_MPDU_HEADER_AND_SECURITY) / HW_BLOCK_SIZE) + 1; 104 numMpdus = payloadDataLen / fragThreshold; 105 memBlocks = numMpdus * numMemBlocksPerFullFrag; 106 payloadDataLen -= numMpdus * fragThreshold; 107 numMpdus++; 108 } 109 else 110 { 111 numMemBlocksPerFullFrag = 0; 112 memBlocks = 0; 113 numMpdus = 1; 114 } 115 116 memBlocks += (payloadDataLen / HW_BLOCK_SIZE) + 1; 117 118 /* If fragmentation needed, add spare blocks for FW internal copy purposes. */ 119 if (numMpdus > 1) 120 memBlocks += min(numMpdus, numMemBlocksPerFullFrag); 121 122 #ifdef TI_DBG 123 if (memBlocks > 255) 124 WLAN_REPORT_ERROR (pTxHwQueue->hReport, TX_HW_QUEUE_MODULE_LOG, 125 ("txHwQueueCalc_BlocksNum(): number of required blocks is bigger than 255 = %d\n", memBlocks)); 126 #endif 127 128 /* Copy the frag-threshold and HW blocks number to the descriptor. */ 129 pPktCtrlBlk->txDescriptor.numMemBlks = (UINT8)memBlocks; 130 pPktCtrlBlk->txDescriptor.fragThreshold = fragThreshold; 131 132 WLAN_REPORT_INFORMATION(pTxHwQueue->hReport, TX_HW_QUEUE_MODULE_LOG, 133 ("txHwQueueCalc_BlocksNum(): FragThresh=%d, NumBlks=%d, NumMpdus=%d, DataLen=%d\n", 134 fragThreshold, memBlocks, numMpdus, payloadDataLen)); 135 } 136 137 138 139 140 /**************************************************************************** 141 * CalcFragThreshold() 142 **************************************************************************** 143 DESCRIPTION: Calculates the frag threshold per frame according to the frag threshold 144 defined by the user and the TxOp fragmentation (if WME is used). 145 146 PARAMETERS: pTxHwQueue - The module object. 147 pPktCtrlBlk - The current packet control block (including descriptor). 148 149 RETURNS: The final fragmentation threshold. 150 ****************************************************************************/ 151 static UINT16 CalcFragThreshold(TxHwQueueObj_t *pTxHwQueue, txCtrlBlkEntry_t *pPktCtrlBlk) 152 { 153 UINT32 txOpLimit; 154 UINT16 fragThreshold, uMaxHdrLen; 155 WlanParams_T *pWlanParams = &(pTxHwQueue->pWhalParams->WlanParams); 156 dot11_header_t *pDot11Hdr = (dot11_header_t*)((UINT8 *)pPktCtrlBlk->txPktParams.pFrame + TX_TOTAL_OFFSET_BEFORE_DATA); 157 158 /* 159 * It is prohibited by the standard to fragment multicast/broadcast 160 * frames both in Infrastructure and Independent BSS types 161 */ 162 163 /* check for multicast packet in the destination address (address1 or address3)*/ 164 if (MAC_MULTICAST(GET_DA_FROM_DOT11_HEADER_T(pDot11Hdr))) 165 return MAX_FRAG_THRESHOLD; 166 167 /* For 4X don't fragment (use max frag threshold). */ 168 if (pWlanParams->Enable4x) 169 return MAX_FRAG_THRESHOLD; 170 171 /* Non-QOS mode */ 172 if (IS_LEGACY_DATA (pPktCtrlBlk->txPktParams.headerFrameCtrl)) 173 { 174 /* use "legacy" mode for the WLAN header length */ 175 uMaxHdrLen = WLAN_HDR_LEN; 176 /* Use "legacy" fragmentation */ 177 fragThreshold = pWlanParams->FragmentThreshold; 178 } 179 180 /* QOS mode */ 181 else 182 { 183 uMaxHdrLen = WLAN_QOS_HDR_LEN; 184 185 txOpLimit = pTxHwQueue->pWhalParams->AcParams.ac[pPktCtrlBlk->txDescriptor.xmitQueue].txopLimit; 186 187 if (txOpLimit == 0) 188 { 189 /* 190 * If working in WME and TXOP limit is not set for this AC - 191 * Use "legacy" fragmentation and substract the over head of the QoS header 192 */ 193 /* TODO yuval - check why 2 is needed */ 194 fragThreshold = pWlanParams->FragmentThreshold - DIFF_HEADER_LENGTH_LEGACY_TO_QOS; 195 } 196 else 197 198 { 199 /* 200 * If TXOP-limit value is set (may require fragmentation for the time limit) - 201 * calculate the fragmentation threshold for the given TXOP-limit 202 */ 203 fragThreshold = GetTxOpFragThreshold (pTxHwQueue, pPktCtrlBlk, txOpLimit, pWlanParams); 204 } 205 } 206 207 /* If the frag threshold is below minimal frag, use minimal frag threshold */ 208 if (fragThreshold < MIN_FRAG_THRESH) 209 fragThreshold = MIN_FRAG_THRESH; 210 211 /* Subtract header length and CRC length */ 212 fragThreshold -= uMaxHdrLen + FCS_LENGTH; 213 214 /* Return the frag threshold. */ 215 /* Note that security overheads are excluded as they are allowed to exceed the time limit. */ 216 return fragThreshold; 217 } 218 219 220 221 222 223 /**************************************************************************** 224 * GetTxOpFragThreshold() 225 **************************************************************************** 226 DESCRIPTION: Calculates the fragmentation threshold caused by the TxOpLimit. 227 228 PARAMETERS: pTxHwQueue - The module object. 229 pPktCtrlBlk - The current packet control block (including descriptor structure). 230 231 RETURNS: The fragmentation threshold calculated for the TXOP limit. 232 ****************************************************************************/ 233 static UINT16 GetTxOpFragThreshold(TxHwQueueObj_t *pTxHwQueue, txCtrlBlkEntry_t *pPktCtrlBlk, 234 UINT16 txOpLimit, WlanParams_T *pWlanParams) 235 { 236 UINT16 fragDataTime; 237 UINT16 txOpFragThresh; 238 UINT16 plcpHdrTimeBRate; 239 UINT16 plcpHdrTime; 240 UINT16 durationOverhead; 241 UINT16 rateMbps; 242 rate_e initialRate; 243 BOOL rtsSet; 244 rate_e ctrlFrameRate = pTxHwQueue->pWhalParams->BssInfoParams.txCtrlFrmRateDriverFormat; 245 uint8 ackPolicy; 246 247 initialRate = ConvertRateTnetToDriver(pPktCtrlBlk->txDescriptor.rate); 248 249 #ifdef TI_DBG 250 if (initialRate == DRV_RATE_INVALID) 251 { 252 WLAN_REPORT_ERROR(pTxHwQueue->hReport, TX_HW_QUEUE_MODULE_LOG, 253 ("GetTxOpFragThreshold(): Unexpected Tx-Rate = %d\n", initialRate)); 254 } 255 #endif 256 257 rateMbps = TxMemCalcRateValueTable[initialRate]; /* Convert from driver enum to Mbps value */ 258 259 /* Set the PLCP header time for B rates according to the preamble type. */ 260 if ( (pWlanParams->preamble == PREAMBLE_LONG) || (initialRate == DRV_RATE_1M) ) 261 plcpHdrTimeBRate = LONG_PREAMBLE_MICROSECONDS; 262 else 263 plcpHdrTimeBRate = SHORT_PREAMBLE_MICROSECONDS; 264 265 /* Get PLCP header duration overhead. */ 266 if (initialRate >= DRV_RATE_6M) /* If it's an OFDM rate. */ 267 plcpHdrTime = OFDM_PLCP_HDR_MICROSECONDS; 268 else 269 plcpHdrTime = plcpHdrTimeBRate; 270 271 durationOverhead = plcpHdrTime; 272 273 /* Add ACK overhead if not using No-ACK. */ 274 { 275 TxDescCtrl_t tmpTxDesc; 276 COPY_UNALIGNED_LONG(&tmpTxDesc, &(pPktCtrlBlk->txDescriptor.txAttr)); 277 ackPolicy = tmpTxDesc.ackPolicy; 278 } 279 if ( !ackPolicy ) 280 { 281 durationOverhead += TxMemCalcAckDurationTable[initialRate] + plcpHdrTime; 282 if (initialRate >= DRV_RATE_6M) 283 durationOverhead += OFDM_SIGNAL_EXT_MICROSECONDS; /* If OFDM add SIFS extra 6 uSec. */ 284 } 285 286 /* If packet length bigger than RTS threshold, add RTS time to the duration overhead. */ 287 if (pPktCtrlBlk->txDescriptor.length > pWlanParams->RtsThreshold) 288 { 289 durationOverhead += RTS_FRAG_DATA_TIME; 290 rtsSet = TRUE; 291 } 292 else 293 rtsSet = FALSE; 294 295 /* If protection CTS required for OFDM packet or RTS needed, add CTS time to duration overhead. */ 296 if ( (pWlanParams->CtsToSelf && (initialRate >= DRV_RATE_6M)) || rtsSet ) 297 durationOverhead += TxMemCalcAckDurationTable[ctrlFrameRate] + plcpHdrTimeBRate; 298 299 /* If the TXOP time is longer than the packet overheads, get the delta (fragment body time). */ 300 if (txOpLimit > durationOverhead) 301 fragDataTime = txOpLimit - durationOverhead; 302 303 /* Else, Can't get into the TXOP limit time. The minimal frag threshold (256) will be used. */ 304 else 305 fragDataTime = 0; 306 307 /* Calculate the fragmentation threshold in data bytes from the required duration and rate. */ 308 txOpFragThresh = fragDataTime * rateMbps / BIT_TO_BYTE_FACTOR; 309 310 /* If rate is 5.5M, a value of 55 is used so compensate for the 10 times factor. */ 311 if (rateMbps == 55) 312 txOpFragThresh = txOpFragThresh / 10; 313 314 /* Firmware requires the fragmentation threshold to be an EVEN number */ 315 txOpFragThresh &= ~1; 316 317 WLAN_REPORT_INFORMATION(pTxHwQueue->hReport, TX_HW_QUEUE_MODULE_LOG, 318 ("GetTxOpFragThreshold(): FragThresh=%d, Rate=%d, TXOP=%d, Overhead=%d, NoACK=%d, CTS=%d, RTS=%d\n", 319 txOpFragThresh, initialRate, txOpLimit, durationOverhead, ackPolicy, 320 pWlanParams->CtsToSelf, rtsSet)); 321 322 return (txOpFragThresh); 323 } 324 325 326 327 328 /**************************************************************************** 329 * ConvertRateTnetToDriver 330 **************************************************************************** 331 * DESCRIPTION: Convert the given rate from TNET format (Tx-descriptor) to driver format. 332 * 333 * INPUTS: txDescRate - Rate value in Tx-descriptor format 334 * 335 * OUTPUT: None 336 * 337 * RETURNS: The converted rate in driver format. 338 ****************************************************************************/ 339 static rate_e ConvertRateTnetToDriver (UINT16 tnetRate) 340 { 341 switch (tnetRate) 342 { 343 case HW_BIT_RATE_1MBPS: return DRV_RATE_1M; 344 case HW_BIT_RATE_2MBPS: return DRV_RATE_2M; 345 case HW_BIT_RATE_5_5MBPS: return DRV_RATE_5_5M; 346 case HW_BIT_RATE_6MBPS: return DRV_RATE_6M; 347 case HW_BIT_RATE_9MBPS: return DRV_RATE_9M; 348 case HW_BIT_RATE_11MBPS: return DRV_RATE_11M; 349 case HW_BIT_RATE_12MBPS: return DRV_RATE_12M; 350 case HW_BIT_RATE_18MBPS: return DRV_RATE_18M; 351 case HW_BIT_RATE_22MBPS: return DRV_RATE_22M; 352 case HW_BIT_RATE_24MBPS: return DRV_RATE_24M; 353 case HW_BIT_RATE_36MBPS: return DRV_RATE_36M; 354 case HW_BIT_RATE_48MBPS: return DRV_RATE_48M; 355 case HW_BIT_RATE_54MBPS: return DRV_RATE_54M; 356 357 default: return DRV_RATE_INVALID; 358 } 359 } 360 361 362 363 364