]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/pdk.git/blob - packages/ti/drv/emac/example/cpswRateLimitExample/src/cpsw_rateLimit_test.c
emac-lld: add to PDK
[processor-sdk/pdk.git] / packages / ti / drv / emac / example / cpswRateLimitExample / src / cpsw_rateLimit_test.c
1 /**  
2  * @file cpsw_rateLimit_test.c
3  *
4  *   @n This example verifies the CPSW rate limit feature. It demostrates how to 
5  *      configure the CPSW for rate limiting operation and then generates traffic 
6  *      patterns to the CPSW according to the test scenario and then meausre the 
7  *      bandwidth of the received packet stream per priority against the expected 
8  *      results since the CPSW is set to internal or external loopback mode.
9  *
10  * @brief 
11  *  Example to illustrate the usage of EMAC CPSW switch to perform egress traffic 
12  *  rate limiting using CPPI, QMSS low level drivers and CSL.
13  *
14  *      This example application does the following:
15  *          (1) Initializes:
16  *                  (a) Queue Manager (QM) Subsystem 
17  *                  (b) Packet Accelerator (PA) CPPI DMA 
18  *                  (c) Ethernet Subsystem (Ethernet switch + CPTS + SGMII/RGMII + MDIO) 
19  *                  - (Note: Applicable only for NO_BOOT mode)
20  *
21  *          (2) Sets up the CPPI descriptors and Queues required for sending and
22  *              receiving data using Ethernet.
23  *                  (a) Uses Host descriptors
24  *
25  *          (3) Run CPSW rate limit test scenarios, for each test scenario
26  *          - configure CPSW rate limit control registers
27  *          - prepare and send multiple packet streams and process
28  *            receive packets. Record Tx and Rx packet information.
29  *          - Calculate the bandwidth of each receive data stream and
30  *            verify against expected result.
31  *
32  *      (4) Clear all resources           
33  *
34  *  \par
35  *  ============================================================================
36  *  @n   (C) Copyright 2015, Texas Instruments, Inc.
37  * 
38  *  Redistribution and use in source and binary forms, with or without 
39  *  modification, are permitted provided that the following conditions 
40  *  are met:
41  *
42  *    Redistributions of source code must retain the above copyright 
43  *    notice, this list of conditions and the following disclaimer.
44  *
45  *    Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the 
47  *    documentation and/or other materials provided with the   
48  *    distribution.
49  *
50  *    Neither the name of Texas Instruments Incorporated nor the names of
51  *    its contributors may be used to endorse or promote products derived
52  *    from this software without specific prior written permission.
53  *
54  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
55  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
56  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
57  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
58  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
59  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
60  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
61  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
62  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
63  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
64  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
65  *
66 */
67 #include <ti/board/board.h>
68 #include <ti/drv/emac/example/cpswRateLimitExample/src/cpsw_rateLimit_test.h>
69 #include <stdio.h>
71 /**************************************************************
72 ************************** DEFINITIONS ************************
73 ***************************************************************/
74 /*
75  * Default test configuration for the silicon
76  *
77  * To run test at the CCS simulator
78  *    cpswSimTest = 1
79  *    cpswLpbkMode = CPSW_LOOPBACK_INTERNAL
80  */
81 #ifdef  SIMULATOR_SUPPORT
82 int cpswSimTest = 1;
83 int cpswLpbkMode = CPSW_LOOPBACK_INTERNAL;
84 #else
85 int cpswSimTest = 0;
86 int cpswLpbkMode = CPSW_LOOPBACK_INTERNAL;
87 #endif
89 #ifdef __LINUX_USER_SPACE
90 uint32_t no_bootMode = FALSE;
91 /* Linux Specific global variables per process */
92 sock_h                 rmClientSocket;
93 sem_t                  mutex;
94 #else
95 uint32_t no_bootMode = TRUE;
96 #endif
98 #define DESC_ID_OFFSET         16
100 /* Define test packet templates, one per packet stream (priority) */
102 /* 
103  * packet 0: priority 0
104  * mac dest = 0a:0b:0c:0d:0e:0f
105  */                         
106 static uint8_t pkt0[1518] = {
107         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,               /* Dest MAC */
108         0x00, 0xe0, 0xa6, 0x66, 0x57, 0x04,               /* Src MAC  */
109         0x81, 0x00,                                       /* Ethertype = VLAN */
110         0x0a, 0xaa,                                       /* VLAN ID = 0xaaa, PCP = 0 */
111         0x00,                                             /* Group Id = priority */
112         };    
113         
114 /* 
115  * packet 1: priority 1
116  * mac dest = 0a:0b:0c:0d:0e:0f
117  */                         
118 static uint8_t pkt1[1518] = {
119         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,               /* Dest MAC */
120         0x00, 0xe0, 0xa6, 0x66, 0x57, 0x04,               /* Src MAC  */
121         0x81, 0x00,                                       /* Ethertype = VLAN */
122         0x2a, 0xaa,                                       /* VLAN ID = 0xaaa, PCP = 0 */
123         0x01,                                             /* Group Id = priority */
124         };    
125         
126 /* 
127  * packet 2: priority 2
128  * mac dest = 0a:0b:0c:0d:0e:0f
129  */                         
130 static uint8_t pkt2[1518] = {
131         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,               /* Dest MAC */
132         0x00, 0xe0, 0xa6, 0x66, 0x57, 0x04,               /* Src MAC  */
133         0x81, 0x00,                                       /* Ethertype = VLAN */
134         0x4a, 0xaa,                                       /* VLAN ID = 0xaaa, PCP = 0 */
135         0x02,                                             /* Group Id = priority */
136         };    
137         
138 /* 
139  * packet 3: priority 3
140  * mac dest = 0a:0b:0c:0d:0e:0f
141  */                         
142 static uint8_t pkt3[1518] = {
143         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,               /* Dest MAC */
144         0x00, 0xe0, 0xa6, 0x66, 0x57, 0x04,               /* Src MAC  */
145         0x81, 0x00,                                       /* Ethertype = VLAN */
146         0x6a, 0xaa,                                       /* VLAN ID = 0xaaa, PCP = 0 */
147         0x03,                                             /* Group Id = priority */
148         };    
149         
150 /* 
151  * packet 4: priority 4
152  * mac dest = 0a:0b:0c:0d:0e:0f
153  */                         
154 static uint8_t pkt4[1518] = {
155         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,               /* Dest MAC */
156         0x00, 0xe0, 0xa6, 0x66, 0x57, 0x04,               /* Src MAC  */
157         0x81, 0x00,                                       /* Ethertype = VLAN */
158         0x8a, 0xaa,                                       /* VLAN ID = 0xaaa, PCP = 0 */
159         0x04,                                             /* Group Id = priority */
160         };    
161 /* 
162  * packet 5: priority 5
163  * mac dest = 0a:0b:0c:0d:0e:0f
164  */                         
165 static uint8_t pkt5[1518] = {
166         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,               /* Dest MAC */
167         0x00, 0xe0, 0xa6, 0x66, 0x57, 0x04,               /* Src MAC  */
168         0x81, 0x00,                                       /* Ethertype = VLAN */
169         0xaa, 0xaa,                                       /* VLAN ID = 0xaaa, PCP = 0 */
170         0x05,                                             /* Group Id = priority */
171         };    
172         
173 /* 
174  * packet 6: priority 6
175  * mac dest = 0a:0b:0c:0d:0e:0f
176  */                         
177 static uint8_t pkt6[1518] = {
178         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,               /* Dest MAC */
179         0x00, 0xe0, 0xa6, 0x66, 0x57, 0x04,               /* Src MAC  */
180         0x81, 0x00,                                       /* Ethertype = VLAN */
181         0xca, 0xaa,                                       /* VLAN ID = 0xaaa, PCP = 0 */
182         0x06,                                             /* Group Id = priority */
183         }; 
184         
185 /* 
186  * packet 7: priority 7
187  * mac dest = 0a:0b:0c:0d:0e:0f
188  */                         
189 static uint8_t pkt7[1518] = {
190         0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,               /* Dest MAC */
191         0x00, 0xe0, 0xa6, 0x66, 0x57, 0x04,               /* Src MAC  */
192         0x81, 0x00,                                       /* Ethertype = VLAN */
193         0xea, 0xaa,                                       /* VLAN ID = 0xaaa, PCP = 0 */
194         0x07,                                             /* Group Id = priority */
195         };    
196         
197 static uint8_t* testPkt[MAX_PKT_GEN_INSTANCES] =
199     pkt0,
200     pkt1,
201     pkt2,
202     pkt3,
203     pkt4,
204     pkt5,
205     pkt6,
206     pkt7
207 };    
209 /************************ GLOBAL VARIABLES ********************/
210     
211            
212 uint32_t core_speed  = CORE_SPEED;                        /* Initialize system clock to be the default value */
213                                                           /* core_speed should be set to the actual system clock
214                                                              before the test starts if it is not the default value */
215 pktGenEngList_t pktGenEngList;                            /* Packet generate engine list */
216 pktGenEngState_t pktGenEngStates[MAX_PKT_GEN_INSTANCES];  /* Packet generate engines */
218 /* Error counter */
219 uint32_t                  errorCount = 0;
221 /************************ EXTERN VARIABLES ********************/
222 extern   Qmss_QueueHnd gRxQHnd;
224 /** ============================================================================
225  *   @n@b read_timer64
226  *
227  *   @b Description
228  *   @n Utility function to get 64 bit timer
229  *
230  *   @param[in]  
231  *   @n None
232  * 
233  *   @return    uint64_t: timer value
234  *               
235  * =============================================================================
236  */
237 static inline uint64_t read_timer64 ()
239     uint32_t low = TSCL;
240     uint32_t high = TSCH;
241     return _itoll (high, low);
244 /** ============================================================================
245  *   @n@b queue_divert_and_check
246  *
247  *   @b Description
248  *   @n Utility function to move all entries from the source queue to the
249  *      destination queue with error check.
250  *
251  *   @param[in]   src       The source queue handle
252  *   @param[in]   dst       The destination queue handle
253  * 
254  *   @return    None
255  * =============================================================================
256  */
257 static void queue_divert_and_check (Qmss_QueueHnd src, Qmss_QueueHnd dst)
259     Qmss_Result result;
261     if ((result = Qmss_queueDivert (src, dst, Qmss_Location_TAIL)) != QMSS_SOK)
262     {
263         UInt32 corenum = CSL_chipReadReg(CSL_CHIP_DNUM); 
264         errorCount++;
265         System_printf("core %d: queue divert from %d to %d failed: %d\n", corenum, src, dst, result);
266     }
269 /** ============================================================================
270  *   @n@b pkt_gen_reinsert_engine
271  *
272  *   @b Description
273  *   @n Utility function to Insert engine #idx into list based on updated head 
274  *      engine's nextTime
275  *      destination queue with error check.
276  *
277  *   @param[in]   
278  *   @n None   
279  * 
280  *   @return    None
281  * =============================================================================
282  */
283 static void pkt_gen_reinsert_engine (void)
285     uint32_t *list = pktGenEngList.idx;
286     int      tableEnd = pktGenEngList.numPresent;
287     uint32_t headIdx = list[0];
288     uint64_t val = pktGenEngStates[headIdx].nextTime;
289     uint32_t idx;
291     /* Shift list and insert head back into correct location based on nextTime */
292     for (idx = 1; idx < tableEnd; idx++)
293     {
294         if (val > pktGenEngStates[list[idx]].nextTime)
295         {
296             list[idx - 1] = list[idx];
297         }
298         else 
299         {
300             break;
301         }
302     }
303     list[idx - 1] = headIdx;
306 /** ============================================================================
307  *   @n@b ScenReceivePacket
308  *
309  *   @b Description
310  *   @n This API is called to process Rx packets.
311  *
312  *   @param[in] fRecordTime    flag to indicate whether to record the packet 
313  *                             receiving time
314  *   @return    int32_t        
315  *              1       -   One packet is received
316  *              0       -   No packet received
317  * =============================================================================
318  */
319 int32_t ScenReceivePacket (int fRecordTime)
321         Cppi_HostDesc       *pHostDesc;
322     uint32_t outIdx;
323     uint8_t*  pDataBuffer;
324     
325     /* Can only pop with size if something is there, else can
326      * get 0 for size and a pointer for the next desc! */
327     if (Qmss_getQueueEntryCount (gRxQHnd))
328     {
329         pHostDesc = (Cppi_HostDesc *)(((uint32_t)Qmss_queuePop (gRxQHnd)) & ~0xf);
330         pDataBuffer = (uint8_t *) pHostDesc->buffPtr;
331         
332         if (fRecordTime)
333         {
334             outIdx = pDataBuffer[DESC_ID_OFFSET];
335             pktGenEngStates[outIdx].packetsRx++;
336             pktGenEngStates[outIdx].bytesRx += pHostDesc->buffLen;
337             pktGenEngStates[outIdx].lastRxTime = read_timer64();
338         }
339     
340         /* Reset the buffer lenght and put the descriptor back on the free queue */    
341         pHostDesc->buffLen = pHostDesc->origBufferLen;
342         Qmss_queuePush (gRxFreeQHnd, (Ptr)pHostDesc, pHostDesc->buffLen, SIZE_HOST_DESC, Qmss_Location_TAIL);
343         
344         return (1);
345     }
346     
347     /* Verify packet done. Return success. */
348         return 0;
351 /** ============================================================================
352  *   @n@b sendScenarioModel
353  *
354  *   @b Description
355  *   @n Execute use case scenarios as defined at the packet generation 
356  *      configuration structure.
357  *      - Prepare and generate the packet streams accodingly
358  *      - Process receive packets
359  *      - Record Tx and Rx packet information
360  *
361  *   @param[in]   pktGen        The traffic generation configuration
362  *   @param[in]   startTime_p   The place to record traffic start time
363  * 
364  *   @return    
365  *   @n None
366  * =============================================================================
367  */
368 void sendScenarioModel (packetGenCfg_t *pktGen, uint64_t *startTime_p)
370     int gen;
371     Cppi_Desc*          pCppiDesc;
372     pktGenEngState_t    *genState;
373     packetGenInstCfg_t  *genCfg;
374     uint64_t            startTime, genEndTime, sampTime, thisTime, nextPlayTime, backlogTime;
375     uint32_t            pktSize;
376     Cppi_DescTag        tag;
378     /* Generate the packets while simutaneosly checking the results */
379     *startTime_p = startTime = read_timer64();
381     pktGenEngList.numPresent = 0;
382 #if defined(RATE_LIMIT_FAST_SCENARIO)
383     pktGen->genTime /= 100;
384     pktGen->readTime /= 100;
385 #endif
387     for (gen = 0; gen < MAX_PKT_GEN_INSTANCES; gen++)
388     {
389         genState = &pktGenEngStates[gen];
390         genCfg   = &pktGen->inst[gen];
391         
392         if(genCfg->pps == 0)
393             continue;
394         
395         genState->nextTime     = startTime;
396         genState->deltaTime    = core_speed / genCfg->pps;
397         genState->sizeIdx      = 0;
398         genState->packetsRx    = 0;
399         genState->bytesRx      = 0;
400         genState->bytesTx      = 0;
401         genState->packetsTx    = 0;
402         genState->packetsYanked = 0;
403         genState->packetsDropped = 0;
404         genState->outputQ = gPaTxQHnd[NSS_CPSW_QUEUE_ETH_INDEX_LITE + gen];
405         genState->pkt = testPkt[gen];
406         pktGenEngList.idx[pktGenEngList.numPresent++] = gen;
408         /* Check that valid sizes are given */
409         if (genCfg->sizeMode == packet_GEN_SIZE_MODE_RANDOM)
410         {
411             if ((genCfg->nSizes != 2) || 
412                 (genCfg->pktSize[0] > genCfg->pktSize[1]))
413             {
414                 System_printf("found invalid size mode configuration for gen %d\n", gen);
415             }
416         }
417     }
419     /* Generate the packets while simutaneosly checking the results */
420     genEndTime   = startTime + (uint64_t)(core_speed / 1000) * pktGen->genTime;
421     sampTime     = startTime + (uint64_t)(core_speed / 1000) * pktGen->readTime;
422     nextPlayTime = startTime;
423     genState     = &pktGenEngStates[pktGenEngList.idx[0]];
424     genCfg       = &pktGen->inst[pktGenEngList.idx[0]];
425     
426     tag.srcTagHi  = 0;
427     tag.srcTagLo  = 0;
428     tag.destTagHi = 0;
429     backlogTime   = 0;
430                 
431     while ( ((thisTime = read_timer64()) < genEndTime) && (thisTime < sampTime))
432     {
433         /* Should we send packet on first (soonest) engine? */
434         if (thisTime > nextPlayTime)
435         {
436             if((thisTime - nextPlayTime) > backlogTime)
437                 backlogTime = thisTime - nextPlayTime;
438             
439             if (Qmss_getQueueEntryCount (genState->outputQ) <= 5)
440             {
441                 /* Get a free descriptor */
442                 if ((pCppiDesc = Qmss_queuePop (gTxFreeQHnd)) == NULL)
443                 {
444                     System_printf ("No Tx free descriptor. Cant run sendScenarioModel \n");
445                     break;
446                 }
447             
448                 /* Decide the "size" of the packet (no real data is DMAd) */
449                 if (genCfg->sizeMode == packet_GEN_SIZE_MODE_ROUND_ROBIN)
450                 {
451                     pktSize = genCfg->pktSize[genState->sizeIdx++];
452                     if (genState->sizeIdx >= genCfg->nSizes)
453                     {
454                         genState->sizeIdx = 0;
455                     }
456                 }
457                 else
458                 {
459                     pktSize = (rand() % (genCfg->pktSize[1] - genCfg->pktSize[0])) + 
460                                 genCfg->pktSize[0];
461                 }
462             
463                 /* The descriptor address returned from the hardware has the
464                 * descriptor size appended to the address in the last 4 bits.
465                 *
466                 * To get the true descriptor size, always mask off the last
467                 * 4 bits of the address.
468                 */
469                 pCppiDesc = (Ptr) ((uint32_t) pCppiDesc & 0xFFFFFFF0);
471                 Cppi_setData (  Cppi_DescType_HOST,
472                                 (Cppi_Desc *) pCppiDesc,
473                                 (uint8_t *) Convert_CoreLocal2GlobalAddr((uint32_t)genState->pkt),
474                                 pktSize
475                             );
476                 Cppi_setPacketLen (Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, pktSize);
477         
478                 /* Clear PS Data */
479                 //Cppi_setPSLen (Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, 0);
480                 
481                 tag.destTagLo = EMAC_PORT_0;
482                 Cppi_setTag(Cppi_DescType_HOST, (Cppi_Desc *)pCppiDesc, (Cppi_DescTag *)&tag);
483     
484                     /* Send the packet out the mac. */
485                 Qmss_queuePush (genState->outputQ, pCppiDesc, pktSize, SIZE_HOST_DESC, Qmss_Location_TAIL);
486             
487                 /* stats */
488                 genState->packetsTx ++;
489                 genState->bytesTx += pktSize;
490             }
491             else
492             {
493                 /* There is no room to insert new packets */
494                 genState->packetsDropped++;
495             }
497             /* Reschedule the engine */
498             genState->nextTime += genState->deltaTime;
499             pkt_gen_reinsert_engine ();
500             
501             /* setup next generator */
502             genState     = &pktGenEngStates[pktGenEngList.idx[0]];
503             genCfg       = &pktGen->inst[pktGenEngList.idx[0]];
504             nextPlayTime = genState->nextTime;
505         }
506         
507         /* Try to drain the input */
508         ScenReceivePacket (1);
509     }
510     
511     /* Wait for sample time */
512     while ( ((thisTime = read_timer64()) < sampTime))
513     {
514         ScenReceivePacket (1);
515     }
517     /* Remove any remaining input */
518     for (gen = 0; gen < MAX_PKT_GEN_INSTANCES; gen++)
519     {
520         uint32_t bytes, entries;
521         
522         /* Skip unused channel */
523         if(pktGen->inst[gen].pps == 0)
524             continue; 
525         
526         queue_divert_and_check (pktGenEngStates[gen].outputQ, gDivQHnd);
527         bytes = Qmss_getQueueByteCount (gDivQHnd);
528         entries = Qmss_getQueueEntryCount (gDivQHnd);
529         pktGenEngStates[gen].bytesTx -= bytes;
530         pktGenEngStates[gen].packetsTx -= entries;
531         pktGenEngStates[gen].packetsYanked += entries;
532         queue_divert_and_check (gDivQHnd, gTxFreeQHnd);
533     }
535     /* Drain rest of output */
536     CycleDelay (10000);
537     while (ScenReceivePacket(0));
539     if (backlogTime > 250000)
540     {
541         System_printf ("NOTE: packet generator got behind by 0x%x%08x cycles\n",
542                        (uint32_t)(backlogTime >> 32), (uint32_t)backlogTime);
543     }
544 }  /* sendScenarioModel */
546 /** ============================================================================
547  *   @n@b scenario_test
548  *
549  *   @b Description
550  *   @n Execute each test scenario and check its results 
551  *
552  *   @param[in]   
553  *   @n None
554  * 
555  *   @return    
556  *   @n None
557  * =============================================================================
558  */
559 void scenario_test (void)
561     packetGenCfg_t      pktGen;
562     UInt32              corenum = CSL_chipReadReg(CSL_CHIP_DNUM); 
563     int                 i, gen;
564     packetGenInstCfg_t  *genCfg;
565     pktGenEngState_t    *genState;
566     uint64_t            startTime;
567     uint32_t            actRxTimeMs;
569     /* Read BOOTCFG_EFUSE_BOOTROM to determine core clock speed for EVM_K2G*/
570 #ifndef ICE_K2G
571     core_speed = Board_getDEVSPEED() * 1000000;
572 #endif
573     for (i = 0; rateLimitTestScenCfgs[i].fcn; i++)
574     {
575         /* Run the test case */
576         System_printf ("Core %d: Running scenario %d: %s\n", corenum, i + 1, rateLimitTestScenCfgs[i].desc);
577         System_flush();
578         
579         memset(&pktGen, 0, sizeof(pktGen));
580         
581         /* Test test scenario configuration */
582         if (rateLimitTestScenCfgs[i].fcn (&pktGen))
583         {
584             errorCount++;
585             continue;
586         }
587         
588         /* Run the model */
589         sendScenarioModel (&pktGen, &startTime);
591         /* Check results */
592         for (gen = 0; gen < MAX_PKT_GEN_INSTANCES; gen++)
593         {
594             uint32_t                actBPS;
595             uint32_t                actError;
597             genState = &pktGenEngStates[gen];
598             genCfg   = &pktGen.inst[gen];
599             
600             /* Skip unused channel */
601             if(genCfg->pps == 0)
602                 continue; 
603             
605             /* Check BPS */
606             actRxTimeMs = (genState->lastRxTime - startTime) / (core_speed/1000);
608             /* This reduces rounding error when packets go at low rate */
609             if (actRxTimeMs < pktGen.genTime)
610             {
611                 actRxTimeMs = pktGen.genTime;
612             }
613             actBPS = ((((uint64_t)genState->packetsRx * (ENET_DATA_PACKET_OVHD - 4)) + genState->bytesRx) * 8000) / actRxTimeMs;
614             actError = abs(genCfg->bpsExp - actBPS);
615             System_printf ("Core %d : stream %d : found %d bps, expected %d bps, error %d, allowed %d ", 
616                            corenum, gen, actBPS, genCfg->bpsExp, actError, genCfg->bpsError);
617                            
618 #ifndef SIMULATOR_SUPPORT
619             if (actError > genCfg->bpsError)
620             {
621                 System_printf ("(*** FAIL ***)\n");
622                 errorCount++;
623             }
624             else
625             {
626                 System_printf ("(PASS)\n");
627             }
628 #else
629             System_printf ("(*** Timing check skipped on simulator ***)\n");
630 #endif
632         }
633         
634         System_flush();
636     }
637 } /* scenario_test */
639 /**************************************************************
640 **************** EXAMPLE APP FUNCTIONS ************************
641 ***************************************************************/
644 /** ============================================================================
645  *   @n@b Cpsw_RateLimitTestApp
646  *
647  *   @b Description
648  *   @n Example application that sets up the application, run the rate limit
649  *      test scenarios and then clear all resources.
650  *
651  *   @param[in]  
652  *   @n None
653  * 
654  *   @return
655  *   @n None
656  *
657  * =============================================================================
658  */
659 #ifdef __LINUX_USER_SPACE
660 void* Cpsw_RateLimitTestApp (void *args)
661 #else
662 void Cpsw_RateLimitTestApp (void)
663 #endif
666     System_printf ("**************************************************\n");
667     System_printf ("********** CPSW Rate Limit Test Starts ***********\n");
668     System_printf ("**************************************************\n");
669     System_flush();
671 #if RM
672     if (setupRm ())
673     {
674       System_printf ("Function setupRm failed\n");
675       System_flush();
676       return;
677     }
678 #endif
680     /* Initialize the components required to run the example:
681      *  (1) QMSS
682      *  (2) CPPI
683      *  (3) Ethernet switch subsystem + MDIO + SGMII
684      */
685     
686     /* Initialize QMSS */
687     if (Init_Qmss () != 0)
688     {
689         System_printf ("QMSS init failed \n");
690         System_flush();
691         APP_exit (-1);
692     }
693     else
694     {
695         System_printf ("QMSS successfully initialized \n");
696         System_flush();
697     }
699     /* Initialize CPPI */
700     if (Init_Cppi () != 0)
701     {
702         System_printf ("CPPI init failed \n");
703         System_flush();
704         APP_exit (-1);
705     }
706     else
707     {
708         System_printf ("CPPI successfully initialized \n");
709         System_flush();
710     }
711  
712 #ifndef __LINUX_USER_SPACE
713     if (no_bootMode == TRUE)
714     {
715         /* Initialize the CPSW switch */
716         if (Init_Cpsw () != 0)
717         {
718             System_printf ("Ethernet subsystem init failed \n");
719             System_flush();
720             APP_exit (-1);
721         }
722         else
723         {
724             System_printf ("Ethernet subsystem successfully initialized \n");
725             System_flush();
726         }
727     }
728 #endif
730     /* Setup Tx */
731     if (Setup_Tx () != 0)
732     {
733         System_printf ("Tx setup failed \n");
734         System_flush();
735         APP_exit (-1);
736     }
737     else
738     {
739         System_printf ("Tx setup successfully done \n");
740         System_flush();
741     }
743     /* Setup Rx */
744     if (Setup_Rx () != 0)
745     {
746         System_printf ("Rx setup failed \n");
747         System_flush();
748         APP_exit (-1);
749     }
750     else
751     {
752         System_printf ("Rx setup successfully done \n");
753         System_flush();
754     }
755     
756     System_printf ("Running CPSW Rate Limit Scenarios!\n");
757     System_flush();
758     
759     /* run all test scenarios */
760     scenario_test ();
762     if(!errorCount)
763         System_printf("All tests have passed!\n");
764     System_printf ("**************************************************\n");
765     System_printf ("*********** CPSW Rate Limit Test Ends ************\n");
766     System_printf ("**************************************************\n");
767     System_flush();
769     /* Clear framework */
770         if (clearFramework() < 0) 
771         {
772         System_printf ("Failed to Clean the example application \n");
773         System_flush();
774         }
776 #if (RM) && !defined(__LINUX_USER_SPACE)
777     {
778         int32_t rmResult;
780         if ((rmResult = Rm_resourceStatus(rmHandle, FALSE)) != 0)
781         {
782             System_printf ("Error : Number of unfreed resources : %d\n", rmResult);
783             System_flush();
784         }
785         else
786         {
787             System_printf ("All resources freed successfully\n");
788             System_flush();
789         }
790     }
791 #endif
792     /* Example application done. Return success */
793     APP_exit (0);
796 /* Nothing past this point */