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