1 /**
2  * @file    QMgrQCfg.c
3  *
4  * @author Intel Corporation
5  * @date    30-Oct-2001
6  *
7  * @brief   This modules provides an interface for setting up the static
8  * configuration of AQM queues.This file contains the following
9  * functions:
10  *
11  *
12  *
13  * @par
14  * IXP400 SW Release version 2.0
15  *
16  * -- Copyright Notice --
17  *
18  * @par
19  * Copyright 2001-2005, Intel Corporation.
20  * All rights reserved.
21  *
22  * @par
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  * 1. Redistributions of source code must retain the above copyright
27  *    notice, this list of conditions and the following disclaimer.
28  * 2. Redistributions in binary form must reproduce the above copyright
29  *    notice, this list of conditions and the following disclaimer in the
30  *    documentation and/or other materials provided with the distribution.
31  * 3. Neither the name of the Intel Corporation nor the names of its contributors
32  *    may be used to endorse or promote products derived from this software
33  *    without specific prior written permission.
34  *
35  * @par
36  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
37  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
40  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  *
48  * @par
49  * -- End of Copyright Notice --
50 */
51 
52 /*
53  * System defined include files.
54  */
55 
56 /*
57  * User defined include files.
58  */
59 #include "IxOsal.h"
60 #include "IxQMgr.h"
61 #include "IxQMgrAqmIf_p.h"
62 #include "IxQMgrQCfg_p.h"
63 #include "IxQMgrDefines_p.h"
64 
65 /*
66  * #defines and macros used in this file.
67  */
68 
69 #define IX_QMGR_MIN_ENTRY_SIZE_IN_WORDS 16
70 
71 /* Total size of SRAM */
72 #define IX_QMGR_AQM_SRAM_SIZE_IN_BYTES 0x4000
73 
74 /*
75  * Check that qId is a valid queue identifier. This is provided to
76  * make the code easier to read.
77  */
78 #define IX_QMGR_QID_IS_VALID(qId) \
79 (((qId) >= (IX_QMGR_MIN_QID)) && ((qId) <= (IX_QMGR_MAX_QID)))
80 
81 /*
82  * Typedefs whose scope is limited to this file.
83  */
84 
85 /*
86  * This struct describes an AQM queue.
87  * N.b. bufferSizeInWords and qEntrySizeInWords are stored in the queue
88  * as these are requested by Access in the data path. sizeInEntries is
89  * not required by the data path so it can be calculated dynamically.
90  *
91  */
92 typedef struct
93 {
94     char qName[IX_QMGR_MAX_QNAME_LEN+1];       /* Textual description of a queue*/
95     IxQMgrQSizeInWords qSizeInWords;           /* The number of words in the queue */
96     IxQMgrQEntrySizeInWords qEntrySizeInWords; /* Number of words per queue entry*/
97     BOOL isConfigured;                         /* This flag is TRUE if the queue has
98                                                 *   been configured
99                                                 */
100 } IxQMgrCfgQ;
101 
102 /*
103  * Variable declarations global to this file. Externs are followed by
104  * statics.
105  */
106 
107 extern UINT32 * ixQMgrAqmIfQueAccRegAddr[];
108 
109 /* Store data required to inline read and write access
110  */
111 IxQMgrQInlinedReadWriteInfo ixQMgrQInlinedReadWriteInfo[IX_QMGR_MAX_NUM_QUEUES];
112 
113 static IxQMgrCfgQ cfgQueueInfo[IX_QMGR_MAX_NUM_QUEUES];
114 
115 /* This pointer holds the starting address of AQM SRAM not used by
116  * the AQM queues.
117  */
118 static UINT32 freeSramAddress=0;
119 
120 /* 4 words of zeroed memory for inline access */
121 static UINT32 zeroedPlaceHolder[4] = { 0, 0, 0, 0 };
122 
123 static BOOL cfgInitialized = FALSE;
124 
125 static IxOsalMutex ixQMgrQCfgMutex;
126 
127 /*
128  * Statistics
129  */
130 static IxQMgrQCfgStats stats;
131 
132 /*
133  * Function declarations
134  */
135 PRIVATE BOOL
136 watermarkLevelIsOk (IxQMgrQId qId, IxQMgrWMLevel level);
137 
138 PRIVATE BOOL
139 qSizeInWordsIsOk (IxQMgrQSizeInWords qSize);
140 
141 PRIVATE BOOL
142 qEntrySizeInWordsIsOk (IxQMgrQEntrySizeInWords entrySize);
143 
144 /*
145  * Function definitions.
146  */
147 void
ixQMgrQCfgInit(void)148 ixQMgrQCfgInit (void)
149 {
150     int loopIndex;
151 
152     for (loopIndex=0; loopIndex < IX_QMGR_MAX_NUM_QUEUES;loopIndex++)
153     {
154 	/* info for code inlining */
155 	ixQMgrAqmIfQueAccRegAddr[loopIndex] = zeroedPlaceHolder;
156 
157 	/* info for code inlining */
158 	ixQMgrQInlinedReadWriteInfo[loopIndex].qReadCount = 0;
159 	ixQMgrQInlinedReadWriteInfo[loopIndex].qWriteCount = 0;
160 	ixQMgrQInlinedReadWriteInfo[loopIndex].qAccRegAddr = zeroedPlaceHolder;
161 	ixQMgrQInlinedReadWriteInfo[loopIndex].qUOStatRegAddr = zeroedPlaceHolder;
162 	ixQMgrQInlinedReadWriteInfo[loopIndex].qUflowStatBitMask = 0;
163 	ixQMgrQInlinedReadWriteInfo[loopIndex].qOflowStatBitMask = 0;
164 	ixQMgrQInlinedReadWriteInfo[loopIndex].qEntrySizeInWords = 0;
165 	ixQMgrQInlinedReadWriteInfo[loopIndex].qSizeInEntries = 0;
166 	ixQMgrQInlinedReadWriteInfo[loopIndex].qConfigRegAddr = zeroedPlaceHolder;
167    }
168 
169     /* Initialise the AqmIf component */
170     ixQMgrAqmIfInit ();
171 
172     /* Reset all queues to have queue name = NULL, entry size = 0 and
173      * isConfigured = false
174      */
175     for (loopIndex=0; loopIndex < IX_QMGR_MAX_NUM_QUEUES;loopIndex++)
176     {
177 	strcpy (cfgQueueInfo[loopIndex].qName, "");
178 	cfgQueueInfo[loopIndex].qSizeInWords = 0;
179 	cfgQueueInfo[loopIndex].qEntrySizeInWords = 0;
180 	cfgQueueInfo[loopIndex].isConfigured = FALSE;
181 
182 	/* Statistics */
183 	stats.qStats[loopIndex].isConfigured = FALSE;
184 	stats.qStats[loopIndex].qName = cfgQueueInfo[loopIndex].qName;
185     }
186 
187     /* Statistics */
188     stats.wmSetCnt = 0;
189 
190     ixQMgrAqmIfSramBaseAddressGet (&freeSramAddress);
191 
192     ixOsalMutexInit(&ixQMgrQCfgMutex);
193 
194     cfgInitialized = TRUE;
195 }
196 
197 void
ixQMgrQCfgUninit(void)198 ixQMgrQCfgUninit (void)
199 {
200     cfgInitialized = FALSE;
201 
202     /* Uninitialise the AqmIf component */
203     ixQMgrAqmIfUninit ();
204 }
205 
206 IX_STATUS
ixQMgrQConfig(char * qName,IxQMgrQId qId,IxQMgrQSizeInWords qSizeInWords,IxQMgrQEntrySizeInWords qEntrySizeInWords)207 ixQMgrQConfig (char *qName,
208 	      IxQMgrQId qId,
209 	      IxQMgrQSizeInWords qSizeInWords,
210 	      IxQMgrQEntrySizeInWords qEntrySizeInWords)
211 {
212     UINT32 aqmLocalBaseAddress;
213 
214     if (!cfgInitialized)
215     {
216         return IX_FAIL;
217     }
218 
219     if (!IX_QMGR_QID_IS_VALID(qId))
220     {
221 	return IX_QMGR_INVALID_Q_ID;
222     }
223 
224     else if (NULL == qName)
225     {
226 	return IX_QMGR_PARAMETER_ERROR;
227     }
228 
229     else if (strlen (qName) > IX_QMGR_MAX_QNAME_LEN)
230     {
231 	return IX_QMGR_PARAMETER_ERROR;
232     }
233 
234     else if (!qSizeInWordsIsOk (qSizeInWords))
235     {
236 	return IX_QMGR_INVALID_QSIZE;
237     }
238 
239     else if (!qEntrySizeInWordsIsOk (qEntrySizeInWords))
240     {
241 	return IX_QMGR_INVALID_Q_ENTRY_SIZE;
242     }
243 
244     else if (cfgQueueInfo[qId].isConfigured)
245     {
246 	return IX_QMGR_Q_ALREADY_CONFIGURED;
247     }
248 
249     ixOsalMutexLock(&ixQMgrQCfgMutex, IX_OSAL_WAIT_FOREVER);
250 
251     /* Write the config register */
252     ixQMgrAqmIfQueCfgWrite (qId,
253 			   qSizeInWords,
254 			   qEntrySizeInWords,
255 			   freeSramAddress);
256 
257 
258     strcpy (cfgQueueInfo[qId].qName, qName);
259     cfgQueueInfo[qId].qSizeInWords = qSizeInWords;
260     cfgQueueInfo[qId].qEntrySizeInWords = qEntrySizeInWords;
261 
262     /* store pre-computed information in the same cache line
263      * to facilitate inlining of QRead and QWrite functions
264      * in IxQMgr.h
265      */
266     ixQMgrQInlinedReadWriteInfo[qId].qReadCount = 0;
267     ixQMgrQInlinedReadWriteInfo[qId].qWriteCount = 0;
268     ixQMgrQInlinedReadWriteInfo[qId].qEntrySizeInWords = qEntrySizeInWords;
269     ixQMgrQInlinedReadWriteInfo[qId].qSizeInEntries =
270 		(UINT32)qSizeInWords / (UINT32)qEntrySizeInWords;
271 
272     /* Calculate the new freeSramAddress from the size of the queue
273      * currently being configured.
274      */
275     freeSramAddress += (qSizeInWords * IX_QMGR_NUM_BYTES_PER_WORD);
276 
277     /* Get the virtual SRAM address */
278     ixQMgrAqmIfBaseAddressGet (&aqmLocalBaseAddress);
279 
280     IX_OSAL_ASSERT((freeSramAddress - (aqmLocalBaseAddress + (IX_QMGR_QUEBUFFER_SPACE_OFFSET))) <=
281 	      IX_QMGR_QUE_BUFFER_SPACE_SIZE);
282 
283     /* The queue is now configured */
284     cfgQueueInfo[qId].isConfigured = TRUE;
285 
286     ixOsalMutexUnlock(&ixQMgrQCfgMutex);
287 
288 #ifndef NDEBUG
289     /* Update statistics */
290     stats.qStats[qId].isConfigured = TRUE;
291     stats.qStats[qId].qName = cfgQueueInfo[qId].qName;
292 #endif
293     return IX_SUCCESS;
294 }
295 
296 IxQMgrQSizeInWords
ixQMgrQSizeInWordsGet(IxQMgrQId qId)297 ixQMgrQSizeInWordsGet (IxQMgrQId qId)
298 {
299     /* No parameter checking as this is used on the data path */
300     return (cfgQueueInfo[qId].qSizeInWords);
301 }
302 
303 IX_STATUS
ixQMgrQSizeInEntriesGet(IxQMgrQId qId,unsigned * qSizeInEntries)304 ixQMgrQSizeInEntriesGet (IxQMgrQId qId,
305 			 unsigned *qSizeInEntries)
306 {
307     if (!ixQMgrQIsConfigured(qId))
308     {
309         return IX_QMGR_Q_NOT_CONFIGURED;
310     }
311 
312     if(NULL == qSizeInEntries)
313     {
314         return IX_QMGR_PARAMETER_ERROR;
315     }
316 
317     *qSizeInEntries = (UINT32)(cfgQueueInfo[qId].qSizeInWords) /
318         (UINT32)cfgQueueInfo[qId].qEntrySizeInWords;
319 
320     return IX_SUCCESS;
321 }
322 
323 IxQMgrQEntrySizeInWords
ixQMgrQEntrySizeInWordsGet(IxQMgrQId qId)324 ixQMgrQEntrySizeInWordsGet (IxQMgrQId qId)
325 {
326     /* No parameter checking as this is used on the data path */
327     return (cfgQueueInfo[qId].qEntrySizeInWords);
328 }
329 
330 IX_STATUS
ixQMgrWatermarkSet(IxQMgrQId qId,IxQMgrWMLevel ne,IxQMgrWMLevel nf)331 ixQMgrWatermarkSet (IxQMgrQId qId,
332 		    IxQMgrWMLevel ne,
333 		    IxQMgrWMLevel nf)
334 {
335     IxQMgrQStatus qStatusOnEntry;/* The queue status on entry/exit */
336     IxQMgrQStatus qStatusOnExit; /* to this function               */
337 
338     if (!ixQMgrQIsConfigured(qId))
339     {
340         return IX_QMGR_Q_NOT_CONFIGURED;
341     }
342 
343     if (!watermarkLevelIsOk (qId, ne))
344     {
345 	return IX_QMGR_INVALID_Q_WM;
346     }
347 
348     if (!watermarkLevelIsOk (qId, nf))
349     {
350 	return IX_QMGR_INVALID_Q_WM;
351     }
352 
353     /* Get the current queue status */
354     ixQMgrAqmIfQueStatRead (qId, &qStatusOnEntry);
355 
356 #ifndef NDEBUG
357     /* Update statistics */
358     stats.wmSetCnt++;
359 #endif
360 
361     ixQMgrAqmIfWatermarkSet (qId,
362 			    ne,
363 			    nf);
364 
365     /* Get the current queue status */
366     ixQMgrAqmIfQueStatRead (qId, &qStatusOnExit);
367 
368     /* If the status has changed return a warning */
369     if (qStatusOnEntry != qStatusOnExit)
370     {
371 	return IX_QMGR_WARNING;
372     }
373 
374     return IX_SUCCESS;
375 }
376 
377 IX_STATUS
ixQMgrAvailableSramAddressGet(UINT32 * address,unsigned * sizeOfFreeRam)378 ixQMgrAvailableSramAddressGet (UINT32 *address,
379 			      unsigned *sizeOfFreeRam)
380 {
381     UINT32 aqmLocalBaseAddress;
382 
383     if ((NULL == address)||(NULL == sizeOfFreeRam))
384     {
385 	return IX_QMGR_PARAMETER_ERROR;
386     }
387     if (!cfgInitialized)
388     {
389 	return IX_FAIL;
390     }
391 
392     *address = freeSramAddress;
393 
394     /* Get the virtual SRAM address */
395     ixQMgrAqmIfBaseAddressGet (&aqmLocalBaseAddress);
396 
397     /*
398      * Calculate the size in bytes of free sram
399      * i.e. current free SRAM virtual pointer from
400      *      (base + total size)
401      */
402     *sizeOfFreeRam =
403 	(aqmLocalBaseAddress +
404 	IX_QMGR_AQM_SRAM_SIZE_IN_BYTES) -
405 	freeSramAddress;
406 
407     if (0 == *sizeOfFreeRam)
408     {
409 	return IX_QMGR_NO_AVAILABLE_SRAM;
410     }
411 
412     return IX_SUCCESS;
413 }
414 
415 BOOL
ixQMgrQIsConfigured(IxQMgrQId qId)416 ixQMgrQIsConfigured (IxQMgrQId qId)
417 {
418     if (!IX_QMGR_QID_IS_VALID(qId))
419     {
420 	return FALSE;
421     }
422 
423     return cfgQueueInfo[qId].isConfigured;
424 }
425 
426 IxQMgrQCfgStats*
ixQMgrQCfgStatsGet(void)427 ixQMgrQCfgStatsGet (void)
428 {
429     return &stats;
430 }
431 
432 IxQMgrQCfgStats*
ixQMgrQCfgQStatsGet(IxQMgrQId qId)433 ixQMgrQCfgQStatsGet (IxQMgrQId qId)
434 {
435     unsigned int ne;
436     unsigned int nf;
437     UINT32 baseAddress;
438     UINT32 readPtr;
439     UINT32 writePtr;
440 
441     stats.qStats[qId].qSizeInWords = cfgQueueInfo[qId].qSizeInWords;
442     stats.qStats[qId].qEntrySizeInWords = cfgQueueInfo[qId].qEntrySizeInWords;
443 
444     if (IX_SUCCESS != ixQMgrQNumEntriesGet (qId, &stats.qStats[qId].numEntries))
445     {
446         if (IX_QMGR_WARNING != ixQMgrQNumEntriesGet (qId, &stats.qStats[qId].numEntries))
447         {
448 	   IX_QMGR_LOG_WARNING1("Failed to get the number of entries in queue.... %d\n", qId);
449         }
450     }
451 
452     ixQMgrAqmIfQueCfgRead (qId,
453 			   stats.qStats[qId].numEntries,
454 			   &baseAddress,
455 			   &ne,
456 			   &nf,
457 			   &readPtr,
458 			   &writePtr);
459 
460     stats.qStats[qId].baseAddress = baseAddress;
461     stats.qStats[qId].ne = ne;
462     stats.qStats[qId].nf = nf;
463     stats.qStats[qId].readPtr = readPtr;
464     stats.qStats[qId].writePtr = writePtr;
465 
466     return &stats;
467 }
468 
469 /*
470  * Static function definitions
471  */
472 
473 PRIVATE BOOL
watermarkLevelIsOk(IxQMgrQId qId,IxQMgrWMLevel level)474 watermarkLevelIsOk (IxQMgrQId qId, IxQMgrWMLevel level)
475 {
476     unsigned qSizeInEntries;
477 
478     switch (level)
479     {
480 	case IX_QMGR_Q_WM_LEVEL0:
481 	case IX_QMGR_Q_WM_LEVEL1:
482 	case IX_QMGR_Q_WM_LEVEL2:
483 	case IX_QMGR_Q_WM_LEVEL4:
484 	case IX_QMGR_Q_WM_LEVEL8:
485 	case IX_QMGR_Q_WM_LEVEL16:
486 	case IX_QMGR_Q_WM_LEVEL32:
487 	case IX_QMGR_Q_WM_LEVEL64:
488 	    break;
489 	default:
490 	    return FALSE;
491     }
492 
493     /* Check watermark is not bigger than the qSizeInEntries */
494     ixQMgrQSizeInEntriesGet(qId, &qSizeInEntries);
495 
496     if ((unsigned)level > qSizeInEntries)
497     {
498 	return FALSE;
499     }
500 
501     return TRUE;
502 }
503 
504 PRIVATE BOOL
qSizeInWordsIsOk(IxQMgrQSizeInWords qSize)505 qSizeInWordsIsOk (IxQMgrQSizeInWords qSize)
506 {
507     BOOL status;
508 
509     switch (qSize)
510     {
511 	case IX_QMGR_Q_SIZE16:
512 	case IX_QMGR_Q_SIZE32:
513 	case IX_QMGR_Q_SIZE64:
514 	case IX_QMGR_Q_SIZE128:
515 	    status = TRUE;
516 	    break;
517 	default:
518 	    status = FALSE;
519 	    break;
520     }
521 
522     return status;
523 }
524 
525 PRIVATE BOOL
qEntrySizeInWordsIsOk(IxQMgrQEntrySizeInWords entrySize)526 qEntrySizeInWordsIsOk (IxQMgrQEntrySizeInWords entrySize)
527 {
528     BOOL status;
529 
530     switch (entrySize)
531     {
532 	case IX_QMGR_Q_ENTRY_SIZE1:
533 	case IX_QMGR_Q_ENTRY_SIZE2:
534 	case IX_QMGR_Q_ENTRY_SIZE4:
535 	    status = TRUE;
536 	    break;
537 	default:
538 	    status = FALSE;
539 	    break;
540     }
541 
542     return status;
543 }
544