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