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