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