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