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