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://aws.amazon.com/freertos
\r
23 http://www.FreeRTOS.org
\r
26 /* Standard includes. */
\r
32 /* FreeRTOS includes. */
\r
33 #include "FreeRTOS.h"
\r
38 /* FreeRTOS+TCP includes. */
\r
39 #include "FreeRTOS_IP.h"
\r
40 #include "FreeRTOS_Sockets.h"
\r
41 #include "FreeRTOS_IP_Private.h"
\r
42 #include "NetworkBufferManagement.h"
\r
43 #include "NetworkInterface.h"
\r
45 #include "sam4e_xplained_pro.h"
\r
46 #include "hr_gettime.h"
\r
47 #include "conf_eth.h"
\r
48 #include "ksz8851snl.h"
\r
49 #include "ksz8851snl_reg.h"
\r
51 /* Some files from the Atmel Software Framework */
\r
53 #include <pdc/pdc.h>
\r
54 #include <spi/spi.h>
\r
59 1) Called by UP-task, add buffer to the TX-list:
\r
60 xNetworkInterfaceOutput()
\r
61 tx_buffers[ us_tx_head ] = pxNetworkBuffer;
\r
62 tx_busy[ us_tx_head ] = pdTRUE;
\r
65 2) Called by EMAC-Task: start SPI transfer
\r
67 if( ul_spi_pdc_status == SPI_PDC_IDLE )
\r
69 if( ( tx_busy[ us_tx_tail ] != pdFALSE ) &&
\r
70 ( us_pending_frame == 0 ) &&
\r
71 ( ul_had_intn_interrupt == 0 ) )
\r
73 // disable all interrupts.
\r
74 ksz8851_reg_write( REG_INT_MASK, 0 );
\r
75 Bring KSZ8851SNL_CSN_GPIO low
\r
76 ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
\r
77 ul_spi_pdc_status = SPI_PDC_TX_START;
\r
78 tx_cur_buffer = pxNetworkBuffer;
\r
81 3) Wait for SPI RXBUFF interrupt
\r
83 if( ul_spi_pdc_status == SPI_PDC_TX_START )
\r
85 if( SPI_Status & SPI_SR_RXBUFF )
\r
87 ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;
\r
91 4) Called by EMAC-Task: finish SPI transfer
\r
93 if( ul_spi_pdc_status == SPI_PDC_TX_COMPLETE )
\r
95 ul_spi_pdc_status = SPI_PDC_IDLE;
\r
96 Bring KSZ8851SNL_CSN_GPIO high
\r
97 // TX step12: disable TXQ write access.
\r
98 ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
\r
99 // TX step12.1: enqueue frame in TXQ.
\r
100 ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
\r
102 // RX step13: enable INT_RX flag.
\r
103 ksz8851_reg_write( REG_INT_MASK, INT_RX );
\r
105 // Buffer sent, free the corresponding buffer and mark descriptor as owned by software.
\r
106 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
108 tx_buffers[ us_tx_tail ] = NULL;
\r
109 tx_busy[ us_tx_tail ] = pdFALSE;
\r
113 Receiving a packet:
\r
115 1) Wait for a INTN interrupt
\r
117 ul_had_intn_interrupt = 1
\r
118 vTaskNotifyGiveFromISR(); // Wake up the EMAC task
\r
120 2) Called by EMAC-Task: check for new fragments and start SPI transfer
\r
121 ksz8851snl_update()
\r
122 if( ul_spi_pdc_status == SPI_PDC_IDLE )
\r
124 if( ( ul_had_intn_interrupt != 0 ) || ( us_pending_frame > 0 ) )
\r
126 if( us_pending_frame == 0 )
\r
128 us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
\r
129 if( us_pending_frame == 0 )
\r
134 // RX step2: disable all interrupts.
\r
135 ksz8851_reg_write( REG_INT_MASK, 0 );
\r
136 Check if there is a valid packet: REG_RX_FHR_STATUS
\r
137 Read the length of the next fragment: REG_RX_FHR_BYTE_CNT
\r
138 ul_spi_pdc_status = SPI_PDC_RX_START;
\r
139 gpio_set_pin_low(KSZ8851SNL_CSN_GPIO);
\r
140 // Start SPI data transfer
\r
141 ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer, xReadLength );
\r
145 3) Wait for SPI RXBUFF interrupt
\r
147 if( ul_spi_pdc_status == SPI_PDC_RX_START:
\r
149 if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )
\r
151 // Transfer complete, disable SPI RXBUFF interrupt.
\r
152 spi_disable_interrupt( KSZ8851SNL_SPI, SPI_IDR_RXBUFF );
\r
154 ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;
\r
159 4) Finish SPI transfer
\r
160 ksz8851snl_update()
\r
161 if( ul_spi_pdc_status == SPI_PDC_RX_COMPLETE )
\r
163 ul_spi_pdc_status = SPI_PDC_IDLE;
\r
164 Bring KSZ8851SNL_CSN_GPIO high
\r
165 // RX step21: end RXQ read access.
\r
166 ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);
\r
167 // RX step22-23: update frame count to be read.
\r
169 // RX step24: enable INT_RX flag if transfer complete.
\r
170 if( us_pending_frame == 0 )
\r
172 // Allow more RX interrupts.
\r
173 ksz8851_reg_write( REG_INT_MASK, INT_RX );
\r
176 // Mark descriptor ready to be read.
\r
177 rx_ready[ rxHead ] = pdTRUE;
\r
182 #define PHY_REG_00_BMCR 0x00 // Basic mode control register
\r
183 #define PHY_REG_01_BMSR 0x01 // Basic mode status register
\r
184 #define PHY_REG_02_PHYSID1 0x02 // PHYS ID 1
\r
185 #define PHY_REG_03_PHYSID2 0x03 // PHYS ID 2
\r
186 #define PHY_REG_04_ADVERTISE 0x04 // Advertisement control reg
\r
187 #define PHY_REG_05_LPA 0x05 // Link partner ability reg
\r
188 #define PHY_REG_06_ANER 0x06 // 6 RW Auto-Negotiation Expansion Register
\r
189 #define PHY_REG_07_ANNPTR 0x07 // 7 RW Auto-Negotiation Next Page TX
\r
190 #define PHY_REG_08_RESERVED0 0x08 // 0x08..0x0Fh 8-15 RW RESERVED
\r
192 #define BMSR_LINK_STATUS 0x0004 //!< Link status
\r
194 #ifndef PHY_LS_HIGH_CHECK_TIME_MS
\r
195 /* Check if the LinkSStatus in the PHY is still high after 15 seconds of not
\r
196 receiving packets. */
\r
197 #define PHY_LS_HIGH_CHECK_TIME_MS 15000
\r
200 #ifndef PHY_LS_LOW_CHECK_TIME_MS
\r
201 /* Check if the LinkSStatus in the PHY is still low every second. */
\r
202 #define PHY_LS_LOW_CHECK_TIME_MS 1000
\r
205 /* Interrupt events to process. Currently only the Rx event is processed
\r
206 although code for other events is included to allow for possible future
\r
208 #define EMAC_IF_RX_EVENT 1UL
\r
209 #define EMAC_IF_TX_EVENT 2UL
\r
210 #define EMAC_IF_ERR_EVENT 4UL
\r
211 #define EMAC_IF_ALL_EVENT ( EMAC_IF_RX_EVENT | EMAC_IF_TX_EVENT | EMAC_IF_ERR_EVENT )
\r
213 #define ETHERNET_CONF_PHY_ADDR BOARD_GMAC_PHY_ADDR
\r
215 #ifdef ipconfigHAS_TX_CRC_OFFLOADING
\r
216 #undef ipconfigHAS_TX_CRC_OFFLOADING
\r
218 /* Override this define because the KSZ8851 is programmed to set all outgoing CRC's */
\r
219 #define ipconfigHAS_TX_CRC_OFFLOADING 1
\r
221 #ifndef EMAC_MAX_BLOCK_TIME_MS
\r
222 #define EMAC_MAX_BLOCK_TIME_MS 100ul
\r
225 /* Default the size of the stack used by the EMAC deferred handler task to 4x
\r
226 the size of the stack used by the idle task - but allow this to be overridden in
\r
227 FreeRTOSConfig.h as configMINIMAL_STACK_SIZE is a user definable constant. */
\r
228 #ifndef configEMAC_TASK_STACK_SIZE
\r
229 #define configEMAC_TASK_STACK_SIZE ( 6 * configMINIMAL_STACK_SIZE )
\r
232 #define SPI_PDC_IDLE 0
\r
233 #define SPI_PDC_RX_START 1
\r
234 #define SPI_PDC_TX_ERROR 2
\r
235 #define SPI_PDC_RX_COMPLETE 3
\r
236 #define SPI_PDC_TX_START 4
\r
237 #define SPI_PDC_RX_ERROR 5
\r
238 #define SPI_PDC_TX_COMPLETE 6
\r
241 * ksz8851snl driver structure.
\r
244 /** Set to 1 when owner is software (ready to read), 0 for Micrel. */
\r
245 uint32_t rx_ready[MICREL_RX_BUFFERS];
\r
246 /** Set to 1 when owner is Micrel, 0 for software. */
\r
247 uint32_t tx_busy[MICREL_TX_BUFFERS];
\r
248 /** RX NetworkBufferDescriptor_t pointer list */
\r
249 NetworkBufferDescriptor_t *rx_buffers[MICREL_RX_BUFFERS];
\r
250 /** TX NetworkBufferDescriptor_t pointer list */
\r
251 NetworkBufferDescriptor_t *tx_buffers[MICREL_TX_BUFFERS];
\r
252 NetworkBufferDescriptor_t *tx_cur_buffer;
\r
254 /** Circular buffer head pointer for packet received. */
\r
255 uint32_t us_rx_head;
\r
256 /** Circular buffer tail pointer for packet to be read. */
\r
257 uint32_t us_rx_tail;
\r
258 /** Circular buffer head pointer by upper layer (buffer to be sent). */
\r
259 uint32_t us_tx_head;
\r
260 /** Circular buffer tail pointer incremented by handlers (buffer sent). */
\r
261 uint32_t us_tx_tail;
\r
263 uint32_t ul_total_tx;
\r
264 uint32_t ul_total_rx;
\r
267 /** Still experimental: hash table to allow certain multicast addresses. */
\r
268 uint16_t pusHashTable[ 4 ];
\r
270 /* ul_spi_pdc_status has "SPI_PDC_xxx" values. */
\r
271 volatile uint32_t ul_spi_pdc_status;
\r
273 /* ul_had_intn_interrupt becomes true within the INTN interrupt. */
\r
274 volatile uint32_t ul_had_intn_interrupt;
\r
276 uint16_t us_pending_frame;
\r
277 } xKSZ8851_Device_t;
\r
279 /* SPI PDC register base.
\r
280 Declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */
\r
281 extern Pdc *g_p_spi_pdc;
\r
283 /* Temporary buffer for PDC reception.
\r
284 declared in ASF\sam\components\ksz8851snl\ksz8851snl.c */
\r
285 extern uint8_t tmpbuf[1536];
\r
287 COMPILER_ALIGNED(8)
\r
288 static xKSZ8851_Device_t xMicrelDevice;
\r
290 static TaskHandle_t xTransmitHandle;
\r
292 /*-----------------------------------------------------------*/
\r
295 * Wait a fixed time for the link status to indicate the network is up.
\r
297 static BaseType_t xGMACWaitLS( TickType_t xMaxTime );
\r
300 * A deferred interrupt handler task that processes GMAC interrupts.
\r
302 static void prvEMACHandlerTask( void *pvParameters );
\r
305 * Try to obtain an Rx packet from the hardware.
\r
307 static uint32_t prvEMACRxPoll( void );
\r
309 static inline unsigned long ulReadMDIO( unsigned uAddress );
\r
311 static void ksz8851snl_low_level_init( void );
\r
313 static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void );
\r
315 /*-----------------------------------------------------------*/
\r
317 /* Bit map of outstanding ETH interrupt events for processing. Currently only
\r
318 the Rx interrupt is handled, although code is included for other events to
\r
319 enable future expansion. */
\r
320 static volatile uint32_t ulISREvents;
\r
322 /* A copy of PHY register 1: 'PHY_REG_01_BMSR' */
\r
323 static uint32_t ulPHYLinkStatus = 0;
\r
324 static volatile BaseType_t xGMACSwitchRequired;
\r
326 static void ksz8851snl_update( void );
\r
328 static void ksz8851snl_rx_init( void );
\r
330 static void ksz8851snl_tx_init( void );
\r
332 /* Holds the handle of the task used as a deferred interrupt processor. The
\r
333 handle is used so direct notifications can be sent to the task for all EMAC/DMA
\r
334 related interrupts. */
\r
335 TaskHandle_t xEMACTaskHandle = NULL;
\r
338 /*-----------------------------------------------------------*/
\r
340 BaseType_t xNetworkInterfaceInitialise( void )
\r
342 const TickType_t x5_Seconds = 5000UL;
\r
344 if( xEMACTaskHandle == NULL )
\r
346 ksz8851snl_low_level_init();
\r
348 /* Wait at most 5 seconds for a Link Status in the PHY. */
\r
349 xGMACWaitLS( pdMS_TO_TICKS( x5_Seconds ) );
\r
351 /* The handler task is created at the highest possible priority to
\r
352 ensure the interrupt handler can return directly to it. */
\r
353 xTaskCreate( prvEMACHandlerTask, "KSZ8851", configEMAC_TASK_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, &xEMACTaskHandle );
\r
354 configASSERT( xEMACTaskHandle );
\r
357 /* When returning non-zero, the stack will become active and
\r
358 start DHCP (in configured) */
\r
359 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
361 return ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0;
\r
363 /*-----------------------------------------------------------*/
\r
365 BaseType_t xGetPhyLinkStatus( void )
\r
367 BaseType_t xResult;
\r
369 /* This function returns true if the Link Status in the PHY is high. */
\r
370 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
381 /*-----------------------------------------------------------*/
\r
383 BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxNetworkBuffer, BaseType_t bReleaseAfterSend )
\r
385 BaseType_t xResult = pdFALSE;
\r
386 int txHead = xMicrelDevice.us_tx_head;
\r
388 /* Make sure the next descriptor is free. */
\r
389 if( xMicrelDevice.tx_busy[ txHead ] != pdFALSE )
\r
391 /* All TX buffers busy. */
\r
393 else if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) == 0 )
\r
395 /* Output: LS low. */
\r
399 /* Pass the packet. */
\r
400 xMicrelDevice.tx_buffers[ txHead ] = pxNetworkBuffer;
\r
401 /* The descriptor is now owned by Micrel. */
\r
402 xMicrelDevice.tx_busy[ txHead ] = pdTRUE;
\r
404 /* Move the head pointer. */
\r
405 if( ++txHead == MICREL_TX_BUFFERS )
\r
409 xMicrelDevice.us_tx_head = txHead;
\r
410 if( xEMACTaskHandle != NULL )
\r
412 xTaskNotifyGive( xEMACTaskHandle );
\r
415 #if( ipconfigZERO_COPY_TX_DRIVER != 1 )
\r
416 #warning Please ipconfigZERO_COPY_TX_DRIVER as 1
\r
418 configASSERT( bReleaseAfterSend != pdFALSE );
\r
421 if( ( xResult == pdFALSE ) && ( bReleaseAfterSend != pdFALSE ) )
\r
423 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
427 /*-----------------------------------------------------------*/
\r
429 /* This Micrel has numbered it's PHY registers in a different way.
\r
430 Translate the register index. */
\r
431 static int ks8851_phy_reg( int reg )
\r
434 case PHY_REG_00_BMCR:
\r
435 return REG_PHY_CNTL; // P1MBCR;
\r
436 case PHY_REG_01_BMSR:
\r
437 return REG_PHY_STATUS;
\r
438 case PHY_REG_02_PHYSID1:
\r
439 return REG_PHY_ID_LOW;
\r
440 case PHY_REG_03_PHYSID2:
\r
441 return REG_PHY_ID_HIGH;
\r
442 case PHY_REG_04_ADVERTISE:
\r
443 return REG_PHY_AUTO_NEGOTIATION;
\r
444 case PHY_REG_05_LPA:
\r
445 return REG_PHY_REMOTE_CAPABILITY;
\r
450 /*-----------------------------------------------------------*/
\r
452 static inline unsigned long ulReadMDIO( unsigned uAddress )
\r
454 uint16_t usPHYStatus;
\r
455 int ks8851_reg = ks8851_phy_reg( uAddress );
\r
457 if( ks8851_reg != 0 )
\r
459 usPHYStatus = ksz8851_reg_read( ks8851_reg );
\r
463 /* Other addresses not yet implemented. */
\r
466 return usPHYStatus;
\r
468 /*-----------------------------------------------------------*/
\r
470 static BaseType_t xGMACWaitLS( TickType_t xMaxTime )
\r
472 TickType_t xStartTime = xTaskGetTickCount();
\r
473 TickType_t xEndTime;
\r
474 BaseType_t xReturn;
\r
475 const TickType_t xShortTime = pdMS_TO_TICKS( 100UL );
\r
476 const uint32_t ulHz_Per_MHz = 1000000UL;
\r
480 xEndTime = xTaskGetTickCount();
\r
482 if( ( xEndTime - xStartTime ) > xMaxTime )
\r
484 /* Wated more than xMaxTime, return. */
\r
489 /* Check the link status again. */
\r
490 ulPHYLinkStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
492 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
494 /* Link is up - return. */
\r
499 /* Link is down - wait in the Blocked state for a short while (to allow
\r
500 other tasks to execute) before checking again. */
\r
501 vTaskDelay( xShortTime );
\r
504 FreeRTOS_printf( ( "xGMACWaitLS: %ld freq %lu Mz\n",
\r
506 sysclk_get_cpu_hz() / ulHz_Per_MHz ) );
\r
510 /*-----------------------------------------------------------*/
\r
512 static void vPioSetPinHigh(uint32_t ul_pin)
\r
514 Pio *p_pio = (Pio *)((uint32_t)PIOA + (PIO_DELTA * (ul_pin >> 5)));
\r
515 // Value to be driven on the I/O line: 1.
\r
516 p_pio->PIO_SODR = 1 << (ul_pin & 0x1F);
\r
520 * \brief Handler for SPI interrupt.
\r
522 void SPI_Handler(void)
\r
524 BaseType_t xDoWakeup = pdFALSE;
\r
525 BaseType_t xKSZTaskWoken = pdFALSE;
\r
526 uint32_t ulCurrentSPIStatus;
\r
527 uint32_t ulEnabledSPIStatus;
\r
529 ulCurrentSPIStatus = spi_read_status( KSZ8851SNL_SPI );
\r
530 ulEnabledSPIStatus = spi_read_interrupt_mask( KSZ8851SNL_SPI );
\r
531 ulCurrentSPIStatus &= ulEnabledSPIStatus;
\r
532 spi_disable_interrupt( KSZ8851SNL_SPI, ulCurrentSPIStatus );
\r
535 switch( xMicrelDevice.ul_spi_pdc_status )
\r
537 case SPI_PDC_RX_START:
\r
539 if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )
\r
541 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
\r
542 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_ERROR;
\r
543 xDoWakeup = pdTRUE;
\r
547 if( ( ulCurrentSPIStatus & SPI_SR_RXBUFF ) != 0 )
\r
549 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_COMPLETE;
\r
550 xDoWakeup = pdTRUE;
\r
556 case SPI_PDC_TX_START:
\r
558 /* Middle of TX. */
\r
559 if( ( ulCurrentSPIStatus & SPI_SR_OVRES ) != 0 )
\r
561 pdc_disable_transfer(g_p_spi_pdc, PERIPH_PTCR_RXTDIS | PERIPH_PTCR_TXTDIS);
\r
562 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_ERROR;
\r
563 xDoWakeup = pdTRUE;
\r
567 if( ( ulCurrentSPIStatus & SPI_SR_ENDRX ) != 0 )
\r
569 /* Enable RX complete interrupt. */
\r
570 spi_enable_interrupt( KSZ8851SNL_SPI, SPI_IER_RXBUFF );
\r
573 if( ( ulCurrentSPIStatus & SPI_END_OF_TX ) != 0 )
\r
575 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_COMPLETE;
\r
576 xDoWakeup = pdTRUE;
\r
581 } /* switch( xMicrelDevice.ul_spi_pdc_status ) */
\r
583 if( xDoWakeup != pdFALSE )
\r
585 if( xEMACTaskHandle != NULL )
\r
587 vTaskNotifyGiveFromISR( xEMACTaskHandle, ( BaseType_t * ) &xKSZTaskWoken );
\r
593 portEND_SWITCHING_ISR( xKSZTaskWoken );
\r
595 /*-----------------------------------------------------------*/
\r
597 static void INTN_Handler(uint32_t id, uint32_t mask)
\r
599 BaseType_t xKSZTaskWoken = pdFALSE;
\r
601 if( ( id == INTN_ID ) &&
\r
602 ( mask == INTN_PIN_MSK ) )
\r
604 /* Clear the PIO interrupt flags. */
\r
605 pio_get_interrupt_status( INTN_PIO );
\r
607 /* Set the INTN flag. */
\r
608 xMicrelDevice.ul_had_intn_interrupt++;
\r
609 if( xEMACTaskHandle != NULL )
\r
611 vTaskNotifyGiveFromISR( xEMACTaskHandle, &( xKSZTaskWoken ) );
\r
614 portEND_SWITCHING_ISR( xKSZTaskWoken );
\r
616 /*-----------------------------------------------------------*/
\r
619 * \brief Populate the RX descriptor ring buffers with pbufs.
\r
621 * \param p_ksz8851snl_dev Pointer to driver data structure.
\r
623 static void ksz8851snl_rx_populate_queue( void )
\r
625 uint32_t ul_index = 0;
\r
626 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
628 /* Set up the RX descriptors */
\r
629 for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {
\r
630 if( xMicrelDevice.rx_buffers[ ul_index ] == NULL )
\r
632 /* Allocate a new NetworkBufferDescriptor_t with the maximum size. */
\r
633 pxNetworkBuffer = pxGetNetworkBufferWithDescriptor( ipconfigNETWORK_MTU + 36, 100 );
\r
634 if( pxNetworkBuffer == NULL )
\r
636 FreeRTOS_printf( ( "ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t allocation failure\n" ) );
\r
637 configASSERT( 1 == 2 );
\r
640 /* Make sure lwIP is well configured so one NetworkBufferDescriptor_t can contain the maximum packet size. */
\r
641 //LWIP_ASSERT("ksz8851snl_rx_populate_queue: NetworkBufferDescriptor_t size too small!", pbuf_clen(pxNetworkBuffer) <= 1);
\r
643 /* Save NetworkBufferDescriptor_t pointer to be sent to lwIP upper layer. */
\r
644 xMicrelDevice.rx_buffers[ ul_index ] = pxNetworkBuffer;
\r
645 /* Pass it to Micrel for reception. */
\r
646 xMicrelDevice.rx_ready[ ul_index ] = pdFALSE;
\r
651 unsigned tx_space, wait_tx_space, tx_status, fhr_status;
\r
652 unsigned rx_debug = 0;
\r
654 * \brief Update Micrel state machine and perform required actions.
\r
656 * \param netif the lwIP network interface structure for this ethernetif.
\r
658 static void ksz8851snl_update()
\r
660 uint16_t txmir = 0;
\r
662 /* Check for free PDC. */
\r
663 switch( xMicrelDevice.ul_spi_pdc_status )
\r
665 case SPI_PDC_TX_ERROR:
\r
668 // /* TX step11: end TX transfer. */
\r
669 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
671 vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
\r
672 vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
675 /* Disable asynchronous transfer mode. */
\r
676 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
\r
678 /* TX step12: disable TXQ write access. */
\r
679 ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
\r
681 ulValue = ksz8851snl_reset_tx();
\r
683 xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
\r
685 FreeRTOS_printf( ("SPI_PDC_TX_ERROR %02X\n", ulValue ) );
\r
689 case SPI_PDC_RX_ERROR:
\r
692 /* TX step11: end TX transfer. */
\r
693 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
695 vTaskDelay( 2 ); gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
\r
696 vTaskDelay( 1 ); gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
699 /* Disable asynchronous transfer mode. */
\r
700 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
\r
702 /* TX step12: disable TXQ write access. */
\r
703 ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
\r
705 //ulValue = ksz8851snl_reset_rx();
\r
706 ulValue = ksz8851snl_reinit();
\r
708 xGMACWaitLS( pdMS_TO_TICKS( 5000UL ) );
\r
710 FreeRTOS_printf( ("SPI_PDC_RX_ERROR %02X\n", ulValue ) );
\r
714 switch( xMicrelDevice.ul_spi_pdc_status )
\r
718 int txTail = xMicrelDevice.us_tx_tail;
\r
721 * ========================== Handle RX ==========================
\r
723 if( ( xMicrelDevice.ul_had_intn_interrupt != 0 ) || ( xMicrelDevice.us_pending_frame > 0 ) )
\r
725 int rxHead = xMicrelDevice.us_rx_head;
\r
726 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
728 xMicrelDevice.ul_had_intn_interrupt = 0;
\r
730 if( xMicrelDevice.us_pending_frame == 0 )
\r
732 uint16_t int_status;
\r
733 /* RX step1: read interrupt status for INT_RX flag. */
\r
734 int_status = ksz8851_reg_read( REG_INT_STATUS );
\r
737 /* RX step2: disable all interrupts. */
\r
738 ksz8851_reg_write( REG_INT_MASK, 0 );
\r
740 /* RX step3: clear INT_RX flag. */
\r
741 ksz8851_reg_setbits( REG_INT_STATUS, INT_RX );
\r
743 /* RX step4-5: check for received frames. */
\r
744 xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
\r
745 if( xMicrelDevice.us_pending_frame == 0 )
\r
747 /* RX step24: enable INT_RX flag. */
\r
748 ksz8851_reg_write(REG_INT_MASK, INT_RX);
\r
753 xMicrelDevice.ul_had_intn_interrupt = 0;
\r
755 /* Now xMicrelDevice.us_pending_frame != 0 */
\r
757 /* Don't break Micrel state machine, wait for a free descriptor first! */
\r
758 if( xMicrelDevice.rx_ready[ rxHead ] != pdFALSE )
\r
760 FreeRTOS_printf( ( "ksz8851snl_update: out of free descriptor! [tail=%u head=%u]\n",
\r
761 xMicrelDevice.us_rx_tail, rxHead ) );
\r
764 pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxHead ];
\r
766 if( pxNetworkBuffer == NULL )
\r
768 ksz8851snl_rx_populate_queue();
\r
769 FreeRTOS_printf( ( "ksz8851snl_update: no buffer set [head=%u]\n", rxHead ) );
\r
773 /* RX step6: get RX packet status. */
\r
774 fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
\r
775 if( ( ( fhr_status & RX_VALID ) == 0 ) || ( ( fhr_status & RX_ERRORS ) != 0 ) )
\r
777 ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_CMD_FREE_PACKET);
\r
778 FreeRTOS_printf( ( "ksz8851snl_update: RX packet error!\n" ) );
\r
780 /* RX step4-5: check for received frames. */
\r
781 xMicrelDevice.us_pending_frame = ksz8851_reg_read(REG_RX_FRAME_CNT_THRES) >> 8;
\r
782 if( xMicrelDevice.us_pending_frame == 0 )
\r
784 /* RX step24: enable INT_RX flag. */
\r
785 ksz8851_reg_write(REG_INT_MASK, INT_RX);
\r
787 ulISREvents |= EMAC_IF_ERR_EVENT;
\r
792 /* RX step7: read frame length. */
\r
793 xLength = ksz8851_reg_read(REG_RX_FHR_BYTE_CNT) & RX_BYTE_CNT_MASK;
\r
795 /* RX step8: Drop packet if len is invalid or no descriptor available. */
\r
798 ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET );
\r
799 FreeRTOS_printf( ( "ksz8851snl_update: RX bad len!\n" ) );
\r
800 ulISREvents |= EMAC_IF_ERR_EVENT;
\r
804 size_t xReadLength = xLength;
\r
806 xMicrelDevice.ul_total_rx++;
\r
807 /* RX step9: reset RX frame pointer. */
\r
808 ksz8851_reg_clrbits(REG_RX_ADDR_PTR, ADDR_PTR_MASK);
\r
810 /* RX step10: start RXQ read access. */
\r
811 ksz8851_reg_setbits(REG_RXQ_CMD, RXQ_START);
\r
812 /* RX step11-17: start asynchronous FIFO read operation. */
\r
813 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_START;
\r
814 gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
\r
815 if( ( xReadLength & ( sizeof( size_t ) - 1 ) ) != 0 )
\r
817 xReadLength = ( xReadLength | ( sizeof( size_t ) - 1 ) ) + 1;
\r
820 /* Pass the buffer minus 2 bytes, see ksz8851snl.c: RXQ_TWOBYTE_OFFSET. */
\r
821 ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer - 2, xReadLength );
\r
822 /* Remove CRC and update buffer length. */
\r
824 pxNetworkBuffer->xDataLength = xLength;
\r
825 /* Wait for SPI interrupt to set status 'SPI_PDC_RX_COMPLETE'. */
\r
829 } /* ul_had_intn_interrupt || us_pending_frame */
\r
831 * ========================== Handle TX ==========================
\r
834 /* Fetch next packet to be sent. */
\r
835 if( ( xMicrelDevice.tx_busy[ txTail ] != pdFALSE ) &&
\r
836 ( xMicrelDevice.us_pending_frame == 0 ) &&
\r
837 ( xMicrelDevice.ul_had_intn_interrupt == 0 ) )
\r
839 NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
\r
840 size_t xLength = pxNetworkBuffer->xDataLength;
\r
841 int iIndex = xLength;
\r
843 xLength = 4 * ( ( xLength + 3 ) / 4 );
\r
844 while( iIndex < ( int ) xLength )
\r
846 pxNetworkBuffer->pucEthernetBuffer[ iIndex ] = '\0';
\r
849 pxNetworkBuffer->xDataLength = xLength;
\r
851 /* TX step1: check if TXQ memory size is available for transmit. */
\r
852 txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
\r
853 txmir = txmir & TX_MEM_AVAILABLE_MASK;
\r
855 if( txmir < ( xLength + 8 ) )
\r
857 if( wait_tx_space == pdFALSE )
\r
859 tx_status = ksz8851_reg_read( REG_TX_STATUS );
\r
860 fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
\r
861 wait_tx_space = pdTRUE;
\r
871 /* TX step2: disable all interrupts. */
\r
872 ksz8851_reg_write( REG_INT_MASK, 0 );
\r
874 xMicrelDevice.tx_space -= xLength;
\r
876 /* TX step3: enable TXQ write access. */
\r
877 ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START );
\r
878 /* TX step4-8: perform FIFO write operation. */
\r
879 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_START;
\r
880 xMicrelDevice.tx_cur_buffer = pxNetworkBuffer;
\r
881 /* Bring SPI SS low. */
\r
882 gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
\r
883 xMicrelDevice.ul_total_tx++;
\r
885 ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
\r
889 break; /* SPI_PDC_IDLE */
\r
891 case SPI_PDC_RX_COMPLETE:
\r
893 int rxHead = xMicrelDevice.us_rx_head;
\r
894 /* RX step18-19: pad with dummy data to keep dword alignment. */
\r
895 /* Packet lengths will be rounded up to a multiple of "sizeof size_t". */
\r
896 // xLength = xMicrelDevice.rx_buffers[ rxHead ]->xDataLength & 3;
\r
897 // if( xLength != 0 )
\r
899 // ksz8851_fifo_dummy( 4 - xLength );
\r
902 /* RX step20: end RX transfer. */
\r
903 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
905 /* Disable asynchronous transfer mode. */
\r
906 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
\r
908 /* RX step21: end RXQ read access. */
\r
909 ksz8851_reg_clrbits(REG_RXQ_CMD, RXQ_START);
\r
911 /* RX step22-23: update frame count to be read. */
\r
912 xMicrelDevice.us_pending_frame -= 1;
\r
914 /* RX step24: enable INT_RX flag if transfer complete. */
\r
915 if( xMicrelDevice.us_pending_frame == 0 )
\r
917 ksz8851_reg_write(REG_INT_MASK, INT_RX);
\r
920 /* Mark descriptor ready to be read. */
\r
921 xMicrelDevice.rx_ready[ rxHead ] = pdTRUE;
\r
922 if( ++rxHead == MICREL_RX_BUFFERS )
\r
926 xMicrelDevice.us_rx_head = rxHead;
\r
927 if( rx_debug != 0 )
\r
931 txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
\r
932 txmir = txmir & TX_MEM_AVAILABLE_MASK;
\r
934 /* Tell prvEMACHandlerTask that RX packets are available. */
\r
935 ulISREvents |= EMAC_IF_RX_EVENT;
\r
936 } /* case SPI_PDC_RX_COMPLETE */
\r
939 case SPI_PDC_TX_COMPLETE:
\r
941 int txTail = xMicrelDevice.us_tx_tail;
\r
942 NetworkBufferDescriptor_t *pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
\r
945 /* TX step9-10: pad with dummy data to keep dword alignment. */
\r
946 /* Not necessary: length is already a multiple of 4. */
\r
947 xLength = pxNetworkBuffer->xDataLength & 3;
\r
950 // ksz8851_fifo_dummy( 4 - xLength );
\r
953 // /* TX step11: end TX transfer. */
\r
954 gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
\r
956 /* Disable asynchronous transfer mode. */
\r
957 xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
\r
959 /* TX step12: disable TXQ write access. */
\r
960 ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
\r
962 xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
\r
964 /* TX step12.1: enqueue frame in TXQ. */
\r
965 ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
\r
967 /* RX step13: enable INT_RX flag. */
\r
968 // ksz8851_reg_write( REG_INT_MASK, INT_RX );
\r
969 /* Buffer sent, free the corresponding buffer and mark descriptor as owned by software. */
\r
970 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
972 xMicrelDevice.tx_buffers[ txTail ] = NULL;
\r
973 xMicrelDevice.tx_busy[ txTail ] = pdFALSE;
\r
974 if( ++txTail == MICREL_TX_BUFFERS )
\r
979 xMicrelDevice.us_tx_tail = txTail;
\r
981 //xMicrelDevice.ul_had_intn_interrupt = 1;
\r
982 if( xTransmitHandle != NULL )
\r
984 xTaskNotifyGive( xTransmitHandle );
\r
986 #warning moved downward
\r
987 /* RX step13: enable INT_RX flag. */
\r
988 ksz8851_reg_write( REG_INT_MASK, INT_RX );
\r
989 /* Prevent the EMAC task from sleeping a single time. */
\r
990 ulISREvents |= EMAC_IF_TX_EVENT;
\r
991 } /* case SPI_PDC_TX_COMPLETE */
\r
993 } /* switch( xMicrelDevice.ul_spi_pdc_status ) */
\r
997 * \brief Set up the RX descriptor ring buffers.
\r
999 * This function sets up the descriptor list used for RX packets.
\r
1002 static void ksz8851snl_rx_init()
\r
1004 uint32_t ul_index = 0;
\r
1006 /* Init pointer index. */
\r
1007 xMicrelDevice.us_rx_head = 0;
\r
1008 xMicrelDevice.us_rx_tail = 0;
\r
1010 /* Set up the RX descriptors. */
\r
1011 for (ul_index = 0; ul_index < MICREL_RX_BUFFERS; ul_index++) {
\r
1012 xMicrelDevice.rx_buffers[ul_index] = NULL;
\r
1013 xMicrelDevice.rx_ready[ul_index] = pdFALSE;
\r
1016 /* Build RX buffer and descriptors. */
\r
1017 ksz8851snl_rx_populate_queue();
\r
1021 * \brief Set up the TX descriptor ring buffers.
\r
1023 * This function sets up the descriptor list used for TX packets.
\r
1026 static void ksz8851snl_tx_init()
\r
1028 uint32_t ul_index = 0;
\r
1030 /* Init TX index pointer. */
\r
1031 xMicrelDevice.us_tx_head = 0;
\r
1032 xMicrelDevice.us_tx_tail = 0;
\r
1034 /* Set up the TX descriptors */
\r
1035 for( ul_index = 0; ul_index < MICREL_TX_BUFFERS; ul_index++ )
\r
1037 xMicrelDevice.tx_busy[ul_index] = pdFALSE;
\r
1039 xMicrelDevice.tx_space = 6144;
\r
1043 * \brief Initialize ksz8851snl ethernet controller.
\r
1045 * \note Called from ethernetif_init().
\r
1047 * \param netif the lwIP network interface structure for this ethernetif.
\r
1049 static void ksz8851snl_low_level_init( void )
\r
1051 ksz8851snl_rx_init();
\r
1052 ksz8851snl_tx_init();
\r
1054 /* Enable NVIC interrupts. */
\r
1055 NVIC_SetPriority(SPI_IRQn, INT_PRIORITY_SPI);
\r
1056 NVIC_EnableIRQ(SPI_IRQn);
\r
1058 /* Initialize SPI link. */
\r
1059 if( ksz8851snl_init() < 0 )
\r
1061 FreeRTOS_printf( ( "ksz8851snl_low_level_init: failed to initialize the Micrel driver!\n" ) );
\r
1062 configASSERT(0 == 1);
\r
1064 memset( xMicrelDevice.pusHashTable, 255, sizeof( xMicrelDevice.pusHashTable ) );
\r
1065 ksz8851_reg_write( REG_MAC_HASH_0, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 0 ] ) );
\r
1066 ksz8851_reg_write( REG_MAC_HASH_2, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 1 ] ) );
\r
1067 ksz8851_reg_write( REG_MAC_HASH_4, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 2 ] ) );
\r
1068 ksz8851_reg_write( REG_MAC_HASH_6, FreeRTOS_htons( xMicrelDevice.pusHashTable[ 3 ] ) );
\r
1070 /* Initialize interrupt line INTN. */
\r
1071 configure_intn( INTN_Handler );
\r
1075 * \brief Use pre-allocated pbuf as DMA source and return the incoming packet.
\r
1077 * \param netif the lwIP network interface structure for this ethernetif.
\r
1079 * \return a pbuf filled with the received packet (including MAC header).
\r
1080 * 0 on memory error.
\r
1082 static NetworkBufferDescriptor_t *ksz8851snl_low_level_input( void )
\r
1084 NetworkBufferDescriptor_t *pxNetworkBuffer = NULL;
\r
1085 int rxTail = xMicrelDevice.us_rx_tail;
\r
1087 /* Check that descriptor is owned by software (ie packet received). */
\r
1088 if( xMicrelDevice.rx_ready[ rxTail ] != pdFALSE )
\r
1091 /* Fetch pre-allocated buffer */
\r
1092 pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxTail ];
\r
1094 /* Remove this pbuf from its descriptor. */
\r
1095 xMicrelDevice.rx_buffers[ rxTail ] = NULL;
\r
1097 /* Clears rx_ready and sets rx_buffers. */
\r
1098 ksz8851snl_rx_populate_queue();
\r
1100 if( ++rxTail == MICREL_RX_BUFFERS )
\r
1104 xMicrelDevice.us_rx_tail = rxTail;
\r
1107 return pxNetworkBuffer;
\r
1109 /*-----------------------------------------------------------*/
\r
1111 static uint32_t prvEMACRxPoll( void )
\r
1113 NetworkBufferDescriptor_t *pxNetworkBuffer;
\r
1114 IPStackEvent_t xRxEvent = { eNetworkRxEvent, NULL };
\r
1115 uint32_t ulReturnValue = 0;
\r
1119 /* Only for logging. */
\r
1120 int rxTail = xMicrelDevice.us_rx_tail;
\r
1121 EthernetHeader_t *pxEthernetHeader;
\r
1123 pxNetworkBuffer = ksz8851snl_low_level_input();
\r
1125 if( pxNetworkBuffer == NULL )
\r
1129 pxEthernetHeader = ( EthernetHeader_t * ) ( pxNetworkBuffer->pucEthernetBuffer );
\r
1131 if( ( pxEthernetHeader->usFrameType != ipIPv4_FRAME_TYPE ) &&
\r
1132 ( pxEthernetHeader->usFrameType != ipARP_FRAME_TYPE ) )
\r
1134 FreeRTOS_printf( ( "Frame type %02X received\n", pxEthernetHeader->usFrameType ) );
\r
1138 xRxEvent.pvData = ( void * )pxNetworkBuffer;
\r
1139 /* Send the descriptor to the IP task for processing. */
\r
1140 if( xSendEventStructToIPTask( &xRxEvent, 100UL ) != pdTRUE )
\r
1142 vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
\r
1143 iptraceETHERNET_RX_EVENT_LOST();
\r
1144 FreeRTOS_printf( ( "prvEMACRxPoll: Can not queue return packet!\n" ) );
\r
1148 return ulReturnValue;
\r
1150 /*-----------------------------------------------------------*/
\r
1152 static void prvEMACHandlerTask( void *pvParameters )
\r
1154 TimeOut_t xPhyTime;
\r
1155 TickType_t xPhyRemTime;
\r
1156 TickType_t xLoggingTime;
\r
1157 UBaseType_t uxLastMinBufferCount = 0;
\r
1158 UBaseType_t uxCurrentCount;
\r
1159 BaseType_t xResult = 0;
\r
1161 const TickType_t ulMaxBlockTime = pdMS_TO_TICKS( EMAC_MAX_BLOCK_TIME_MS );
\r
1162 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
1163 UBaseType_t uxLastMinQueueSpace = 0;
\r
1166 /* Remove compiler warnings about unused parameters. */
\r
1167 ( void ) pvParameters;
\r
1169 configASSERT( xEMACTaskHandle );
\r
1171 vTaskSetTimeOutState( &xPhyTime );
\r
1172 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
1173 xLoggingTime = xTaskGetTickCount();
\r
1177 uxCurrentCount = uxGetMinimumFreeNetworkBuffers();
\r
1178 if( uxLastMinBufferCount != uxCurrentCount )
\r
1180 /* The logging produced below may be helpful
\r
1181 while tuning +TCP: see how many buffers are in use. */
\r
1182 uxLastMinBufferCount = uxCurrentCount;
\r
1183 FreeRTOS_printf( ( "Network buffers: %lu lowest %lu\n",
\r
1184 uxGetNumberOfFreeNetworkBuffers(), uxCurrentCount ) );
\r
1187 #if( ipconfigCHECK_IP_QUEUE_SPACE != 0 )
\r
1189 uxCurrentCount = uxGetMinimumIPQueueSpace();
\r
1190 if( uxLastMinQueueSpace != uxCurrentCount )
\r
1192 /* The logging produced below may be helpful
\r
1193 while tuning +TCP: see how many buffers are in use. */
\r
1194 uxLastMinQueueSpace = uxCurrentCount;
\r
1195 FreeRTOS_printf( ( "Queue space: lowest %lu\n", uxCurrentCount ) );
\r
1198 #endif /* ipconfigCHECK_IP_QUEUE_SPACE */
\r
1200 /* Run the state-machine of the ksz8851 driver. */
\r
1201 ksz8851snl_update();
\r
1203 if( ( ulISREvents & EMAC_IF_ALL_EVENT ) == 0 )
\r
1205 /* No events to process now, wait for the next. */
\r
1206 ulTaskNotifyTake( pdTRUE, ulMaxBlockTime );
\r
1209 if( ( xTaskGetTickCount() - xLoggingTime ) > 10000 )
\r
1211 xLoggingTime += 10000;
\r
1212 FreeRTOS_printf( ( "Now Tx/Rx %7d /%7d\n",
\r
1213 xMicrelDevice.ul_total_tx, xMicrelDevice.ul_total_rx ) );
\r
1216 if( ( ulISREvents & EMAC_IF_RX_EVENT ) != 0 )
\r
1218 ulISREvents &= ~EMAC_IF_RX_EVENT;
\r
1220 /* Wait for the EMAC interrupt to indicate that another packet has been
\r
1222 xResult = prvEMACRxPoll();
\r
1225 if( ( ulISREvents & EMAC_IF_TX_EVENT ) != 0 )
\r
1227 /* Future extension: code to release TX buffers if zero-copy is used. */
\r
1228 ulISREvents &= ~EMAC_IF_TX_EVENT;
\r
1231 if( ( ulISREvents & EMAC_IF_ERR_EVENT ) != 0 )
\r
1233 /* Future extension: logging about errors that occurred. */
\r
1234 ulISREvents &= ~EMAC_IF_ERR_EVENT;
\r
1239 /* As long as packets are being received, assume that
\r
1240 the Link Status is high. */
\r
1241 ulPHYLinkStatus |= BMSR_LINK_STATUS;
\r
1242 /* A packet was received. No need to check for the PHY status now,
\r
1243 but set a timer to check it later on. */
\r
1244 vTaskSetTimeOutState( &xPhyTime );
\r
1245 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
1248 else if( ( xTaskCheckForTimeOut( &xPhyTime, &xPhyRemTime ) != pdFALSE ) &&
\r
1249 ( xMicrelDevice.ul_spi_pdc_status == SPI_PDC_IDLE ) )
\r
1251 /* Check the link status again. */
\r
1252 xStatus = ulReadMDIO( PHY_REG_01_BMSR );
\r
1254 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != ( xStatus & BMSR_LINK_STATUS ) )
\r
1256 ulPHYLinkStatus = xStatus;
\r
1257 FreeRTOS_printf( ( "prvEMACHandlerTask: PHY LS now %d\n", ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 ) );
\r
1260 vTaskSetTimeOutState( &xPhyTime );
\r
1261 if( ( ulPHYLinkStatus & BMSR_LINK_STATUS ) != 0 )
\r
1263 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_HIGH_CHECK_TIME_MS );
\r
1267 xPhyRemTime = pdMS_TO_TICKS( PHY_LS_LOW_CHECK_TIME_MS );
\r
1272 /*-----------------------------------------------------------*/
\r