]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/LPC18xx/NetworkInterface.c
Update to MIT licensed FreeRTOS V10.0.0 - see https://www.freertos.org/History.txt
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / LPC18xx / NetworkInterface.c
1 /*\r
2  * FreeRTOS+TCP V2.0.0\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. If you wish to use our Amazon\r
14  * FreeRTOS name, please do so in a fair use way that does not cause confusion.\r
15  *\r
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\r
18  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\r
19  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\r
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
22  *\r
23  * http://www.FreeRTOS.org\r
24  * http://aws.amazon.com/freertos\r
25  *\r
26  * 1 tab == 4 spaces!\r
27  */\r
28 \r
29 /* Standard includes. */\r
30 #include <stdint.h>\r
31 #include <stdio.h>\r
32 #include <stdlib.h>\r
33 \r
34 /* FreeRTOS includes. */\r
35 #include "FreeRTOS.h"\r
36 #include "task.h"\r
37 #include "queue.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 #include "NetworkInterface.h"\r
46 \r
47 /* LPCOpen includes. */\r
48 #include "chip.h"\r
49 #include "lpc_phy.h"\r
50 \r
51 /* The size of the stack allocated to the task that handles Rx packets. */\r
52 #define nwRX_TASK_STACK_SIZE    140\r
53 \r
54 #ifndef PHY_LS_HIGH_CHECK_TIME_MS\r
55         /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not\r
56         receiving packets. */\r
57         #define PHY_LS_HIGH_CHECK_TIME_MS       15000\r
58 #endif\r
59 \r
60 #ifndef PHY_LS_LOW_CHECK_TIME_MS\r
61         /* Check if the LinkSStatus in the PHY is still low every second. */\r
62         #define PHY_LS_LOW_CHECK_TIME_MS        1000\r
63 #endif\r
64 \r
65 #ifndef configUSE_RMII\r
66         #define configUSE_RMII 1\r
67 #endif\r
68 \r
69 #ifndef configNUM_RX_DESCRIPTORS\r
70         #error please define configNUM_RX_DESCRIPTORS in your FreeRTOSIPConfig.h\r
71 #endif\r
72 \r
73 #ifndef configNUM_TX_DESCRIPTORS\r
74         #error please define configNUM_TX_DESCRIPTORS in your FreeRTOSIPConfig.h\r
75 #endif\r
76 \r
77 #ifndef NETWORK_IRQHandler\r
78         #error NETWORK_IRQHandler must be defined to the name of the function that is installed in the interrupt vector table to handle Ethernet interrupts.\r
79 #endif\r
80 \r
81 #if !defined( MAC_FF_HMC )\r
82         /* Hash for multicast. */\r
83         #define MAC_FF_HMC     ( 1UL << 2UL )\r
84 #endif\r
85 \r
86 #ifndef iptraceEMAC_TASK_STARTING\r
87         #define iptraceEMAC_TASK_STARTING()     do { } while( 0 )\r
88 #endif\r
89 \r
90 /* Define the bits of .STATUS that indicate a reception error. */\r
91 #define nwRX_STATUS_ERROR_BITS \\r
92         ( RDES_CE  /* CRC Error */                        | \\r
93           RDES_RE  /* Receive Error */                    | \\r
94           RDES_DE  /* Descriptor Error */                 | \\r
95           RDES_RWT /* Receive Watchdog Timeout */         | \\r
96           RDES_LC  /* Late Collision */                   | \\r
97           RDES_OE  /* Overflow Error */                   | \\r
98           RDES_SAF /* Source Address Filter Fail */       | \\r
99           RDES_AFM /* Destination Address Filter Fail */  | \\r
100           RDES_LE  /* Length Error */                     )\r
101 \r
102 /* Define the EMAC status bits that should trigger an interrupt. */\r
103 #define nwDMA_INTERRUPT_MASK \\r
104         ( DMA_IE_TIE  /* Transmit interrupt enable */         | \\r
105           DMA_IE_TSE  /* Transmit stopped enable */           | \\r
106           DMA_IE_OVE  /* Overflow interrupt enable */         | \\r
107           DMA_IE_RIE  /* Receive interrupt enable */          | \\r
108           DMA_IE_NIE  /* Normal interrupt summary enable */   | \\r
109           DMA_IE_AIE  /* Abnormal interrupt summary enable */ | \\r
110           DMA_IE_RUE  /* Receive buffer unavailable enable */ | \\r
111           DMA_IE_UNE  /* Underflow interrupt enable. */       | \\r
112           DMA_IE_TJE  /* Transmit jabber timeout enable */    | \\r
113           DMA_IE_RSE  /* Received stopped enable */           | \\r
114           DMA_IE_RWE  /* Receive watchdog timeout enable */   | \\r
115           DMA_IE_FBE )/* Fatal bus error enable */\r
116 \r
117 /* Interrupt events to process.  Currently only the RX/TX events are processed\r
118 although code for other events is included to allow for possible future\r
119 expansion. */\r
120 #define EMAC_IF_RX_EVENT        1UL\r
121 #define EMAC_IF_TX_EVENT        2UL\r
122 #define EMAC_IF_ERR_EVENT       4UL\r
123 #define EMAC_IF_ALL_EVENT       ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )\r
124 \r
125  /* If ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES is set to 1, then the Ethernet\r
126  driver will filter incoming packets and only pass the stack those packets it\r
127  considers need processing. */\r
128  #if( ipconfigETHERNET_DRIVER_FILTERS_FRAME_TYPES == 0 )\r
129         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eProcessBuffer\r
130  #else\r
131         #define ipCONSIDER_FRAME_FOR_PROCESSING( pucEthernetBuffer ) eConsiderFrameForProcessing( ( pucEthernetBuffer ) )\r
132  #endif\r
133 \r
134 #if( ipconfigZERO_COPY_RX_DRIVER == 0 ) || ( ipconfigZERO_COPY_TX_DRIVER == 0 )\r
135         #warning It is adviced to enable both macros\r
136 #endif\r
137 \r
138 #ifndef configPLACE_IN_SECTION_RAM\r
139         #define configPLACE_IN_SECTION_RAM\r
140 /*\r
141         #define configPLACE_IN_SECTION_RAM      __attribute__ ((section(".ramfunc")))\r
142 */\r
143 #endif\r
144 \r
145 /*-----------------------------------------------------------*/\r
146 \r
147 /*\r
148  * Delay function passed into the library.  The implementation uses FreeRTOS\r
149  * calls so the scheduler must be started before the driver can be used.\r
150  */\r
151 static void prvDelay( uint32_t ulMilliSeconds );\r
152 \r
153 /*\r
154  * Initialises the Tx and Rx descriptors respectively.\r
155  */\r
156 static void prvSetupTxDescriptors( void );\r
157 static void prvSetupRxDescriptors( void );\r
158 \r
159 /*\r
160  * A task that processes received frames.\r
161  */\r
162 static void prvEMACHandlerTask( void *pvParameters );\r
163 \r
164 /*\r
165  * Sets up the MAC with the results of an auto-negotiation.\r
166  */\r
167 static BaseType_t prvSetLinkSpeed( void );\r
168 \r
169 /*\r
170  * Generates a CRC for a MAC address that is then used to generate a hash index.\r
171  */\r
172 static uint32_t prvGenerateCRC32( const uint8_t *ucAddress );\r
173 \r
174 /*\r
175  * Generates a hash index when setting a filter to permit a MAC address.\r
176  */\r
177 static uint32_t prvGetHashIndex( const uint8_t *ucAddress );\r
178 \r
179 /*\r
180  * Update the hash table to allow a MAC address.\r
181  */\r
182 static void prvAddMACAddress( const uint8_t* ucMacAddress );\r
183 \r
184 /*\r
185  * Sometimes the DMA will report received data as being longer than the actual\r
186  * received from length.  This function checks the reported length and corrects\r
187  * if if necessary.\r
188  */\r
189 static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor );\r
190 \r
191 /*-----------------------------------------------------------*/\r
192 \r
193 /* Bit map of outstanding ETH interrupt events for processing.  Currently only\r
194 the Rx and Tx interrupt is handled, although code is included for other events\r
195 to enable future expansion. */\r
196 static volatile uint32_t ulISREvents;\r
197 \r
198 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */\r
199 static uint32_t ulPHYLinkStatus = 0;\r
200 \r
201 /* Tx descriptors and index. */\r
202 static ENET_ENHTXDESC_T xDMATxDescriptors[ configNUM_TX_DESCRIPTORS ];\r
203 \r
204 /* ulNextFreeTxDescriptor is declared volatile, because it is accessed from\r
205 to different tasks. */\r
206 static volatile uint32_t ulNextFreeTxDescriptor;\r
207 static uint32_t ulTxDescriptorToClear;\r
208 \r
209 /* Rx descriptors and index. */\r
210 static ENET_ENHRXDESC_T xDMARxDescriptors[ configNUM_RX_DESCRIPTORS ];\r
211 static uint32_t ulNextRxDescriptorToProcess;\r
212 \r
213 /* Must be defined externally - the demo applications define this in main.c. */\r
214 extern uint8_t ucMACAddress[ 6 ];\r
215 \r
216 /* The handle of the task that processes Rx packets.  The handle is required so\r
217 the task can be notified when new packets arrive. */\r
218 static TaskHandle_t xRxHanderTask = NULL;\r
219 \r
220 #if( ipconfigUSE_LLMNR == 1 )\r
221         static const uint8_t xLLMNR_MACAddress[] = { '\x01', '\x00', '\x5E', '\x00', '\x00', '\xFC' };\r
222 #endif  /* ipconfigUSE_LLMNR == 1 */\r
223 \r
224 /* xTXDescriptorSemaphore is a counting semaphore with\r
225 a maximum count of ETH_TXBUFNB, which is the number of\r
226 DMA TX descriptors. */\r
227 static SemaphoreHandle_t xTXDescriptorSemaphore = NULL;\r
228 \r
229 /*-----------------------------------------------------------*/\r
230 \r
231 \r
232 BaseType_t xNetworkInterfaceInitialise( void )\r
233 {\r
234 BaseType_t xReturn = pdPASS;\r
235 static BaseType_t xHasInitialised = pdFALSE;\r
236 \r
237         if( xHasInitialised == pdFALSE )\r
238         {\r
239                 xHasInitialised = pdTRUE;\r
240 \r
241                 /* The interrupt will be turned on when a link is established. */\r
242                 NVIC_DisableIRQ( ETHERNET_IRQn );\r
243 \r
244                 /* Disable receive and transmit DMA processes. */\r
245                 LPC_ETHERNET->DMA_OP_MODE &= ~( DMA_OM_ST | DMA_OM_SR );\r
246 \r
247                 /* Disable packet reception. */\r
248                 LPC_ETHERNET->MAC_CONFIG &= ~( MAC_CFG_RE | MAC_CFG_TE );\r
249 \r
250                 /* Call the LPCOpen function to initialise the hardware. */\r
251                 Chip_ENET_Init( LPC_ETHERNET );\r
252 \r
253                 /* Save MAC address. */\r
254                 Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );\r
255 \r
256                 /* Clear all MAC address hash entries. */\r
257                 LPC_ETHERNET->MAC_HASHTABLE_HIGH = 0;\r
258                 LPC_ETHERNET->MAC_HASHTABLE_LOW = 0;\r
259 \r
260                 #if( ipconfigUSE_LLMNR == 1 )\r
261                 {\r
262                         prvAddMACAddress( xLLMNR_MACAddress );\r
263                 }\r
264                 #endif /* ipconfigUSE_LLMNR == 1 */\r
265 \r
266                 /* Promiscuous flag (PR) and Receive All flag (RA) set to zero.  The\r
267                 registers MAC_HASHTABLE_[LOW|HIGH] will be loaded to allow certain\r
268                 multi-cast addresses. */\r
269                 LPC_ETHERNET->MAC_FRAME_FILTER = MAC_FF_HMC;\r
270 \r
271                 #if( configUSE_RMII == 1 )\r
272                 {\r
273                         if( lpc_phy_init( pdTRUE, prvDelay ) != SUCCESS )\r
274                         {\r
275                                 xReturn = pdFAIL;\r
276                         }\r
277                 }\r
278                 #else\r
279                 {\r
280                         #warning This path has not been tested.\r
281                         if( lpc_phy_init( pdFALSE, prvDelay ) != SUCCESS )\r
282                         {\r
283                                 xReturn = pdFAIL;\r
284                         }\r
285                 }\r
286                 #endif\r
287 \r
288                 if( xReturn == pdPASS )\r
289                 {\r
290                         if( xTXDescriptorSemaphore == NULL )\r
291                         {\r
292                                 /* Create a counting semaphore, with a value of 'configNUM_TX_DESCRIPTORS'\r
293                                 and a maximum of 'configNUM_TX_DESCRIPTORS'. */\r
294                                 xTXDescriptorSemaphore = xSemaphoreCreateCounting( ( UBaseType_t ) configNUM_TX_DESCRIPTORS, ( UBaseType_t ) configNUM_TX_DESCRIPTORS );\r
295                                 configASSERT( xTXDescriptorSemaphore );\r
296                         }\r
297 \r
298                         /* Enable MAC interrupts. */\r
299                         LPC_ETHERNET->DMA_INT_EN = nwDMA_INTERRUPT_MASK;\r
300 \r
301                         /* Auto-negotiate was already started.  Wait for it to complete. */\r
302                         xReturn = prvSetLinkSpeed();\r
303 \r
304                         if( xReturn == pdPASS )\r
305                         {\r
306                                 /* Initialise the descriptors. */\r
307                                 prvSetupTxDescriptors();\r
308                                 prvSetupRxDescriptors();\r
309 \r
310                                 /* Clear all interrupts. */\r
311                                 LPC_ETHERNET->DMA_STAT = DMA_ST_ALL;\r
312 \r
313                                 /* Enable receive and transmit DMA processes. */\r
314                                 LPC_ETHERNET->DMA_OP_MODE |= DMA_OM_ST | DMA_OM_SR;\r
315 \r
316                                 /* Set Receiver / Transmitter Enable. */\r
317                                 LPC_ETHERNET->MAC_CONFIG |= MAC_CFG_RE | MAC_CFG_TE;\r
318 \r
319                                 /* Start receive polling. */\r
320                                 LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;\r
321 \r
322                                 /* Enable interrupts in the NVIC. */\r
323                                 NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );\r
324                                 NVIC_EnableIRQ( ETHERNET_IRQn );\r
325                         }\r
326                         /* Guard against the task being created more than once and the\r
327                         descriptors being initialised more than once. */\r
328                         if( xRxHanderTask == NULL )\r
329                         {\r
330                                 xReturn = xTaskCreate( prvEMACHandlerTask, "EMAC", nwRX_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xRxHanderTask );\r
331                                 configASSERT( xReturn );\r
332                         }\r
333                 }\r
334         }\r
335 \r
336         /* Once prvEMACHandlerTask() has started, the variable\r
337         'ulPHYLinkStatus' will be updated by that task. \r
338         The IP-task will keep on calling this function untill\r
339         it finally returns pdPASS.\r
340         Only then can the DHCP-procedure start (if configured). */\r
341         if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 )\r
342         {\r
343                 xReturn = pdPASS;\r
344         }\r
345         else\r
346         {\r
347                 xReturn = pdFAIL;\r
348         }\r
349 \r
350         return xReturn;\r
351 }\r
352 /*-----------------------------------------------------------*/\r
353 \r
354 #define niBUFFER_1_PACKET_SIZE          1536\r
355 \r
356 static __attribute__ ((section("._ramAHB32"))) uint8_t ucNetworkPackets[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS * niBUFFER_1_PACKET_SIZE ] __attribute__ ( ( aligned( 32 ) ) );\r
357 \r
358 void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] )\r
359 {\r
360 \r
361 uint8_t *ucRAMBuffer = ucNetworkPackets;\r
362 uint32_t ul;\r
363 \r
364         for( ul = 0; ul < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; ul++ )\r
365         {\r
366                 pxNetworkBuffers[ ul ].pucEthernetBuffer = ucRAMBuffer + ipBUFFER_PADDING;\r
367                 *( ( unsigned * ) ucRAMBuffer ) = ( unsigned ) ( &( pxNetworkBuffers[ ul ] ) );\r
368                 ucRAMBuffer += niBUFFER_1_PACKET_SIZE;\r
369         }\r
370 }\r
371 /*-----------------------------------------------------------*/\r
372 \r
373 configPLACE_IN_SECTION_RAM\r
374 static void vClearTXBuffers()\r
375 {\r
376 uint32_t ulLastDescriptor = ulNextFreeTxDescriptor;\r
377 size_t uxCount = ( ( size_t ) configNUM_TX_DESCRIPTORS ) - uxSemaphoreGetCount( xTXDescriptorSemaphore );\r
378 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
379         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
380         uint8_t *ucPayLoad;\r
381 #endif\r
382 \r
383         /* This function is called after a TX-completion interrupt.\r
384         It will release each Network Buffer used in xNetworkInterfaceOutput().\r
385         'uxCount' represents the number of descriptors given to DMA for transmission.\r
386         After sending a packet, the DMA will clear the 'TDES_OWN' bit. */\r
387         while( ( uxCount > ( size_t ) 0u ) && ( ( xDMATxDescriptors[ ulTxDescriptorToClear ].CTRLSTAT & TDES_OWN ) == 0 ) )\r
388         {\r
389                 if( ( ulTxDescriptorToClear == ulLastDescriptor ) && ( uxCount != ( size_t ) configNUM_TX_DESCRIPTORS ) )\r
390                 {\r
391                         break;\r
392                 }\r
393 \r
394 \r
395                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
396                 {\r
397                         ucPayLoad = ( uint8_t * )xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD;\r
398                         if( ucPayLoad != NULL )\r
399                         {\r
400                                 /* B1ADD points to a pucEthernetBuffer of a Network Buffer descriptor. */\r
401                                 pxNetworkBuffer = pxPacketBuffer_to_NetworkBuffer( ucPayLoad );\r
402 \r
403                                 configASSERT( pxNetworkBuffer != NULL );\r
404 \r
405                                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer ) ;\r
406                                 xDMATxDescriptors[ ulTxDescriptorToClear ].B1ADD = ( uint32_t )0u;\r
407                         }\r
408                 }\r
409                 #endif /* ipconfigZERO_COPY_TX_DRIVER */\r
410 \r
411                 /* Move onto the next descriptor, wrapping if necessary. */\r
412                 ulTxDescriptorToClear++;\r
413                 if( ulTxDescriptorToClear >= configNUM_TX_DESCRIPTORS )\r
414                 {\r
415                         ulTxDescriptorToClear = 0;\r
416                 }\r
417 \r
418                 uxCount--;\r
419                 /* Tell the counting semaphore that one more TX descriptor is available. */\r
420                 xSemaphoreGive( xTXDescriptorSemaphore );\r
421         }\r
422 }\r
423 \r
424 /*-----------------------------------------------------------*/\r
425 \r
426 configPLACE_IN_SECTION_RAM\r
427 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t bReleaseAfterSend )\r
428 {\r
429 BaseType_t xReturn = pdFAIL;\r
430 const TickType_t xBlockTimeTicks = pdMS_TO_TICKS( 50 );\r
431 \r
432         /* Attempt to obtain access to a Tx descriptor. */\r
433         do\r
434         {\r
435                 if( xTXDescriptorSemaphore == NULL )\r
436                 {\r
437                         break;\r
438                 }\r
439                 if( xSemaphoreTake( xTXDescriptorSemaphore, xBlockTimeTicks ) != pdPASS )\r
440                 {\r
441                         /* Time-out waiting for a free TX descriptor. */\r
442                         break;\r
443                 }\r
444 \r
445                 /* If the descriptor is still owned by the DMA it can't be used. */\r
446                 if( ( xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT & TDES_OWN ) != 0 )\r
447                 {\r
448                         /* The semaphore was taken, the TX DMA-descriptor is still not available.\r
449                         Actually that should not occur, the 'TDES_OWN' was already confirmed low in vClearTXBuffers(). */\r
450                         xSemaphoreGive( xTXDescriptorSemaphore );\r
451                 }\r
452                 else\r
453                 {\r
454                         #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
455                         {\r
456                                 /* bReleaseAfterSend should always be set when using the zero\r
457                                 copy driver. */\r
458                                 configASSERT( bReleaseAfterSend != pdFALSE );\r
459 \r
460                                 /* The DMA's descriptor to point directly to the data in the\r
461                                 network buffer descriptor.  The data is not copied. */\r
462                                 xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD = ( uint32_t ) pxDescriptor->pucEthernetBuffer;\r
463 \r
464                                 /* The DMA descriptor will 'own' this Network Buffer,\r
465                                 until it has been sent.  So don't release it now. */\r
466                                 bReleaseAfterSend = pdFALSE;\r
467                         }\r
468                         #else\r
469                         {\r
470                                 /* The data is copied from the network buffer descriptor into\r
471                                 the DMA's descriptor. */\r
472                                 memcpy( ( void * ) xDMATxDescriptors[ ulNextFreeTxDescriptor ].B1ADD, ( void * ) pxDescriptor->pucEthernetBuffer, pxDescriptor->xDataLength );\r
473                         }\r
474                         #endif\r
475 \r
476                         xDMATxDescriptors[ ulNextFreeTxDescriptor ].BSIZE = ( uint32_t ) TDES_ENH_BS1( pxDescriptor->xDataLength );\r
477 \r
478                         /* This descriptor is given back to the DMA. */\r
479                         xDMATxDescriptors[ ulNextFreeTxDescriptor ].CTRLSTAT |= TDES_OWN;\r
480 \r
481                         /* Ensure the DMA is polling Tx descriptors. */\r
482                         LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;\r
483 \r
484             iptraceNETWORK_INTERFACE_TRANSMIT();\r
485 \r
486                         /* Move onto the next descriptor, wrapping if necessary. */\r
487                         ulNextFreeTxDescriptor++;\r
488                         if( ulNextFreeTxDescriptor >= configNUM_TX_DESCRIPTORS )\r
489                         {\r
490                                 ulNextFreeTxDescriptor = 0;\r
491                         }\r
492 \r
493                         /* The Tx has been initiated. */\r
494                         xReturn = pdPASS;\r
495                 }\r
496         } while( 0 );\r
497 \r
498         /* The buffer has been sent so can be released. */\r
499         if( bReleaseAfterSend != pdFALSE )\r
500         {\r
501                 vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
502         }\r
503 \r
504         return xReturn;\r
505 }\r
506 /*-----------------------------------------------------------*/\r
507 \r
508 static void prvDelay( uint32_t ulMilliSeconds )\r
509 {\r
510         /* Ensure the scheduler was started before attempting to use the scheduler to\r
511         create a delay. */\r
512         configASSERT( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING );\r
513 \r
514         vTaskDelay( pdMS_TO_TICKS( ulMilliSeconds ) );\r
515 }\r
516 /*-----------------------------------------------------------*/\r
517 \r
518 static void prvSetupTxDescriptors( void )\r
519 {\r
520 BaseType_t x;\r
521 \r
522         /* Start with Tx descriptors clear. */\r
523         memset( ( void * ) xDMATxDescriptors, 0, sizeof( xDMATxDescriptors ) );\r
524 \r
525         /* Index to the next Tx descriptor to use. */\r
526         ulNextFreeTxDescriptor = 0ul;\r
527 \r
528         /* Index to the next Tx descriptor to clear ( after transmission ). */\r
529         ulTxDescriptorToClear = 0ul;\r
530 \r
531         for( x = 0; x < configNUM_TX_DESCRIPTORS; x++ )\r
532         {\r
533                 #if( ipconfigZERO_COPY_TX_DRIVER != 0 )\r
534                 {\r
535                         /* Nothing to do, B1ADD will be set when data is ready to transmit.\r
536                         Currently the memset above will have set it to NULL. */\r
537                 }\r
538                 #else\r
539                 {\r
540                         /* Allocate a buffer to the Tx descriptor.  This is the most basic\r
541                         way of creating a driver as the data is then copied into the\r
542                         buffer. */\r
543                         xDMATxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );\r
544 \r
545                         /* Use an assert to check the allocation as +TCP applications will\r
546                         often not use a malloc() failed hook as the TCP stack will recover\r
547                         from allocation failures. */\r
548                         configASSERT( xDMATxDescriptors[ x ].B1ADD );\r
549                 }\r
550                 #endif\r
551 \r
552                 /* Buffers hold an entire frame so all buffers are both the start and\r
553                 end of a frame. */\r
554                 /* TDES_ENH_TCH     Second Address Chained. */\r
555                 /* TDES_ENH_CIC(n)  Checksum Insertion Control, tried but it does not work for the LPC18xx... */\r
556                 /* TDES_ENH_FS      First Segment. */\r
557                 /* TDES_ENH_LS      Last Segment. */\r
558                 /* TDES_ENH_IC      Interrupt on Completion. */\r
559                 xDMATxDescriptors[ x ].CTRLSTAT = TDES_ENH_TCH | TDES_ENH_CIC( 3 ) | TDES_ENH_FS | TDES_ENH_LS | TDES_ENH_IC;\r
560                 xDMATxDescriptors[ x ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ x + 1 ];\r
561         }\r
562 \r
563         xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].CTRLSTAT |= TDES_ENH_TER;\r
564         xDMATxDescriptors[ configNUM_TX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &xDMATxDescriptors[ 0 ];\r
565 \r
566         /* Point the DMA to the base of the descriptor list. */\r
567         LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xDMATxDescriptors;\r
568 }\r
569 /*-----------------------------------------------------------*/\r
570 \r
571 static void prvSetupRxDescriptors( void )\r
572 {\r
573 BaseType_t x;\r
574 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
575         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
576 #endif\r
577 \r
578         /* Index to the next Rx descriptor to use. */\r
579         ulNextRxDescriptorToProcess = 0;\r
580 \r
581         /* Clear RX descriptor list. */\r
582         memset( ( void * )  xDMARxDescriptors, 0, sizeof( xDMARxDescriptors ) );\r
583 \r
584         for( x = 0; x < configNUM_RX_DESCRIPTORS; x++ )\r
585         {\r
586                 /* Allocate a buffer of the largest     possible frame size as it is not\r
587                 known what size received frames will be. */\r
588 \r
589                 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
590                 {\r
591                         pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, 0 );\r
592 \r
593                         /* During start-up there should be enough Network Buffers available,\r
594                         so it is safe to use configASSERT().\r
595                         In case this assert fails, please check: configNUM_RX_DESCRIPTORS,\r
596                         ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS, and in case BufferAllocation_2.c\r
597                         is included, check the amount of available heap. */\r
598                         configASSERT( pxNetworkBuffer != NULL );\r
599 \r
600                         /* Pass the actual buffer to DMA. */\r
601                         xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;\r
602                 }\r
603                 #else\r
604                 {\r
605                         /* All DMA descriptors are populated with permanent memory blocks.\r
606                         Their contents will be copy to Network Buffers. */\r
607                         xDMARxDescriptors[ x ].B1ADD = ( uint32_t ) pvPortMalloc( ipTOTAL_ETHERNET_FRAME_SIZE );\r
608                 }\r
609                 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
610 \r
611                 /* Use an assert to check the allocation as +TCP applications will often\r
612                 not use a malloc failed hook as the TCP stack will recover from\r
613                 allocation failures. */\r
614                 configASSERT( xDMARxDescriptors[ x ].B1ADD );\r
615 \r
616                 xDMARxDescriptors[ x ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ x + 1 ] );\r
617                 xDMARxDescriptors[ x ].CTRL = ( uint32_t ) RDES_ENH_BS1( ipTOTAL_ETHERNET_FRAME_SIZE ) | RDES_ENH_RCH;\r
618 \r
619                 /* The descriptor is available for use by the DMA. */\r
620                 xDMARxDescriptors[ x ].STATUS = RDES_OWN;\r
621         }\r
622 \r
623         /* RDES_ENH_RER  Receive End of Ring. */\r
624         xDMARxDescriptors[ ( configNUM_RX_DESCRIPTORS - 1 ) ].CTRL |= RDES_ENH_RER;\r
625         xDMARxDescriptors[ configNUM_RX_DESCRIPTORS - 1 ].B2ADD = ( uint32_t ) &( xDMARxDescriptors[ 0 ] );\r
626 \r
627         /* Point the DMA to the base of the descriptor list. */\r
628         LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xDMARxDescriptors;\r
629 }\r
630 /*-----------------------------------------------------------*/\r
631 configPLACE_IN_SECTION_RAM\r
632 static void prvRemoveTrailingBytes( NetworkBufferDescriptor_t *pxDescriptor )\r
633 {\r
634 size_t xExpectedLength;\r
635 IPPacket_t *pxIPPacket;\r
636 \r
637         pxIPPacket = ( IPPacket_t * ) pxDescriptor->pucEthernetBuffer;\r
638         /* Look at the actual length of the packet, translate it to a host-endial notation. */\r
639         xExpectedLength = sizeof( EthernetHeader_t ) + ( size_t ) FreeRTOS_htons( pxIPPacket->xIPHeader.usLength );\r
640 \r
641         if( xExpectedLength == ( pxDescriptor->xDataLength + 4 ) )\r
642         {\r
643                 pxDescriptor->xDataLength -= 4;\r
644         }\r
645         else\r
646         {\r
647                 if( pxDescriptor->xDataLength > xExpectedLength )\r
648                 {\r
649                         pxDescriptor->xDataLength = ( size_t ) xExpectedLength;\r
650                 }\r
651         }\r
652 }\r
653 /*-----------------------------------------------------------*/\r
654 configPLACE_IN_SECTION_RAM\r
655 BaseType_t xGetPhyLinkStatus( void )\r
656 {\r
657 BaseType_t xReturn;\r
658 \r
659         if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )\r
660         {\r
661                 xReturn = pdFALSE;\r
662         }\r
663         else\r
664         {\r
665                 xReturn = pdTRUE;\r
666         }\r
667 \r
668         return xReturn;\r
669 }\r
670 /*-----------------------------------------------------------*/\r
671 \r
672 configPLACE_IN_SECTION_RAM\r
673 static BaseType_t prvNetworkInterfaceInput()\r
674 {\r
675 BaseType_t xResult = pdFALSE;\r
676 uint32_t ulStatus;\r
677 eFrameProcessingResult_t eResult;\r
678 const TickType_t xDescriptorWaitTime = pdMS_TO_TICKS( 250 );\r
679 const UBaseType_t uxMinimumBuffersRemaining = 3UL;\r
680 uint16_t usLength;\r
681 NetworkBufferDescriptor_t *pxDescriptor;\r
682 #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
683         NetworkBufferDescriptor_t *pxNewDescriptor;\r
684 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
685 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
686 \r
687         /* Process each descriptor that is not still in use by the DMA. */\r
688         ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;\r
689         if( ( ulStatus & RDES_OWN ) == 0 )\r
690         {\r
691                 /* Check packet for errors */\r
692                 if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 )\r
693                 {\r
694                         /* There is some reception error. */\r
695                         /* Clear error bits. */\r
696                         ulStatus &= ~( ( uint32_t )nwRX_STATUS_ERROR_BITS );\r
697                 }\r
698                 else\r
699                 {\r
700                         xResult++;\r
701 \r
702                         eResult = ipCONSIDER_FRAME_FOR_PROCESSING( ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD ) );\r
703                         if( eResult == eProcessBuffer )\r
704                         {\r
705                                 if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) == 0 )\r
706                                 {\r
707                                         ulPHYLinkStatus |= PHY_LINK_CONNECTED;\r
708                                         FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (message received)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );\r
709                                 }\r
710 \r
711                         #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
712                                 if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )\r
713                                 {\r
714                                         pxNewDescriptor = pxGetNetworkBufferWithDescriptor( ipTOTAL_ETHERNET_FRAME_SIZE, xDescriptorWaitTime );\r
715                                 }\r
716                                 else\r
717                                 {\r
718                                         /* Too risky to allocate a new Network Buffer. */\r
719                                         pxNewDescriptor = NULL;\r
720                                 }\r
721                                 if( pxNewDescriptor != NULL )\r
722                         #else\r
723                                 if( uxGetNumberOfFreeNetworkBuffers() > uxMinimumBuffersRemaining )\r
724                         #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
725                                 {\r
726                         #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
727                                 const uint8_t *pucBuffer;\r
728                         #endif\r
729 \r
730                                         /* Get the actual length. */\r
731                                         usLength = RDES_FLMSK( ulStatus );\r
732 \r
733                                         #if( ipconfigZERO_COPY_RX_DRIVER != 0 )\r
734                                         {\r
735                                                 /* Replace the character buffer 'B1ADD'. */\r
736                                                 pucBuffer = ( const uint8_t * const ) ( xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD );\r
737                                                 xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD = ( uint32_t ) pxNewDescriptor->pucEthernetBuffer;\r
738 \r
739                                                 /* 'B1ADD' contained the address of a 'pucEthernetBuffer' that\r
740                                                 belongs to a Network Buffer.  Find the original Network Buffer. */\r
741                                                 pxDescriptor = pxPacketBuffer_to_NetworkBuffer( pucBuffer );\r
742                                                 /* This zero-copy driver makes sure that every 'xDMARxDescriptors' contains\r
743                                                 a reference to a Network Buffer at any time.\r
744                                                 In case it runs out of Network Buffers, a DMA buffer won't be replaced,\r
745                                                 and the received messages is dropped. */\r
746                                                 configASSERT( pxDescriptor != NULL );\r
747                                         }\r
748                                         #else\r
749                                         {\r
750                                                 /* Create a buffer of exactly the required length. */\r
751                                                 pxDescriptor = pxGetNetworkBufferWithDescriptor( usLength, xDescriptorWaitTime );\r
752                                         }\r
753                                         #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
754 \r
755                                         if( pxDescriptor != NULL )\r
756                                         {\r
757                                                 pxDescriptor->xDataLength = ( size_t ) usLength;\r
758                                                 #if( ipconfigZERO_COPY_RX_DRIVER == 0 )\r
759                                                 {\r
760                                                         /* Copy the data into the allocated buffer. */\r
761                                                         memcpy( ( void * ) pxDescriptor->pucEthernetBuffer, ( void * ) xDMARxDescriptors[ ulNextRxDescriptorToProcess ].B1ADD, usLength );\r
762                                                 }\r
763                                                 #endif /* ipconfigZERO_COPY_RX_DRIVER */\r
764                                                 /* It is possible that more data was copied than\r
765                                                 actually makes up the frame.  If this is the case\r
766                                                 adjust the length to remove any trailing bytes. */\r
767                                                 prvRemoveTrailingBytes( pxDescriptor );\r
768 \r
769                                                 /* Pass the data to the TCP/IP task for processing. */\r
770                                                 xRxEvent.pvData = ( void * ) pxDescriptor;\r
771                                                 if( xSendEventStructToIPTask( &xRxEvent, xDescriptorWaitTime ) == pdFALSE )\r
772                                                 {\r
773                                                         /* Could not send the descriptor into the TCP/IP\r
774                                                         stack, it must be released. */\r
775                                                         vReleaseNetworkBufferAndDescriptor( pxDescriptor );\r
776                                                 }\r
777                                                 else\r
778                                                 {\r
779                                                         iptraceNETWORK_INTERFACE_RECEIVE();\r
780                                                 }\r
781                                         }\r
782                                 }\r
783                         }\r
784                         /* Got here because received data was sent to the IP task or the\r
785                         data contained an error and was discarded.  Give the descriptor\r
786                         back to the DMA. */\r
787                         xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS = ulStatus | RDES_OWN;\r
788 \r
789                         /* Move onto the next descriptor. */\r
790                         ulNextRxDescriptorToProcess++;\r
791                         if( ulNextRxDescriptorToProcess >= configNUM_RX_DESCRIPTORS )\r
792                         {\r
793                                 ulNextRxDescriptorToProcess = 0;\r
794                         }\r
795 \r
796                         ulStatus = xDMARxDescriptors[ ulNextRxDescriptorToProcess ].STATUS;\r
797                 } /* if( ( ulStatus & nwRX_STATUS_ERROR_BITS ) != 0 ) */\r
798         } /* if( ( ulStatus & RDES_OWN ) == 0 ) */\r
799 \r
800         /* Restart receive polling. */\r
801         LPC_ETHERNET->DMA_REC_POLL_DEMAND = 1;\r
802 \r
803         return xResult;\r
804 }\r
805 /*-----------------------------------------------------------*/\r
806 \r
807 configPLACE_IN_SECTION_RAM\r
808 void NETWORK_IRQHandler( void )\r
809 {\r
810 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
811 uint32_t ulDMAStatus;\r
812 const uint32_t ulRxInterruptMask =\r
813         DMA_ST_RI |             /* Receive interrupt */\r
814         DMA_ST_RU;              /* Receive buffer unavailable */\r
815 const uint32_t ulTxInterruptMask =\r
816         DMA_ST_TI |             /* Transmit interrupt */\r
817         DMA_ST_TPS;             /* Transmit process stopped */\r
818 \r
819         configASSERT( xRxHanderTask );\r
820 \r
821         /* Get pending interrupts. */\r
822         ulDMAStatus = LPC_ETHERNET->DMA_STAT;\r
823 \r
824         /* RX group interrupt(s). */\r
825         if( ( ulDMAStatus & ulRxInterruptMask ) != 0x00 )\r
826         {\r
827                 /* Remember that an RX event has happened. */\r
828                 ulISREvents |= EMAC_IF_RX_EVENT;\r
829                 vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );\r
830         }\r
831 \r
832         /* TX group interrupt(s). */\r
833         if( ( ulDMAStatus & ulTxInterruptMask ) != 0x00 )\r
834         {\r
835                 /* Remember that a TX event has happened. */\r
836                 ulISREvents |= EMAC_IF_TX_EVENT;\r
837                 vTaskNotifyGiveFromISR( xRxHanderTask, &xHigherPriorityTaskWoken );\r
838         }\r
839 \r
840         /* Test for 'Abnormal interrupt summary'. */\r
841         if( ( ulDMAStatus & DMA_ST_AIE ) != 0x00 )\r
842         {\r
843                 /* The trace macro must be written such that it can be called from\r
844                 an interrupt. */\r
845                 iptraceETHERNET_RX_EVENT_LOST();\r
846         }\r
847 \r
848         /* Clear pending interrupts */\r
849         LPC_ETHERNET->DMA_STAT = ulDMAStatus;\r
850 \r
851         /* Context switch needed? */\r
852         portYIELD_FROM_ISR( xHigherPriorityTaskWoken );\r
853 }\r
854 /*-----------------------------------------------------------*/\r
855 \r
856 static BaseType_t prvSetLinkSpeed( void )\r
857 {\r
858 BaseType_t xReturn = pdFAIL;\r
859 TickType_t xTimeOnEntering;\r
860 uint32_t ulPhyStatus;\r
861 const TickType_t xAutoNegotiateDelay = pdMS_TO_TICKS( 5000UL );\r
862 \r
863         /* Ensure polling does not starve lower priority tasks by temporarily\r
864         setting the priority of this task to that of the idle task. */\r
865         vTaskPrioritySet( NULL, tskIDLE_PRIORITY );\r
866 \r
867         xTimeOnEntering = xTaskGetTickCount();\r
868         do\r
869         {\r
870                 ulPhyStatus = lpcPHYStsPoll();\r
871                 if( ( ulPhyStatus & PHY_LINK_CONNECTED ) != 0x00 )\r
872                 {\r
873                         /* Set interface speed and duplex. */\r
874                         if( ( ulPhyStatus & PHY_LINK_SPEED100 ) != 0x00 )\r
875                         {\r
876                                 Chip_ENET_SetSpeed( LPC_ETHERNET, 1 );\r
877                         }\r
878                         else\r
879                         {\r
880                                 Chip_ENET_SetSpeed( LPC_ETHERNET, 0 );\r
881                         }\r
882 \r
883                         if( ( ulPhyStatus & PHY_LINK_FULLDUPLX ) != 0x00 )\r
884                         {\r
885                                 Chip_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );\r
886                         }\r
887                         else\r
888                         {\r
889                                 Chip_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );\r
890                         }\r
891 \r
892                         xReturn = pdPASS;\r
893                         break;\r
894                 }\r
895         } while( ( xTaskGetTickCount() - xTimeOnEntering ) < xAutoNegotiateDelay );\r
896 \r
897         /* Reset the priority of this task back to its original value. */\r
898         vTaskPrioritySet( NULL, ipconfigIP_TASK_PRIORITY );\r
899 \r
900         return xReturn;\r
901 }\r
902 /*-----------------------------------------------------------*/\r
903 \r
904 static uint32_t prvGenerateCRC32( const uint8_t *ucAddress )\r
905 {\r
906 unsigned int j;\r
907 const uint32_t Polynomial = 0xEDB88320;\r
908 uint32_t crc = ~0ul;\r
909 const uint8_t *pucCurrent = ( const uint8_t * ) ucAddress;\r
910 const uint8_t *pucLast = pucCurrent + 6;\r
911 \r
912     /* Calculate  normal CRC32 */\r
913     while( pucCurrent < pucLast )\r
914     {\r
915         crc ^= *( pucCurrent++ );\r
916         for( j = 0; j < 8; j++ )\r
917         {\r
918             if( ( crc & 1 ) != 0 )\r
919             {\r
920                 crc = (crc >> 1) ^ Polynomial;\r
921             }\r
922             else\r
923             {\r
924                 crc >>= 1;\r
925             }\r
926         }\r
927     }\r
928     return ~crc;\r
929 }\r
930 /*-----------------------------------------------------------*/\r
931 \r
932 static uint32_t prvGetHashIndex( const uint8_t *ucAddress )\r
933 {\r
934 uint32_t ulCrc = prvGenerateCRC32( ucAddress );\r
935 uint32_t ulIndex = 0ul;\r
936 BaseType_t xCount = 6;\r
937 \r
938     /* Take the lowest 6 bits of the CRC32 and reverse them */\r
939     while( xCount-- )\r
940     {\r
941         ulIndex <<= 1;\r
942         ulIndex |= ( ulCrc & 1 );\r
943         ulCrc >>= 1;\r
944     }\r
945 \r
946     /* This is the has value of 'ucAddress' */\r
947     return ulIndex;\r
948 }\r
949 /*-----------------------------------------------------------*/\r
950 \r
951 static void prvAddMACAddress( const uint8_t* ucMacAddress )\r
952 {\r
953 BaseType_t xIndex;\r
954 \r
955     xIndex = prvGetHashIndex( ucMacAddress );\r
956     if( xIndex >= 32 )\r
957     {\r
958         LPC_ETHERNET->MAC_HASHTABLE_HIGH |= ( 1u << ( xIndex - 32 ) );\r
959     }\r
960     else\r
961     {\r
962         LPC_ETHERNET->MAC_HASHTABLE_LOW |= ( 1u << xIndex );\r
963     }\r
964 }\r
965 /*-----------------------------------------------------------*/\r
966 \r
967 configPLACE_IN_SECTION_RAM\r
968 static void prvEMACHandlerTask( void *pvParameters )\r
969 {\r
970 TimeOut_t xPhyTime;\r
971 TickType_t xPhyRemTime;\r
972 UBaseType_t uxLastMinBufferCount = 0;\r
973 UBaseType_t uxCurrentCount;\r
974 BaseType_t xResult = 0;\r
975 uint32_t ulStatus;\r
976 const TickType_t xBlockTime = pdMS_TO_TICKS( 5000ul );\r
977 \r
978         /* Remove compiler warning about unused parameter. */\r
979         ( void ) pvParameters;\r
980 \r
981         /* A possibility to set some additional task properties. */\r
982         iptraceEMAC_TASK_STARTING();\r
983 \r
984         vTaskSetTimeOutState( &xPhyTime );\r
985         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
986 \r
987         for( ;; )\r
988         {\r
989                 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();\r
990                 if( uxLastMinBufferCount != uxCurrentCount )\r
991                 {\r
992                         /* The logging produced below may be helpful\r
993                         while tuning +TCP: see how many buffers are in use. */\r
994                         uxLastMinBufferCount = uxCurrentCount;\r
995                         FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",\r
996                                 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );\r
997                 }\r
998 \r
999                 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
1000                 {\r
1001                 static UBaseType_t uxLastMinQueueSpace = 0;\r
1002 \r
1003                         uxCurrentCount = uxGetMinimumIPQueueSpace();\r
1004                         if( uxLastMinQueueSpace != uxCurrentCount )\r
1005                         {\r
1006                                 /* The logging produced below may be helpful\r
1007                                 while tuning +TCP: see how many buffers are in use. */\r
1008                                 uxLastMinQueueSpace = uxCurrentCount;\r
1009                                 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );\r
1010                         }\r
1011                 }\r
1012                 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
1013 \r
1014                 ulTaskNotifyTake( pdTRUE, xBlockTime );\r
1015 \r
1016                 xResult = ( BaseType_t ) 0;\r
1017 \r
1018                 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )\r
1019                 {\r
1020                         /* Code to release TX buffers if zero-copy is used. */\r
1021                         ulISREvents &= ~EMAC_IF_TX_EVENT;\r
1022                         {\r
1023                                 /* Check if DMA packets have been delivered. */\r
1024                                 vClearTXBuffers();\r
1025                         }\r
1026                 }\r
1027 \r
1028                 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )\r
1029                 {\r
1030                         ulISREvents &= ~EMAC_IF_RX_EVENT;\r
1031 \r
1032                         xResult = prvNetworkInterfaceInput();\r
1033                         if( xResult > 0 )\r
1034                         {\r
1035                                 while( prvNetworkInterfaceInput() > 0 )\r
1036                                 {\r
1037                                 }\r
1038                         }\r
1039                 }\r
1040 \r
1041                 if( xResult > 0 )\r
1042                 {\r
1043                         /* A packet was received. No need to check for the PHY status now,\r
1044                         but set a timer to check it later on. */\r
1045                         vTaskSetTimeOutState( &xPhyTime );\r
1046                         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
1047                         xResult = 0;\r
1048                 }\r
1049                 else if( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE )\r
1050                 {\r
1051                         ulStatus = lpcPHYStsPoll();\r
1052 \r
1053                         if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != ( ulStatus & PHY_LINK_CONNECTED ) )\r
1054                         {\r
1055                                 ulPHYLinkStatus = ulStatus;\r
1056                                 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d (polled PHY)\n", ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 ) );\r
1057                         }\r
1058 \r
1059                         vTaskSetTimeOutState( &xPhyTime );\r
1060                         if( ( ulPHYLinkStatus & PHY_LINK_CONNECTED ) != 0 )\r
1061                         {\r
1062                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
1063                         }\r
1064                         else\r
1065                         {\r
1066                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
1067                         }\r
1068                 }\r
1069         }\r
1070 }\r
1071 /*-----------------------------------------------------------*/\r