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