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