]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/Zynq/x_emacpsif_dma.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / Zynq / x_emacpsif_dma.c
1 /*\r
2  * FreeRTOS V202002.00\r
3  * Copyright (C) 2020 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 #define dmaRX_TX_BUFFER_SIZE                    1536\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                 {\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                 /* Clear all but the "used" and "wrap" bits. */\r
142                 if( tail < ipconfigNIC_N_TX_DESC - 1 )\r
143                 {\r
144                         xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK;\r
145                 }\r
146                 else\r
147                 {\r
148                         xemacpsif->txSegments[ tail ].flags = XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
149                 }\r
150                 uxCount--;\r
151                 /* Tell the counting semaphore that one more TX descriptor is available. */\r
152                 xSemaphoreGive( xTXDescriptorSemaphore );\r
153                 if( ++tail == ipconfigNIC_N_TX_DESC )\r
154                 {\r
155                         tail = 0;\r
156                 }\r
157                 xemacpsif->txTail = tail;\r
158         }\r
159 \r
160         return;\r
161 }\r
162 \r
163 void emacps_send_handler(void *arg)\r
164 {\r
165 xemacpsif_s   *xemacpsif;\r
166 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
167 \r
168         xemacpsif = (xemacpsif_s *)(arg);\r
169 \r
170         /* This function is called from an ISR. The Xilinx ISR-handler has already\r
171         cleared the TXCOMPL and TXSR_USEDREAD status bits in the XEMACPS_TXSR register.\r
172         But it forgets to do a read-back. Do so now to avoid ever-returning ISR's. */\r
173         ( void ) XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_TXSR_OFFSET);\r
174 \r
175         /* In this port for FreeRTOS+TCP, the EMAC interrupts will only set a bit in\r
176         "isr_events". The task in NetworkInterface will wake-up and do the necessary work.\r
177         */\r
178         xemacpsif->isr_events |= EMAC_IF_TX_EVENT;\r
179         xemacpsif->txBusy = pdFALSE;\r
180 \r
181         if( xEMACTaskHandle != NULL )\r
182         {\r
183                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
184         }\r
185 \r
186         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
187 }\r
188 \r
189 static BaseType_t xValidLength( BaseType_t xLength )\r
190 {\r
191 BaseType_t xReturn;\r
192 \r
193         if( ( xLength >= ( BaseType_t ) sizeof( struct xARP_PACKET ) ) && ( ( ( uint32_t ) xLength ) <= dmaRX_TX_BUFFER_SIZE ) )\r
194         {\r
195                 xReturn = pdTRUE;\r
196         }\r
197         else\r
198         {\r
199                 xReturn =  pdFALSE;\r
200         }\r
201 \r
202         return xReturn;\r
203 }\r
204 \r
205 XStatus emacps_send_message(xemacpsif_s *xemacpsif, NetworkBufferDescriptor_t *pxBuffer, int iReleaseAfterSend )\r
206 {\r
207 int head = xemacpsif->txHead;\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         /* This driver wants to own all network buffers which are to be transmitted. */\r
213         configASSERT( iReleaseAfterSend != pdFALSE );\r
214 \r
215         /* Open a do {} while ( 0 ) loop to be able to call break. */\r
216         do\r
217         {\r
218         uint32_t ulFlags = 0;\r
219 \r
220                 if( xValidLength( pxBuffer->xDataLength ) != pdTRUE )\r
221                 {\r
222                         break;\r
223                 }\r
224 \r
225                 if( xTXDescriptorSemaphore == NULL )\r
226                 {\r
227                         break;\r
228                 }\r
229 \r
230                 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
231                 {\r
232                         FreeRTOS_printf( ( "emacps_send_message: Time-out waiting for TX buffer\n" ) );\r
233                         break;\r
234                 }\r
235 \r
236                 /* Pass the pointer (and its ownership) directly to DMA. */\r
237                 pxDMA_tx_buffers[ head ] = pxBuffer->pucEthernetBuffer;\r
238                 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
239                 {\r
240                         Xil_DCacheFlushRange( ( unsigned )pxBuffer->pucEthernetBuffer, pxBuffer->xDataLength );\r
241                 }\r
242                 /* Buffer has been transferred, do not release it. */\r
243                 iReleaseAfterSend = pdFALSE;\r
244 \r
245                 /* Packets will be sent one-by-one, so for each packet\r
246                 the TXBUF_LAST bit will be set. */\r
247                 ulFlags |= XEMACPS_TXBUF_LAST_MASK;\r
248                 ulFlags |= ( pxBuffer->xDataLength & XEMACPS_TXBUF_LEN_MASK );\r
249                 if( head == ( ipconfigNIC_N_TX_DESC - 1 ) )\r
250                 {\r
251                         ulFlags |= XEMACPS_TXBUF_WRAP_MASK;\r
252                 }\r
253 \r
254                 /* Copy the address of the buffer and set the flags. */\r
255                 xemacpsif->txSegments[ head ].address = ( uint32_t )pxDMA_tx_buffers[ head ];\r
256                 xemacpsif->txSegments[ head ].flags = ulFlags;\r
257 \r
258                 iHasSent = pdTRUE;\r
259                 if( ++head == ipconfigNIC_N_TX_DESC )\r
260                 {\r
261                         head = 0;\r
262                 }\r
263                 /* Update the TX-head index. These variable are declared volatile so they will be\r
264                 accessed as little as possible. */\r
265                 xemacpsif->txHead = head;\r
266         } while( pdFALSE );\r
267 \r
268         if( iReleaseAfterSend != pdFALSE )\r
269         {\r
270                 vReleaseNetworkBufferAndDescriptor( pxBuffer );\r
271                 pxBuffer = NULL;\r
272         }\r
273 \r
274         /* Data Synchronization Barrier */\r
275         dsb();\r
276 \r
277         if( iHasSent != pdFALSE )\r
278         {\r
279                 /* Make STARTTX high */\r
280                 uint32_t ulValue = XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET);\r
281                 /* Start transmit */\r
282                 xemacpsif->txBusy = pdTRUE;\r
283                 XEmacPs_WriteReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET, ( ulValue | XEMACPS_NWCTRL_STARTTX_MASK ) );\r
284                 /* Read back the register to make sure the data is flushed. */\r
285                 ( void ) XEmacPs_ReadReg( ulBaseAddress, XEMACPS_NWCTRL_OFFSET );\r
286         }\r
287         dsb();\r
288 \r
289         return 0;\r
290 }\r
291 \r
292 void emacps_recv_handler(void *arg)\r
293 {\r
294         xemacpsif_s *xemacpsif;\r
295         BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
296 \r
297         xemacpsif = (xemacpsif_s *)(arg);\r
298         xemacpsif->isr_events |= EMAC_IF_RX_EVENT;\r
299 \r
300         /* The driver has already cleared the FRAMERX, BUFFNA and error bits\r
301         in the XEMACPS_RXSR register,\r
302         But it forgets to do a read-back. Do so now. */\r
303         ( void ) XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXSR_OFFSET);\r
304 \r
305         if( xEMACTaskHandle != NULL )\r
306         {\r
307                 vTaskNotifyGiveFromISR( xEMACTaskHandle, &xHigherPriorityTaskWoken );\r
308         }\r
309 \r
310         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
311 }\r
312 \r
313 static void prvPassEthMessages( NetworkBufferDescriptor_t *pxDescriptor )\r
314 {\r
315 IPStackEvent_t xRxEvent;\r
316 \r
317         xRxEvent.eEventType = eNetworkRxEvent;\r
318         xRxEvent.pvData = ( void * ) pxDescriptor;\r
319 \r
320         if( xSendEventStructToIPTask( &xRxEvent, ( TickType_t ) 1000 ) != pdPASS )\r
321         {\r
322                 /* The buffer could not be sent to the stack so must be released again.\r
323                 This is a deferred handler taskr, not a real interrupt, so it is ok to\r
324                 use the task level function here. */\r
325                 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
326                 {\r
327                         do\r
328                         {\r
329                                 NetworkBufferDescriptor_t *pxNext = pxDescriptor->pxNextBuffer;\r
330                                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
331                                 pxDescriptor = pxNext;\r
332                         } while( pxDescriptor != NULL );\r
333                 }\r
334                 #else\r
335                 {\r
336                         vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
337                 }\r
338                 #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
339                 iptraceETHERNET_RX_EVENT_LOST();\r
340                 FreeRTOS_printf( ( "prvPassEthMessages: Can not queue return packet!\n" ) );\r
341         }\r
342 }\r
343 \r
344 int emacps_check_rx( xemacpsif_s *xemacpsif )\r
345 {\r
346 NetworkBufferDescriptor_t *pxBuffer, *pxNewBuffer;\r
347 int rx_bytes;\r
348 volatile int msgCount = 0;\r
349 int head = xemacpsif->rxHead;\r
350 #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
351         NetworkBufferDescriptor_t *pxFirstDescriptor = NULL;\r
352         NetworkBufferDescriptor_t *pxLastDescriptor = NULL;\r
353 #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\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( dmaRX_TX_BUFFER_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 Network 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                         #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
400                         {\r
401                                 pxBuffer->pxNextBuffer = NULL;\r
402 \r
403                                 if( pxFirstDescriptor == NULL )\r
404                                 {\r
405                                         // Becomes the first message\r
406                                         pxFirstDescriptor = pxBuffer;\r
407                                 }\r
408                                 else if( pxLastDescriptor != NULL )\r
409                                 {\r
410                                         // Add to the tail\r
411                                         pxLastDescriptor->pxNextBuffer = pxBuffer;\r
412                                 }\r
413 \r
414                                 pxLastDescriptor = pxBuffer;\r
415                         }\r
416                         #else\r
417                         {\r
418                                 prvPassEthMessages( pxBuffer );\r
419                         }\r
420                         #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
421 \r
422                         msgCount++;\r
423                 }\r
424                 {\r
425                         if( ucIsCachedMemory( pxNewBuffer->pucEthernetBuffer ) != 0 )\r
426                         {\r
427                                 Xil_DCacheInvalidateRange( ( ( uint32_t ) pxNewBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE, ( uint32_t ) dmaRX_TX_BUFFER_SIZE );\r
428                         }\r
429                         {\r
430                                 uint32_t addr = ( ( uint32_t )pxNewBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
431                                 if( head == ( ipconfigNIC_N_RX_DESC - 1 ) )\r
432                                 {\r
433                                         addr |= XEMACPS_RXBUF_WRAP_MASK;\r
434                                 }\r
435                                 /* Clearing 'XEMACPS_RXBUF_NEW_MASK'       0x00000001 *< Used bit.. */\r
436                                 xemacpsif->rxSegments[ head ].flags = 0;\r
437                                 xemacpsif->rxSegments[ head ].address = addr;\r
438                                 /* Make sure that the value has reached the peripheral by reading it back. */\r
439                                 ( void ) xemacpsif->rxSegments[ head ].address;\r
440                         }\r
441                 }\r
442 \r
443                 if( ++head == ipconfigNIC_N_RX_DESC )\r
444                 {\r
445                         head = 0;\r
446                 }\r
447                 xemacpsif->rxHead = head;\r
448         }\r
449 \r
450         #if( ipconfigUSE_LINKED_RX_MESSAGES != 0 )\r
451         {\r
452                 if( pxFirstDescriptor != NULL )\r
453                 {\r
454                         prvPassEthMessages( pxFirstDescriptor );\r
455                 }\r
456         }\r
457         #endif  /* ipconfigUSE_LINKED_RX_MESSAGES */\r
458 \r
459         return msgCount;\r
460 }\r
461 \r
462 void clean_dma_txdescs(xemacpsif_s *xemacpsif)\r
463 {\r
464 int index;\r
465 unsigned char *ucTxBuffer;\r
466 \r
467         /* Clear all TX descriptors and assign uncached memory to each descriptor.\r
468         "tx_space" points to the first available TX buffer. */\r
469         ucTxBuffer = xemacpsif->tx_space;\r
470 \r
471         for( index = 0; index < ipconfigNIC_N_TX_DESC; index++ )\r
472         {\r
473                 xemacpsif->txSegments[ index ].address = ( uint32_t )ucTxBuffer;\r
474                 xemacpsif->txSegments[ index ].flags = XEMACPS_TXBUF_USED_MASK;\r
475                 pxDMA_tx_buffers[ index ] = ( unsigned char * )NULL;\r
476                 ucTxBuffer += xemacpsif->uTxUnitSize;\r
477         }\r
478         xemacpsif->txSegments[ ipconfigNIC_N_TX_DESC - 1 ].flags =\r
479                 XEMACPS_TXBUF_USED_MASK | XEMACPS_TXBUF_WRAP_MASK;\r
480 }\r
481 \r
482 XStatus init_dma(xemacpsif_s *xemacpsif)\r
483 {\r
484         NetworkBufferDescriptor_t *pxBuffer;\r
485 \r
486         int iIndex;\r
487         UBaseType_t xRxSize;\r
488         UBaseType_t xTxSize;\r
489         struct xtopology_t *xtopologyp = &xXTopology;\r
490 \r
491         xRxSize = ipconfigNIC_N_RX_DESC * sizeof( xemacpsif->rxSegments[ 0 ] );\r
492 \r
493         xTxSize = ipconfigNIC_N_TX_DESC * sizeof( xemacpsif->txSegments[ 0 ] );\r
494 \r
495         xemacpsif->uTxUnitSize = dmaRX_TX_BUFFER_SIZE;\r
496         /*\r
497          * We allocate 65536 bytes for RX BDs which can accommodate a\r
498          * maximum of 8192 BDs which is much more than any application\r
499          * will ever need.\r
500          */\r
501         xemacpsif->rxSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xRxSize )  );\r
502         xemacpsif->txSegments = ( struct xBD_TYPE * )( pucGetUncachedMemory ( xTxSize ) );\r
503         xemacpsif->tx_space   = ( unsigned char *   )( pucGetUncachedMemory ( ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize ) );\r
504 \r
505         /* These variables will be used in XEmacPs_Start (see src/xemacps.c). */\r
506         xemacpsif->emacps.RxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->rxSegments;\r
507         xemacpsif->emacps.TxBdRing.BaseBdAddr = ( uint32_t ) xemacpsif->txSegments;\r
508 \r
509         if( xTXDescriptorSemaphore == NULL )\r
510         {\r
511                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) ipconfigNIC_N_TX_DESC, ( UBaseType_t ) ipconfigNIC_N_TX_DESC );\r
512                 configASSERT( xTXDescriptorSemaphore );\r
513         }\r
514         /*\r
515          * Allocate RX descriptors, 1 RxBD at a time.\r
516          */\r
517         for( iIndex = 0; iIndex < ipconfigNIC_N_RX_DESC; iIndex++ )\r
518         {\r
519                 pxBuffer = pxDMA_rx_buffers[ iIndex ];\r
520                 if( pxBuffer == NULL )\r
521                 {\r
522                         pxBuffer = pxGetNetworkBufferWithDescriptor( dmaRX_TX_BUFFER_SIZE, ( TickType_t ) 0 );\r
523                         if( pxBuffer == NULL )\r
524                         {\r
525                                 FreeRTOS_printf( ("Unable to allocate a network buffer in recv_handler\n" ) );\r
526                                 return -1;\r
527                         }\r
528                 }\r
529 \r
530                 xemacpsif->rxSegments[ iIndex ].flags = 0;\r
531                 xemacpsif->rxSegments[ iIndex ].address = ( ( uint32_t )pxBuffer->pucEthernetBuffer ) & XEMACPS_RXBUF_ADD_MASK;\r
532 \r
533                 pxDMA_rx_buffers[ iIndex ] = pxBuffer;\r
534                 /* Make sure this memory is not in cache for now. */\r
535                 if( ucIsCachedMemory( pxBuffer->pucEthernetBuffer ) != 0 )\r
536                 {\r
537                         Xil_DCacheInvalidateRange( ( ( uint32_t )pxBuffer->pucEthernetBuffer ) - ipconfigPACKET_FILLER_SIZE,\r
538                                 (unsigned)dmaRX_TX_BUFFER_SIZE );\r
539                 }\r
540         }\r
541 \r
542         xemacpsif->rxSegments[ ipconfigNIC_N_RX_DESC - 1 ].address |= XEMACPS_RXBUF_WRAP_MASK;\r
543 \r
544         memset( xemacpsif->tx_space, '\0', ipconfigNIC_N_TX_DESC * xemacpsif->uTxUnitSize );\r
545 \r
546         clean_dma_txdescs( xemacpsif );\r
547 \r
548         {\r
549                 uint32_t value;\r
550                 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET );\r
551 \r
552                 // 1xxxx: Attempt to use INCR16 AHB bursts\r
553                 value = ( value & ~( XEMACPS_DMACR_BLENGTH_MASK ) ) | XEMACPS_DMACR_INCR16_AHB_BURST;\r
554 #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 )\r
555                 value |= XEMACPS_DMACR_TCPCKSUM_MASK;\r
556 #else\r
557 #warning Are you sure the EMAC should not calculate outgoing checksums?\r
558                 value &= ~XEMACPS_DMACR_TCPCKSUM_MASK;\r
559 #endif\r
560                 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_DMACR_OFFSET, value );\r
561         }\r
562         {\r
563                 uint32_t value;\r
564                 value = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET );\r
565 \r
566                 /* Network buffers are 32-bit aligned + 2 bytes (because ipconfigPACKET_FILLER_SIZE = 2 ).\r
567                 Now tell the EMAC that received messages should be stored at "address + 2". */\r
568                 value = ( value & ~XEMACPS_NWCFG_RXOFFS_MASK ) | 0x8000;\r
569 \r
570 #if( ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM != 0 )\r
571                 value |= XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
572 #else\r
573 #warning Are you sure the EMAC should not calculate incoming checksums?\r
574                 value &= ~XEMACPS_NWCFG_RXCHKSUMEN_MASK;\r
575 #endif\r
576                 XEmacPs_WriteReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCFG_OFFSET, value );\r
577         }\r
578 \r
579         /*\r
580          * Connect the device driver handler that will be called when an\r
581          * interrupt for the device occurs, the handler defined above performs\r
582          * the specific interrupt processing for the device.\r
583          */\r
584         XScuGic_RegisterHandler(INTC_BASE_ADDR, xtopologyp->scugic_emac_intr,\r
585                 (Xil_ExceptionHandler)XEmacPs_IntrHandler,\r
586                 (void *)&xemacpsif->emacps);\r
587         /*\r
588          * Enable the interrupt for emacps.\r
589          */\r
590         EmacEnableIntr( );\r
591 \r
592         return 0;\r
593 }\r
594 \r
595 /*\r
596  * resetrx_on_no_rxdata():\r
597  *\r
598  * It is called at regular intervals through the API xemacpsif_resetrx_on_no_rxdata\r
599  * called by the user.\r
600  * The EmacPs has a HW bug (SI# 692601) on the Rx path for heavy Rx traffic.\r
601  * Under heavy Rx traffic because of the HW bug there are times when the Rx path\r
602  * becomes unresponsive. The workaround for it is to check for the Rx path for\r
603  * traffic (by reading the stats registers regularly). If the stats register\r
604  * does not increment for sometime (proving no Rx traffic), the function resets\r
605  * the Rx data path.\r
606  *\r
607  */\r
608 \r
609 void resetrx_on_no_rxdata(xemacpsif_s *xemacpsif)\r
610 {\r
611         unsigned long regctrl;\r
612         unsigned long tempcntr;\r
613 \r
614         tempcntr = XEmacPs_ReadReg( xemacpsif->emacps.Config.BaseAddress, XEMACPS_RXCNT_OFFSET );\r
615         if ( ( tempcntr == 0 ) && ( xemacpsif->last_rx_frms_cntr == 0 ) )\r
616         {\r
617                 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress,\r
618                                 XEMACPS_NWCTRL_OFFSET);\r
619                 regctrl &= (~XEMACPS_NWCTRL_RXEN_MASK);\r
620                 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress,\r
621                                 XEMACPS_NWCTRL_OFFSET, regctrl);\r
622                 regctrl = XEmacPs_ReadReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET);\r
623                 regctrl |= (XEMACPS_NWCTRL_RXEN_MASK);\r
624                 XEmacPs_WriteReg(xemacpsif->emacps.Config.BaseAddress, XEMACPS_NWCTRL_OFFSET, regctrl);\r
625         }\r
626         xemacpsif->last_rx_frms_cntr = tempcntr;\r
627 }\r
628 \r
629 void EmacDisableIntr(void)\r
630 {\r
631         XScuGic_DisableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
632 }\r
633 \r
634 void EmacEnableIntr(void)\r
635 {\r
636         XScuGic_EnableIntr(INTC_DIST_BASE_ADDR, xXTopology.scugic_emac_intr);\r
637 }\r
638 \r