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