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