2 * FreeRTOS+TCP V2.0.1
\r
3 * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
\r
5 * Permission is hereby granted, free of charge, to any person obtaining a copy of
\r
6 * this software and associated documentation files (the "Software"), to deal in
\r
7 * the Software without restriction, including without limitation the rights to
\r
8 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
\r
9 * the Software, and to permit persons to whom the Software is furnished to do so,
\r
10 * subject to the following conditions:
\r
12 * The above copyright notice and this permission notice shall be included in all
\r
13 * copies or substantial portions of the Software.
\r
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
\r
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
\r
17 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
\r
18 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
\r
19 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
20 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
22 * http://www.FreeRTOS.org
\r
23 * http://aws.amazon.com/freertos
\r
25 * 1 tab == 4 spaces!
\r
28 /* Standard includes. */
\r
34 /* FreeRTOS includes. */
\r
35 #include "FreeRTOS.h"
\r
40 /* FreeRTOS+TCP includes. */
\r
41 #include "FreeRTOS_IP.h"
\r
42 #include "FreeRTOS_Sockets.h"
\r
43 #include "FreeRTOS_IP_Private.h"
\r
44 #include "NetworkBufferManagement.h"
\r
45 #include "NetworkInterface.h"
\r
47 #include "sam4e_xplained_pro.h"
\r
48 #include "hr_gettime.h"
\r
49 #include "conf_eth.h"
\r
50 #include "ksz8851snl.h"
\r
51 #include "ksz8851snl_reg.h"
\r
53 /* Some files from the Atmel Software Framework */
\r
55 #include <pdc/pdc.h>
\r
56 #include <spi/spi.h>
\r
61 1) Called by UP-task, add buffer to the TX-list:
\r
62 xNetworkInterfaceOutput()
\r
63 tx_buffers[ us_tx_head ] = pxNetworkBuffer;
\r
64 tx_busy[ us_tx_head ] = pdTRUE;
\r
67 2) Called by EMAC-Task: start SPI transfer
\r
69 if( ul_spi_pdc_status == SPI_PDC_IDLE )
\r
71 if( ( tx_busy[ us_tx_tail ] != pdFALSE ) &&
\r
72 ( us_pending_frame == 0 ) &&
\r
73 ( ul_had_intn_interrupt == 0 ) )
\r
75 // disable all interrupts.
\r
76 ksz8851_reg_write( REG_INT_MASK, 0 );
\r
77 Bring KSZ8851SNL_CSN_GPIO low
\r
78 ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
\r
79 ul_spi_pdc_status = SPI_PDC_TX_START;
\r
80 tx_cur_buffer = pxNetworkBuffer;
\r
83 3) Wait for SPI RXBUFF interrupt
\r
85 if( ul_spi_pdc_status == SPI_PDC_TX_START )
\r
87 if( SPI_Status & SPI_SR_RXBUFF )
\r
89 ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;
\r
93 4) Called by EMAC-Task: finish SPI transfer
\r
95 if( ul_spi_pdc_status == SPI_PDC_TX_COMPLETE )
\r
97 ul_spi_pdc_status = SPI_PDC_IDLE;
\r
98 Bring KSZ8851SNL_CSN_GPIO high
\r
99 // TX step12: disable TXQ write access.
\r
100 ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
\r
101 // TX step12.1: enqueue frame in TXQ.
\r
102 ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
\r
104 // RX step13: enable INT_RX flag.
\r
105 ksz8851_reg_write( REG_INT_MASK, INT_RX );
\r
107 // Buffer sent, free the corresponding buffer and mark descriptor as owned by software.
\r
108 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
110 tx_buffers[ us_tx_tail ] = NULL;
\r
111 tx_busy[ us_tx_tail ] = pdFALSE;
\r
115 Receiving a packet:
\r
117 1) Wait for a INTN interrupt
\r
119 ul_had_intn_interrupt = 1
\r
120 vTaskNotifyGiveFromISR(); // Wake up the EMAC task
\r
122 2) Called by EMAC-Task: check for new fragments and start SPI transfer
\r
123 ksz8851snl_update()
\r
124 if( ul_spi_pdc_status == SPI_PDC_IDLE )
\r
126 if( ( ul_had_intn_interrupt != 0 ) || ( us_pending_frame > 0 ) )
\r
128 if( us_pending_frame == 0 )
\r
130 us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
\r
131 if( us_pending_frame == 0 )
\r
136 // RX step2: disable all interrupts.
\r
137 ksz8851_reg_write( REG_INT_MASK, 0 );
\r
138 Check if there is a valid packet: REG_RX_FHR_STATUS
\r
139 Read the length of the next fragment: REG_RX_FHR_BYTE_CNT
\r
140 ul_spi_pdc_status = SPI_PDC_RX_START;
\r
141 gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);
\r
142 // Start SPI data transfer
\r
143 ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer, xReadLength );
\r
147 3) Wait for SPI RXBUFF interrupt
\r
149 if( ul_spi_pdc_status == SPI_PDC_RX_START:
\r
151 if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )
\r
153 // Transfer complete, disable SPI RXBUFF interrupt.
\r
154 spi_disable_interrupt( KSZ8851SNL_SPI, SPI_IDR_RXBUFF );
\r
156 ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;
\r
161 4) Finish SPI transfer
\r
162 ksz8851snl_update()
\r
163 if( ul_spi_pdc_status == SPI_PDC_RX_COMPLETE )
\r
165 ul_spi_pdc_status = SPI_PDC_IDLE;
\r
166 Bring KSZ8851SNL_CSN_GPIO high
\r
167 // RX step21: end RXQ read access.
\r
168 ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);
\r
169 // RX step22-23: update frame count to be read.
\r
171 // RX step24: enable INT_RX flag if transfer complete.
\r
172 if( us_pending_frame == 0 )
\r
174 // Allow more RX interrupts.
\r
175 ksz8851_reg_write( REG_INT_MASK, INT_RX );
\r
178 // Mark descriptor ready to be read.
\r
179 rx_ready[ rxHead ] = pdTRUE;
\r
184 #define PHY_REG_00_BMCR 0x00 // Basic mode control register
\r
185 #define PHY_REG_01_BMSR 0x01 // Basic mode status register
\r
186 #define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1
\r
187 #define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2
\r
188 #define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg
\r
189 #define PHY_REG_05_LPA 0x05 // Link partner ability reg
\r
190 #define PHY_REG_06_ANER 0x06 // 6 RW Auto-Negotiation Expansion Register
\r
191 #define PHY_REG_07_ANNPTR 0x07 // 7 RW Auto-Negotiation Next Page TX
\r
192 #define PHY_REG_08_RESERVED0 0x08 // 0x08..0x0Fh 8-15 RW RESERVED
\r
194 #define BMSR_LINK_STATUS 0x0004 //!< Link status
\r
196 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
\r
197 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
\r
198 receiving packets. */
\r
199 #define PHY_LS_HIGH_CHECK_TIME_MS 15000
\r
202 #ifndef PHY_LS_LOW_CHECK_TIME_MS
\r
203 /* Check if the LinkSStatus in the PHY is still low every second. */
\r
204 #define PHY_LS_LOW_CHECK_TIME_MS 1000
\r
207 /* Interrupt events to process. Currently only the Rx event is processed
\r
208 although code for other events is included to allow for possible future
\r
210 #define EMAC_IF_RX_EVENT 1UL
\r
211 #define EMAC_IF_TX_EVENT 2UL
\r
212 #define EMAC_IF_ERR_EVENT 4UL
\r
213 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
\r
215 #define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
\r
217 #ifdef ipconfigHAS_TX_CRC_OFFLOADING
\r
218 #undef ipconfigHAS_TX_CRC_OFFLOADING
\r
220 /* Override this define because the KSZ8851 is programmed to set all outgoing CRC's */
\r
221 #define ipconfigHAS_TX_CRC_OFFLOADING 1
\r
223 #ifndef EMAC_MAX_BLOCK_TIME_MS
\r
224 #define EMAC_MAX_BLOCK_TIME_MS 100ul
\r
227 /* Default the size of the stack used by the EMAC deferred handler task to 4x
\r
228 the size of the stack used by the idle task - but allow this to be overridden in
\r
229 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
\r
230 #ifndef configEMAC_TASK_STACK_SIZE
\r
231 #define configEMAC_TASK_STACK_SIZE ( 6 * configMINIMAL_STACK_SIZE )
\r
234 #define SPI_PDC_IDLE 0
\r
235 #define SPI_PDC_RX_START 1
\r
236 #define SPI_PDC_TX_ERROR 2
\r
237 #define SPI_PDC_RX_COMPLETE 3
\r
238 #define SPI_PDC_TX_START 4
\r
239 #define SPI_PDC_RX_ERROR 5
\r
240 #define SPI_PDC_TX_COMPLETE 6
\r
243 * ksz8851snl driver structure.
\r
246 /** Set to 1 when owner is software (ready to read), 0 for Micrel. */
\r
247 uint32_t rx_ready[MICREL_RX_BUFFERS];
\r
248 /** Set to 1 when owner is Micrel, 0 for software. */
\r
249 uint32_t tx_busy[MICREL_TX_BUFFERS];
\r
250 /** RX NetworkBufferDescriptor_t pointer list */
\r
251 NetworkBufferDescriptor_t *rx_buffers[MICREL_RX_BUFFERS];
\r
252 /** TX NetworkBufferDescriptor_t pointer list */
\r
253 NetworkBufferDescriptor_t *tx_buffers[MICREL_TX_BUFFERS];
\r
254 NetworkBufferDescriptor_t *tx_cur_buffer;
\r
256 /** Circular buffer head pointer for packet received. */
\r
257 uint32_t us_rx_head;
\r
258 /** Circular buffer tail pointer for packet to be read. */
\r
259 uint32_t us_rx_tail;
\r
260 /** Circular buffer head pointer by upper layer (buffer to be sent). */
\r
261 uint32_t us_tx_head;
\r
262 /** Circular buffer tail pointer incremented by handlers (buffer sent). */
\r
263 uint32_t us_tx_tail;
\r
265 uint32_t ul_total_tx;
\r
266 uint32_t ul_total_rx;
\r
269 /** Still experimental: hash table to allow certain multicast addresses. */
\r
270 uint16_t pusHashTable[ 4 ];
\r
272 /* ul_spi_pdc_status has "SPI_PDC_xxx" values. */
\r
273 volatile uint32_t ul_spi_pdc_status;
\r
275 /* ul_had_intn_interrupt becomes true within the INTN interrupt. */
\r
276 volatile uint32_t ul_had_intn_interrupt;
\r
278 uint16_t us_pending_frame;
\r
279 } xKSZ8851_Device_t;
\r
281 /* SPI PDC register base.
\r
282 Declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */
\r
283 extern Pdc *g_p_spi_pdc;
\r
285 /* Temporary buffer for PDC reception.
\r
286 declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */
\r
287 extern uint8_t tmpbuf[1536];
\r
289 COMPILER_ALIGNED(8)
\r
290 static xKSZ8851_Device_t xMicrelDevice;
\r
292 static TaskHandle_t xTransmitHandle;
\r
294 /*-----------------------------------------------------------*/
\r
297 * Wait a fixed time for the link status to indicate the network is up.
\r
299 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
\r
302 * A deferred interrupt handler task that processes GMAC interrupts.
\r
304 static void prvEMACHandlerTask( void *pvParameters );
\r
307 * Try to obtain an Rx packet from the hardware.
\r
309 static uint32_t prvEMACRxPoll( void );
\r
311 static inline unsigned long ulReadMDIO( unsigned uAddress );
\r
313 static void ksz8851snl_low_level_init( void );
\r
315 static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void );
\r
317 /*-----------------------------------------------------------*/
\r
319 /* Bit map of outstanding ETH interrupt events for processing. Currently only
\r
320 the Rx interrupt is handled, although code is included for other events to
\r
321 enable future expansion. */
\r
322 static volatile uint32_t ulISREvents;
\r
324 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
\r
325 static uint32_t ulPHYLinkStatus = 0;
\r
326 static volatile BaseType_t xGMACSwitchRequired;
\r
328 static void ksz8851snl_update( void );
\r
330 static void ksz8851snl_rx_init( void );
\r
332 static void ksz8851snl_tx_init( void );
\r
334 /* Holds the handle of the task used as a deferred interrupt processor. The
\r
335 handle is used so direct notifications can be sent to the task for all EMAC/DMA
\r
336 related interrupts. */
\r
337 TaskHandle_t xEMACTaskHandle = NULL;
\r
340 /*-----------------------------------------------------------*/
\r
342 BaseType_t xNetworkInterfaceInitialise( void )
\r
344 const TickType_t x5_Seconds = 5000UL;
\r
346 if( xEMACTaskHandle == NULL )
\r
348 ksz8851snl_low_level_init();
\r
350 /* Wait at most 5 seconds for a Link Status in the PHY. */
\r
351 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
\r
353 /* The handler task is created at the highest possible priority to
\r
354 ensure the interrupt handler can return directly to it. */
\r
355 xTaskCreate( prvEMACHandlerTask, "KSZ8851", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
\r
356 configASSERT( xEMACTaskHandle );
\r
359 /* When returning non-zero, the stack will become active and
\r
360 start DHCP (in configured) */
\r
361 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
363 return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
\r
365 /*-----------------------------------------------------------*/
\r
367 BaseType_t xGetPhyLinkStatus( void )
\r
369 BaseType_t xResult;
\r
371 /* This function returns true if the Link Status in the PHY is high. */
\r
372 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
383 /*-----------------------------------------------------------*/
\r
385 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend )
\r
387 BaseType_t xResult = pdFALSE;
\r
388 int txHead = xMicrelDevice.us_tx_head;
\r
390 /* Make sure the next descriptor is free. */
\r
391 if( xMicrelDevice.tx_busy[ txHead ] != pdFALSE )
\r
393 /* All TX buffers busy. */
\r
395 else if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
\r
397 /* Output: LS low. */
\r
401 /* Pass the packet. */
\r
402 xMicrelDevice.tx_buffers[ txHead ] = pxNetworkBuffer;
\r
403 /* The descriptor is now owned by Micrel. */
\r
404 xMicrelDevice.tx_busy[ txHead ] = pdTRUE;
\r
406 /* Move the head pointer. */
\r
407 if( ++txHead == MICREL_TX_BUFFERS )
\r
411 xMicrelDevice.us_tx_head = txHead;
\r
412 if( xEMACTaskHandle != NULL )
\r
414 xTaskNotifyGive( xEMACTaskHandle );
\r
417 #if( ipconfigZERO_COPY_TX_DRIVER != 1 )
\r
418 #warning Please ipconfigZERO_COPY_TX_DRIVER as 1
\r
420 configASSERT( bReleaseAfterSend != pdFALSE );
\r
423 if( ( xResult == pdFALSE ) && ( bReleaseAfterSend != pdFALSE ) )
\r
425 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
429 /*-----------------------------------------------------------*/
\r
431 /* This Micrel has numbered it's PHY registers in a different way.
\r
432 Translate the register index. */
\r
433 static int ks8851_phy_reg( int reg )
\r
436 case PHY_REG_00_BMCR:
\r
437 return REG_PHY_CNTL; // P1MBCR;
\r
438 case PHY_REG_01_BMSR:
\r
439 return REG_PHY_STATUS;
\r
440 case PHY_REG_02_PHYSID1:
\r
441 return REG_PHY_ID_LOW;
\r
442 case PHY_REG_03_PHYSID2:
\r
443 return REG_PHY_ID_HIGH;
\r
444 case PHY_REG_04_ADVERTISE:
\r
445 return REG_PHY_AUTO_NEGOTIATION;
\r
446 case PHY_REG_05_LPA:
\r
447 return REG_PHY_REMOTE_CAPABILITY;
\r
452 /*-----------------------------------------------------------*/
\r
454 static inline unsigned long ulReadMDIO( unsigned uAddress )
\r
456 uint16_t usPHYStatus;
\r
457 int ks8851_reg = ks8851_phy_reg( uAddress );
\r
459 if( ks8851_reg != 0 )
\r
461 usPHYStatus = ksz8851_reg_read( ks8851_reg );
\r
465 /* Other addresses not yet implemented. */
\r
468 return usPHYStatus;
\r
470 /*-----------------------------------------------------------*/
\r
472 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
\r
474 TickType_t xStartTime = xTaskGetTickCount();
\r
475 TickType_t xEndTime;
\r
476 BaseType_t xReturn;
\r
477 const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
\r
478 const uint32_t ulHz_Per_MHz = 1000000UL;
\r
482 xEndTime = xTaskGetTickCount();
\r
484 if( ( xEndTime - xStartTime ) > xMaxTime )
\r
486 /* Wated more than xMaxTime, return. */
\r
491 /* Check the link status again. */
\r
492 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
494 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
496 /* Link is up - return. */
\r
501 /* Link is down - wait in the Blocked state for a short while (to allow
\r
502 other tasks to execute) before checking again. */
\r
503 vTaskDelay( xShortTime );
\r
506 FreeRTOS_printf( ( "xGMACWaitLS: %ld freq %lu Mz\n",
\r
508 sysclk_get_cpu_hz() / ulHz_Per_MHz ) );
\r
512 /*-----------------------------------------------------------*/
\r
514 static void vPioSetPinHigh(uint32_t ul_pin)
\r
516 Pio *p_pio = (Pio *)((uint32_t)PIOA + (PIO_DELTA * (ul_pin >> 5)));
\r
517 // Value to be driven on the I/O line: 1.
\r
518 p_pio->PIO_SODR = 1 << (ul_pin & 0x1F);
\r
522 * \brief Handler for SPI interrupt.
\r
524 void SPI_Handler(void)
\r
526 BaseType_t xDoWakeup = pdFALSE;
\r
527 BaseType_t xKSZTaskWoken = pdFALSE;
\r
528 uint32_t ulCurrentSPIStatus;
\r
529 uint32_t ulEnabledSPIStatus;
\r
531 ulCurrentSPIStatus = spi_read_status( KSZ8851SNL_SPI );
\r
532 ulEnabledSPIStatus = spi_read_interrupt_mask( KSZ8851SNL_SPI );
\r
533 ulCurrentSPIStatus &= ulEnabledSPIStatus;
\r
534 spi_disable_interrupt( KSZ8851SNL_SPI, ulCurrentSPIStatus );
\r
537 switch( xMicrelDevice.ul_spi_pdc_status )
\r
539 case SPI_PDC_RX_START:
\r
541 if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )
\r
543 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
\r
544 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_ERROR;
\r
545 xDoWakeup = pdTRUE;
\r
549 if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )
\r
551 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;
\r
552 xDoWakeup = pdTRUE;
\r
558 case SPI_PDC_TX_START:
\r
560 /* Middle of TX. */
\r
561 if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )
\r
563 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
\r
564 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_ERROR;
\r
565 xDoWakeup = pdTRUE;
\r
569 if( ( ulCurrentSPIStatus & SPI_SR_ENDRX ) != 0 )
\r
571 /* Enable RX complete interrupt. */
\r
572 spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_RXBUFF );
\r
575 if( ( ulCurrentSPIStatus & SPI_END_OF_TX ) != 0 )
\r
577 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;
\r
578 xDoWakeup = pdTRUE;
\r
583 } /* switch( xMicrelDevice.ul_spi_pdc_status ) */
\r
585 if( xDoWakeup != pdFALSE )
\r
587 if( xEMACTaskHandle != NULL )
\r
589 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xKSZTaskWoken );
\r
595 portEND_SWITCHING_ISR( xKSZTaskWoken );
\r
597 /*-----------------------------------------------------------*/
\r
599 static void INTN_Handler(uint32_t id, uint32_t mask)
\r
601 BaseType_t xKSZTaskWoken = pdFALSE;
\r
603 if( ( id == INTN_ID ) &&
\r
604 ( mask == INTN_PIN_MSK ) )
\r
606 /* Clear the PIO interrupt flags. */
\r
607 pio_get_interrupt_status( INTN_PIO );
\r
609 /* Set the INTN flag. */
\r
610 xMicrelDevice.ul_had_intn_interrupt++;
\r
611 if( xEMACTaskHandle != NULL )
\r
613 vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xKSZTaskWoken ) );
\r
616 portEND_SWITCHING_ISR( xKSZTaskWoken );
\r
618 /*-----------------------------------------------------------*/
\r
621 * \brief Populate the RX descriptor ring buffers with pbufs.
\r
623 * \param p_ksz8851snl_dev Pointer to driver data structure.
\r
625 static void ksz8851snl_rx_populate_queue( void )
\r
627 uint32_t ul_index = 0;
\r
628 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
630 /* Set up the RX descriptors */
\r
631 for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {
\r
632 if( xMicrelDevice.rx_buffers[ ul_index ] == NULL )
\r
634 /* Allocate a new NetworkBufferDescriptor_t with the maximum size. */
\r
635 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipconfigNETWORK_MTU + 36, 100 );
\r
636 if( pxNetworkBuffer == NULL )
\r
638 FreeRTOS_printf( ( "ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t allocation failure\n" ) );
\r
639 configASSERT( 1 == 2 );
\r
642 /* Make sure lwIP is well configured so one NetworkBufferDescriptor_t can contain the maximum packet size. */
\r
643 //LWIP_ASSERT("ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t size too small!", pbuf_clen(pxNetworkBuffer) <= 1);
\r
645 /* Save NetworkBufferDescriptor_t pointer to be sent to lwIP upper layer. */
\r
646 xMicrelDevice.rx_buffers[ ul_index ] = pxNetworkBuffer;
\r
647 /* Pass it to Micrel for reception. */
\r
648 xMicrelDevice.rx_ready[ ul_index ] = pdFALSE;
\r
653 unsigned tx_space, wait_tx_space, tx_status, fhr_status;
\r
654 unsigned rx_debug = 0;
\r
656 * \brief Update Micrel state machine and perform required actions.
\r
658 * \param netif the lwIP network interface structure for this ethernetif.
\r
660 static void ksz8851snl_update()
\r
662 uint16_t txmir = 0;
\r
664 /* Check for free PDC. */
\r
665 switch( xMicrelDevice.ul_spi_pdc_status )
\r
667 case SPI_PDC_TX_ERROR:
\r
670 // /* TX step11: end TX transfer. */
\r
671 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
673 vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
\r
674 vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
677 /* Disable asynchronous transfer mode. */
\r
678 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
\r
680 /* TX step12: disable TXQ write access. */
\r
681 ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
\r
683 ulValue = ksz8851snl_reset_tx();
\r
685 xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
\r
687 FreeRTOS_printf( ("SPI_PDC_TX_ERROR %02X\n", ulValue ) );
\r
691 case SPI_PDC_RX_ERROR:
\r
694 /* TX step11: end TX transfer. */
\r
695 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
697 vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
\r
698 vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
701 /* Disable asynchronous transfer mode. */
\r
702 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
\r
704 /* TX step12: disable TXQ write access. */
\r
705 ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
\r
707 //ulValue = ksz8851snl_reset_rx();
\r
708 ulValue = ksz8851snl_reinit();
\r
710 xGMACWaitLS( pdMS_TO_TICKS( 5000UL ) );
\r
712 FreeRTOS_printf( ("SPI_PDC_RX_ERROR %02X\n", ulValue ) );
\r
716 switch( xMicrelDevice.ul_spi_pdc_status )
\r
720 int txTail = xMicrelDevice.us_tx_tail;
\r
723 * ========================== Handle RX ==========================
\r
725 if( ( xMicrelDevice.ul_had_intn_interrupt != 0 ) || ( xMicrelDevice.us_pending_frame > 0 ) )
\r
727 int rxHead = xMicrelDevice.us_rx_head;
\r
728 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
730 xMicrelDevice.ul_had_intn_interrupt = 0;
\r
732 if( xMicrelDevice.us_pending_frame == 0 )
\r
734 uint16_t int_status;
\r
735 /* RX step1: read interrupt status for INT_RX flag. */
\r
736 int_status = ksz8851_reg_read( REG_INT_STATUS );
\r
739 /* RX step2: disable all interrupts. */
\r
740 ksz8851_reg_write( REG_INT_MASK, 0 );
\r
742 /* RX step3: clear INT_RX flag. */
\r
743 ksz8851_reg_setbits( REG_INT_STATUS, INT_RX );
\r
745 /* RX step4-5: check for received frames. */
\r
746 xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
\r
747 if( xMicrelDevice.us_pending_frame == 0 )
\r
749 /* RX step24: enable INT_RX flag. */
\r
750 ksz8851_reg_write(REG_INT_MASK, INT_RX);
\r
755 xMicrelDevice.ul_had_intn_interrupt = 0;
\r
757 /* Now xMicrelDevice.us_pending_frame != 0 */
\r
759 /* Don't break Micrel state machine, wait for a free descriptor first! */
\r
760 if( xMicrelDevice.rx_ready[ rxHead ] != pdFALSE )
\r
762 FreeRTOS_printf( ( "ksz8851snl_update: out of free descriptor! [tail=%u head=%u]\n",
\r
763 xMicrelDevice.us_rx_tail, rxHead ) );
\r
766 pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxHead ];
\r
768 if( pxNetworkBuffer == NULL )
\r
770 ksz8851snl_rx_populate_queue();
\r
771 FreeRTOS_printf( ( "ksz8851snl_update: no buffer set [head=%u]\n", rxHead ) );
\r
775 /* RX step6: get RX packet status. */
\r
776 fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
\r
777 if( ( ( fhr_status & RX_VALID ) == 0 ) || ( ( fhr_status & RX_ERRORS ) != 0 ) )
\r
779 ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_CMD_FREE_PACKET);
\r
780 FreeRTOS_printf( ( "ksz8851snl_update: RX packet error!\n" ) );
\r
782 /* RX step4-5: check for received frames. */
\r
783 xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
\r
784 if( xMicrelDevice.us_pending_frame == 0 )
\r
786 /* RX step24: enable INT_RX flag. */
\r
787 ksz8851_reg_write(REG_INT_MASK, INT_RX);
\r
789 ulISREvents |= EMAC_IF_ERR_EVENT;
\r
794 /* RX step7: read frame length. */
\r
795 xLength = ksz8851_reg_read(REG_RX_FHR_BYTE_CNT) & RX_BYTE_CNT_MASK;
\r
797 /* RX step8: Drop packet if len is invalid or no descriptor available. */
\r
800 ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET );
\r
801 FreeRTOS_printf( ( "ksz8851snl_update: RX bad len!\n" ) );
\r
802 ulISREvents |= EMAC_IF_ERR_EVENT;
\r
806 size_t xReadLength = xLength;
\r
808 xMicrelDevice.ul_total_rx++;
\r
809 /* RX step9: reset RX frame pointer. */
\r
810 ksz8851_reg_clrbits(REG_RX_ADDR_PTR, ADDR_PTR_MASK);
\r
812 /* RX step10: start RXQ read access. */
\r
813 ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_START);
\r
814 /* RX step11-17: start asynchronous FIFO read operation. */
\r
815 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_START;
\r
816 gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
\r
817 if( ( xReadLength & ( sizeof( size_t ) - 1 ) ) != 0 )
\r
819 xReadLength = ( xReadLength | ( sizeof( size_t ) - 1 ) ) + 1;
\r
822 /* Pass the buffer minus 2 bytes, see ksz8851snl.c: RXQ_TWOBYTE_OFFSET. */
\r
823 ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer - 2, xReadLength );
\r
824 /* Remove CRC and update buffer length. */
\r
826 pxNetworkBuffer->xDataLength = xLength;
\r
827 /* Wait for SPI interrupt to set status 'SPI_PDC_RX_COMPLETE'. */
\r
831 } /* ul_had_intn_interrupt || us_pending_frame */
\r
833 * ========================== Handle TX ==========================
\r
836 /* Fetch next packet to be sent. */
\r
837 if( ( xMicrelDevice.tx_busy[ txTail ] != pdFALSE ) &&
\r
838 ( xMicrelDevice.us_pending_frame == 0 ) &&
\r
839 ( xMicrelDevice.ul_had_intn_interrupt == 0 ) )
\r
841 NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
\r
842 size_t xLength = pxNetworkBuffer->xDataLength;
\r
843 int iIndex = xLength;
\r
845 xLength = 4 * ( ( xLength + 3 ) / 4 );
\r
846 while( iIndex < ( int ) xLength )
\r
848 pxNetworkBuffer->pucEthernetBuffer[ iIndex ] = '\0';
\r
851 pxNetworkBuffer->xDataLength = xLength;
\r
853 /* TX step1: check if TXQ memory size is available for transmit. */
\r
854 txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
\r
855 txmir = txmir & TX_MEM_AVAILABLE_MASK;
\r
857 if( txmir < ( xLength + 8 ) )
\r
859 if( wait_tx_space == pdFALSE )
\r
861 tx_status = ksz8851_reg_read( REG_TX_STATUS );
\r
862 fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
\r
863 wait_tx_space = pdTRUE;
\r
873 /* TX step2: disable all interrupts. */
\r
874 ksz8851_reg_write( REG_INT_MASK, 0 );
\r
876 xMicrelDevice.tx_space -= xLength;
\r
878 /* TX step3: enable TXQ write access. */
\r
879 ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START );
\r
880 /* TX step4-8: perform FIFO write operation. */
\r
881 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_START;
\r
882 xMicrelDevice.tx_cur_buffer = pxNetworkBuffer;
\r
883 /* Bring SPI SS low. */
\r
884 gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
\r
885 xMicrelDevice.ul_total_tx++;
\r
887 ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
\r
891 break; /* SPI_PDC_IDLE */
\r
893 case SPI_PDC_RX_COMPLETE:
\r
895 int rxHead = xMicrelDevice.us_rx_head;
\r
896 /* RX step18-19: pad with dummy data to keep dword alignment. */
\r
897 /* Packet lengths will be rounded up to a multiple of "sizeof size_t". */
\r
898 // xLength = xMicrelDevice.rx_buffers[ rxHead ]->xDataLength & 3;
\r
899 // if( xLength != 0 )
\r
901 // ksz8851_fifo_dummy( 4 - xLength );
\r
904 /* RX step20: end RX transfer. */
\r
905 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
907 /* Disable asynchronous transfer mode. */
\r
908 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
\r
910 /* RX step21: end RXQ read access. */
\r
911 ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);
\r
913 /* RX step22-23: update frame count to be read. */
\r
914 xMicrelDevice.us_pending_frame -= 1;
\r
916 /* RX step24: enable INT_RX flag if transfer complete. */
\r
917 if( xMicrelDevice.us_pending_frame == 0 )
\r
919 ksz8851_reg_write(REG_INT_MASK, INT_RX);
\r
922 /* Mark descriptor ready to be read. */
\r
923 xMicrelDevice.rx_ready[ rxHead ] = pdTRUE;
\r
924 if( ++rxHead == MICREL_RX_BUFFERS )
\r
928 xMicrelDevice.us_rx_head = rxHead;
\r
929 if( rx_debug != 0 )
\r
933 txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
\r
934 txmir = txmir & TX_MEM_AVAILABLE_MASK;
\r
936 /* Tell prvEMACHandlerTask that RX packets are available. */
\r
937 ulISREvents |= EMAC_IF_RX_EVENT;
\r
938 } /* case SPI_PDC_RX_COMPLETE */
\r
941 case SPI_PDC_TX_COMPLETE:
\r
943 int txTail = xMicrelDevice.us_tx_tail;
\r
944 NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
\r
947 /* TX step9-10: pad with dummy data to keep dword alignment. */
\r
948 /* Not necessary: length is already a multiple of 4. */
\r
949 xLength = pxNetworkBuffer->xDataLength & 3;
\r
952 // ksz8851_fifo_dummy( 4 - xLength );
\r
955 // /* TX step11: end TX transfer. */
\r
956 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
958 /* Disable asynchronous transfer mode. */
\r
959 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
\r
961 /* TX step12: disable TXQ write access. */
\r
962 ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
\r
964 xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
\r
966 /* TX step12.1: enqueue frame in TXQ. */
\r
967 ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
\r
969 /* RX step13: enable INT_RX flag. */
\r
970 // ksz8851_reg_write( REG_INT_MASK, INT_RX );
\r
971 /* Buffer sent, free the corresponding buffer and mark descriptor as owned by software. */
\r
972 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
974 xMicrelDevice.tx_buffers[ txTail ] = NULL;
\r
975 xMicrelDevice.tx_busy[ txTail ] = pdFALSE;
\r
976 if( ++txTail == MICREL_TX_BUFFERS )
\r
981 xMicrelDevice.us_tx_tail = txTail;
\r
983 //xMicrelDevice.ul_had_intn_interrupt = 1;
\r
984 if( xTransmitHandle != NULL )
\r
986 xTaskNotifyGive( xTransmitHandle );
\r
988 #warning moved downward
\r
989 /* RX step13: enable INT_RX flag. */
\r
990 ksz8851_reg_write( REG_INT_MASK, INT_RX );
\r
991 /* Prevent the EMAC task from sleeping a single time. */
\r
992 ulISREvents |= EMAC_IF_TX_EVENT;
\r
993 } /* case SPI_PDC_TX_COMPLETE */
\r
995 } /* switch( xMicrelDevice.ul_spi_pdc_status ) */
\r
999 * \brief Set up the RX descriptor ring buffers.
\r
1001 * This function sets up the descriptor list used for RX packets.
\r
1004 static void ksz8851snl_rx_init()
\r
1006 uint32_t ul_index = 0;
\r
1008 /* Init pointer index. */
\r
1009 xMicrelDevice.us_rx_head = 0;
\r
1010 xMicrelDevice.us_rx_tail = 0;
\r
1012 /* Set up the RX descriptors. */
\r
1013 for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {
\r
1014 xMicrelDevice.rx_buffers[ul_index] = NULL;
\r
1015 xMicrelDevice.rx_ready[ul_index] = pdFALSE;
\r
1018 /* Build RX buffer and descriptors. */
\r
1019 ksz8851snl_rx_populate_queue();
\r
1023 * \brief Set up the TX descriptor ring buffers.
\r
1025 * This function sets up the descriptor list used for TX packets.
\r
1028 static void ksz8851snl_tx_init()
\r
1030 uint32_t ul_index = 0;
\r
1032 /* Init TX index pointer. */
\r
1033 xMicrelDevice.us_tx_head = 0;
\r
1034 xMicrelDevice.us_tx_tail = 0;
\r
1036 /* Set up the TX descriptors */
\r
1037 for( ul_index = 0; ul_index < MICREL_TX_BUFFERS; ul_index++ )
\r
1039 xMicrelDevice.tx_busy[ul_index] = pdFALSE;
\r
1041 xMicrelDevice.tx_space = 6144;
\r
1045 * \brief Initialize ksz8851snl ethernet controller.
\r
1047 * \note Called from ethernetif_init().
\r
1049 * \param netif the lwIP network interface structure for this ethernetif.
\r
1051 static void ksz8851snl_low_level_init( void )
\r
1053 ksz8851snl_rx_init();
\r
1054 ksz8851snl_tx_init();
\r
1056 /* Enable NVIC interrupts. */
\r
1057 NVIC_SetPriority(SPI_IRQn, INT_PRIORITY_SPI);
\r
1058 NVIC_EnableIRQ(SPI_IRQn);
\r
1060 /* Initialize SPI link. */
\r
1061 if( ksz8851snl_init() < 0 )
\r
1063 FreeRTOS_printf( ( "ksz8851snl_low_level_init: failed to initialize the Micrel driver!\n" ) );
\r
1064 configASSERT(0 == 1);
\r
1066 memset( xMicrelDevice.pusHashTable, 255, sizeof( xMicrelDevice.pusHashTable ) );
\r
1067 ksz8851_reg_write( REG_MAC_HASH_0, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 0 ] ) );
\r
1068 ksz8851_reg_write( REG_MAC_HASH_2, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 1 ] ) );
\r
1069 ksz8851_reg_write( REG_MAC_HASH_4, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 2 ] ) );
\r
1070 ksz8851_reg_write( REG_MAC_HASH_6, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 3 ] ) );
\r
1072 /* Initialize interrupt line INTN. */
\r
1073 configure_intn( INTN_Handler );
\r
1077 * \brief Use pre-allocated pbuf as DMA source and return the incoming packet.
\r
1079 * \param netif the lwIP network interface structure for this ethernetif.
\r
1081 * \return a pbuf filled with the received packet (including MAC header).
\r
1082 * 0 on memory error.
\r
1084 static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void )
\r
1086 NetworkBufferDescriptor_t *pxNetworkBuffer = NULL;
\r
1087 int rxTail = xMicrelDevice.us_rx_tail;
\r
1089 /* Check that descriptor is owned by software (ie packet received). */
\r
1090 if( xMicrelDevice.rx_ready[ rxTail ] != pdFALSE )
\r
1093 /* Fetch pre-allocated buffer */
\r
1094 pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxTail ];
\r
1096 /* Remove this pbuf from its descriptor. */
\r
1097 xMicrelDevice.rx_buffers[ rxTail ] = NULL;
\r
1099 /* Clears rx_ready and sets rx_buffers. */
\r
1100 ksz8851snl_rx_populate_queue();
\r
1102 if( ++rxTail == MICREL_RX_BUFFERS )
\r
1106 xMicrelDevice.us_rx_tail = rxTail;
\r
1109 return pxNetworkBuffer;
\r
1111 /*-----------------------------------------------------------*/
\r
1113 static uint32_t prvEMACRxPoll( void )
\r
1115 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
1116 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
\r
1117 uint32_t ulReturnValue = 0;
\r
1121 /* Only for logging. */
\r
1122 int rxTail = xMicrelDevice.us_rx_tail;
\r
1123 EthernetHeader_t *pxEthernetHeader;
\r
1125 pxNetworkBuffer = ksz8851snl_low_level_input();
\r
1127 if( pxNetworkBuffer == NULL )
\r
1131 pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1133 if( ( pxEthernetHeader->usFrameType != ipIPv4_FRAME_TYPE ) &&
\r
1134 ( pxEthernetHeader->usFrameType != ipARP_FRAME_TYPE ) )
\r
1136 FreeRTOS_printf( ( "Frame type %02X received\n", pxEthernetHeader->usFrameType ) );
\r
1140 xRxEvent.pvData = ( void * )pxNetworkBuffer;
\r
1141 /* Send the descriptor to the IP task for processing. */
\r
1142 if( xSendEventStructToIPTask( &xRxEvent, 100UL ) != pdTRUE )
\r
1144 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
1145 iptraceETHERNET_RX_EVENT_LOST();
\r
1146 FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
\r
1150 return ulReturnValue;
\r
1152 /*-----------------------------------------------------------*/
\r
1154 static void prvEMACHandlerTask( void *pvParameters )
\r
1156 TimeOut_t xPhyTime;
\r
1157 TickType_t xPhyRemTime;
\r
1158 TickType_t xLoggingTime;
\r
1159 UBaseType_t uxLastMinBufferCount = 0;
\r
1160 UBaseType_t uxCurrentCount;
\r
1161 BaseType_t xResult = 0;
\r
1163 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
\r
1164 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
1165 UBaseType_t uxLastMinQueueSpace = 0;
\r
1168 /* Remove compiler warnings about unused parameters. */
\r
1169 ( void ) pvParameters;
\r
1171 configASSERT( xEMACTaskHandle );
\r
1173 vTaskSetTimeOutState( &xPhyTime );
\r
1174 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
1175 xLoggingTime = xTaskGetTickCount();
\r
1179 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
1180 if( uxLastMinBufferCount != uxCurrentCount )
\r
1182 /* The logging produced below may be helpful
\r
1183 while tuning +TCP: see how many buffers are in use. */
\r
1184 uxLastMinBufferCount = uxCurrentCount;
\r
1185 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
\r
1186 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
\r
1189 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
1191 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
1192 if( uxLastMinQueueSpace != uxCurrentCount )
\r
1194 /* The logging produced below may be helpful
\r
1195 while tuning +TCP: see how many buffers are in use. */
\r
1196 uxLastMinQueueSpace = uxCurrentCount;
\r
1197 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
\r
1200 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
1202 /* Run the state-machine of the ksz8851 driver. */
\r
1203 ksz8851snl_update();
\r
1205 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
1207 /* No events to process now, wait for the next. */
\r
1208 ulTaskNotifyTake( pdTRUE, ulMaxBlockTime );
\r
1211 if( ( xTaskGetTickCount() - xLoggingTime ) > 10000 )
\r
1213 xLoggingTime += 10000;
\r
1214 FreeRTOS_printf( ( "Now Tx/Rx %7d /%7d\n",
\r
1215 xMicrelDevice.ul_total_tx, xMicrelDevice.ul_total_rx ) );
\r
1218 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
1220 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
1222 /* Wait for the EMAC interrupt to indicate that another packet has been
\r
1224 xResult = prvEMACRxPoll();
\r
1227 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\r
1229 /* Future extension: code to release TX buffers if zero-copy is used. */
\r
1230 ulISREvents &= ~EMAC_IF_TX_EVENT;
\r
1233 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
1235 /* Future extension: logging about errors that occurred. */
\r
1236 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\r
1241 /* As long as packets are being received, assume that
\r
1242 the Link Status is high. */
\r
1243 ulPHYLinkStatus |= BMSR_LINK_STATUS;
\r
1244 /* A packet was received. No need to check for the PHY status now,
\r
1245 but set a timer to check it later on. */
\r
1246 vTaskSetTimeOutState( &xPhyTime );
\r
1247 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
1250 else if( ( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) &&
\r
1251 ( xMicrelDevice.ul_spi_pdc_status == SPI_PDC_IDLE ) )
\r
1253 /* Check the link status again. */
\r
1254 xStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
1256 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
1258 ulPHYLinkStatus = xStatus;
\r
1259 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
1262 vTaskSetTimeOutState( &xPhyTime );
\r
1263 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
1265 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
1269 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
1274 /*-----------------------------------------------------------*/
\r