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