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