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