1 /* =============================================================================
2 * Copyright (c) Texas Instruments Incorporated 2015
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the
14 * distribution.
15 *
16 * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
34 /**
35 * \file test_utils.c
36 *
37 * \brief This file contains common utility functions used by the emac loopback unit
38 * test applications.
39 *
40 */
42 #include <string.h>
44 #include <xdc/std.h>
45 #include <ti/sysbios/BIOS.h>
46 #include <ti/sysbios/knl/Task.h>
48 #include <ti/csl/csl_chip.h>
49 /* EMAC Driver Header File. */
50 #include <ti/drv/emac/emac_drv.h>
52 /* SOC Include Files. */
53 #include <ti/drv/emac/soc/emac_soc_v4.h>
55 /* Test application local header file */
56 #include "test_loc.h"
58 #include <ti/drv/uart/UART.h>
59 #include <ti/drv/uart/UART_stdio.h>
60 #include <ti/board/board.h>
62 extern EMAC_MAC_ADDR_T macAddr1;
63 extern EMAC_OPEN_CONFIG_INFO_T open_cfg;
64 extern uint32_t linkStatus;
65 extern void Osal_enterSingleCoreCriticalSection(Uint32 port_num);
66 extern void Osal_exitSingleCoreCriticalSection(Uint32 port_num);
68 extern void Osal_beginMemAccess(void* addr, Uint32 size);
69 extern void Osal_endMemAccess(void* addr, Uint32 size);
70 /**********************************************************************
71 ************************** Global Variables **************************
72 **********************************************************************/
73 #ifdef _TMS320C6X
74 /* Memory allocated for the packet buffer. This is 128 bytes aligned. */
75 uint8_t app_pkt_buffer[APP_TOTAL_PKTBUF_SIZE];
76 #pragma DATA_ALIGN(app_pkt_buffer, 64)
78 /* Memory allocated for the application control block */
79 #else
80 uint8_t app_pkt_buffer[APP_TOTAL_PKTBUF_SIZE] __attribute__ ((aligned (64)));
81 #endif
83 APP_EMAC_MCB_T app_mcb;
85 static uint32_t pkt_rcv_count = 0;
86 static uint32_t pkt_received = 0;
89 /**********************************************************************
90 ****************** Test Configuration Variables **********************
91 **********************************************************************/
92 #define PKT_SEND_COUNT 100
94 /* DO NOT CHANGE test_pkt UNLESS TEST_PKT_SIZE IS UPDATED */
95 #define TEST_PKT_SIZE 64
97 static const uint8_t test_pkt[64] = {
98 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
99 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
100 0x08, 0x06, 0x00, 0x01,
101 0x08, 0x00, 0x06, 0x04,
102 0x00,0x01,0x01, 0xbb,
103 0xcc, 0xdd, 0xee, 0xff,
104 0xc0, 0xa8, 0x01, 0x16,
105 0x00, 0x00, 0x00, 0x00,
106 0xc0, 0xa8,0x01, 0x02,
107 0x01,0x02,0x03,0x04,
108 0x01,0x02,0x03,0x04,
109 0x01,0x02,0x03,0x04,
110 0x01,0x02,0x03,0x04,
111 0x01,0x02,0x03,0x04,
112 0xfe,0xfe, 0x00, 0x00
113 };
115 /**********************************************************************
116 ************************ EMAC TEST FUNCTIONS *************************
117 **********************************************************************/
119 /**
120 * @b app_queue_pop
121 * @n
122 * Dequeues a packet descriptor from an app queue.
123 *
124 * @param[in] pq
125 * Packet queue of type APP_PKT_QUEUE_T .
126 *
127 * @retval
128 * EMAC_Pkt popped from the queue.
129 */
130 EMAC_PKT_DESC_T*
131 app_queue_pop
132 (
133 Uint32 port_num,
134 APP_PKT_QUEUE_T* pq
135 )
136 {
137 EMAC_PKT_DESC_T* pPktHdr;
139 if (!pq->Count)
140 {
141 return 0;
142 }
144 Osal_enterSingleCoreCriticalSection(port_num);
145 pPktHdr = pq->pHead;
146 if( pPktHdr )
147 {
148 pq->pHead = pPktHdr->pNext;
149 pq->Count--;
150 pPktHdr->pPrev = pPktHdr->pNext = 0;
151 }
152 Osal_exitSingleCoreCriticalSection(port_num);
154 return( pPktHdr );
155 }
157 /**
158 * @b app_queue_push
159 * @n
160 * Enqueues a packet in EMAC_Pkt queue.
161 *
162 * @param[in] pq
163 * Packet queue of type EMAC_PKT_QUEUE_T .
164 * @param[in] pPktHdr
165 * EMAC_PKT_DESC_T type packet to push.
166 *
167 * @retval
168 * void
169 */
170 void
171 app_queue_push
172 (
173 Uint32 port_num,
174 APP_PKT_QUEUE_T* pq,
175 EMAC_PKT_DESC_T* pPktHdr
176 )
177 {
178 Osal_enterSingleCoreCriticalSection(port_num);
179 pPktHdr->pNext = 0;
181 if( !pq->pHead )
182 {
183 /* Queue is empty - Initialize it with this one packet */
184 pq->pHead = pPktHdr;
185 pq->pTail = pPktHdr;
186 }
187 else
188 {
189 /* Queue is not empty - Push onto end */
190 pq->pTail->pNext = pPktHdr;
191 pq->pTail = pPktHdr;
192 }
193 pq->Count++;
194 Osal_exitSingleCoreCriticalSection(port_num);
195 }
198 uint32_t allocFailed = 0;
199 #ifndef EMAC_TEST_ALLOC_FAIL
200 /**
201 * @b Description
202 * @n
203 * Call back function provided by application for EMAC driver
204 * to allocate a packet descriptor.
205 *
206 * @retval
207 * pointer to the allocated packet descriptor.
208 */
209 EMAC_PKT_DESC_T*
210 app_alloc_pkt
211 (
212 Uint32 port_num,
213 Uint32 pkt_size
214 )
215 {
216 EMAC_PKT_DESC_T* p_pkt_desc = NULL;
217 if (pkt_size < APP_EMAC_MAX_PKT_SIZE)
218 {
219 /* Get a packet descriptor from the free queue */
220 p_pkt_desc = app_queue_pop(port_num, &app_mcb.emac_pcb[port_num].freeQueue);
221 p_pkt_desc->AppPrivate = (Uint32)p_pkt_desc;
222 p_pkt_desc->BufferLen = APP_EMAC_MAX_PKT_SIZE;
223 p_pkt_desc->DataOffset = 0;
224 p_pkt_desc->pPrev = NULL;
225 p_pkt_desc->pNext = NULL;
226 }
227 else
228 {
229 UART_printf ("app_alloc_pkt on port %d failed, packet size %d is too big\n", port_num, pkt_size);
230 return NULL;
231 }
232 return p_pkt_desc;
233 }
234 #else
235 /**
236 * @b Description
237 * @n
238 * Call back function provided by application for EMAC driver
239 * to allocate a packet descriptor.
240 *
241 * @retval
242 * pointer to the allocated packet descriptor.
243 */
244 EMAC_PKT_DESC_T*
245 app_alloc_pkt
246 (
247 Uint32 port_num,
248 Uint32 pkt_size
249 )
250 {
251 EMAC_PKT_DESC_T* p_pkt_desc = NULL;
252 static uint32_t allocFailCount = 0;
253 static uint32_t entryCount = 0;
255 /* testing pkt allocation failure for idkAM437x */
256 if (entryCount++ > 64)
257 {
258 if ((++allocFailCount % 50) == 0 )
259 {
260 allocFailed++;
261 return NULL;
262 }
263 }
265 if (pkt_size < APP_EMAC_MAX_PKT_SIZE)
266 {
267 /* Get a packet descriptor from the free queue */
268 p_pkt_desc = app_queue_pop(port_num, &app_mcb.emac_pcb[port_num].freeQueue);
269 p_pkt_desc->AppPrivate = (Uint32)p_pkt_desc;
270 p_pkt_desc->BufferLen = APP_EMAC_MAX_PKT_SIZE;
271 p_pkt_desc->DataOffset = 0;
272 p_pkt_desc->pPrev = NULL;
273 p_pkt_desc->pNext = NULL;
274 }
275 else
276 {
277 UART_printf ("app_alloc_pkt on port %d failed, packet size %d is too big\n", port_num, pkt_size);
278 return NULL;
279 }
280 return p_pkt_desc;
281 }
282 #endif
283 /**
284 * @b Description
285 * @n
286 * Call back function provided by application for EMAC driver
287 * to free a packet descriptor.
288 *
289 * @retval
290 * None.
291 */
292 void
293 app_free_pkt
294 (
295 Uint32 port_num,
296 EMAC_PKT_DESC_T* p_pkt_desc
297 )
298 {
299 /* Free a packet descriptor to the free queue */
300 app_queue_push(port_num, &app_mcb.emac_pcb[port_num].freeQueue,
301 (EMAC_PKT_DESC_T *)p_pkt_desc->AppPrivate);
302 }
305 /**
306 * @b Description
307 * @n
308 * Intialize the application control block, free/rx packet queue.
309 *
310 * @retval
311 * None.
312 */
313 void
314 app_init(void)
315 {
316 Uint32 i, j;
317 EMAC_PKT_DESC_T* p_pkt_desc;
318 Uint8* pktbuf_ptr;
320 UART_printf ("EMAC loopback test application initialization\n");
322 /* Reset application control block */
323 memset(&app_mcb, 0, sizeof (APP_EMAC_MCB_T));
325 #ifdef _TMS320C6X
326 app_mcb.core_num = CSL_chipReadReg (CSL_CHIP_DNUM);
327 #else
328 app_mcb.core_num = 0;
329 #endif
330 pktbuf_ptr = (Uint8 *) ((Uint32) app_pkt_buffer);
332 /* Initialize the free packet queue */
333 for (i=0; i<MAX_NUM_EMAC_PORTS; i++)
334 {
336 for (j=0; j<APP_MAX_PKTS; j++)
337 {
338 p_pkt_desc = &app_mcb.emac_pcb[i].pkt_desc[j];
339 p_pkt_desc->pDataBuffer = pktbuf_ptr;
340 p_pkt_desc->BufferLen = APP_EMAC_MAX_PKT_SIZE;
341 app_queue_push( i, &app_mcb.emac_pcb[i].freeQueue, p_pkt_desc );
342 pktbuf_ptr += APP_EMAC_MAX_PKT_SIZE;
343 }
344 }
345 }
348 /******************************************************************************
349 * Function: EMAC RX packet call back function
350 ******************************************************************************/
351 /**
352 * @brief This function is used to call back the network application when a
353 * packet is received.
354 */
355 void app_test_rx_pkt_cb(Uint32 port_num, EMAC_PKT_DESC_T* p_desc)
356 {
357 EMAC_STATISTICS_T stats;
358 pkt_rcv_count++;
359 if (memcmp(p_desc->pDataBuffer, &test_pkt[0], TEST_PKT_SIZE) == 0)
360 {
361 if (pkt_rcv_count <=PKT_SEND_COUNT)
362 UART_printf("received packet: %d\n", pkt_rcv_count);
364 if ((pkt_rcv_count + allocFailed) == PKT_SEND_COUNT)
365 {
366 #ifdef EMAC_TEST_ALLOC_FAIL
367 UART_printf("Test case to validate burst packet RX at host which could could result in buffer allocation failure\n");
368 UART_printf("Expected alloc failed to be >0 in logs\n");
369 #endif
370 UART_printf("packet received; %d, alloc failed: %d\n", pkt_rcv_count, allocFailed);
371 UART_printStatus("All tests have passed\n");
372 memset(&stats, 0, sizeof(EMAC_STATISTICS_T));
373 emac_get_statistics(0,&stats);
374 UART_printf("stats: rx: 0x%d, tx: 0x%d, RxOctets: %d\n", stats.RxGoodFrames, stats.TxGoodFrames, stats.RxOctets);
375 emac_close(0);
376 }
377 }
378 else
379 {
380 if ((pkt_rcv_count + allocFailed) <=PKT_SEND_COUNT)
381 UART_printStatus("packet match failed\n");
382 }
383 if (p_desc->AppPrivate != NULL)
384 app_free_pkt(port_num, (EMAC_PKT_DESC_T*) p_desc->AppPrivate);
385 pkt_received = 1;
386 }
388 void app_test_task_poll_pkt (UArg arg0, UArg arg1)
389 {
390 while(linkStatus == 0)
391 {
392 Task_sleep(100);
393 }
394 while(1)
395 {
396 emac_poll_pkt(0);
397 Task_sleep(10);
398 }
400 }
402 #if defined (SOC_AM571x) || defined (SOC_DRA72x)| defined (SOC_DRA75x) || defined (SOC_DRA78x)
404 void app_test_task_send_pkts(UArg arg0, UArg arg1)
405 {
406 uint32_t i;
407 uint32_t port_num = 0;
408 int32_t fail_count = 0;
409 EMAC_PKT_DESC_T *p_pkt_desc;
410 EMAC_DRV_ERR_E ret;
412 while(linkStatus == 0)
413 {
414 Task_sleep(1000);
415 }
416 for (i = 0; i < PKT_SEND_COUNT/2; i++)
417 {
418 p_pkt_desc = app_alloc_pkt(0, TEST_PKT_SIZE);
419 memcpy (p_pkt_desc->pDataBuffer, &test_pkt[0], TEST_PKT_SIZE);
420 p_pkt_desc->AppPrivate = (uint32_t)p_pkt_desc;
421 p_pkt_desc->Flags = EMAC_PKT_FLAG_SOP | EMAC_PKT_FLAG_EOP;
422 p_pkt_desc->ValidLen = TEST_PKT_SIZE;
423 p_pkt_desc->DataOffset = 0;
425 p_pkt_desc->PktLength = TEST_PKT_SIZE;
426 p_pkt_desc->PktFrags = 1;
427 p_pkt_desc->pNext = NULL;
428 p_pkt_desc->pPrev = NULL;
429 p_pkt_desc->PktChannel = 0;
430 p_pkt_desc->PktLength = TEST_PKT_SIZE;
432 UART_printf("sending packet: %d\n", i+1);
433 emac_send(port_num, p_pkt_desc);
435 while(pkt_received == 0)
436 {
437 Task_sleep(100);
438 fail_count++;
439 if(fail_count == 5)
440 {
441 fail_count = 0;
442 break;
443 }
444 }
446 pkt_received = 0;
447 }
449 if ((ret = emac_close(0)) == EMAC_DRV_RESULT_OPEN_PORT_ERR)
450 {
451 UART_printf("main: emac_close failure: %d\n", ret);
452 }
453 else
454 UART_printf("main: emac_close sucess\n");
456 if ((ret = emac_open(0, &open_cfg)) == EMAC_DRV_RESULT_OPEN_PORT_ERR)
457 {
458 UART_printf("main: emac_open failure: %d\n", ret);
459 }
460 else
461 UART_printf("main: emac_open1 sucess\n");
463 Task_sleep(50);
466 while(linkStatus == 0)
467 {
468 Task_sleep(100);
469 }
471 for (i = 0; i < PKT_SEND_COUNT/2; i++)
472 {
473 p_pkt_desc = app_alloc_pkt(0, TEST_PKT_SIZE);
474 memcpy (p_pkt_desc->pDataBuffer, &test_pkt[0], TEST_PKT_SIZE);
475 p_pkt_desc->AppPrivate = (uint32_t)p_pkt_desc;
476 p_pkt_desc->Flags = EMAC_PKT_FLAG_SOP | EMAC_PKT_FLAG_EOP;
477 p_pkt_desc->ValidLen = TEST_PKT_SIZE;
478 p_pkt_desc->DataOffset = 0;
480 p_pkt_desc->PktLength = TEST_PKT_SIZE;
481 p_pkt_desc->PktFrags = 1;
482 p_pkt_desc->pNext = NULL;
483 p_pkt_desc->pPrev = NULL;
484 p_pkt_desc->PktChannel = 0;
485 p_pkt_desc->PktLength = TEST_PKT_SIZE;
487 UART_printf("sending packet: %d\n", i+1);
488 emac_send(port_num, p_pkt_desc);
489 while(pkt_received == 0)
490 {
491 Task_sleep(100);
492 fail_count++;
493 if(fail_count == 5)
494 {
495 fail_count = 0;
496 break;
497 }
499 }
501 pkt_received = 0;
502 }
503 }
504 #else
505 void app_test_task_send_pkts(UArg arg0, UArg arg1)
506 {
507 uint32_t i;
508 uint32_t port_num = 0;
509 static uint32_t pkt_send_count =0;
510 uint32_t fail_count = 0;
511 EMAC_PKT_DESC_T *p_pkt_desc;
512 while(linkStatus == 0)
513 {
514 Task_sleep(1000);
515 }
516 Task_sleep(1000);
517 for (i = 0; i < PKT_SEND_COUNT; i++)
518 {
519 p_pkt_desc = app_alloc_pkt(0, TEST_PKT_SIZE);
520 /* app_alloc_pkt can return NULL because of logic added test allocation failure when app_alloc_pkt is called from the driver to replenish
521 packet descriptor during packet receive, just alloc again and it will pass */
522 if (p_pkt_desc == NULL)
523 {
524 p_pkt_desc = app_alloc_pkt(0, TEST_PKT_SIZE);
525 }
526 memcpy (p_pkt_desc->pDataBuffer, &test_pkt[0], TEST_PKT_SIZE);
527 p_pkt_desc->AppPrivate = (uint32_t)p_pkt_desc;
528 p_pkt_desc->Flags = EMAC_PKT_FLAG_SOP | EMAC_PKT_FLAG_EOP;
529 p_pkt_desc->ValidLen = TEST_PKT_SIZE;
530 p_pkt_desc->DataOffset = 0;
532 p_pkt_desc->PktLength = TEST_PKT_SIZE;
533 p_pkt_desc->PktFrags = 1;
534 p_pkt_desc->pNext = NULL;
535 p_pkt_desc->pPrev = NULL;
536 p_pkt_desc->PktChannel = 0;
537 p_pkt_desc->PktLength = TEST_PKT_SIZE;
540 emac_send(port_num, p_pkt_desc);
542 fail_count = 0;
543 while(pkt_received == 0)
544 {
545 Task_sleep(100);
546 fail_count++;
547 if(fail_count == 5)
548 {
549 fail_count = 0;
550 break;
551 }
552 }
553 pkt_received = 0;
554 pkt_send_count++;
555 }
557 }
558 #endif
560 /*
561 * ======== Delay function ========
562 */
563 void app_delay(int32_t delayValue)
564 {
565 volatile int32_t delay = delayValue*100;
566 while (delay--);
567 }