]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
895564ca361ae9dc6804bca237b0a2759f908b68
[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 #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 void passEthMessages( NetworkBufferDescriptor_t *ethMsg )\r
317 {\r
318 IPStackEvent_t xRxEvent;\r
319 \r
320         xRxEvent.eEventType = eNetworkRxEvent;\r
321         xRxEvent.pvData = ( void * ) ethMsg;\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                 do\r
329                 {\r
330                         NetworkBufferDescriptor_t *xNext = ethMsg->pxNextBuffer;\r
331                         vReleaseNetworkBufferAndDescriptor( ethMsg );\r
332                         ethMsg = xNext;\r
333                 } while( ethMsg != NULL );\r
334 \r
335                 iptraceETHERNET_RX_EVENT_LOST();\r
336                 FreeRTOS_printf( ( "passEthMessages: Can not queue return packet!\n" ) );\r
337         }\r
338 }\r
339 \r
340 TickType_t ack_reception_delay = 10;\r
341 \r
342 int emacps_check_rx( xemacpsif_s *xemacpsif )\r
343 {\r
344 NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;\r
345 int rx_bytes;\r
346 volatile int msgCount = 0;\r
347 int head = xemacpsif->rxHead;\r
348 BaseType_t bHasDataPacket = pdFALSE;\r
349 NetworkBufferDescriptor_t *ethMsg = NULL;\r
350 NetworkBufferDescriptor_t *ethLast = NULL;\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         {\r
356                 static int maxcount = 0;\r
357                 int count = 0;\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                         count++;\r
366                         if( ++head == ipconfigNIC_N_RX_DESC )\r
367                         {\r
368                                 head = 0;\r
369                         }\r
370                         if( head == xemacpsif->rxHead )\r
371                         {\r
372                                 break;\r
373                         }\r
374                 }\r
375                 if (maxcount < count) {\r
376                         maxcount = count;\r
377                         FreeRTOS_printf( ( "emacps_check_rx: %d packets\n", maxcount ) );\r
378                 }\r
379                 head = xemacpsif->rxHead;\r
380         }\r
381 \r
382         /* This FreeRTOS+TCP driver shall be compiled with the option\r
383         "ipconfigUSE_LINKED_RX_MESSAGES" enabled.  It allows the driver to send a\r
384         chain of RX messages within one message to the IP-task. */\r
385         for( ;; )\r
386         {\r
387                 if( ( ( xemacpsif->rxSegments[ head ].address & XEMACPS_RXBUF_NEW_MASK ) == 0 ) ||\r
388                         ( pxDMA_rx_buffers[ head ] == NULL ) )\r
389                 {\r
390                         break;\r
391                 }\r
392 \r
393                 pxNewBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );\r
394                 if( pxNewBuffer == NULL )\r
395                 {\r
396                         /* A packet has been received, but there is no replacement for this Network Buffer.\r
397                         The packet will be dropped, and it Network Buffer will stay in place. */\r
398                         FreeRTOS_printf( ("emacps_check_rx: unable to allocate a Netwrok Buffer\n" ) );\r
399                         pxNewBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
400                 }\r
401                 else\r
402                 {\r
403                         pxBuffer = ( NetworkBufferDescriptor_t * )pxDMA_rx_buffers[ head ];\r
404 \r
405                         /* Just avoiding to use or refer to the same buffer again */\r
406                         pxDMA_rx_buffers[ head ] = pxNewBuffer;\r
407 \r
408                         /*\r
409                          * Adjust the buffer size to the actual number of bytes received.\r
410                          */\r
411                         rx_bytes = xemacpsif->rxSegments[ head ].flags & XEMACPS_RXBUF_LEN_MASK;\r
412 \r
413                         pxBuffer->xDataLength = rx_bytes;\r
414 if( rx_bytes > 60 )\r
415 {\r
416         bHasDataPacket = 1;\r
417 }\r
418                         if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
419                         {\r
420                                 Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)rx_bytes );\r
421                         }\r
422 \r
423                         /* store it in the receive queue, where it'll be processed by a\r
424                         different handler. */\r
425                         iptraceNETWORK_INTERFACE_RECEIVE();\r
426                         pxBuffer->pxNextBuffer = NULL;\r
427 \r
428                         if( ethMsg == NULL )\r
429                         {\r
430                                 // Becomes the first message\r
431                                 ethMsg = pxBuffer;\r
432                         }\r
433                         else if( ethLast != NULL )\r
434                         {\r
435                                 // Add to the tail\r
436                                 ethLast->pxNextBuffer = pxBuffer;\r
437                         }\r
438 \r
439                         ethLast = pxBuffer;\r
440                         msgCount++;\r
441                 }\r
442                 {\r
443                         if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )\r
444                         {\r
445                                 Xil_DCacheInvalidateRange( ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );\r
446                         }\r
447                         {\r
448                                 uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
449                                 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )\r
450                                 {\r
451                                         addr |= XEMACPS_RXBUF_WRAP_MASK;\r
452                                 }\r
453                                 /* Clearing 'XEMACPS_RXBUF_NEW_MASK'       0x00000001 *< Used bit.. */\r
454                                 xemacpsif->rxSegments[ head ].flags = 0;\r
455                                 xemacpsif->rxSegments[ head ].address = addr;\r
456                                 if (xemacpsif->rxSegments[ head ].address) {\r
457                                         // Just to read it\r
458                                 }\r
459                         }\r
460                 }\r
461 \r
462                 if( ++head == ipconfigNIC_N_RX_DESC )\r
463                 {\r
464                         head = 0;\r
465                 }\r
466                 xemacpsif->rxHead = head;\r
467         }\r
468 \r
469         if( ethMsg != NULL )\r
470         {\r
471                 if( bHasDataPacket == pdFALSE )\r
472                 {\r
473 //                      vTaskDelay( ack_reception_delay );\r
474                 }\r
475                 passEthMessages( ethMsg );\r
476         }\r
477 \r
478         return msgCount;\r
479 }\r
480 \r
481 void clean_dma_txdescs(xemacpsif_s *xemacpsif)\r
482 {\r
483 int index;\r
484 unsigned char *ucTxBuffer;\r
485 \r
486         /* Clear all TX descriptors and assign uncached memory to each descriptor.\r
487         "tx_space" points to the first available TX buffer. */\r
488         ucTxBuffer = xemacpsif->tx_space;\r
489 \r
490         for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )\r
491         {\r
492                 xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;\r
493                 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;\r
494 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
495                 pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL;\r
496 #else\r
497                 pxDMA_tx_buffers[ index ] = ( unsigned char * )( ucTxBuffer + TX_OFFSET );\r
498 #endif\r
499                 ucTxBuffer += xemacpsif->uTxUnitSize;\r
500         }\r
501         xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =\r
502                 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
503 }\r
504 \r
505 XStatus init_dma(xemacpsif_s *xemacpsif)\r
506 {\r
507         NetworkBufferDescriptor_t *pxBuffer;\r
508 \r
509         int iIndex;\r
510         UBaseType_t xRxSize;\r
511         UBaseType_t xTxSize;\r
512         struct xtopology_t *xtopologyp = &xXTopology;\r
513 \r
514         xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );\r
515 \r
516         xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );\r
517 \r
518         /* Also round-up to 4KB */\r
519         xemacpsif->uTxUnitSize = ( ipTOTAL_ETHERNET_FRAME_SIZE + 0x1000ul ) & ~0xffful;\r
520         /*\r
521          * We allocate 65536 bytes for RX BDs which can accommodate a\r
522          * maximum of 8192 BDs which is much more than any application\r
523          * will ever need.\r
524          */\r
525         xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize )  );\r
526         xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );\r
527         xemacpsif->tx_space   = ( unsigned char *   )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );\r
528 \r
529         /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */\r
530         xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;\r
531         xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;\r
532 \r
533         if( xTXDescriptorSemaphore == NULL )\r
534         {\r
535                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );\r
536                 configASSERT( xTXDescriptorSemaphore );\r
537         }\r
538         /*\r
539          * Allocate RX descriptors, 1 RxBD at a time.\r
540          */\r
541         for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )\r
542         {\r
543                 pxBuffer = pxDMA_rx_buffers[ iIndex ];\r
544                 if( pxBuffer == NULL )\r
545                 {\r
546                         pxBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, ( TickType_t ) 0 );\r
547                         if( pxBuffer == NULL )\r
548                         {\r
549                                 FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );\r
550                                 return -1;\r
551                         }\r
552                 }\r
553 \r
554                 xemacpsif->rxSegments[ iIndex ].flags = 0;\r
555                 xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
556 \r
557                 pxDMA_rx_buffers[ iIndex ] = pxBuffer;\r
558                 /* Make sure this memory is not in cache for now. */\r
559                 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
560                 {\r
561                         Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,\r
562                                 (unsigned)ipTOTAL_ETHERNET_FRAME_SIZE );\r
563                 }\r
564         }\r
565 \r
566         xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;\r
567 \r
568         memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );\r
569 \r
570         clean_dma_txdescs( xemacpsif );\r
571 \r
572         {\r
573                 uint32_t value;\r
574                 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );\r
575 \r
576                 // 1xxxx: Attempt to use INCR16 AHB bursts\r
577                 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;\r
578 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )\r
579                 value |= XEMACPS_DMACR_TCPCKSUM_MASK;\r
580 #else\r
581 #warning Are you sure the EMAC should not calculate outgoing checksums?\r
582                 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;\r
583 #endif\r
584                 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );\r
585         }\r
586         {\r
587                 uint32_t value;\r
588                 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );\r
589 \r
590                 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).\r
591                 Now tell the EMAC that received messages should be stored at "address + 2". */\r
592                 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;\r
593 \r
594 #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )\r
595                 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
596 #else\r
597 #warning Are you sure the EMAC should not calculate incoming checksums?\r
598                 value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
599 #endif\r
600                 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );\r
601         }\r
602 \r
603         /*\r
604          * Connect the device driver handler that will be called when an\r
605          * interrupt for the device occurs, the handler defined above performs\r
606          * the specific interrupt processing for the device.\r
607          */\r
608         XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,\r
609                 (Xil_ExceptionHandler)XEmacPs_IntrHandler,\r
610                 (void *)&xemacpsif->emacps);\r
611         /*\r
612          * Enable the interrupt for emacps.\r
613          */\r
614         EmacEnableIntr( );\r
615 \r
616         return 0;\r
617 }\r
618 \r
619 /*\r
620  * resetrx_on_no_rxdata():\r
621  *\r
622  * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata\r
623  * called by the user.\r
624  * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.\r
625  * Under heavy Rx traffic because of the HW bug there are times when the Rx path\r
626  * becomes unresponsive. The workaround for it is to check for the Rx path for\r
627  * traffic (by reading the stats registers regularly). If the stats register\r
628  * does not increment for sometime (proving no Rx traffic), the function resets\r
629  * the Rx data path.\r
630  *\r
631  */\r
632 \r
633 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)\r
634 {\r
635         unsigned long regctrl;\r
636         unsigned long tempcntr;\r
637 \r
638         tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );\r
639         if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )\r
640         {\r
641 FreeRTOS_printf( ( "resetrx_on_no_rxdata: RESET~\n" ) );\r
642                 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,\r
643                                 XEMACPS_NWCTRL_OFFSET);\r
644                 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);\r
645                 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,\r
646                                 XEMACPS_NWCTRL_OFFSET, regctrl);\r
647                 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);\r
648                 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);\r
649                 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);\r
650         }\r
651         xemacpsif->last_rx_frms_cntr = tempcntr;\r
652 }\r
653 \r
654 void EmacDisableIntr(void)\r
655 {\r
656         XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
657 }\r
658 \r
659 void EmacEnableIntr(void)\r
660 {\r
661         XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
662 }\r
663 \r