1/* 2 * txMgmtQueue.c 3 * 4 * Copyright(c) 1998 - 2009 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/** \file txMgmtQueue.c 37 * \brief The Tx Mgmt Queues module. 38 * 39 * DESCRIPTION: 40 * ============ 41 * The Management-Queues module is responsible for the following tasks: 42 * 1. Queue the driver generated Tx packets, including management, 43 * EAPOL and null packets until they are transmitted. 44 * The management packets are buffered in the management-queue, 45 * and the others in the EAPOL-queue. 46 * 2. Maintain a state machine that follows the queues state and 47 * the connection states and enables specific transmission types 48 * accordingly (e.g. only management). 49 * 3. Gain access to the Tx path when the management queues are not 50 * empty, and return the access to the data queues when the 51 * management queues are empty. 52 * 4. Schedule packets transmission with strict priority of the 53 * management queue over the EAPOL queue, and according to the 54 * backpressure controls from the Port (all queues) and from the 55 * Tx-Ctrl (per queue). 56 * 57 * \see txMgmtQueue.h 58 */ 59 60#define __FILE_ID__ FILE_ID_61 61#include "tidef.h" 62#include "paramOut.h" 63#include "osApi.h" 64#include "TWDriver.h" 65#include "DataCtrl_Api.h" 66#include "report.h" 67#include "queue.h" 68#include "context.h" 69#include "DrvMainModules.h" 70 71 72#define MGMT_QUEUES_TID MAX_USER_PRIORITY 73 74typedef enum 75{ 76 QUEUE_TYPE_MGMT, /* Mgmt-queue - high-priority, for mgmt packets only. */ 77 QUEUE_TYPE_EAPOL, /* EAPOL-queue - low-priority, for other internal packets (EAPOL, NULL, IAPP). */ 78 NUM_OF_MGMT_QUEUES 79} EMgmtQueueTypes; 80 81/* State-Machine Events */ 82typedef enum 83{ 84 SM_EVENT_CLOSE, /* All Tx types should be closed. */ 85 SM_EVENT_MGMT, /* Allow only mgmt packets. */ 86 SM_EVENT_EAPOL, /* Allow mgmt and EAPOL packets. */ 87 SM_EVENT_OPEN, /* Allow all packets. */ 88 SM_EVENT_QUEUES_EMPTY, /* Mgmt-aQueues are now both empty. */ 89 SM_EVENT_QUEUES_NOT_EMPTY /* At least one of the Mgmt-aQueues is now not empty. */ 90} ESmEvent; 91 92/* State-Machine States */ 93typedef enum 94{ 95 SM_STATE_CLOSE, /* All Tx path is closed. */ 96 SM_STATE_MGMT, /* Only mgmt Tx is permitted. */ 97 SM_STATE_EAPOL, /* Only mgmt and EAPOL Tx is permitted. */ 98 SM_STATE_OPEN_MGMT, /* All Tx permitted and Mgmt aQueues are currently active (date disabled). */ 99 SM_STATE_OPEN_DATA /* All Tx permitted and Data aQueues are currently active (mgmt disabled). */ 100} ESmState; 101 102/* State-Machine Actions */ 103typedef enum 104{ 105 SM_ACTION_NULL, 106 SM_ACTION_ENABLE_DATA, 107 SM_ACTION_ENABLE_MGMT, 108 SM_ACTION_RUN_SCHEDULER 109} ESmAction; 110 111/* TI_TRUE if both aQueues are empty. */ 112#define ARE_ALL_MGMT_QUEUES_EMPTY(aQueues) ( (que_Size(aQueues[QUEUE_TYPE_MGMT] ) == 0) && \ 113 (que_Size(aQueues[QUEUE_TYPE_EAPOL]) == 0) ) 114 115typedef struct 116{ 117 TI_UINT32 aEnqueuePackets[NUM_OF_MGMT_QUEUES]; 118 TI_UINT32 aDequeuePackets[NUM_OF_MGMT_QUEUES]; 119 TI_UINT32 aRequeuePackets[NUM_OF_MGMT_QUEUES]; 120 TI_UINT32 aDroppedPackets[NUM_OF_MGMT_QUEUES]; 121 TI_UINT32 aXmittedPackets[NUM_OF_MGMT_QUEUES]; 122} TDbgCount; 123 124/* The module object. */ 125typedef struct 126{ 127 /* Handles */ 128 TI_HANDLE hOs; 129 TI_HANDLE hReport; 130 TI_HANDLE hTxCtrl; 131 TI_HANDLE hTxPort; 132 TI_HANDLE hContext; 133 134 TI_BOOL bMgmtPortEnable;/* Port open for mgmt-aQueues or not. */ 135 ESmState eSmState; /* The current state of the SM. */ 136 ETxConnState eTxConnState; /* See typedef in module API. */ 137 TI_UINT32 uContextId; /* ID allocated to this module on registration to context module */ 138 139 /* Mgmt aQueues */ 140 TI_HANDLE aQueues[NUM_OF_MGMT_QUEUES]; /* The mgmt-aQueues handles. */ 141 TI_BOOL aQueueBusy[NUM_OF_MGMT_QUEUES]; /* Related AC is busy. */ 142 TI_BOOL aQueueEnabledBySM[NUM_OF_MGMT_QUEUES]; /* Queue is enabled by the SM. */ 143 144 /* Debug Counters */ 145 TDbgCount tDbgCounters; /* Save Tx statistics per mgmt-queue. */ 146 147} TTxMgmtQ; 148 149/* The module internal functions */ 150static void mgmtQueuesSM (TTxMgmtQ *pTxMgmtQ, ESmEvent smEvent); 151static void runSchedulerNotFromSm (TTxMgmtQ *pTxMgmtQ); 152static void runScheduler (TTxMgmtQ *pTxMgmtQ); 153static void updateQueuesBusyMap (TTxMgmtQ *pTxMgmtQ, TI_UINT32 tidBitMap); 154 155/******************************************************************************* 156* PUBLIC FUNCTIONS IMPLEMENTATION * 157********************************************************************************/ 158 159 160/** 161 * \fn txMgmtQ_Create 162 * \brief Create the module and its queues 163 * 164 * Create the Tx Mgmt Queue module and its queues. 165 * 166 * \note 167 * \param hOs - Handle to the Os Abstraction Layer 168 * \return Handle to the allocated Tx Mgmt Queue module (NULL if failed) 169 * \sa 170 */ 171TI_HANDLE txMgmtQ_Create (TI_HANDLE hOs) 172{ 173 TTxMgmtQ *pTxMgmtQ; 174 175 /* allocate TxMgmtQueue module */ 176 pTxMgmtQ = os_memoryAlloc (hOs, (sizeof(TTxMgmtQ))); 177 178 if(!pTxMgmtQ) 179 { 180 WLAN_OS_REPORT(("Error allocating the TxMgmtQueue Module\n")); 181 return NULL; 182 } 183 184 /* Reset TxMgmtQueue module */ 185 os_memoryZero (hOs, pTxMgmtQ, (sizeof(TTxMgmtQ))); 186 187 return (TI_HANDLE)pTxMgmtQ; 188} 189 190 191/** 192 * \fn txMgmtQ_Init 193 * \brief Configure module with default settings 194* 195 * Get other modules handles. 196 * Init the Tx Mgmt queues. 197 * Register as the context-engine client. 198 * 199 * \note 200 * \param pStadHandles - The driver modules handles 201 * \return void 202 * \sa 203 */ 204void txMgmtQ_Init (TStadHandlesList *pStadHandles) 205{ 206 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)(pStadHandles->hTxMgmtQ); 207 TI_UINT32 uNodeHeaderOffset = TI_FIELD_OFFSET(TTxnStruct, tTxnQNode); 208 int uQueId; 209 210 /* configure modules handles */ 211 pTxMgmtQ->hOs = pStadHandles->hOs; 212 pTxMgmtQ->hReport = pStadHandles->hReport; 213 pTxMgmtQ->hTxCtrl = pStadHandles->hTxCtrl; 214 pTxMgmtQ->hTxPort = pStadHandles->hTxPort; 215 pTxMgmtQ->hContext = pStadHandles->hContext; 216 217 pTxMgmtQ->bMgmtPortEnable = TI_TRUE; /* Port Default status is open (data-queues are disabled). */ 218 pTxMgmtQ->eSmState = SM_STATE_CLOSE; /* SM default state is CLOSE. */ 219 pTxMgmtQ->eTxConnState = TX_CONN_STATE_CLOSE; 220 221 /* initialize tx Mgmt queues */ 222 for (uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 223 { 224 pTxMgmtQ->aQueues[uQueId] = que_Create (pTxMgmtQ->hOs, 225 pTxMgmtQ->hReport, 226 MGMT_QUEUES_DEPTH, 227 uNodeHeaderOffset); 228 229 /* If any Queues' allocation failed, print error, free TxMgmtQueue module and exit */ 230 if (pTxMgmtQ->aQueues[uQueId] == NULL) 231 { 232 TRACE0(pTxMgmtQ->hReport, REPORT_SEVERITY_CONSOLE , "Failed to create queue\n"); 233 WLAN_OS_REPORT(("Failed to create queue\n")); 234 os_memoryFree (pTxMgmtQ->hOs, pTxMgmtQ, sizeof(TTxMgmtQ)); 235 return; 236 } 237 238 pTxMgmtQ->aQueueBusy[uQueId] = TI_FALSE; /* aQueueBusy default is not busy. */ 239 pTxMgmtQ->aQueueEnabledBySM[uQueId] = TI_FALSE; /* Queue is disabled by the SM (state is CLOSE). */ 240 } 241 242 /* Register to the context engine and get the client ID */ 243 pTxMgmtQ->uContextId = context_RegisterClient (pTxMgmtQ->hContext, 244 txMgmtQ_QueuesNotEmpty, 245 (TI_HANDLE)pTxMgmtQ, 246 TI_TRUE, 247 "TX_MGMT", 248 sizeof("TX_MGMT")); 249 250TRACE0(pTxMgmtQ->hReport, REPORT_SEVERITY_INIT, ".....Tx Mgmt Queue configured successfully\n"); 251} 252 253 254/** 255 * \fn txMgmtQ_Destroy 256 * \brief Destroy the module and its queues 257 * 258 * Clear and destroy the queues and then destroy the module object. 259 * 260 * \note 261 * \param hTxMgmtQ - The module's object 262 * \return TI_OK - Unload succesfull, TI_NOK - Unload unsuccesfull 263 * \sa 264 */ 265TI_STATUS txMgmtQ_Destroy (TI_HANDLE hTxMgmtQ) 266{ 267 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 268 TI_STATUS eStatus = TI_OK; 269 int uQueId; 270 271 /* Dequeue and free all queued packets */ 272 txMgmtQ_ClearQueues (hTxMgmtQ); 273 274 /* free Mgmt queues */ 275 for (uQueId = 0 ; uQueId < NUM_OF_MGMT_QUEUES ; uQueId++) 276 { 277 if (que_Destroy(pTxMgmtQ->aQueues[uQueId]) != TI_OK) 278 { 279 TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, "txMgmtQueue_unLoad: fail to free Mgmt Queue number: %d\n",uQueId); 280 eStatus = TI_NOK; 281 } 282 } 283 284 /* free Tx Mgmt Queue Module */ 285 os_memoryFree (pTxMgmtQ->hOs, pTxMgmtQ, sizeof(TTxMgmtQ)); 286 287 return eStatus; 288} 289 290 291/** 292 * \fn txMgmtQ_ClearQueues 293 * \brief Clear all queues 294 * 295 * Dequeue and free all queued packets. 296 * 297 * \note 298 * \param hTxMgmtQ - The object 299 * \return void 300 * \sa 301 */ 302void txMgmtQ_ClearQueues (TI_HANDLE hTxMgmtQ) 303{ 304 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 305 TTxCtrlBlk *pPktCtrlBlk; 306 TI_UINT32 uQueId; 307 308 /* Dequeue and free all queued packets */ 309 for (uQueId = 0 ; uQueId < NUM_OF_MGMT_QUEUES ; uQueId++) 310 { 311 do { 312 context_EnterCriticalSection (pTxMgmtQ->hContext); 313 pPktCtrlBlk = (TTxCtrlBlk *)que_Dequeue(pTxMgmtQ->aQueues[uQueId]); 314 context_LeaveCriticalSection (pTxMgmtQ->hContext); 315 if (pPktCtrlBlk != NULL) { 316 txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); 317 } 318 } while (pPktCtrlBlk != NULL); 319 } 320} 321 322 323/** 324 * \fn txMgmtQ_Xmit 325 * \brief Insert non-data packet for transmission 326 * 327 * This function is used by the driver applications to send Tx packets other than the 328 * regular data traffic, including the following packet types: 329* - Management 330* - EAPOL 331* - NULL 332* - IAPP 333 * The managment packets are enqueued to the Mgmt-queue and the others to the Eapol-queue. 334 * EAPOL packets may be inserted from the network stack context, so it requires switching 335 * to the driver's context (after the packet is enqueued). 336 * If the selected queue was empty before the packet insertion, the SM is called 337 * with QUEUES_NOT_EMPTY event (in case of external context, only after the context switch). 338 * 339 * \note 340 * \param hTxMgmtQ - The module's object 341 * \param pPktCtrlBlk - Pointer to the packet CtrlBlk 342 * \param bExternalContext - Indicates if called from non-driver context 343 * \return TI_OK - if the packet was queued, TI_NOK - if the packet was dropped. 344 * \sa txMgmtQ_QueuesNotEmpty 345 */ 346TI_STATUS txMgmtQ_Xmit (TI_HANDLE hTxMgmtQ, TTxCtrlBlk *pPktCtrlBlk, TI_BOOL bExternalContext) 347{ 348 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 349 TI_STATUS eStatus; 350 TI_UINT32 uQueId; 351 TI_UINT32 uQueSize; 352 353 /* Always set highest TID for mgmt-queues packets. */ 354 pPktCtrlBlk->tTxDescriptor.tid = MGMT_QUEUES_TID; 355 356 /* Select queue asccording to the packet type */ 357 uQueId = (pPktCtrlBlk->tTxPktParams.uPktType == TX_PKT_TYPE_MGMT) ? QUEUE_TYPE_MGMT : QUEUE_TYPE_EAPOL ; 358 359 /* Enter critical section to protect queue access */ 360 context_EnterCriticalSection (pTxMgmtQ->hContext); 361 362 /* Enqueue the packet in the appropriate Queue */ 363 eStatus = que_Enqueue (pTxMgmtQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); 364 365 /* Get number of packets in current queue */ 366 uQueSize = que_Size (pTxMgmtQ->aQueues[uQueId]); 367 368 /* Leave critical section */ 369 context_LeaveCriticalSection (pTxMgmtQ->hContext); 370 371 /* If packet enqueued successfully */ 372 if (eStatus == TI_OK) 373 { 374 pTxMgmtQ->tDbgCounters.aEnqueuePackets[uQueId]++; 375 376 /* If selected queue was empty before packet insertion */ 377 if (uQueSize == 1) 378 { 379 /* If called from external context (EAPOL from network), request switch to the driver's context. */ 380 if (bExternalContext) 381 { 382 context_RequestSchedule (pTxMgmtQ->hContext, pTxMgmtQ->uContextId); 383 } 384 385 /* If already in the driver's context, call the SM with QUEUES_NOT_EMPTY event. */ 386 else 387 { 388 mgmtQueuesSM(pTxMgmtQ, SM_EVENT_QUEUES_NOT_EMPTY); 389 } 390 } 391 } 392 393 else 394 { 395 /* If the packet can't be queued so drop it */ 396 txCtrl_FreePacket (pTxMgmtQ->hTxCtrl, pPktCtrlBlk, TI_NOK); 397 pTxMgmtQ->tDbgCounters.aDroppedPackets[uQueId]++; 398 } 399 400 return eStatus; 401} 402 403 404/** 405 * \fn txMgmtQ_QueuesNotEmpty 406 * \brief Context-Engine Callback 407 * 408 * Context-Engine Callback for processing queues in driver's context. 409 * Called after driver's context scheduling was requested in txMgmtQ_Xmit(). 410 * Calls the SM with QUEUES_NOT_EMPTY event. 411 * 412 * \note 413 * \param hTxMgmtQ - The module's object 414 * \return void 415 * \sa txMgmtQ_Xmit 416 */ 417void txMgmtQ_QueuesNotEmpty (TI_HANDLE hTxMgmtQ) 418{ 419 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 420 421 /* Call the SM with QUEUES_NOT_EMPTY event. */ 422 mgmtQueuesSM(pTxMgmtQ, SM_EVENT_QUEUES_NOT_EMPTY); 423} 424 425 426/** 427 * \fn txMgmtQ_StopQueue 428 * \brief Context-Engine Callback 429 * 430 * This function is called by the txCtrl_xmitMgmt() if the queue's backpressure indication 431 * is set. It sets the internal queue's Busy indication. 432 * 433 * \note 434 * \param hTxMgmtQ - The module's object 435 * \param uTidBitMap - The busy TIDs bitmap 436 * \return void 437 * \sa txMgmtQ_UpdateBusyMap 438 */ 439void txMgmtQ_StopQueue (TI_HANDLE hTxMgmtQ, TI_UINT32 uTidBitMap) 440{ 441 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 442 443 /* Update the Queue(s) mode */ 444 updateQueuesBusyMap (pTxMgmtQ, uTidBitMap); 445} 446 447 448/** 449 * \fn txMgmtQ_UpdateBusyMap 450 * \brief Update the queues busy map 451 * 452 * This function is called by the txCtrl if the backpressure map per TID is changed. 453 * This could be as a result of Tx-Complete, admission change or association. 454 * The function modifies the internal queues Busy indication and calls the scheduler. 455 * 456 * \note 457 * \param hTxMgmtQ - The module's object 458 * \param uTidBitMap - The busy TIDs bitmap 459 * \return void 460 * \sa txMgmtQ_StopQueue 461 */ 462void txMgmtQ_UpdateBusyMap (TI_HANDLE hTxMgmtQ, TI_UINT32 uTidBitMap) 463{ 464 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 465 466 /* Update the Queue(s) busy map. */ 467 updateQueuesBusyMap (pTxMgmtQ, uTidBitMap); 468 469 /* If the queues are not empty, run the scheduler and if they become empty update the SM. */ 470 runSchedulerNotFromSm (pTxMgmtQ); 471} 472 473 474/** 475 * \fn txMgmtQ_StopAll 476 * \brief Stop all queues transmission 477 * 478 * This function is called by the Tx-Port when the whole Mgmt-queue is stopped. 479 * It clears the common queues enable indication. 480 * 481 * \note 482 * \param hTxMgmtQ - The module's object 483 * \return void 484 * \sa txMgmtQ_WakeAll 485 */ 486void txMgmtQ_StopAll (TI_HANDLE hTxMgmtQ) 487{ 488 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 489 490 /* Disable the Mgmt Tx port */ 491 pTxMgmtQ->bMgmtPortEnable = TI_FALSE; 492} 493 494 495/** 496 * \fn txMgmtQ_WakeAll 497 * \brief Enable all queues transmission 498 * 499 * This function is called by the Tx-Port when the whole Mgmt-queue is enabled. 500 * It sets the common queues enable indication and calls the scheduler. 501 * 502 * \note 503 * \param hTxMgmtQ - The module's object 504 * \return void 505 * \sa txMgmtQ_StopAll 506 */ 507void txMgmtQ_WakeAll (TI_HANDLE hTxMgmtQ) 508{ 509 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 510 511 /* Enable the Mgmt Tx port */ 512 pTxMgmtQ->bMgmtPortEnable = TI_TRUE; 513 514 /* If the queues are not empty, run the scheduler and if they become empty update the SM. */ 515 runSchedulerNotFromSm (pTxMgmtQ); 516} 517 518 519/** 520 * \fn txMgmtQ_SetConnState 521 * \brief Enable all queues transmission 522 * 523 * Called by the connection SM and updates the connection state from Tx perspective 524 * (i.e. which packet types are permitted). 525* Calls the local SM to handle this state change. 526* 527 * \note 528 * \param hTxMgmtQ - The module's object 529 * \param eTxConnState - The new Tx connection state 530 * \return void 531 * \sa mgmtQueuesSM 532 */ 533void txMgmtQ_SetConnState (TI_HANDLE hTxMgmtQ, ETxConnState eTxConnState) 534{ 535 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 536 537 pTxMgmtQ->eTxConnState = eTxConnState; 538 539 /* Call the SM with the current event. */ 540 switch (eTxConnState) 541 { 542 case TX_CONN_STATE_CLOSE: mgmtQueuesSM(pTxMgmtQ, SM_EVENT_CLOSE); break; 543 case TX_CONN_STATE_MGMT: mgmtQueuesSM(pTxMgmtQ, SM_EVENT_MGMT); break; 544 case TX_CONN_STATE_EAPOL: mgmtQueuesSM(pTxMgmtQ, SM_EVENT_EAPOL); break; 545 case TX_CONN_STATE_OPEN: mgmtQueuesSM(pTxMgmtQ, SM_EVENT_OPEN); break; 546 547 default: 548TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, ": Unknown eTxConnState = %d\n", eTxConnState); 549 } 550} 551 552 553 554/******************************************************************************* 555* INTERNAL FUNCTIONS IMPLEMENTATION * 556********************************************************************************/ 557 558 559/** 560 * \fn mgmtQueuesSM 561 * \brief The module state-machine (static function) 562 * 563 * The SM follows the system management states (see ETxConnState) and the Mgmt queues 564 * status (empty or not), and contorls the Tx queues flow accordingly (mgmt and data queues). 565 * For detailed explanation, see the Tx-Path LLD document! 566 * 567 * \note To avoid recursion issues, all SM actions are done at the end of the function, 568 * since some of them may invoke the SM again. 569 * \param pTxMgmtQ - The module's object 570 * \param eSmEvent - The event to act upon 571 * \return void 572 * \sa txMgmtQ_SetConnState 573 */ 574static void mgmtQueuesSM (TTxMgmtQ *pTxMgmtQ, ESmEvent eSmEvent) 575{ 576 ESmState ePrevState = pTxMgmtQ->eSmState; 577 ESmAction eSmAction = SM_ACTION_NULL; 578 579 switch(eSmEvent) 580 { 581 case SM_EVENT_CLOSE: 582 /* 583 * Tx link is closed (expected in any state), so disable both mgmt queues 584 * and if data-queues are active disable them via txPort module. 585 */ 586 pTxMgmtQ->eSmState = SM_STATE_CLOSE; 587 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_FALSE; 588 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_FALSE; 589 if (ePrevState == SM_STATE_OPEN_DATA) 590 eSmAction = SM_ACTION_ENABLE_MGMT; 591 break; 592 593 case SM_EVENT_MGMT: 594 /* 595 * Only Mgmt packets are permitted (expected from any state): 596 * - Enable the mgmt queue and disable the Eapol queue. 597 * - If data-queues are active disable them via txPort (this will run the scheduler). 598 * - Else run the scheduler (to send mgmt packets if waiting). 599 */ 600 pTxMgmtQ->eSmState = SM_STATE_MGMT; 601 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_TRUE; 602 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_FALSE; 603 if (ePrevState == SM_STATE_OPEN_DATA) 604 eSmAction = SM_ACTION_ENABLE_MGMT; 605 else 606 eSmAction = SM_ACTION_RUN_SCHEDULER; 607 break; 608 609 case SM_EVENT_EAPOL: 610 /* 611 * EAPOL packets are also permitted (expected in MGMT or CLOSE state), so enable the 612 * EAPOL queue and run the scheduler (to send packets from EAPOL queue if waiting). 613 */ 614 if ( (ePrevState != SM_STATE_CLOSE) && (ePrevState != SM_STATE_MGMT) ) 615 { 616TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, "mgmtQueuesSM: Got SmEvent=EAPOL when eSmState=%d\n", ePrevState); 617 } 618 pTxMgmtQ->eSmState = SM_STATE_EAPOL; 619 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_TRUE; 620 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_TRUE; 621 eSmAction = SM_ACTION_RUN_SCHEDULER; 622 break; 623 624 case SM_EVENT_OPEN: 625 /* 626 * All packets are now permitted (expected in EAPOL state), so if the mgmt-queues 627 * are empty disable them and enable the data queues via txPort module. 628 */ 629 if (ePrevState != SM_STATE_EAPOL) 630 { 631TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, "mgmtQueuesSM: Got SmEvent=OPEN when eSmState=%d\n", ePrevState); 632 } 633 if ( ARE_ALL_MGMT_QUEUES_EMPTY(pTxMgmtQ->aQueues) ) 634 { 635 pTxMgmtQ->eSmState = SM_STATE_OPEN_DATA; 636 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_FALSE; 637 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_FALSE; 638 eSmAction = SM_ACTION_ENABLE_DATA; 639 } 640 else 641 { 642 pTxMgmtQ->eSmState = SM_STATE_OPEN_MGMT; 643 } 644 break; 645 646 case SM_EVENT_QUEUES_EMPTY: 647 /* 648 * The mgmt-queues are empty, so if in OPEN_MGMT state disable the 649 * mgmt-queues and enable the data-queues via txPort module. 650 */ 651 if (ePrevState == SM_STATE_OPEN_MGMT) 652 { 653 pTxMgmtQ->eSmState = SM_STATE_OPEN_DATA; 654 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_FALSE; 655 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_FALSE; 656 eSmAction = SM_ACTION_ENABLE_DATA; 657 } 658 else 659 { 660 /* This may happen so it's just a warning and not an error. */ 661TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_WARNING, "mgmtQueuesSM: Got SmEvent=QUEUES_EMPTY when eSmState=%d\n", ePrevState); 662 } 663 break; 664 665 case SM_EVENT_QUEUES_NOT_EMPTY: 666 667 /* A packet was inserted to the mgmt-queues */ 668 669 /* 670 * If in OPEN_DATA state, enable mgmt-queues and disable data-queues via txPort module. 671 * 672 * Note: The scheduler is not run here because the txPort will call 673 * txMgmtQueue_wakeAll() which will run the scheduler. 674 */ 675 if (ePrevState == SM_STATE_OPEN_DATA) 676 { 677 pTxMgmtQ->eSmState = SM_STATE_OPEN_MGMT; 678 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_MGMT] = TI_TRUE; 679 pTxMgmtQ->aQueueEnabledBySM[QUEUE_TYPE_EAPOL] = TI_TRUE; 680 eSmAction = SM_ACTION_ENABLE_MGMT; 681 } 682 683 /* 684 * If in MGMT or EAPOL state, run the scheduler to transmit the packet. 685 */ 686 else if ( (ePrevState == SM_STATE_MGMT) || (ePrevState == SM_STATE_EAPOL) ) 687 { 688 eSmAction = SM_ACTION_RUN_SCHEDULER; 689 } 690 691 else 692 { 693 /* This may happen so it's just a warning and not an error. */ 694TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_WARNING, "mgmtQueuesSM: Got SmEvent=QUEUES_NOT_EMPTY when eSmState=%d\n", ePrevState); 695 } 696 break; 697 698 default: 699TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, "mgmtQueuesSM: Unknown SmEvent = %d\n", eSmEvent); 700 break; 701 } 702 703TRACE6( pTxMgmtQ->hReport, REPORT_SEVERITY_INFORMATION, "mgmtQueuesSM: <currentState = %d, event = %d> --> nextState = %d, action = %d, MgmtQueEnbl=%d, EapolQueEnbl=%d\n", ePrevState, eSmEvent, pTxMgmtQ->eSmState, eSmAction, pTxMgmtQ->aQueueEnabledBySM[0], pTxMgmtQ->aQueueEnabledBySM[1]); 704 705 /* 706 * Execute the required action. 707 * Note: This is done at the end of the SM because it may start a sequence that will call the SM again! 708 */ 709 switch (eSmAction) 710 { 711 case SM_ACTION_NULL: 712 break; 713 714 case SM_ACTION_ENABLE_DATA: 715 txPort_enableData(pTxMgmtQ->hTxPort); 716 break; 717 718 case SM_ACTION_ENABLE_MGMT: 719 txPort_enableMgmt(pTxMgmtQ->hTxPort); 720 break; 721 722 case SM_ACTION_RUN_SCHEDULER: 723 runScheduler(pTxMgmtQ); 724 break; 725 726 default: 727TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, ": Unknown SmAction = %d\n", eSmAction); 728 break; 729 } 730} 731 732 733/** 734 * \fn runSchedulerNotFromSm 735 * \brief Run scheduler due to other events then from SM (static function) 736 * 737 * To comply with the SM behavior, this function is used for any case where the 738 * Mgmt-Queues scheduler may have work to do due to events external to the SM. 739 * If the queues are not empty, this function runs the scheduler. 740* If the scheduler emptied the queues, update the SM. 741 * 742 * \note 743 * \param pTxMgmtQ - The module's object 744 * \return void 745 * \sa 746 */ 747static void runSchedulerNotFromSm (TTxMgmtQ *pTxMgmtQ) 748{ 749 /* If the queues are not empty, run the scheduler. */ 750 if ( !ARE_ALL_MGMT_QUEUES_EMPTY(pTxMgmtQ->aQueues) ) 751 { 752 runScheduler (pTxMgmtQ); 753 754 /* If the queues are now both empty, call the SM with QUEUES_EMPTY event. */ 755 if ( ARE_ALL_MGMT_QUEUES_EMPTY(pTxMgmtQ->aQueues) ) 756 { 757 mgmtQueuesSM (pTxMgmtQ, SM_EVENT_QUEUES_EMPTY); 758 } 759 } 760} 761 762 763/** 764 * \fn runScheduler 765 * \brief The scheduler processing (static function) 766 * 767 * Loops over the mgmt-queues (high priority first) and if queue enabled and 768 * has packets, dequeue a packet and send it to the TxCtrl. 769* Exit if the port level is disabled or if couldn't send anything from both queues. 770 * 771 * \note Protect the queues access against preemption from external context (EAPOL). 772 * \param pTxMgmtQ - The module's object 773 * \return void 774 * \sa 775 */ 776static void runScheduler (TTxMgmtQ *pTxMgmtQ) 777{ 778 TI_STATUS eStatus; 779 TTxCtrlBlk *pPktCtrlBlk; 780 TI_UINT32 uQueId = 0; /* start from highest priority queue */ 781 782 while(1) 783 { 784 /* If the Mgmt port is closed exit. */ 785 if ( !pTxMgmtQ->bMgmtPortEnable ) 786 { 787 return; 788 } 789 790 /* Check that the current queue is not busy and is enabled by the state-machine. */ 791 if ( !pTxMgmtQ->aQueueBusy[uQueId] && pTxMgmtQ->aQueueEnabledBySM[uQueId]) 792 { 793 /* Dequeue a packet in a critical section */ 794 context_EnterCriticalSection (pTxMgmtQ->hContext); 795 pPktCtrlBlk = (TTxCtrlBlk *) que_Dequeue (pTxMgmtQ->aQueues[uQueId]); 796 context_LeaveCriticalSection (pTxMgmtQ->hContext); 797 798 if (pPktCtrlBlk) 799 { 800 pTxMgmtQ->tDbgCounters.aDequeuePackets[uQueId]++; 801 802 /* Send the packet */ 803 eStatus = txCtrl_XmitMgmt (pTxMgmtQ->hTxCtrl, pPktCtrlBlk); 804 805 /* In case the return status is busy it means that the packet wasn't handled 806 so we need to requeue the packet for future try. */ 807 if(eStatus == STATUS_XMIT_BUSY) 808 { 809 /* Requeue the packet in a critical section */ 810 context_EnterCriticalSection (pTxMgmtQ->hContext); 811 que_Requeue (pTxMgmtQ->aQueues[uQueId], (TI_HANDLE)pPktCtrlBlk); 812 context_LeaveCriticalSection (pTxMgmtQ->hContext); 813 814 pTxMgmtQ->tDbgCounters.aRequeuePackets[uQueId]++; 815 } 816 817 /* The packet was handled by the lower Tx layers. */ 818 else 819 { 820 pTxMgmtQ->tDbgCounters.aXmittedPackets[uQueId]++; 821 822 /* Successful delivery so start next tx from the high priority queue (mgmt), 823 * giving it strict priority over the lower queue. 824 */ 825 uQueId = 0; 826 continue; 827 } 828 } 829 } 830 831 832 /* If we got here we couldn't deliver a packet from current queue, so progress to lower 833 * priority queue and if already in lowest queue exit. 834 */ 835 uQueId++; 836 if (uQueId < NUM_OF_MGMT_QUEUES) 837 continue; /* Try sending from next queue (i.e. the EAPOL queue). */ 838 else 839 return; /* We couldn't send from both queues so exit. */ 840 841 } /* End of while */ 842 843 /* Unreachable code */ 844} 845 846 847/** 848 * \fn updateQueuesBusyMap 849 * \brief Update queues busy map (static function) 850 * 851 * Set the queues busy indication on or off according to the highest TID bit 852 * in the tidBitMap (1 = busy). 853* Note that both Mgmt and Eapol queues are mapped to TID 7. 854* 855 * \note 856 * \param pTxMgmtQ - The module's object 857 * \param uTidBitMap - The TIDs bitmap of the queue(s) to update 858 * \return void 859 * \sa 860 */ 861static void updateQueuesBusyMap (TTxMgmtQ *pTxMgmtQ, TI_UINT32 uTidBitMap) 862{ 863 /* Set the queues busy indication on or off according to the highest TID bit (1 = busy). */ 864 if(uTidBitMap & (1 << MGMT_QUEUES_TID) ) 865 { 866 pTxMgmtQ->aQueueBusy[QUEUE_TYPE_MGMT ] = TI_TRUE; 867 pTxMgmtQ->aQueueBusy[QUEUE_TYPE_EAPOL] = TI_TRUE; 868 } 869 else 870 { 871 pTxMgmtQ->aQueueBusy[QUEUE_TYPE_MGMT ] = TI_FALSE; 872 pTxMgmtQ->aQueueBusy[QUEUE_TYPE_EAPOL] = TI_FALSE; 873 } 874} 875 876 877 878/******************************************************************************* 879* DEBUG FUNCTIONS IMPLEMENTATION * 880********************************************************************************/ 881 882#ifdef TI_DBG 883 884/** 885 * \fn txMgmtQ_PrintModuleParams 886 * \brief Print module's parameters (debug) 887 * 888 * This function prints the module's parameters. 889 * 890 * \note 891 * \param hTxMgmtQ - The module's object 892 * \return void 893 * \sa 894 */ 895void txMgmtQ_PrintModuleParams (TI_HANDLE hTxMgmtQ) 896{ 897 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 898 TI_UINT32 uQueId; 899 900 WLAN_OS_REPORT(("-------------- txMgmtQueue Module Params -----------------\n")); 901 WLAN_OS_REPORT(("==========================================================\n")); 902 903 WLAN_OS_REPORT(("eSmState = %d\n", pTxMgmtQ->eSmState)); 904 WLAN_OS_REPORT(("bMgmtPortEnable = %d\n", pTxMgmtQ->bMgmtPortEnable)); 905 WLAN_OS_REPORT(("eTxConnState = %d\n", pTxMgmtQ->eTxConnState)); 906 WLAN_OS_REPORT(("uContextId = %d\n", pTxMgmtQ->uContextId)); 907 908 WLAN_OS_REPORT(("-------------- Queues Busy (in HW) -----------------------\n")); 909 for(uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 910 { 911 WLAN_OS_REPORT(("Que[%d]: %d\n", uQueId, pTxMgmtQ->aQueueBusy[uQueId])); 912 } 913 914 WLAN_OS_REPORT(("-------------- Queues Enabled By SM ----------------------\n")); 915 for(uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 916 { 917 WLAN_OS_REPORT(("Que[%d]: %d\n", uQueId, pTxMgmtQ->aQueueBusy[uQueId])); 918 } 919 920 WLAN_OS_REPORT(("-------------- Queues Info -------------------------------\n")); 921 for(uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 922 { 923 WLAN_OS_REPORT(("Que %d:\n", uQueId)); 924 que_Print (pTxMgmtQ->aQueues[uQueId]); 925 } 926 927 WLAN_OS_REPORT(("==========================================================\n\n")); 928} 929 930 931/** 932 * \fn txMgmtQ_PrintQueueStatistics 933 * \brief Print queues statistics (debug) 934 * 935 * This function prints the module's Tx statistics per Queue. 936 * 937 * \note 938 * \param hTxMgmtQ - The module's object 939 * \return void 940 * \sa 941 */ 942void txMgmtQ_PrintQueueStatistics (TI_HANDLE hTxMgmtQ) 943{ 944#ifdef REPORT_LOG 945 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 946 TI_UINT32 uQueId; 947 948 WLAN_OS_REPORT(("-------------- Mgmt Queues Statistics -------------------\n")); 949 WLAN_OS_REPORT(("==========================================================\n")); 950 951 WLAN_OS_REPORT(("-------------- Enqueue Packets ---------------------------\n")); 952 for(uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 953 WLAN_OS_REPORT(("Que[%d]: %d\n", uQueId, pTxMgmtQ->tDbgCounters.aEnqueuePackets[uQueId])); 954 955 WLAN_OS_REPORT(("-------------- Dequeue Packets ---------------------------\n")); 956 for(uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 957 WLAN_OS_REPORT(("Que[%d]: %d\n", uQueId, pTxMgmtQ->tDbgCounters.aDequeuePackets[uQueId])); 958 959 WLAN_OS_REPORT(("-------------- Requeue Packets ---------------------------\n")); 960 for(uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 961 WLAN_OS_REPORT(("Que[%d]: %d\n", uQueId, pTxMgmtQ->tDbgCounters.aRequeuePackets[uQueId])); 962 963 WLAN_OS_REPORT(("-------------- Xmitted Packets ---------------------------\n")); 964 for(uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 965 WLAN_OS_REPORT(("Que[%d]: %d\n", uQueId, pTxMgmtQ->tDbgCounters.aXmittedPackets[uQueId])); 966 967 WLAN_OS_REPORT(("-------------- Dropped Packets (queue full) --------------\n")); 968 for(uQueId = 0; uQueId < NUM_OF_MGMT_QUEUES; uQueId++) 969 WLAN_OS_REPORT(("Que[%d]: %d\n", uQueId, pTxMgmtQ->tDbgCounters.aDroppedPackets[uQueId])); 970 971 WLAN_OS_REPORT(("==========================================================\n\n")); 972#endif 973} 974 975 976/** 977 * \fn txMgmtQ_ResetQueueStatistics 978 * \brief Reset queues statistics (debug) 979 * 980 * This function Resets the module's Tx statistics per Queue. 981 * 982 * \note 983 * \param hTxMgmtQ - The module's object 984 * \return void 985 * \sa 986 */ 987void txMgmtQ_ResetQueueStatistics (TI_HANDLE hTxMgmtQ) 988{ 989 TTxMgmtQ *pTxMgmtQ = (TTxMgmtQ *)hTxMgmtQ; 990 991 os_memoryZero(pTxMgmtQ->hOs, (void *)&(pTxMgmtQ->tDbgCounters), sizeof(TDbgCount)); 992} 993 994#endif /* TI_DBG */ 995 996