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 
    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 */
    150 static void mgmtQueuesSM (TTxMgmtQ *pTxMgmtQ, ESmEvent smEvent);
    151 static void runSchedulerNotFromSm (TTxMgmtQ *pTxMgmtQ);
    152 static void runScheduler (TTxMgmtQ *pTxMgmtQ);
    153 static 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  */
    171 TI_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  */
    204 void 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 
    250 TRACE0(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  */
    265 TI_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  */
    302 void 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  */
    346 TI_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  */
    417 void 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  */
    439 void 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  */
    462 void 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  */
    486 void 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  */
    507 void 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  */
    533 void 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:
    548 TRACE1(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  */
    574 static 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 			{
    616 TRACE1(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 			{
    631 TRACE1(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. */
    661 TRACE1(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. */
    694 TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_WARNING, "mgmtQueuesSM: Got SmEvent=QUEUES_NOT_EMPTY when eSmState=%d\n", ePrevState);
    695 			}
    696 			break;
    697 
    698 		default:
    699 TRACE1(pTxMgmtQ->hReport, REPORT_SEVERITY_ERROR, "mgmtQueuesSM: Unknown SmEvent = %d\n", eSmEvent);
    700 			break;
    701 	}
    702 
    703 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]);
    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:
    727 TRACE1(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  */
    747 static 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  */
    776 static 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  */
    861 static 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  */
    895 void 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  */
    942 void 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  */
    987 void 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