• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
txMgmtQ_Create(TI_HANDLE hOs)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  */
txMgmtQ_Init(TStadHandlesList * pStadHandles)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  */
txMgmtQ_Destroy(TI_HANDLE hTxMgmtQ)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  */
txMgmtQ_ClearQueues(TI_HANDLE hTxMgmtQ)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  */
txMgmtQ_Xmit(TI_HANDLE hTxMgmtQ,TTxCtrlBlk * pPktCtrlBlk,TI_BOOL bExternalContext)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  */
txMgmtQ_QueuesNotEmpty(TI_HANDLE hTxMgmtQ)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  */
txMgmtQ_StopQueue(TI_HANDLE hTxMgmtQ,TI_UINT32 uTidBitMap)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  */
txMgmtQ_UpdateBusyMap(TI_HANDLE hTxMgmtQ,TI_UINT32 uTidBitMap)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  */
txMgmtQ_StopAll(TI_HANDLE hTxMgmtQ)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  */
txMgmtQ_WakeAll(TI_HANDLE hTxMgmtQ)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  */
txMgmtQ_SetConnState(TI_HANDLE hTxMgmtQ,ETxConnState eTxConnState)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  */
mgmtQueuesSM(TTxMgmtQ * pTxMgmtQ,ESmEvent eSmEvent)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  */
runSchedulerNotFromSm(TTxMgmtQ * pTxMgmtQ)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  */
runScheduler(TTxMgmtQ * pTxMgmtQ)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  */
updateQueuesBusyMap(TTxMgmtQ * pTxMgmtQ,TI_UINT32 uTidBitMap)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  */
txMgmtQ_PrintModuleParams(TI_HANDLE hTxMgmtQ)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  */
txMgmtQ_PrintQueueStatistics(TI_HANDLE hTxMgmtQ)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  */
txMgmtQ_ResetQueueStatistics(TI_HANDLE hTxMgmtQ)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