]> git.sur5r.net Git - freertos/blob
1e64a4974e5be845b50d1b8ea505894cbfdec80a
[freertos] /
1 /*\r
2  * FreeRTOS+UDP V1.0.4\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 /* FreeRTOS includes. */\r
29 #include "FreeRTOS.h"\r
30 #include "task.h"\r
31 #include "semphr.h"\r
32 \r
33 /* FreeRTOS+UDP includes. */\r
34 #include "FreeRTOS_UDP_IP.h"\r
35 #include "FreeRTOS_IP_Private.h"\r
36 #include "NetworkBufferManagement.h"\r
37 \r
38 /* Library includes. */\r
39 #include "board.h"\r
40 \r
41 /* Descriptors that reference received buffers are expected to have both the\r
42 first and last frame bits set because buffers are dimensioned to hold complete\r
43 Ethernet frames. */\r
44 #define emacEXPECTED_RX_STATUS_MASK     ( RDES_LS | RDES_FS )\r
45 \r
46 /*-----------------------------------------------------------*/\r
47 \r
48 /*\r
49  * Set the Rx and Tx descriptors into their expected initial state.\r
50  */\r
51 static void prvResetRxDescriptors( void );\r
52 static void prvResetTxDescriptors( void );\r
53 \r
54 /*\r
55  * Returns the length of the data pointed to by the next Rx descriptor.\r
56  */\r
57 static uint32_t prvReceivedDataLength( void );\r
58 \r
59 \r
60 /*-----------------------------------------------------------*/\r
61 \r
62 /* Rx and Tx descriptors and data array. */\r
63 static volatile IP_ENET_001_ENHRXDESC_T xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS ];\r
64 static volatile IP_ENET_001_ENHTXDESC_T xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS ];\r
65 \r
66 /* Indexes into the Rx and Tx descriptor arrays. */\r
67 static unsigned int xRxDescriptorIndex = 0;\r
68 static unsigned int xTxDescriptorIndex = 0;\r
69 \r
70 /*-----------------------------------------------------------*/\r
71 \r
72 BaseType_t xEMACInit( uint8_t ucMACAddress[ 6 ] )\r
73 {\r
74 BaseType_t xReturn;\r
75 uint32_t ulPHYStatus;\r
76 \r
77         /* Configure the hardware. */\r
78         Chip_ENET_Init( LPC_ETHERNET );\r
79 \r
80         if( lpc_phy_init( pdTRUE, vTaskDelay ) == SUCCESS )\r
81         {\r
82                 /* The MAC address is passed in as the function parameter. */\r
83                 Chip_ENET_SetADDR( LPC_ETHERNET, ucMACAddress );\r
84 \r
85                 /* Wait for autonegotiation to complete. */\r
86                 do\r
87                 {\r
88                         vTaskDelay( 100 );\r
89                         ulPHYStatus = lpcPHYStsPoll();\r
90                 } while( ( ulPHYStatus & PHY_LINK_CONNECTED ) == 0x00 );\r
91 \r
92                 /* Configure the hardware as per the negotiated link. */\r
93                 if( ( ulPHYStatus & PHY_LINK_FULLDUPLX ) == PHY_LINK_FULLDUPLX )\r
94                 {\r
95                         IP_ENET_SetDuplex( LPC_ETHERNET, pdTRUE );\r
96                 }\r
97                 else\r
98                 {\r
99                         IP_ENET_SetDuplex( LPC_ETHERNET, pdFALSE );\r
100                 }\r
101 \r
102                 if( ( ulPHYStatus & PHY_LINK_SPEED100 ) == PHY_LINK_SPEED100 )\r
103                 {\r
104                         IP_ENET_SetSpeed( LPC_ETHERNET, pdTRUE );\r
105                 }\r
106                 else\r
107                 {\r
108                         IP_ENET_SetSpeed( LPC_ETHERNET, pdFALSE );\r
109                 }\r
110 \r
111                 /* Set descriptors to their initial state. */\r
112                 prvResetRxDescriptors();\r
113                 prvResetTxDescriptors();\r
114 \r
115                 /* Enable RX and TX. */\r
116                 Chip_ENET_TXEnable( LPC_ETHERNET );\r
117                 Chip_ENET_RXEnable( LPC_ETHERNET );\r
118 \r
119                 /* Enable the interrupt and set its priority as configured.  THIS\r
120                 DRIVER REQUIRES configMAC_INTERRUPT_PRIORITY TO BE DEFINED, PREFERABLY\r
121                 IN FreeRTOSConfig.h. */\r
122                 NVIC_SetPriority( ETHERNET_IRQn, configMAC_INTERRUPT_PRIORITY );\r
123                 NVIC_EnableIRQ( ETHERNET_IRQn );\r
124 \r
125                 /* Enable interrupts. */\r
126                 LPC_ETHERNET->DMA_INT_EN =  DMA_IE_NIE | DMA_IE_RIE;\r
127 \r
128                 xReturn = pdPASS;\r
129         }\r
130         else\r
131         {\r
132                 xReturn = pdFAIL;\r
133         }\r
134 \r
135         return xReturn;\r
136 }\r
137 /*-----------------------------------------------------------*/\r
138 \r
139 BaseType_t xEMACIsTxDescriptorAvailable( void )\r
140 {\r
141 BaseType_t xReturn;\r
142 \r
143         if( ( xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT & RDES_OWN ) == 0 )\r
144         {\r
145                 xReturn = pdPASS;\r
146         }\r
147         else\r
148         {\r
149                 xReturn = pdFAIL;\r
150         }\r
151 \r
152         return xReturn;\r
153 }\r
154 /*-----------------------------------------------------------*/\r
155 \r
156 void vEMACAssignBufferToDescriptor( uint8_t * pucBuffer )\r
157 {\r
158         /* The old packet is now finished with and can be freed. */\r
159         vEthernetBufferRelease( ( void * ) xTxDescriptors[ xTxDescriptorIndex ].B1ADD );\r
160 \r
161         /* Assign the new packet to the descriptor. */\r
162         xTxDescriptors[ xTxDescriptorIndex ].B1ADD = ( uint32_t ) pucBuffer;\r
163 }\r
164 /*-----------------------------------------------------------*/\r
165 \r
166 void vEMACStartNextTransmission( uint32_t ulLength )\r
167 {\r
168         xTxDescriptors[ xTxDescriptorIndex ].BSIZE = ulLength;\r
169         xTxDescriptors[ xTxDescriptorIndex ].CTRLSTAT |= RDES_OWN;\r
170 \r
171         /* Wake Up the DMA if it's in Suspended Mode. */\r
172         LPC_ETHERNET->DMA_TRANS_POLL_DEMAND = 1;\r
173         xTxDescriptorIndex++;\r
174 \r
175         if( xTxDescriptorIndex == configNUM_TX_ETHERNET_DMA_DESCRIPTORS )\r
176         {\r
177                 xTxDescriptorIndex = 0;\r
178         }\r
179 }\r
180 /*-----------------------------------------------------------*/\r
181 \r
182 static uint32_t prvReceivedDataLength( void )\r
183 {\r
184 unsigned short RxLen = 0;\r
185 \r
186         RxLen = ( xRXDescriptors[ xRxDescriptorIndex ].STATUS >> 16 ) & 0x03FFF;\r
187         return RxLen;\r
188 }\r
189 /*-----------------------------------------------------------*/\r
190 \r
191 void vEMACReturnRxDescriptor( void )\r
192 {\r
193         xRXDescriptors[ xRxDescriptorIndex ].STATUS = RDES_OWN;\r
194         xRxDescriptorIndex++;\r
195 \r
196         if( xRxDescriptorIndex == configNUM_RX_ETHERNET_DMA_DESCRIPTORS )\r
197         {\r
198                 xRxDescriptorIndex = 0;\r
199         }\r
200 }\r
201 /*-----------------------------------------------------------*/\r
202 \r
203 BaseType_t xEMACRxDataAvailable( void )\r
204 {\r
205 BaseType_t xReturn;\r
206 \r
207         if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & RDES_OWN ) == 0 )\r
208         {\r
209                 xReturn = pdPASS;\r
210         }\r
211         else\r
212         {\r
213                 xReturn = pdFAIL;\r
214         }\r
215 \r
216         return xReturn;\r
217 }\r
218 /*-----------------------------------------------------------*/\r
219 \r
220 void vEMACSwapEmptyBufferForRxedData( xNetworkBufferDescriptor_t *pxNetworkBuffer )\r
221 {\r
222 uint8_t *pucTemp;\r
223 \r
224         /* Swap the buffer in the network buffer with the buffer used by the DMA.\r
225         This allows the data to be passed out without having to perform any copies. */\r
226         pucTemp = ( uint8_t * ) xRXDescriptors[ xRxDescriptorIndex ].B1ADD;\r
227         xRXDescriptors[ xRxDescriptorIndex ].B1ADD = ( uint32_t ) pxNetworkBuffer->pucEthernetBuffer;\r
228         pxNetworkBuffer->pucEthernetBuffer = pucTemp;\r
229 \r
230         /* Only supports frames coming in single buffers.  If this frame is split\r
231         across multiple buffers then reject it (and if the frame is needed increase\r
232         the ipconfigNETWORK_MTU setting). */\r
233         if( ( xRXDescriptors[ xRxDescriptorIndex ].STATUS & emacEXPECTED_RX_STATUS_MASK ) != emacEXPECTED_RX_STATUS_MASK )\r
234         {\r
235                 pxNetworkBuffer->xDataLength = 0;\r
236         }\r
237         else\r
238         {\r
239                 pxNetworkBuffer->xDataLength = ( size_t ) prvReceivedDataLength() - ( ipETHERNET_CRC_BYTES - 1U );;\r
240         }\r
241 }\r
242 /*-----------------------------------------------------------*/\r
243 \r
244 static void prvResetRxDescriptors( void )\r
245 {\r
246 uint32_t x;\r
247 size_t xBufferSize = ipTOTAL_ETHERNET_FRAME_SIZE;\r
248 \r
249         for( x = 0; x < configNUM_RX_ETHERNET_DMA_DESCRIPTORS; x++ )\r
250         {\r
251                 /* Obtain the buffer first, as the size of the buffer might be changed\r
252                 within the pucEthernetBufferGet() call. */\r
253                 xRXDescriptors[ x ].B1ADD  = ( uint32_t ) pucEthernetBufferGet( &xBufferSize );\r
254                 xRXDescriptors[ x ].STATUS = RDES_OWN;\r
255                 xRXDescriptors[ x ].CTRL  = xBufferSize;\r
256                 xRXDescriptors[ x ].B2ADD = ( uint32_t ) &xRXDescriptors[ x + 1 ];\r
257                 \r
258                 configASSERT( ( ( ( uint32_t ) xRXDescriptors[x].B1ADD ) & 0x07 ) == 0 );\r
259         }\r
260 \r
261         /* Last Descriptor */\r
262         xRXDescriptors[ configNUM_RX_ETHERNET_DMA_DESCRIPTORS - 1 ].CTRL |= RDES_ENH_RER;\r
263 \r
264         xRxDescriptorIndex = 0;\r
265 \r
266         /* Set Starting address of RX Descriptor list */\r
267         LPC_ETHERNET->DMA_REC_DES_ADDR = ( uint32_t ) xRXDescriptors;\r
268 }\r
269 /*-----------------------------------------------------------*/\r
270 \r
271 static void prvResetTxDescriptors( void )\r
272 {\r
273 /* Initialize Transmit Descriptor and Status array. */\r
274 uint32_t x;\r
275 \r
276         for( x = 0; x < configNUM_TX_ETHERNET_DMA_DESCRIPTORS; x++ )\r
277         {\r
278                 xTxDescriptors[ x ].CTRLSTAT = TDES_ENH_FS | TDES_ENH_LS;\r
279                 xTxDescriptors[ x ].BSIZE  = 0;\r
280                 xTxDescriptors[ x ].B2ADD = ( uint32_t ) &xTxDescriptors[ x + 1 ];\r
281 \r
282                 /* Packet is assigned when a Tx is initiated. */\r
283                 xTxDescriptors[ x ].B1ADD   = ( uint32_t )NULL;\r
284         }\r
285 \r
286         /* Last Descriptor? */\r
287         xTxDescriptors[ configNUM_TX_ETHERNET_DMA_DESCRIPTORS-1 ].CTRLSTAT |= TDES_ENH_TER;\r
288 \r
289         /* Set Starting address of TX Descriptor list */\r
290         LPC_ETHERNET->DMA_TRANS_DES_ADDR = ( uint32_t ) xTxDescriptors;\r
291 }\r
292 /*-----------------------------------------------------------*/\r
293 \r
294 void ETH_IRQHandler( void )\r
295 {\r
296 uint32_t ulInterruptCause;\r
297 extern xSemaphoreHandle xEMACRxEventSemaphore;\r
298 \r
299         configASSERT( xEMACRxEventSemaphore );\r
300 \r
301         ulInterruptCause = LPC_ETHERNET->DMA_STAT ;\r
302 \r
303         /* Clear the interrupt. */\r
304         LPC_ETHERNET->DMA_STAT |= ( DMA_ST_NIS | DMA_ST_RI );\r
305 \r
306         /* Clear fatal error conditions.  NOTE:  The driver does not clear all\r
307         errors, only those actually experienced.  For future reference, range\r
308         errors are not actually errors so can be ignored. */\r
309         if( ( ulInterruptCause & DMA_ST_FBI ) != 0U )\r
310         {\r
311                 LPC_ETHERNET->DMA_STAT |= DMA_ST_FBI;\r
312         }\r
313 \r
314         /* Unblock the deferred interrupt handler task if the event was an Rx. */\r
315         if( ( ulInterruptCause & DMA_IE_RIE ) != 0UL )\r
316         {\r
317                 xSemaphoreGiveFromISR( xEMACRxEventSemaphore, NULL );\r
318         }\r
319 \r
320         /* ulInterruptCause is used for convenience here.  A context switch is\r
321         wanted, but coding portEND_SWITCHING_ISR( 1 ) would likely result in a\r
322         compiler warning. */\r
323         portEND_SWITCHING_ISR( ulInterruptCause );\r
324 }\r
325 \r