]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-TCP/portable/NetworkInterface/ksz8851snl/NetworkInterface.c
544e5ba095497386218b939f7dbc2d1ba1ee632c
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-TCP / portable / NetworkInterface / ksz8851snl / NetworkInterface.c
1 /*\r
2 FreeRTOS+TCP V2.0.11\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://aws.amazon.com/freertos\r
23  http://www.FreeRTOS.org\r
24 */\r
25 \r
26 /* Standard includes. */\r
27 #include <stdint.h>\r
28 #include <stdio.h>\r
29 #include <stdlib.h>\r
30 #include <stdarg.h>\r
31 \r
32 /* FreeRTOS includes. */\r
33 #include "FreeRTOS.h"\r
34 #include "task.h"\r
35 #include "queue.h"\r
36 #include "semphr.h"\r
37 \r
38 /* FreeRTOS+TCP includes. */\r
39 #include "FreeRTOS_IP.h"\r
40 #include "FreeRTOS_Sockets.h"\r
41 #include "FreeRTOS_IP_Private.h"\r
42 #include "NetworkBufferManagement.h"\r
43 #include "NetworkInterface.h"\r
44 \r
45 #include "sam4e_xplained_pro.h"\r
46 #include "hr_gettime.h"\r
47 #include "conf_eth.h"\r
48 #include "ksz8851snl.h"\r
49 #include "ksz8851snl_reg.h"\r
50 \r
51 /* Some files from the Atmel Software Framework */\r
52 #include <sysclk.h>\r
53 #include <pdc/pdc.h>\r
54 #include <spi/spi.h>\r
55 \r
56 /*\r
57         Sending a packet:\r
58 \r
59                 1) Called by UP-task, add buffer to the TX-list:\r
60                         xNetworkInterfaceOutput()\r
61                                 tx_buffers[ us_tx_head ] = pxNetworkBuffer;\r
62                                 tx_busy[ us_tx_head ] = pdTRUE;\r
63                                 us_tx_head++;\r
64 \r
65                 2) Called by EMAC-Task: start SPI transfer\r
66                         ksz8851snl_update()\r
67                         if( ul_spi_pdc_status == SPI_PDC_IDLE )\r
68                         {\r
69                                 if( ( tx_busy[ us_tx_tail ] != pdFALSE ) &&\r
70                                         ( us_pending_frame == 0 ) &&\r
71                                         ( ul_had_intn_interrupt == 0 ) )\r
72                                 {\r
73                                         // disable all interrupts.\r
74                                         ksz8851_reg_write( REG_INT_MASK, 0 );\r
75                                         Bring KSZ8851SNL_CSN_GPIO low\r
76                                         ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );\r
77                                         ul_spi_pdc_status = SPI_PDC_TX_START;\r
78                                         tx_cur_buffer = pxNetworkBuffer;\r
79                                 }\r
80                         }\r
81                 3) Wait for SPI RXBUFF interrupt\r
82                         SPI_Handler()\r
83                                 if( ul_spi_pdc_status == SPI_PDC_TX_START )\r
84                                 {\r
85                                         if( SPI_Status & SPI_SR_RXBUFF )\r
86                                         {\r
87                                                 ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;\r
88                                         }\r
89                                 }\r
90 \r
91                 4) Called by EMAC-Task: finish SPI transfer\r
92                         ksz8851snl_update()\r
93                                 if( ul_spi_pdc_status == SPI_PDC_TX_COMPLETE )\r
94                                 {\r
95                                         ul_spi_pdc_status = SPI_PDC_IDLE;\r
96                                         Bring KSZ8851SNL_CSN_GPIO high\r
97                                         // TX step12: disable TXQ write access.\r
98                                         ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );\r
99                                         // TX step12.1: enqueue frame in TXQ.\r
100                                         ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );\r
101 \r
102                                         // RX step13: enable INT_RX flag.\r
103                                         ksz8851_reg_write( REG_INT_MASK, INT_RX );\r
104 \r
105                                         // Buffer sent, free the corresponding buffer and mark descriptor as owned by software.\r
106                                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
107 \r
108                                         tx_buffers[ us_tx_tail ] = NULL;\r
109                                         tx_busy[ us_tx_tail ] = pdFALSE;\r
110                                         us_tx_tail++\r
111                                 }\r
112 \r
113         Receiving a packet:\r
114 \r
115                 1) Wait for a INTN interrupt\r
116                         INTN_Handler()\r
117                                 ul_had_intn_interrupt = 1\r
118                                 vTaskNotifyGiveFromISR();       // Wake up the EMAC task\r
119 \r
120                 2) Called by EMAC-Task: check for new fragments and start SPI transfer\r
121                         ksz8851snl_update()\r
122                                 if( ul_spi_pdc_status == SPI_PDC_IDLE )\r
123                                 {\r
124                                         if( ( ul_had_intn_interrupt != 0 ) || ( us_pending_frame > 0 ) )\r
125                                         {\r
126                                                 if( us_pending_frame == 0 )\r
127                                                 {\r
128                                                         us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;\r
129                                                         if( us_pending_frame == 0 )\r
130                                                         {\r
131                                                                 break;\r
132                                                         }\r
133                                                 }\r
134                                                 // RX step2: disable all interrupts.\r
135                                                 ksz8851_reg_write( REG_INT_MASK, 0 );\r
136                                                 Check if there is a valid packet: REG_RX_FHR_STATUS\r
137                                                 Read the length of the next fragment: REG_RX_FHR_BYTE_CNT\r
138                                                 ul_spi_pdc_status = SPI_PDC_RX_START;\r
139                                                 gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);\r
140                                                 // Start SPI data transfer\r
141                                                 ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer, xReadLength );\r
142                                         }\r
143                                 }\r
144 \r
145                 3) Wait for SPI RXBUFF interrupt\r
146                         SPI_Handler()\r
147                         if( ul_spi_pdc_status == SPI_PDC_RX_START:\r
148                         {\r
149                                 if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )\r
150                                 {\r
151                                         // Transfer complete, disable SPI RXBUFF interrupt.\r
152                                         spi_disable_interrupt( KSZ8851SNL_SPI, SPI_IDR_RXBUFF );\r
153 \r
154                                         ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;\r
155                                 }\r
156                         }\r
157                 }\r
158 \r
159                 4) Finish SPI transfer\r
160                         ksz8851snl_update()\r
161                                 if( ul_spi_pdc_status == SPI_PDC_RX_COMPLETE )\r
162                                 {\r
163                                         ul_spi_pdc_status = SPI_PDC_IDLE;\r
164                                         Bring KSZ8851SNL_CSN_GPIO high\r
165                                         // RX step21: end RXQ read access.\r
166                                         ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);\r
167                                         // RX step22-23: update frame count to be read.\r
168                                         us_pending_frame--\r
169                                         // RX step24: enable INT_RX flag if transfer complete.\r
170                                         if( us_pending_frame == 0 )\r
171                                         {\r
172                                                 // Allow more RX interrupts.\r
173                                                 ksz8851_reg_write( REG_INT_MASK, INT_RX );\r
174                                         }\r
175 \r
176                                         // Mark descriptor ready to be read.\r
177                                         rx_ready[ rxHead ] = pdTRUE;\r
178                                         rxHead++\r
179                                 }\r
180 */\r
181 \r
182 #define PHY_REG_00_BMCR            0x00 // Basic mode control register\r
183 #define PHY_REG_01_BMSR            0x01 // Basic mode status register\r
184 #define PHY_REG_02_PHYSID1         0x02 // PHYS ID 1\r
185 #define PHY_REG_03_PHYSID2         0x03 // PHYS ID 2\r
186 #define PHY_REG_04_ADVERTISE       0x04 // Advertisement control reg\r
187 #define PHY_REG_05_LPA             0x05 // Link partner ability reg\r
188 #define PHY_REG_06_ANER            0x06 //      6       RW              Auto-Negotiation Expansion Register\r
189 #define PHY_REG_07_ANNPTR          0x07 //      7       RW              Auto-Negotiation Next Page TX\r
190 #define PHY_REG_08_RESERVED0       0x08 // 0x08..0x0Fh  8-15    RW              RESERVED\r
191 \r
192 #define BMSR_LINK_STATUS            0x0004  //!< Link status\r
193 \r
194 #ifndef PHY_LS_HIGH_CHECK_TIME_MS\r
195         /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not\r
196         receiving packets. */\r
197         #define PHY_LS_HIGH_CHECK_TIME_MS       15000\r
198 #endif\r
199 \r
200 #ifndef PHY_LS_LOW_CHECK_TIME_MS\r
201         /* Check if the LinkSStatus in the PHY is still low every second. */\r
202         #define PHY_LS_LOW_CHECK_TIME_MS        1000\r
203 #endif\r
204 \r
205 /* Interrupt events to process.  Currently only the Rx event is processed\r
206 although code for other events is included to allow for possible future\r
207 expansion. */\r
208 #define EMAC_IF_RX_EVENT                                1UL\r
209 #define EMAC_IF_TX_EVENT                                2UL\r
210 #define EMAC_IF_ERR_EVENT                               4UL\r
211 #define EMAC_IF_ALL_EVENT                               ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )\r
212 \r
213 #define ETHERNET_CONF_PHY_ADDR  BOARD_GMAC_PHY_ADDR\r
214 \r
215 #ifdef ipconfigHAS_TX_CRC_OFFLOADING\r
216         #undef ipconfigHAS_TX_CRC_OFFLOADING\r
217 #endif\r
218 /* Override this define because the KSZ8851 is programmed to set all outgoing CRC's */\r
219 #define ipconfigHAS_TX_CRC_OFFLOADING   1\r
220 \r
221 #ifndef EMAC_MAX_BLOCK_TIME_MS\r
222         #define EMAC_MAX_BLOCK_TIME_MS  100ul\r
223 #endif\r
224 \r
225 /* Default the size of the stack used by the EMAC deferred handler task to 4x\r
226 the size of the stack used by the idle task - but allow this to be overridden in\r
227 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */\r
228 #ifndef configEMAC_TASK_STACK_SIZE\r
229         #define configEMAC_TASK_STACK_SIZE ( 6 * configMINIMAL_STACK_SIZE )\r
230 #endif\r
231 \r
232 #define SPI_PDC_IDLE                    0\r
233 #define SPI_PDC_RX_START                1\r
234 #define SPI_PDC_TX_ERROR                2\r
235 #define SPI_PDC_RX_COMPLETE             3\r
236 #define SPI_PDC_TX_START                4\r
237 #define SPI_PDC_RX_ERROR                5\r
238 #define SPI_PDC_TX_COMPLETE             6\r
239 \r
240 /**\r
241  * ksz8851snl driver structure.\r
242  */\r
243 typedef struct {\r
244         /** Set to 1 when owner is software (ready to read), 0 for Micrel. */\r
245         uint32_t rx_ready[MICREL_RX_BUFFERS];\r
246         /** Set to 1 when owner is Micrel, 0 for software. */\r
247         uint32_t tx_busy[MICREL_TX_BUFFERS];\r
248         /** RX NetworkBufferDescriptor_t pointer list */\r
249         NetworkBufferDescriptor_t *rx_buffers[MICREL_RX_BUFFERS];\r
250         /** TX NetworkBufferDescriptor_t pointer list */\r
251         NetworkBufferDescriptor_t *tx_buffers[MICREL_TX_BUFFERS];\r
252         NetworkBufferDescriptor_t *tx_cur_buffer;\r
253 \r
254         /** Circular buffer head pointer for packet received. */\r
255         uint32_t us_rx_head;\r
256         /** Circular buffer tail pointer for packet to be read. */\r
257         uint32_t us_rx_tail;\r
258         /** Circular buffer head pointer by upper layer (buffer to be sent). */\r
259         uint32_t us_tx_head;\r
260         /** Circular buffer tail pointer incremented by handlers (buffer sent). */\r
261         uint32_t us_tx_tail;\r
262 \r
263         uint32_t ul_total_tx;\r
264         uint32_t ul_total_rx;\r
265         uint32_t tx_space;\r
266 \r
267         /** Still experimental: hash table to allow certain multicast addresses. */\r
268         uint16_t pusHashTable[ 4 ];\r
269 \r
270         /* ul_spi_pdc_status has "SPI_PDC_xxx" values. */\r
271         volatile uint32_t ul_spi_pdc_status;\r
272 \r
273         /* ul_had_intn_interrupt becomes true within the INTN interrupt. */\r
274         volatile uint32_t ul_had_intn_interrupt;\r
275 \r
276         uint16_t us_pending_frame;\r
277 } xKSZ8851_Device_t;\r
278 \r
279 /* SPI PDC register base.\r
280 Declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */\r
281 extern Pdc *g_p_spi_pdc;\r
282 \r
283 /* Temporary buffer for PDC reception.\r
284 declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */\r
285 extern uint8_t tmpbuf[1536];\r
286 \r
287 COMPILER_ALIGNED(8)\r
288 static xKSZ8851_Device_t xMicrelDevice;\r
289 \r
290 static TaskHandle_t xTransmitHandle;\r
291 \r
292 /*-----------------------------------------------------------*/\r
293 \r
294 /*\r
295  * Wait a fixed time for the link status to indicate the network is up.\r
296  */\r
297 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );\r
298 \r
299 /*\r
300  * A deferred interrupt handler task that processes GMAC interrupts.\r
301  */\r
302 static void prvEMACHandlerTask( void *pvParameters );\r
303 \r
304 /*\r
305  * Try to obtain an Rx packet from the hardware.\r
306  */\r
307 static uint32_t prvEMACRxPoll( void );\r
308 \r
309 static inline unsigned long ulReadMDIO( unsigned uAddress );\r
310 \r
311 static void ksz8851snl_low_level_init( void );\r
312 \r
313 static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void );\r
314 \r
315 /*-----------------------------------------------------------*/\r
316 \r
317 /* Bit map of outstanding ETH interrupt events for processing.  Currently only\r
318 the Rx interrupt is handled, although code is included for other events to\r
319 enable future expansion. */\r
320 static volatile uint32_t ulISREvents;\r
321 \r
322 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */\r
323 static uint32_t ulPHYLinkStatus = 0;\r
324 static volatile BaseType_t xGMACSwitchRequired;\r
325 \r
326 static void ksz8851snl_update( void );\r
327 \r
328 static void ksz8851snl_rx_init( void );\r
329 \r
330 static void ksz8851snl_tx_init( void );\r
331 \r
332 /* Holds the handle of the task used as a deferred interrupt processor.  The\r
333 handle is used so direct notifications can be sent to the task for all EMAC/DMA\r
334 related interrupts. */\r
335 TaskHandle_t xEMACTaskHandle = NULL;\r
336 \r
337 \r
338 /*-----------------------------------------------------------*/\r
339 \r
340 BaseType_t xNetworkInterfaceInitialise( void )\r
341 {\r
342 const TickType_t x5_Seconds = 5000UL;\r
343 \r
344         if( xEMACTaskHandle == NULL )\r
345         {\r
346                 ksz8851snl_low_level_init();\r
347 \r
348                 /* Wait at most 5 seconds for a Link Status in the PHY. */\r
349                 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );\r
350 \r
351                 /* The handler task is created at the highest possible priority to\r
352                 ensure the interrupt handler can return directly to it. */\r
353                 xTaskCreate( prvEMACHandlerTask, "KSZ8851", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );\r
354                 configASSERT( xEMACTaskHandle );\r
355         }\r
356 \r
357         /* When returning non-zero, the stack will become active and\r
358     start DHCP (in configured) */\r
359         ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );\r
360 \r
361         return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;\r
362 }\r
363 /*-----------------------------------------------------------*/\r
364 \r
365 BaseType_t xGetPhyLinkStatus( void )\r
366 {\r
367 BaseType_t xResult;\r
368 \r
369         /* This function returns true if the Link Status in the PHY is high. */\r
370         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
371         {\r
372                 xResult = pdTRUE;\r
373         }\r
374         else\r
375         {\r
376                 xResult = pdFALSE;\r
377         }\r
378 \r
379         return xResult;\r
380 }\r
381 /*-----------------------------------------------------------*/\r
382 \r
383 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend )\r
384 {\r
385 BaseType_t xResult = pdFALSE;\r
386 int txHead = xMicrelDevice.us_tx_head;\r
387 \r
388         /* Make sure the next descriptor is free. */\r
389         if( xMicrelDevice.tx_busy[ txHead ] != pdFALSE )\r
390         {\r
391                 /* All TX buffers busy. */\r
392         }\r
393         else if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )\r
394         {\r
395                 /* Output: LS low. */\r
396         }\r
397         else\r
398         {\r
399                 /* Pass the packet. */\r
400                 xMicrelDevice.tx_buffers[ txHead ] = pxNetworkBuffer;\r
401                 /* The descriptor is now owned by Micrel. */\r
402                 xMicrelDevice.tx_busy[ txHead ] = pdTRUE;\r
403 \r
404                 /* Move the head pointer. */\r
405                 if( ++txHead == MICREL_TX_BUFFERS )\r
406                 {\r
407                         txHead = 0;\r
408                 }\r
409                 xMicrelDevice.us_tx_head = txHead;\r
410                 if( xEMACTaskHandle != NULL )\r
411                 {\r
412                         xTaskNotifyGive( xEMACTaskHandle );\r
413                 }\r
414 \r
415         #if( ipconfigZERO_COPY_TX_DRIVER != 1 )\r
416                 #warning Please ipconfigZERO_COPY_TX_DRIVER as 1\r
417         #endif\r
418                 configASSERT( bReleaseAfterSend != pdFALSE );\r
419                 xResult = pdTRUE;\r
420         }\r
421         if( ( xResult == pdFALSE ) && ( bReleaseAfterSend  != pdFALSE ) )\r
422         {\r
423                 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
424         }\r
425         return xResult;\r
426 }\r
427 /*-----------------------------------------------------------*/\r
428 \r
429 /* This Micrel has numbered it's PHY registers in a different way.\r
430 Translate the register index. */\r
431 static int ks8851_phy_reg( int reg )\r
432 {\r
433         switch (reg) {\r
434         case PHY_REG_00_BMCR:\r
435                 return REG_PHY_CNTL;    // P1MBCR;\r
436         case PHY_REG_01_BMSR:\r
437                 return REG_PHY_STATUS;\r
438         case PHY_REG_02_PHYSID1:\r
439                 return REG_PHY_ID_LOW;\r
440         case PHY_REG_03_PHYSID2:\r
441                 return REG_PHY_ID_HIGH;\r
442         case PHY_REG_04_ADVERTISE:\r
443                 return REG_PHY_AUTO_NEGOTIATION;\r
444         case PHY_REG_05_LPA:\r
445                 return REG_PHY_REMOTE_CAPABILITY;\r
446         }\r
447 \r
448         return 0x0;\r
449 }\r
450 /*-----------------------------------------------------------*/\r
451 \r
452 static inline unsigned long ulReadMDIO( unsigned uAddress )\r
453 {\r
454 uint16_t usPHYStatus;\r
455 int ks8851_reg = ks8851_phy_reg( uAddress );\r
456 \r
457         if( ks8851_reg != 0 )\r
458         {\r
459                 usPHYStatus = ksz8851_reg_read( ks8851_reg );\r
460         }\r
461         else\r
462         {\r
463                 /* Other addresses not yet implemented. */\r
464                 usPHYStatus = 0;\r
465         }\r
466         return usPHYStatus;\r
467 }\r
468 /*-----------------------------------------------------------*/\r
469 \r
470 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )\r
471 {\r
472 TickType_t xStartTime = xTaskGetTickCount();\r
473 TickType_t xEndTime;\r
474 BaseType_t xReturn;\r
475 const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );\r
476 const uint32_t ulHz_Per_MHz = 1000000UL;\r
477 \r
478         for( ;; )\r
479         {\r
480                 xEndTime = xTaskGetTickCount();\r
481 \r
482                 if( ( xEndTime - xStartTime ) > xMaxTime )\r
483                 {\r
484                         /* Wated more than xMaxTime, return. */\r
485                         xReturn = pdFALSE;\r
486                         break;\r
487                 }\r
488 \r
489                 /* Check the link status again. */\r
490                 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );\r
491 \r
492                 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
493                 {\r
494                         /* Link is up - return. */\r
495                         xReturn = pdTRUE;\r
496                         break;\r
497                 }\r
498 \r
499                 /* Link is down - wait in the Blocked state for a short while (to allow\r
500                 other tasks to execute) before checking again. */\r
501                 vTaskDelay( xShortTime );\r
502         }\r
503 \r
504         FreeRTOS_printf( ( "xGMACWaitLS: %ld freq %lu Mz\n",\r
505                 xReturn,\r
506                 sysclk_get_cpu_hz() / ulHz_Per_MHz ) );\r
507 \r
508         return xReturn;\r
509 }\r
510 /*-----------------------------------------------------------*/\r
511 \r
512 static void vPioSetPinHigh(uint32_t ul_pin)\r
513 {\r
514         Pio *p_pio = (Pio *)((uint32_t)PIOA + (PIO_DELTA * (ul_pin >> 5)));\r
515         // Value to be driven on the I/O line: 1.\r
516         p_pio->PIO_SODR = 1 << (ul_pin & 0x1F);\r
517 }\r
518 \r
519 /**\r
520  * \brief Handler for SPI interrupt.\r
521  */\r
522 void SPI_Handler(void)\r
523 {\r
524 BaseType_t xDoWakeup = pdFALSE;\r
525 BaseType_t xKSZTaskWoken = pdFALSE;\r
526 uint32_t ulCurrentSPIStatus;\r
527 uint32_t ulEnabledSPIStatus;\r
528 \r
529         ulCurrentSPIStatus = spi_read_status( KSZ8851SNL_SPI );\r
530         ulEnabledSPIStatus = spi_read_interrupt_mask( KSZ8851SNL_SPI );\r
531         ulCurrentSPIStatus &= ulEnabledSPIStatus;\r
532         spi_disable_interrupt( KSZ8851SNL_SPI, ulCurrentSPIStatus );\r
533 \r
534 \r
535         switch( xMicrelDevice.ul_spi_pdc_status )\r
536         {\r
537                 case SPI_PDC_RX_START:\r
538                 {\r
539                         if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )\r
540                         {\r
541                                 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
542                                 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_ERROR;\r
543                                 xDoWakeup = pdTRUE;\r
544                         }\r
545                         else\r
546                         {\r
547                                 if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )\r
548                                 {\r
549                                         xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;\r
550                                         xDoWakeup = pdTRUE;\r
551                                 }\r
552                         }\r
553                 }\r
554                 break;\r
555 \r
556                 case SPI_PDC_TX_START:\r
557                 {\r
558                         /* Middle of TX. */\r
559                         if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )\r
560                         {\r
561                                 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);\r
562                                 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_ERROR;\r
563                                 xDoWakeup = pdTRUE;\r
564                         }\r
565                         else\r
566                         {\r
567                                 if( ( ulCurrentSPIStatus & SPI_SR_ENDRX ) != 0 )\r
568                                 {\r
569                                         /* Enable RX complete interrupt. */\r
570                                         spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_RXBUFF );\r
571                                 }\r
572                                 /* End of TX. */\r
573                                 if( ( ulCurrentSPIStatus & SPI_END_OF_TX ) != 0 )\r
574                                 {\r
575                                         xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;\r
576                                         xDoWakeup = pdTRUE;\r
577                                 }\r
578                         }\r
579                 }\r
580                 break;\r
581         }       /* switch( xMicrelDevice.ul_spi_pdc_status ) */\r
582 \r
583         if( xDoWakeup != pdFALSE )\r
584         {\r
585                 if( xEMACTaskHandle != NULL )\r
586                 {\r
587                         vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xKSZTaskWoken );\r
588                 }\r
589         }\r
590         else\r
591         {\r
592         }\r
593         portEND_SWITCHING_ISR( xKSZTaskWoken );\r
594 }\r
595 /*-----------------------------------------------------------*/\r
596 \r
597 static void INTN_Handler(uint32_t id, uint32_t mask)\r
598 {\r
599 BaseType_t xKSZTaskWoken = pdFALSE;\r
600 \r
601         if( ( id == INTN_ID ) &&\r
602                 ( mask == INTN_PIN_MSK ) )\r
603         {\r
604                 /* Clear the PIO interrupt flags. */\r
605                 pio_get_interrupt_status( INTN_PIO );\r
606 \r
607                 /* Set the INTN flag. */\r
608                 xMicrelDevice.ul_had_intn_interrupt++;\r
609                 if( xEMACTaskHandle != NULL )\r
610                 {\r
611                         vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xKSZTaskWoken ) );\r
612                 }\r
613         }\r
614         portEND_SWITCHING_ISR( xKSZTaskWoken );\r
615 }\r
616 /*-----------------------------------------------------------*/\r
617 \r
618 /**\r
619  * \brief Populate the RX descriptor ring buffers with pbufs.\r
620  *\r
621  * \param p_ksz8851snl_dev Pointer to driver data structure.\r
622  */\r
623 static void ksz8851snl_rx_populate_queue( void )\r
624 {\r
625         uint32_t ul_index = 0;\r
626         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
627 \r
628         /* Set up the RX descriptors */\r
629         for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {\r
630                 if( xMicrelDevice.rx_buffers[ ul_index ] == NULL )\r
631                 {\r
632                         /* Allocate a new NetworkBufferDescriptor_t with the maximum size. */\r
633                         pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipconfigNETWORK_MTU + 36, 100 );\r
634                         if( pxNetworkBuffer == NULL )\r
635                         {\r
636                                 FreeRTOS_printf( ( "ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t allocation failure\n" ) );\r
637                                 configASSERT( 1 == 2 );\r
638                         }\r
639 \r
640                         /* Make sure lwIP is well configured so one NetworkBufferDescriptor_t can contain the maximum packet size. */\r
641                         //LWIP_ASSERT("ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t size too small!", pbuf_clen(pxNetworkBuffer) <= 1);\r
642 \r
643                         /* Save NetworkBufferDescriptor_t pointer to be sent to lwIP upper layer. */\r
644                         xMicrelDevice.rx_buffers[ ul_index ] = pxNetworkBuffer;\r
645                         /* Pass it to Micrel for reception. */\r
646                         xMicrelDevice.rx_ready[ ul_index ] = pdFALSE;\r
647                 }\r
648         }\r
649 }\r
650 \r
651 unsigned tx_space, wait_tx_space, tx_status, fhr_status;\r
652 unsigned rx_debug = 0;\r
653 /**\r
654  * \brief Update Micrel state machine and perform required actions.\r
655  *\r
656  * \param netif the lwIP network interface structure for this ethernetif.\r
657  */\r
658 static void ksz8851snl_update()\r
659 {\r
660         uint16_t txmir = 0;\r
661 \r
662 /* Check for free PDC. */\r
663         switch( xMicrelDevice.ul_spi_pdc_status )\r
664         {\r
665         case SPI_PDC_TX_ERROR:\r
666                 {\r
667                 uint32_t ulValue;\r
668         //              /* TX step11: end TX transfer. */\r
669                         gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
670 \r
671                         vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );\r
672                         vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
673                         vTaskDelay( 1 );\r
674 \r
675                         /* Disable asynchronous transfer mode. */\r
676                         xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;\r
677 \r
678                         /* TX step12: disable TXQ write access. */\r
679                         ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );\r
680 \r
681                         ulValue = ksz8851snl_reset_tx();\r
682 \r
683                         xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;\r
684 \r
685                         FreeRTOS_printf( ("SPI_PDC_TX_ERROR %02X\n", ulValue ) );\r
686                 }\r
687                 break;\r
688 \r
689         case SPI_PDC_RX_ERROR:\r
690                 {\r
691                 uint32_t ulValue;\r
692                         /* TX step11: end TX transfer. */\r
693                         gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
694 \r
695                         vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );\r
696                         vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
697                         vTaskDelay( 1 );\r
698 \r
699                         /* Disable asynchronous transfer mode. */\r
700                         xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;\r
701 \r
702                         /* TX step12: disable TXQ write access. */\r
703                         ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );\r
704 \r
705                         //ulValue = ksz8851snl_reset_rx();\r
706                         ulValue = ksz8851snl_reinit();\r
707 \r
708                         xGMACWaitLS( pdMS_TO_TICKS( 5000UL ) );\r
709 \r
710                         FreeRTOS_printf( ("SPI_PDC_RX_ERROR %02X\n", ulValue ) );\r
711                 }\r
712                 break;\r
713         }\r
714         switch( xMicrelDevice.ul_spi_pdc_status )\r
715         {\r
716                 case SPI_PDC_IDLE:\r
717                 {\r
718                 int txTail = xMicrelDevice.us_tx_tail;\r
719 \r
720                         /*\r
721                          * ========================== Handle RX ==========================\r
722                          */\r
723                         if( ( xMicrelDevice.ul_had_intn_interrupt != 0 ) || ( xMicrelDevice.us_pending_frame > 0 ) )\r
724                         {\r
725                         int rxHead = xMicrelDevice.us_rx_head;\r
726                         NetworkBufferDescriptor_t *pxNetworkBuffer;\r
727 #warning try\r
728                                 xMicrelDevice.ul_had_intn_interrupt = 0;\r
729 \r
730                                 if( xMicrelDevice.us_pending_frame == 0 )\r
731                                 {\r
732                                 uint16_t int_status;\r
733                                         /* RX step1: read interrupt status for INT_RX flag. */\r
734                                         int_status = ksz8851_reg_read( REG_INT_STATUS );\r
735 \r
736 \r
737                                         /* RX step2: disable all interrupts. */\r
738                                         ksz8851_reg_write( REG_INT_MASK, 0 );\r
739 \r
740                                         /* RX step3: clear INT_RX flag. */\r
741                                         ksz8851_reg_setbits( REG_INT_STATUS, INT_RX );\r
742 \r
743                                         /* RX step4-5: check for received frames. */\r
744                                         xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;\r
745                                         if( xMicrelDevice.us_pending_frame == 0 )\r
746                                         {\r
747                                                 /* RX step24: enable INT_RX flag. */\r
748                                                 ksz8851_reg_write(REG_INT_MASK, INT_RX);\r
749                                                 return;\r
750                                         }\r
751                                 }\r
752 #warning try\r
753                                 xMicrelDevice.ul_had_intn_interrupt = 0;\r
754 \r
755                                 /* Now xMicrelDevice.us_pending_frame != 0 */\r
756 \r
757                                 /* Don't break Micrel state machine, wait for a free descriptor first! */\r
758                                 if( xMicrelDevice.rx_ready[ rxHead ] != pdFALSE )\r
759                                 {\r
760                                         FreeRTOS_printf( ( "ksz8851snl_update: out of free descriptor! [tail=%u head=%u]\n",\r
761                                                         xMicrelDevice.us_rx_tail, rxHead ) );\r
762                                         return;\r
763                                 }\r
764                                 pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxHead ];\r
765 \r
766                                 if( pxNetworkBuffer == NULL )\r
767                                 {\r
768                                         ksz8851snl_rx_populate_queue();\r
769                                         FreeRTOS_printf( ( "ksz8851snl_update: no buffer set [head=%u]\n", rxHead ) );\r
770                                         return;\r
771                                 }\r
772 \r
773                                 /* RX step6: get RX packet status. */\r
774                                 fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );\r
775                                 if( ( ( fhr_status & RX_VALID ) == 0 ) || ( ( fhr_status & RX_ERRORS ) != 0 ) )\r
776                                 {\r
777                                         ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_CMD_FREE_PACKET);\r
778                                         FreeRTOS_printf( ( "ksz8851snl_update: RX packet error!\n" ) );\r
779 \r
780                                         /* RX step4-5: check for received frames. */\r
781                                         xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;\r
782                                         if( xMicrelDevice.us_pending_frame == 0 )\r
783                                         {\r
784                                                 /* RX step24: enable INT_RX flag. */\r
785                                                 ksz8851_reg_write(REG_INT_MASK, INT_RX);\r
786                                         }\r
787                                         ulISREvents |= EMAC_IF_ERR_EVENT;\r
788                                 }\r
789                                 else\r
790                                 {\r
791                                 size_t xLength;\r
792                                         /* RX step7: read frame length. */\r
793                                         xLength = ksz8851_reg_read(REG_RX_FHR_BYTE_CNT) & RX_BYTE_CNT_MASK;\r
794 \r
795                                         /* RX step8: Drop packet if len is invalid or no descriptor available. */\r
796                                         if( xLength == 0 )\r
797                                         {\r
798                                                 ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET );\r
799                                                 FreeRTOS_printf( ( "ksz8851snl_update: RX bad len!\n" ) );\r
800                                                 ulISREvents |= EMAC_IF_ERR_EVENT;\r
801                                         }\r
802                                         else\r
803                                         {\r
804                                         size_t xReadLength = xLength;\r
805 \r
806                                                 xMicrelDevice.ul_total_rx++;\r
807                                                 /* RX step9: reset RX frame pointer. */\r
808                                                 ksz8851_reg_clrbits(REG_RX_ADDR_PTR, ADDR_PTR_MASK);\r
809 \r
810                                                 /* RX step10: start RXQ read access. */\r
811                                                 ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_START);\r
812                                                 /* RX step11-17: start asynchronous FIFO read operation. */\r
813                                                 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_START;\r
814                                                 gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );\r
815                                                 if( ( xReadLength & ( sizeof( size_t ) - 1 ) ) != 0 )\r
816                                                 {\r
817                                                         xReadLength = ( xReadLength | ( sizeof( size_t ) - 1 ) ) + 1;\r
818                                                 }\r
819 \r
820                                                 /* Pass the buffer minus 2 bytes, see ksz8851snl.c: RXQ_TWOBYTE_OFFSET. */\r
821                                                 ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer - 2, xReadLength );\r
822                                                 /* Remove CRC and update buffer length. */\r
823                                                 xLength -= 4;\r
824                                                 pxNetworkBuffer->xDataLength = xLength;\r
825                                                 /* Wait for SPI interrupt to set status 'SPI_PDC_RX_COMPLETE'. */\r
826                                         }\r
827                                 }\r
828                                 break;\r
829                         } /* ul_had_intn_interrupt || us_pending_frame */\r
830                         /*\r
831                          * ========================== Handle TX ==========================\r
832                          */\r
833 \r
834                         /* Fetch next packet to be sent. */\r
835                         if( ( xMicrelDevice.tx_busy[ txTail ] != pdFALSE ) &&\r
836                                 ( xMicrelDevice.us_pending_frame == 0 ) &&\r
837                                 ( xMicrelDevice.ul_had_intn_interrupt == 0 ) )\r
838                         {\r
839                         NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];\r
840                         size_t xLength = pxNetworkBuffer->xDataLength;\r
841                         int iIndex = xLength;\r
842 \r
843                                 xLength = 4 * ( ( xLength + 3 ) / 4 );\r
844                                 while( iIndex < ( int ) xLength )\r
845                                 {\r
846                                         pxNetworkBuffer->pucEthernetBuffer[ iIndex ] = '\0';\r
847                                         iIndex++;\r
848                                 }\r
849                                 pxNetworkBuffer->xDataLength = xLength;\r
850 \r
851                                 /* TX step1: check if TXQ memory size is available for transmit. */\r
852                                 txmir = ksz8851_reg_read( REG_TX_MEM_INFO );\r
853                                 txmir = txmir & TX_MEM_AVAILABLE_MASK;\r
854 \r
855                                 if( txmir < ( xLength + 8 ) )\r
856                                 {\r
857                                         if( wait_tx_space == pdFALSE )\r
858                                         {\r
859                                                 tx_status = ksz8851_reg_read( REG_TX_STATUS );\r
860                                                 fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );\r
861                                                 wait_tx_space = pdTRUE;\r
862                                         }\r
863                                         //return;\r
864                                         rx_debug = 1;\r
865                                         tx_space = txmir;\r
866                                 }\r
867                                 else\r
868                                 {\r
869                                         tx_space = txmir;\r
870 \r
871                                         /* TX step2: disable all interrupts. */\r
872                                         ksz8851_reg_write( REG_INT_MASK, 0 );\r
873 \r
874                                         xMicrelDevice.tx_space -= xLength;\r
875 \r
876                                         /* TX step3: enable TXQ write access. */\r
877                                         ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START );\r
878                                         /* TX step4-8: perform FIFO write operation. */\r
879                                         xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_START;\r
880                                         xMicrelDevice.tx_cur_buffer = pxNetworkBuffer;\r
881                                         /* Bring SPI SS low. */\r
882                                         gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );\r
883                                         xMicrelDevice.ul_total_tx++;\r
884 \r
885                                         ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );\r
886                                 }\r
887                         }\r
888                 }\r
889                 break;  /* SPI_PDC_IDLE */\r
890 \r
891         case SPI_PDC_RX_COMPLETE:\r
892                 {\r
893                 int rxHead = xMicrelDevice.us_rx_head;\r
894                         /* RX step18-19: pad with dummy data to keep dword alignment. */\r
895                         /* Packet lengths will be rounded up to a multiple of "sizeof size_t". */\r
896 //                      xLength = xMicrelDevice.rx_buffers[ rxHead ]->xDataLength & 3;\r
897 //                      if( xLength != 0 )\r
898 //                      {\r
899 //                              ksz8851_fifo_dummy( 4 - xLength );\r
900 //                      }\r
901 \r
902                         /* RX step20: end RX transfer. */\r
903                         gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
904 \r
905                         /* Disable asynchronous transfer mode. */\r
906                         xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;\r
907 \r
908                         /* RX step21: end RXQ read access. */\r
909                         ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);\r
910 \r
911                         /* RX step22-23: update frame count to be read. */\r
912                         xMicrelDevice.us_pending_frame -= 1;\r
913 \r
914                         /* RX step24: enable INT_RX flag if transfer complete. */\r
915                         if( xMicrelDevice.us_pending_frame == 0 )\r
916                         {\r
917                                 ksz8851_reg_write(REG_INT_MASK, INT_RX);\r
918                         }\r
919 \r
920                         /* Mark descriptor ready to be read. */\r
921                         xMicrelDevice.rx_ready[ rxHead ] = pdTRUE;\r
922                         if( ++rxHead == MICREL_RX_BUFFERS )\r
923                         {\r
924                                 rxHead = 0;\r
925                         }\r
926                         xMicrelDevice.us_rx_head = rxHead;\r
927                         if( rx_debug != 0 )\r
928                         {\r
929                         uint32_t txmir;\r
930                                 rx_debug = 0;\r
931                                 txmir = ksz8851_reg_read( REG_TX_MEM_INFO );\r
932                                 txmir = txmir & TX_MEM_AVAILABLE_MASK;\r
933                         }\r
934                         /* Tell prvEMACHandlerTask that RX packets are available. */\r
935                         ulISREvents |= EMAC_IF_RX_EVENT;\r
936                 }       /* case SPI_PDC_RX_COMPLETE */\r
937                 break;\r
938 \r
939         case SPI_PDC_TX_COMPLETE:\r
940                 {\r
941                 int txTail = xMicrelDevice.us_tx_tail;\r
942                 NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];\r
943 \r
944                 size_t xLength;\r
945                         /* TX step9-10: pad with dummy data to keep dword alignment. */\r
946                         /* Not necessary: length is already a multiple of 4. */\r
947                         xLength = pxNetworkBuffer->xDataLength & 3;\r
948                         if( xLength != 0 )\r
949                         {\r
950 //                              ksz8851_fifo_dummy( 4 - xLength );\r
951                         }\r
952 \r
953 //                      /* TX step11: end TX transfer. */\r
954                         gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );\r
955 \r
956                         /* Disable asynchronous transfer mode. */\r
957                         xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;\r
958 \r
959                         /* TX step12: disable TXQ write access. */\r
960                         ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );\r
961 \r
962                         xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;\r
963 \r
964                         /* TX step12.1: enqueue frame in TXQ. */\r
965                         ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );\r
966 \r
967                         /* RX step13: enable INT_RX flag. */\r
968 //                      ksz8851_reg_write( REG_INT_MASK, INT_RX );\r
969                         /* Buffer sent, free the corresponding buffer and mark descriptor as owned by software. */\r
970                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
971 \r
972                         xMicrelDevice.tx_buffers[ txTail ] = NULL;\r
973                         xMicrelDevice.tx_busy[ txTail ] = pdFALSE;\r
974                         if( ++txTail == MICREL_TX_BUFFERS )\r
975                         {\r
976                                 txTail = 0;\r
977                         }\r
978 \r
979                         xMicrelDevice.us_tx_tail = txTail;\r
980                         /* Experiment. */\r
981                         //xMicrelDevice.ul_had_intn_interrupt = 1;\r
982                         if( xTransmitHandle != NULL )\r
983                         {\r
984                                 xTaskNotifyGive( xTransmitHandle );\r
985                         }\r
986 #warning moved downward\r
987                         /* RX step13: enable INT_RX flag. */\r
988                         ksz8851_reg_write( REG_INT_MASK, INT_RX );\r
989                         /* Prevent the EMAC task from sleeping a single time. */\r
990                         ulISREvents |= EMAC_IF_TX_EVENT;\r
991                 }       /* case SPI_PDC_TX_COMPLETE */\r
992                 break;\r
993         }       /* switch( xMicrelDevice.ul_spi_pdc_status ) */\r
994 }\r
995 \r
996 /**\r
997  * \brief Set up the RX descriptor ring buffers.\r
998  *\r
999  * This function sets up the descriptor list used for RX packets.\r
1000  *\r
1001  */\r
1002 static void ksz8851snl_rx_init()\r
1003 {\r
1004         uint32_t ul_index = 0;\r
1005 \r
1006         /* Init pointer index. */\r
1007         xMicrelDevice.us_rx_head = 0;\r
1008         xMicrelDevice.us_rx_tail = 0;\r
1009 \r
1010         /* Set up the RX descriptors. */\r
1011         for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {\r
1012                 xMicrelDevice.rx_buffers[ul_index] = NULL;\r
1013                 xMicrelDevice.rx_ready[ul_index] = pdFALSE;\r
1014         }\r
1015 \r
1016         /* Build RX buffer and descriptors. */\r
1017         ksz8851snl_rx_populate_queue();\r
1018 }\r
1019 \r
1020 /**\r
1021  * \brief Set up the TX descriptor ring buffers.\r
1022  *\r
1023  * This function sets up the descriptor list used for TX packets.\r
1024  *\r
1025  */\r
1026 static void ksz8851snl_tx_init()\r
1027 {\r
1028         uint32_t ul_index = 0;\r
1029 \r
1030         /* Init TX index pointer. */\r
1031         xMicrelDevice.us_tx_head = 0;\r
1032         xMicrelDevice.us_tx_tail = 0;\r
1033 \r
1034         /* Set up the TX descriptors */\r
1035         for( ul_index = 0; ul_index < MICREL_TX_BUFFERS; ul_index++ )\r
1036         {\r
1037                 xMicrelDevice.tx_busy[ul_index] = pdFALSE;\r
1038         }\r
1039         xMicrelDevice.tx_space = 6144;\r
1040 }\r
1041 \r
1042 /**\r
1043  * \brief Initialize ksz8851snl ethernet controller.\r
1044  *\r
1045  * \note Called from ethernetif_init().\r
1046  *\r
1047  * \param netif the lwIP network interface structure for this ethernetif.\r
1048  */\r
1049 static void ksz8851snl_low_level_init( void )\r
1050 {\r
1051         ksz8851snl_rx_init();\r
1052         ksz8851snl_tx_init();\r
1053 \r
1054         /* Enable NVIC interrupts. */\r
1055         NVIC_SetPriority(SPI_IRQn, INT_PRIORITY_SPI);\r
1056         NVIC_EnableIRQ(SPI_IRQn);\r
1057 \r
1058         /* Initialize SPI link. */\r
1059         if( ksz8851snl_init() < 0 )\r
1060         {\r
1061                 FreeRTOS_printf( ( "ksz8851snl_low_level_init: failed to initialize the Micrel driver!\n" ) );\r
1062                 configASSERT(0 == 1);\r
1063         }\r
1064         memset( xMicrelDevice.pusHashTable, 255, sizeof( xMicrelDevice.pusHashTable ) );\r
1065         ksz8851_reg_write( REG_MAC_HASH_0, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 0 ] ) );\r
1066         ksz8851_reg_write( REG_MAC_HASH_2, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 1 ] ) );\r
1067         ksz8851_reg_write( REG_MAC_HASH_4, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 2 ] ) );\r
1068         ksz8851_reg_write( REG_MAC_HASH_6, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 3 ] ) );\r
1069 \r
1070         /* Initialize interrupt line INTN. */\r
1071         configure_intn( INTN_Handler );\r
1072 }\r
1073 \r
1074 /**\r
1075  * \brief Use pre-allocated pbuf as DMA source and return the incoming packet.\r
1076  *\r
1077  * \param netif the lwIP network interface structure for this ethernetif.\r
1078  *\r
1079  * \return a pbuf filled with the received packet (including MAC header).\r
1080  * 0 on memory error.\r
1081  */\r
1082 static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void )\r
1083 {\r
1084 NetworkBufferDescriptor_t *pxNetworkBuffer = NULL;\r
1085 int rxTail = xMicrelDevice.us_rx_tail;\r
1086 \r
1087         /* Check that descriptor is owned by software (ie packet received). */\r
1088         if( xMicrelDevice.rx_ready[ rxTail ] != pdFALSE )\r
1089         {\r
1090 \r
1091                 /* Fetch pre-allocated buffer */\r
1092                 pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxTail ];\r
1093 \r
1094                 /* Remove this pbuf from its descriptor. */\r
1095                 xMicrelDevice.rx_buffers[ rxTail ] = NULL;\r
1096 \r
1097                 /* Clears rx_ready and sets rx_buffers. */\r
1098                 ksz8851snl_rx_populate_queue();\r
1099 \r
1100                 if( ++rxTail == MICREL_RX_BUFFERS )\r
1101                 {\r
1102                         rxTail = 0;\r
1103                 }\r
1104                 xMicrelDevice.us_rx_tail = rxTail;\r
1105         }\r
1106 \r
1107         return pxNetworkBuffer;\r
1108 }\r
1109 /*-----------------------------------------------------------*/\r
1110 \r
1111 static uint32_t prvEMACRxPoll( void )\r
1112 {\r
1113 NetworkBufferDescriptor_t *pxNetworkBuffer;\r
1114 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };\r
1115 uint32_t ulReturnValue = 0;\r
1116 \r
1117         for( ;; )\r
1118         {\r
1119         /* Only for logging. */\r
1120         int rxTail = xMicrelDevice.us_rx_tail;\r
1121         EthernetHeader_t *pxEthernetHeader;\r
1122 \r
1123         pxNetworkBuffer = ksz8851snl_low_level_input();\r
1124         \r
1125                 if( pxNetworkBuffer == NULL )\r
1126                 {\r
1127                         break;\r
1128                 }\r
1129                 pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );\r
1130 \r
1131                 if( ( pxEthernetHeader->usFrameType != ipIPv4_FRAME_TYPE ) &&\r
1132                         ( pxEthernetHeader->usFrameType != ipARP_FRAME_TYPE     ) )\r
1133                 {\r
1134                         FreeRTOS_printf( ( "Frame type %02X received\n", pxEthernetHeader->usFrameType ) );\r
1135                 }\r
1136                 ulReturnValue++;\r
1137 \r
1138                 xRxEvent.pvData = ( void * )pxNetworkBuffer;\r
1139                 /* Send the descriptor to the IP task for processing. */\r
1140                 if( xSendEventStructToIPTask( &xRxEvent, 100UL ) != pdTRUE )\r
1141                 {\r
1142                         vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );\r
1143                         iptraceETHERNET_RX_EVENT_LOST();\r
1144                         FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );\r
1145                 }\r
1146         }\r
1147 \r
1148         return ulReturnValue;\r
1149 }\r
1150 /*-----------------------------------------------------------*/\r
1151 \r
1152 static void prvEMACHandlerTask( void *pvParameters )\r
1153 {\r
1154 TimeOut_t xPhyTime;\r
1155 TickType_t xPhyRemTime;\r
1156 TickType_t xLoggingTime;\r
1157 UBaseType_t uxLastMinBufferCount = 0;\r
1158 UBaseType_t uxCurrentCount;\r
1159 BaseType_t xResult = 0;\r
1160 uint32_t xStatus;\r
1161 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );\r
1162 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
1163         UBaseType_t uxLastMinQueueSpace = 0;\r
1164 #endif\r
1165 \r
1166         /* Remove compiler warnings about unused parameters. */\r
1167         ( void ) pvParameters;\r
1168 \r
1169         configASSERT( xEMACTaskHandle );\r
1170 \r
1171         vTaskSetTimeOutState( &xPhyTime );\r
1172         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
1173         xLoggingTime = xTaskGetTickCount();\r
1174 \r
1175         for( ;; )\r
1176         {\r
1177                 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();\r
1178                 if( uxLastMinBufferCount != uxCurrentCount )\r
1179                 {\r
1180                         /* The logging produced below may be helpful\r
1181                         while tuning +TCP: see how many buffers are in use. */\r
1182                         uxLastMinBufferCount = uxCurrentCount;\r
1183                         FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",\r
1184                                 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );\r
1185                 }\r
1186 \r
1187                 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )\r
1188                 {\r
1189                         uxCurrentCount = uxGetMinimumIPQueueSpace();\r
1190                         if( uxLastMinQueueSpace != uxCurrentCount )\r
1191                         {\r
1192                                 /* The logging produced below may be helpful\r
1193                                 while tuning +TCP: see how many buffers are in use. */\r
1194                                 uxLastMinQueueSpace = uxCurrentCount;\r
1195                                 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );\r
1196                         }\r
1197                 }\r
1198                 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */\r
1199 \r
1200                 /* Run the state-machine of the ksz8851 driver. */\r
1201                 ksz8851snl_update();\r
1202 \r
1203                 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )\r
1204                 {\r
1205                         /* No events to process now, wait for the next. */\r
1206                         ulTaskNotifyTake( pdTRUE, ulMaxBlockTime );\r
1207                 }\r
1208 \r
1209                 if( ( xTaskGetTickCount() - xLoggingTime ) > 10000 )\r
1210                 {\r
1211                         xLoggingTime += 10000;\r
1212                         FreeRTOS_printf( ( "Now Tx/Rx %7d /%7d\n",\r
1213                                 xMicrelDevice.ul_total_tx, xMicrelDevice.ul_total_rx ) );\r
1214                 }\r
1215 \r
1216                 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )\r
1217                 {\r
1218                         ulISREvents &= ~EMAC_IF_RX_EVENT;\r
1219 \r
1220                         /* Wait for the EMAC interrupt to indicate that another packet has been\r
1221                         received. */\r
1222                         xResult = prvEMACRxPoll();\r
1223                 }\r
1224 \r
1225                 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )\r
1226                 {\r
1227                         /* Future extension: code to release TX buffers if zero-copy is used. */\r
1228                         ulISREvents &= ~EMAC_IF_TX_EVENT;\r
1229                 }\r
1230 \r
1231                 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )\r
1232                 {\r
1233                         /* Future extension: logging about errors that occurred. */\r
1234                         ulISREvents &= ~EMAC_IF_ERR_EVENT;\r
1235                 }\r
1236 \r
1237                 if( xResult > 0 )\r
1238                 {\r
1239                         /* As long as packets are being received, assume that\r
1240                         the Link Status is high. */\r
1241                         ulPHYLinkStatus |= BMSR_LINK_STATUS;\r
1242                         /* A packet was received. No need to check for the PHY status now,\r
1243                         but set a timer to check it later on. */\r
1244                         vTaskSetTimeOutState( &xPhyTime );\r
1245                         xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
1246                         xResult = 0;\r
1247                 }\r
1248                 else if( ( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) &&\r
1249                         ( xMicrelDevice.ul_spi_pdc_status == SPI_PDC_IDLE ) )\r
1250                 {\r
1251                         /* Check the link status again. */\r
1252                         xStatus = ulReadMDIO( PHY_REG_01_BMSR );\r
1253 \r
1254                         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )\r
1255                         {\r
1256                                 ulPHYLinkStatus = xStatus;\r
1257                                 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );\r
1258                         }\r
1259 \r
1260                         vTaskSetTimeOutState( &xPhyTime );\r
1261                         if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )\r
1262                         {\r
1263                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );\r
1264                         }\r
1265                         else\r
1266                         {\r
1267                                 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );\r
1268                         }\r
1269                 }\r
1270         }\r
1271 }\r
1272 /*-----------------------------------------------------------*/\r