]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
e92c9c21fdfec28e3a6e65fd3b58d28930d9d4b1
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / Zynq / x_emacpsif_dma.c
1 /*\r
2  * FreeRTOS+TCP V2.0.11\r
3  * Copyright (C) 2017 Amazon.com, Inc. or its affiliates.  All Rights Reserved.\r
4  *\r
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of\r
6  * this software and associated documentation files (the "Software"), to deal in\r
7  * the Software without restriction, including without limitation the rights to\r
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\r
9  * the Software, and to permit persons to whom the Software is furnished to do so,\r
10  * subject to the following conditions:\r
11  *\r
12  * The above copyright notice and this permission notice shall be included in all\r
13  * copies or substantial portions of the Software.\r
14  *\r
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
21  *\r
22  * http://aws.amazon.com/freertos\r
23  * http://www.FreeRTOS.org\r
24  */\r
25 \r
26 #include "FreeRTOS.h"\r
27 #include "task.h"\r
28 #include "timers.h"\r
29 #include "semphr.h"\r
30 \r
31 /* FreeRTOS+TCP includes. */\r
32 #include "FreeRTOS_IP.h"\r
33 #include "FreeRTOS_Sockets.h"\r
34 #include "FreeRTOS_IP_Private.h"\r
35 #include "NetworkBufferManagement.h"\r
36 \r
37 #include "Zynq/x_emacpsif.h"\r
38 #include "Zynq/x_topology.h"\r
39 #include "xstatus.h"\r
40 \r
41 #include "xparameters.h"\r
42 #include "xparameters_ps.h"\r
43 #include "xil_exception.h"\r
44 #include "xil_mmu.h"\r
45 \r
46 #include "uncached_memory.h"\r
47 \r
48 /* Two defines used to set or clear the EMAC interrupt */\r
49 #define INTC_BASE_ADDR          XPAR_SCUGIC_CPU_BASEADDR\r
50 #define INTC_DIST_BASE_ADDR     XPAR_SCUGIC_DIST_BASEADDR\r
51 \r
52 \r
53 \r
54 #if( ipconfigPACKET_FILLER_SIZE != 2 )\r
55         #error Please define ipconfigPACKET_FILLER_SIZE as the value '2'\r
56 #endif\r
57 #define TX_OFFSET                               ipconfigPACKET_FILLER_SIZE\r
58 \r
59 /* Defined in NetworkInterface.c */\r
60 extern TaskHandle_t xEMACTaskHandle;\r
61 \r
62 /*\r
63         pxDMA_tx_buffers: these are character arrays, each one is big enough to hold 1 MTU.\r
64         The actual TX buffers are located in uncached RAM.\r
65 */\r
66 static unsigned char *pxDMA_tx_buffers[ ipconfigNIC_N_TX_DESC ] = { NULL };\r
67 \r
68 /*\r
69         pxDMA_rx_buffers: these are pointers to 'NetworkBufferDescriptor_t'.\r
70         Once a message has been received by the EMAC, the descriptor can be passed\r
71         immediately to the IP-task.\r
72 */\r
73 static NetworkBufferDescriptor_t *pxDMA_rx_buffers[ ipconfigNIC_N_RX_DESC ] = { NULL };\r
74 \r
75 /*\r
76         The FreeRTOS+TCP port is using a fixed 'topology', which is declared in\r
77         ./portable/NetworkInterface/Zynq/NetworkInterface.c\r
78 */\r
79 extern struct xtopology_t xXTopology;\r
80 \r
81 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
82 \r
83 /*\r
84         The FreeRTOS+TCP port does not make use of "src/xemacps_bdring.c".\r
85         In stead 'struct xemacpsif_s' has a "head" and a "tail" index.\r
86         "head" is the next index to be written, used.\r
87         "tail" is the next index to be read, freed.\r
88 */\r
89 \r
90 int is_tx_space_available( xemacpsif_s *xemacpsif )\r
91 {\r
92 size_t uxCount;\r
93 \r
94         if( xTXDescriptorSemaphore != NULL )\r
95         {\r
96                 uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
97         }\r
98         else\r
99         {\r
100                 uxCount = ( UBaseType_t ) 0u;\r
101         }\r
102 \r
103         return uxCount;\r
104 }\r
105 \r
106 void emacps_check_tx( xemacpsif_s *xemacpsif )\r
107 {\r
108 int tail = xemacpsif->txTail;\r
109 int head = xemacpsif->txHead;\r
110 size_t uxCount = ( ( UBaseType_t ) ipconfigNIC_N_TX_DESC ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
111 \r
112         /* uxCount is the number of TX descriptors that are in use by the DMA. */\r
113         /* When done, "TXBUF_USED" will be set. */\r
114 \r
115         while( ( uxCount > 0 ) && ( ( xemacpsif->txSegments[ tail ].flags & XEMACPS_TXBUF_USED_MASK ) != 0 ) )\r
116         {\r
117                 if( ( tail == head ) && ( uxCount != ipconfigNIC_N_TX_DESC ) )\r
118                 {\r
119                         break;\r
120                 }\r
121 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
122                 {\r
123                 void *pvBuffer = pxDMA_tx_buffers[ tail ];\r
124                 NetworkBufferDescriptor_t *pxBuffer;\r
125 \r
126                         if( pvBuffer != NULL )\r
127                         {\r
128                                 pxDMA_tx_buffers[ tail ] = NULL;\r
129                                 pxBuffer = pxPacketBuffer_to_NetworkBuffer( pvBuffer );\r
130                                 if( pxBuffer != NULL )\r
131                                 {\r
132                                         vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
133                                 }\r
134                                 else\r
135                                 {\r
136                                         FreeRTOS_printf( ( "emacps_check_tx: Can not find network buffer\n" ) );\r
137                                 }\r
138                         }\r
139                 }\r
140 #endif\r
141                 /* Clear all but the "used" and "wrap" bits. */\r
142                 if( tail < ipconfigNIC_N_TX_DESC - 1 )\r
143                 {\r
144                         xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;\r
145                 }\r
146                 else\r
147                 {\r
148                         xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
149                 }\r
150                 uxCount--;\r
151                 /* Tell the counting semaphore that one more TX descriptor is available. */\r
152                 xSemaphoreGive( xTXDescriptorSemaphore );\r
153                 if( ++tail == ipconfigNIC_N_TX_DESC )\r
154                 {\r
155                         tail = 0;\r
156                 }\r
157                 xemacpsif->txTail = tail;\r
158         }\r
159 \r
160         return;\r
161 }\r
162 \r
163 void emacps_send_handler(void *arg)\r
164 {\r
165 xemacpsif_s   *xemacpsif;\r
166 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
167 \r
168         xemacpsif = (xemacpsif_s *)(arg);\r
169 \r
170         /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in\r
171         "isr_events". The task in NetworkInterface will wake-up and do the necessary work.\r
172         */\r
173         xemacpsif->isr_events |= EMAC_IF_TX_EVENT;\r
174         xemacpsif->txBusy = pdFALSE;\r
175 \r
176         if( xEMACTaskHandle != NULL )\r
177         {\r
178                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
179         }\r
180 \r
181         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
182 }\r
183 \r
184 static BaseType_t xValidLength( BaseType_t xLength )\r
185 {\r
186 BaseType_t xReturn;\r
187 \r
188         if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= ipTOTAL_ETHERNET_FRAME_SIZE ) )\r
189         {\r
190                 xReturn = pdTRUE;\r
191         }\r
192         else\r
193         {\r
194                 xReturn =  pdFALSE;\r
195         }\r
196 \r
197         return xReturn;\r
198 }\r
199 \r
200 XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )\r
201 {\r
202 int head = xemacpsif->txHead;\r
203 int iHasSent = 0;\r
204 uint32_t ulBaseAddress = xemacpsif->emacps.Config.BaseAddress;\r
205 TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 5000u );\r
206 \r
207         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
208         {\r
209                 /* This driver wants to own all network buffers which are to be transmitted. */\r
210                 configASSERT( iReleaseAfterSend != pdFALSE );\r
211         }\r
212         #endif\r
213 \r
214         /* Open a do {} while ( 0 ) loop to be able to call break. */\r
215         do\r
216         {\r
217         uint32_t ulFlags = 0;\r
218 \r
219                 if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )\r
220                 {\r
221                         break;\r
222                 }\r
223 \r
224                 if( xTXDescriptorSemaphore == NULL )\r
225                 {\r
226                         break;\r
227                 }\r
228 \r
229                 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
230                 {\r
231                         FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );\r
232                         break;\r
233                 }\r
234 \r
235 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
236                 /* Pass the pointer (and its ownership) directly to DMA. */\r
237                 pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;\r
238                 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
239                 {\r
240                         Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );\r
241                 }\r
242                 /* Buffer has been transferred, do not release it. */\r
243                 iReleaseAfterSend = pdFALSE;\r
244 #else\r
245                 if( pxDMA_tx_buffers[ head ] == NULL )\r
246                 {\r
247                         FreeRTOS_printf( ( "emacps_send_message: pxDMA_tx_buffers[ %d ] == NULL\n", head ) );\r
248                         break;\r
249                 }\r
250                 /* Copy the message to unbuffered space in RAM. */\r
251                 memcpy( pxDMA_tx_buffers[ head ], pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );\r
252 #endif\r
253                 /* Packets will be sent one-by-one, so for each packet\r
254                 the TXBUF_LAST bit will be set. */\r
255                 ulFlags |= XEMACPS_TXBUF_LAST_MASK;\r
256                 ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );\r
257                 if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )\r
258                 {\r
259                         ulFlags |= XEMACPS_TXBUF_WRAP_MASK;\r
260                 }\r
261 \r
262                 /* Copy the address of the buffer and set the flags. */\r
263                 xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];\r
264                 xemacpsif->txSegments[ head ].flags = ulFlags;\r
265 \r
266                 iHasSent = pdTRUE;\r
267                 if( ++head == ipconfigNIC_N_TX_DESC )\r
268                 {\r
269                         head = 0;\r
270                 }\r
271                 /* Update the TX-head index. These variable are declared volatile so they will be\r
272                 accessed as little as possible. */\r
273                 xemacpsif->txHead = head;\r
274         } while( pdFALSE );\r
275 \r
276         if( iReleaseAfterSend != pdFALSE )\r
277         {\r
278                 vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
279                 pxBuffer = NULL;\r
280         }\r
281 \r
282         /* Data Synchronization Barrier */\r
283         dsb();\r
284 \r
285         if( iHasSent != pdFALSE )\r
286         {\r
287                 /* Make STARTTX high */\r
288                 uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);\r
289                 /* Start transmit */\r
290                 xemacpsif->txBusy = pdTRUE;\r
291                 XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );\r
292                 /* Reading it back is important compiler is optimised. */\r
293                 XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );\r
294         }\r
295         dsb();\r
296 \r
297         return 0;\r
298 }\r
299 \r
300 void emacps_recv_handler(void *arg)\r
301 {\r
302         xemacpsif_s *xemacpsif;\r
303         BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
304 \r
305         xemacpsif = (xemacpsif_s *)(arg);\r
306         xemacpsif->isr_events |= EMAC_IF_RX_EVENT;\r
307 \r
308         if( xEMACTaskHandle != NULL )\r
309         {\r
310                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
311         }\r
312 \r
313         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
314 }\r
315 \r
316 static void prvPassEthMessages( NetworkBufferDescriptor_t *pxDescriptor )\r
317 {\r
318 IPStackEvent_t xRxEvent;\r
319 \r
320         xRxEvent.eEventType = eNetworkRxEvent;\r
321         xRxEvent.pvData = ( void * ) pxDescriptor;\r
322 \r
323         if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )\r
324         {\r
325                 /* The buffer could not be sent to the stack so must be released again.\r
326                 This is a deferred handler taskr, not a real interrupt, so it is ok to\r
327                 use the task level function here. */\r
328                 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
329                 {\r
330                         do\r
331                         {\r
332                                 NetworkBufferDescriptor_t *pxNext = pxDescriptor->pxNextBuffer;\r
333                                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
334                                 pxDescriptor = pxNext;\r
335                         } while( pxDescriptor != NULL );\r
336                 }\r
337                 #else\r
338                 {\r
339                         vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
340                 }\r
341                 #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
342                 iptraceETHERNET_RX_EVENT_LOST();\r
343                 FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) );\r
344         }\r
345 }\r
346 \r
347 int emacps_check_rx( xemacpsif_s *xemacpsif )\r
348 {\r
349 NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;\r
350 int rx_bytes;\r
351 volatile int msgCount = 0;\r
352 int head = xemacpsif->rxHead;\r
353 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
354         NetworkBufferDescriptor_t *pxFirstDescriptor = NULL;\r
355         NetworkBufferDescriptor_t *pxLastDescriptor = NULL;\r
356 #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
357 \r
358         /* There seems to be an issue (SI# 692601), see comments below. */\r
359         resetrx_on_no_rxdata(xemacpsif);\r
360 \r
361         /* This FreeRTOS+TCP driver shall be compiled with the option\r
362         "ipconfigUSE_LINKED_RX_MESSAGES" enabled.  It allows the driver to send a\r
363         chain of RX messages within one message to the IP-task. */\r
364         for( ;; )\r
365         {\r
366                 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||\r
367                         ( pxDMA_rx_buffers[ head ] == NULL ) )\r
368                 {\r
369                         break;\r
370                 }\r
371 \r
372                 pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );\r
373                 if( pxNewBuffer == NULL )\r
374                 {\r
375                         /* A packet has been received, but there is no replacement for this Network Buffer.\r
376                         The packet will be dropped, and it Network Buffer will stay in place. */\r
377                         FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );\r
378                         pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
379                 }\r
380                 else\r
381                 {\r
382                         pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
383 \r
384                         /* Just avoiding to use or refer to the same buffer again */\r
385                         pxDMA_rx_buffers[ head ] = pxNewBuffer;\r
386 \r
387                         /*\r
388                          * Adjust the buffer size to the actual number of bytes received.\r
389                          */\r
390                         rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;\r
391 \r
392                         pxBuffer->xDataLength = rx_bytes;\r
393                         if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
394                         {\r
395                                 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );\r
396                         }\r
397 \r
398                         /* store it in the receive queue, where it'll be processed by a\r
399                         different handler. */\r
400                         iptraceNETWORK_INTERFACE_RECEIVE();\r
401                         #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
402                         {\r
403                                 pxBuffer->pxNextBuffer = NULL;\r
404 \r
405                                 if( pxFirstDescriptor == NULL )\r
406                                 {\r
407                                         // Becomes the first message\r
408                                         pxFirstDescriptor = pxBuffer;\r
409                                 }\r
410                                 else if( pxLastDescriptor != NULL )\r
411                                 {\r
412                                         // Add to the tail\r
413                                         pxLastDescriptor->pxNextBuffer = pxBuffer;\r
414                                 }\r
415 \r
416                                 pxLastDescriptor = pxBuffer;\r
417                         }\r
418                         #else\r
419                         {\r
420                                 prvPassEthMessages( pxBuffer );\r
421                         }\r
422                         #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
423 \r
424                         msgCount++;\r
425                 }\r
426                 {\r
427                         if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )\r
428                         {\r
429                                 Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );\r
430                         }\r
431                         {\r
432                                 uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
433                                 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )\r
434                                 {\r
435                                         addr |= XEMACPS_RXBUF_WRAP_MASK;\r
436                                 }\r
437                                 /* Clearing 'XEMACPS_RXBUF_NEW_MASK'       0x00000001 *< Used bit.. */\r
438                                 xemacpsif->rxSegments[ head ].flags = 0;\r
439                                 xemacpsif->rxSegments[ head ].address = addr;\r
440                                 if (xemacpsif->rxSegments[ head ].address)\r
441                                 {\r
442                                         // Just to read it\r
443                                 }\r
444                         }\r
445                 }\r
446 \r
447                 if( ++head == ipconfigNIC_N_RX_DESC )\r
448                 {\r
449                         head = 0;\r
450                 }\r
451                 xemacpsif->rxHead = head;\r
452         }\r
453 \r
454         #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
455         {\r
456                 if( pxFirstDescriptor != NULL )\r
457                 {\r
458                         prvPassEthMessages( pxFirstDescriptor );\r
459                 }\r
460         }\r
461         #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
462 \r
463         return msgCount;\r
464 }\r
465 \r
466 void clean_dma_txdescs(xemacpsif_s *xemacpsif)\r
467 {\r
468 int index;\r
469 unsigned char *ucTxBuffer;\r
470 \r
471         /* Clear all TX descriptors and assign uncached memory to each descriptor.\r
472         "tx_space" points to the first available TX buffer. */\r
473         ucTxBuffer = xemacpsif->tx_space;\r
474 \r
475         for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )\r
476         {\r
477                 xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;\r
478                 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;\r
479 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
480                 pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL;\r
481 #else\r
482                 pxDMA_tx_buffers[ index ] = ( unsigned char * )( ucTxBuffer + TX_OFFSET );\r
483 #endif\r
484                 ucTxBuffer += xemacpsif->uTxUnitSize;\r
485         }\r
486         xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =\r
487                 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
488 }\r
489 \r
490 XStatus init_dma(xemacpsif_s *xemacpsif)\r
491 {\r
492         NetworkBufferDescriptor_t *pxBuffer;\r
493 \r
494         int iIndex;\r
495         UBaseType_t xRxSize;\r
496         UBaseType_t xTxSize;\r
497         struct xtopology_t *xtopologyp = &xXTopology;\r
498 \r
499         xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );\r
500 \r
501         xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );\r
502 \r
503         /* Also round-up to 4KB */\r
504         xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;\r
505         /*\r
506          * We allocate 65536 bytes for RX BDs which can accommodate a\r
507          * maximum of 8192 BDs which is much more than any application\r
508          * will ever need.\r
509          */\r
510         xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize )  );\r
511         xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );\r
512         xemacpsif->tx_space   = ( unsigned char *   )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );\r
513 \r
514         /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */\r
515         xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;\r
516         xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;\r
517 \r
518         if( xTXDescriptorSemaphore == NULL )\r
519         {\r
520                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );\r
521                 configASSERT( xTXDescriptorSemaphore );\r
522         }\r
523         /*\r
524          * Allocate RX descriptors, 1 RxBD at a time.\r
525          */\r
526         for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )\r
527         {\r
528                 pxBuffer = pxDMA_rx_buffers[ iIndex ];\r
529                 if( pxBuffer == NULL )\r
530                 {\r
531                         pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );\r
532                         if( pxBuffer == NULL )\r
533                         {\r
534                                 FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );\r
535                                 return -1;\r
536                         }\r
537                 }\r
538 \r
539                 xemacpsif->rxSegments[ iIndex ].flags = 0;\r
540                 xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
541 \r
542                 pxDMA_rx_buffers[ iIndex ] = pxBuffer;\r
543                 /* Make sure this memory is not in cache for now. */\r
544                 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
545                 {\r
546                         Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,\r
547                                 (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );\r
548                 }\r
549         }\r
550 \r
551         xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;\r
552 \r
553         memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );\r
554 \r
555         clean_dma_txdescs( xemacpsif );\r
556 \r
557         {\r
558                 uint32_t value;\r
559                 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );\r
560 \r
561                 // 1xxxx: Attempt to use INCR16 AHB bursts\r
562                 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;\r
563 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )\r
564                 value |= XEMACPS_DMACR_TCPCKSUM_MASK;\r
565 #else\r
566 #warning Are you sure the EMAC should not calculate outgoing checksums?\r
567                 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;\r
568 #endif\r
569                 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );\r
570         }\r
571         {\r
572                 uint32_t value;\r
573                 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );\r
574 \r
575                 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).\r
576                 Now tell the EMAC that received messages should be stored at "address + 2". */\r
577                 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;\r
578 \r
579 #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )\r
580                 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
581 #else\r
582 #warning Are you sure the EMAC should not calculate incoming checksums?\r
583                 value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
584 #endif\r
585                 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );\r
586         }\r
587 \r
588         /*\r
589          * Connect the device driver handler that will be called when an\r
590          * interrupt for the device occurs, the handler defined above performs\r
591          * the specific interrupt processing for the device.\r
592          */\r
593         XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,\r
594                 (Xil_ExceptionHandler)XEmacPs_IntrHandler,\r
595                 (void *)&xemacpsif->emacps);\r
596         /*\r
597          * Enable the interrupt for emacps.\r
598          */\r
599         EmacEnableIntr( );\r
600 \r
601         return 0;\r
602 }\r
603 \r
604 /*\r
605  * resetrx_on_no_rxdata():\r
606  *\r
607  * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata\r
608  * called by the user.\r
609  * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.\r
610  * Under heavy Rx traffic because of the HW bug there are times when the Rx path\r
611  * becomes unresponsive. The workaround for it is to check for the Rx path for\r
612  * traffic (by reading the stats registers regularly). If the stats register\r
613  * does not increment for sometime (proving no Rx traffic), the function resets\r
614  * the Rx data path.\r
615  *\r
616  */\r
617 \r
618 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)\r
619 {\r
620         unsigned long regctrl;\r
621         unsigned long tempcntr;\r
622 \r
623         tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );\r
624         if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )\r
625         {\r
626                 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,\r
627                                 XEMACPS_NWCTRL_OFFSET);\r
628                 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);\r
629                 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,\r
630                                 XEMACPS_NWCTRL_OFFSET, regctrl);\r
631                 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);\r
632                 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);\r
633                 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);\r
634         }\r
635         xemacpsif->last_rx_frms_cntr = tempcntr;\r
636 }\r
637 \r
638 void EmacDisableIntr(void)\r
639 {\r
640         XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
641 }\r
642 \r
643 void EmacEnableIntr(void)\r
644 {\r
645         XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
646 }\r
647 \r