in portable/NetworkInterface/ksz8851snl/NetworkInterface.c [680:1041]
static void ksz8851snl_update()
{
uint16_t txmir = 0;
/* Check for free PDC. */
switch( xMicrelDevice.ul_spi_pdc_status )
{
case SPI_PDC_TX_ERROR:
{
uint32_t ulValue;
/* / * TX step11: end TX transfer. * / */
gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
vTaskDelay( 2 );
gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
vTaskDelay( 1 );
gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
vTaskDelay( 1 );
/* Disable asynchronous transfer mode. */
xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
/* TX step12: disable TXQ write access. */
ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
ulValue = ksz8851snl_reset_tx();
xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
FreeRTOS_printf( ( "SPI_PDC_TX_ERROR %02X\n", ulValue ) );
}
break;
case SPI_PDC_RX_ERROR:
{
uint32_t ulValue;
/* TX step11: end TX transfer. */
gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
vTaskDelay( 2 );
gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
vTaskDelay( 1 );
gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
vTaskDelay( 1 );
/* Disable asynchronous transfer mode. */
xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
/* TX step12: disable TXQ write access. */
ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
/*ulValue = ksz8851snl_reset_rx(); */
ulValue = ksz8851snl_reinit();
xGMACWaitLS( pdMS_TO_TICKS( 5000UL ) );
FreeRTOS_printf( ( "SPI_PDC_RX_ERROR %02X\n", ulValue ) );
}
break;
}
switch( xMicrelDevice.ul_spi_pdc_status )
{
case SPI_PDC_IDLE:
{
int txTail = xMicrelDevice.us_tx_tail;
/*
* ========================== Handle RX ==========================
*/
if( ( xMicrelDevice.ul_had_intn_interrupt != 0 ) || ( xMicrelDevice.us_pending_frame > 0 ) )
{
int rxHead = xMicrelDevice.us_rx_head;
NetworkBufferDescriptor_t * pxNetworkBuffer;
#warning try
xMicrelDevice.ul_had_intn_interrupt = 0;
if( xMicrelDevice.us_pending_frame == 0 )
{
uint16_t int_status;
/* RX step1: read interrupt status for INT_RX flag. */
int_status = ksz8851_reg_read( REG_INT_STATUS );
/* RX step2: disable all interrupts. */
ksz8851_reg_write( REG_INT_MASK, 0 );
/* RX step3: clear INT_RX flag. */
ksz8851_reg_setbits( REG_INT_STATUS, INT_RX );
/* RX step4-5: check for received frames. */
xMicrelDevice.us_pending_frame = ksz8851_reg_read( REG_RX_FRAME_CNT_THRES ) >> 8;
if( xMicrelDevice.us_pending_frame == 0 )
{
/* RX step24: enable INT_RX flag. */
ksz8851_reg_write( REG_INT_MASK, INT_RX );
return;
}
}
#warning try
xMicrelDevice.ul_had_intn_interrupt = 0;
/* Now xMicrelDevice.us_pending_frame != 0 */
/* Don't break Micrel state machine, wait for a free descriptor first! */
if( xMicrelDevice.rx_ready[ rxHead ] != pdFALSE )
{
FreeRTOS_printf( ( "ksz8851snl_update: out of free descriptor! [tail=%u head=%u]\n",
xMicrelDevice.us_rx_tail, rxHead ) );
return;
}
pxNetworkBuffer = xMicrelDevice.rx_buffers[ rxHead ];
if( pxNetworkBuffer == NULL )
{
ksz8851snl_rx_populate_queue();
FreeRTOS_printf( ( "ksz8851snl_update: no buffer set [head=%u]\n", rxHead ) );
return;
}
/* RX step6: get RX packet status. */
fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
if( ( ( fhr_status & RX_VALID ) == 0 ) || ( ( fhr_status & RX_ERRORS ) != 0 ) )
{
ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET );
FreeRTOS_printf( ( "ksz8851snl_update: RX packet error!\n" ) );
/* RX step4-5: check for received frames. */
xMicrelDevice.us_pending_frame = ksz8851_reg_read( REG_RX_FRAME_CNT_THRES ) >> 8;
if( xMicrelDevice.us_pending_frame == 0 )
{
/* RX step24: enable INT_RX flag. */
ksz8851_reg_write( REG_INT_MASK, INT_RX );
}
ulISREvents |= EMAC_IF_ERR_EVENT;
}
else
{
size_t xLength;
/* RX step7: read frame length. */
xLength = ksz8851_reg_read( REG_RX_FHR_BYTE_CNT ) & RX_BYTE_CNT_MASK;
/* RX step8: Drop packet if len is invalid or no descriptor available. */
if( xLength == 0 )
{
ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_CMD_FREE_PACKET );
FreeRTOS_printf( ( "ksz8851snl_update: RX bad len!\n" ) );
ulISREvents |= EMAC_IF_ERR_EVENT;
}
else
{
size_t xReadLength = xLength;
xMicrelDevice.ul_total_rx++;
/* RX step9: reset RX frame pointer. */
ksz8851_reg_clrbits( REG_RX_ADDR_PTR, ADDR_PTR_MASK );
/* RX step10: start RXQ read access. */
ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START );
/* RX step11-17: start asynchronous FIFO read operation. */
xMicrelDevice.ul_spi_pdc_status = SPI_PDC_RX_START;
gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
if( ( xReadLength & ( sizeof( size_t ) - 1 ) ) != 0 )
{
xReadLength = ( xReadLength | ( sizeof( size_t ) - 1 ) ) + 1;
}
/* Pass the buffer minus 2 bytes, see ksz8851snl.c: RXQ_TWOBYTE_OFFSET. */
ksz8851_fifo_read( pxNetworkBuffer->pucEthernetBuffer - 2, xReadLength );
/* Remove CRC and update buffer length. */
xLength -= 4;
pxNetworkBuffer->xDataLength = xLength;
/* Wait for SPI interrupt to set status 'SPI_PDC_RX_COMPLETE'. */
}
}
break;
} /* ul_had_intn_interrupt || us_pending_frame */
/*
* ========================== Handle TX ==========================
*/
/* Fetch next packet to be sent. */
if( ( xMicrelDevice.tx_busy[ txTail ] != pdFALSE ) &&
( xMicrelDevice.us_pending_frame == 0 ) &&
( xMicrelDevice.ul_had_intn_interrupt == 0 ) )
{
NetworkBufferDescriptor_t * pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
size_t xLength = pxNetworkBuffer->xDataLength;
int iIndex = xLength;
xLength = 4 * ( ( xLength + 3 ) / 4 );
while( iIndex < ( int ) xLength )
{
pxNetworkBuffer->pucEthernetBuffer[ iIndex ] = '\0';
iIndex++;
}
pxNetworkBuffer->xDataLength = xLength;
/* TX step1: check if TXQ memory size is available for transmit. */
txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
txmir = txmir & TX_MEM_AVAILABLE_MASK;
if( txmir < ( xLength + 8 ) )
{
if( wait_tx_space == pdFALSE )
{
tx_status = ksz8851_reg_read( REG_TX_STATUS );
fhr_status = ksz8851_reg_read( REG_RX_FHR_STATUS );
wait_tx_space = pdTRUE;
}
/*return; */
rx_debug = 1;
tx_space = txmir;
}
else
{
tx_space = txmir;
/* TX step2: disable all interrupts. */
ksz8851_reg_write( REG_INT_MASK, 0 );
xMicrelDevice.tx_space -= xLength;
/* TX step3: enable TXQ write access. */
ksz8851_reg_setbits( REG_RXQ_CMD, RXQ_START );
/* TX step4-8: perform FIFO write operation. */
xMicrelDevice.ul_spi_pdc_status = SPI_PDC_TX_START;
xMicrelDevice.tx_cur_buffer = pxNetworkBuffer;
/* Bring SPI SS low. */
gpio_set_pin_low( KSZ8851SNL_CSN_GPIO );
xMicrelDevice.ul_total_tx++;
ksz8851_fifo_write( pxNetworkBuffer->pucEthernetBuffer, xLength, xLength );
}
}
}
break; /* SPI_PDC_IDLE */
case SPI_PDC_RX_COMPLETE:
{
int rxHead = xMicrelDevice.us_rx_head;
/* RX step18-19: pad with dummy data to keep dword alignment. */
/* Packet lengths will be rounded up to a multiple of "sizeof size_t". */
/* xLength = xMicrelDevice.rx_buffers[ rxHead ]->xDataLength & 3; */
/* if( xLength != 0 ) */
/* { */
/* ksz8851_fifo_dummy( 4 - xLength ); */
/* } */
/* RX step20: end RX transfer. */
gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
/* Disable asynchronous transfer mode. */
xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
/* RX step21: end RXQ read access. */
ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
/* RX step22-23: update frame count to be read. */
xMicrelDevice.us_pending_frame -= 1;
/* RX step24: enable INT_RX flag if transfer complete. */
if( xMicrelDevice.us_pending_frame == 0 )
{
ksz8851_reg_write( REG_INT_MASK, INT_RX );
}
/* Mark descriptor ready to be read. */
xMicrelDevice.rx_ready[ rxHead ] = pdTRUE;
if( ++rxHead == MICREL_RX_BUFFERS )
{
rxHead = 0;
}
xMicrelDevice.us_rx_head = rxHead;
if( rx_debug != 0 )
{
uint32_t txmir;
rx_debug = 0;
txmir = ksz8851_reg_read( REG_TX_MEM_INFO );
txmir = txmir & TX_MEM_AVAILABLE_MASK;
}
/* Tell prvEMACHandlerTask that RX packets are available. */
ulISREvents |= EMAC_IF_RX_EVENT;
} /* case SPI_PDC_RX_COMPLETE */
break;
case SPI_PDC_TX_COMPLETE:
{
int txTail = xMicrelDevice.us_tx_tail;
NetworkBufferDescriptor_t * pxNetworkBuffer = xMicrelDevice.tx_buffers[ txTail ];
size_t xLength;
/* TX step9-10: pad with dummy data to keep dword alignment. */
/* Not necessary: length is already a multiple of 4. */
xLength = pxNetworkBuffer->xDataLength & 3;
if( xLength != 0 )
{
/* ksz8851_fifo_dummy( 4 - xLength ); */
}
/* / * TX step11: end TX transfer. * / */
gpio_set_pin_high( KSZ8851SNL_CSN_GPIO );
/* Disable asynchronous transfer mode. */
xMicrelDevice.ul_spi_pdc_status = SPI_PDC_IDLE;
/* TX step12: disable TXQ write access. */
ksz8851_reg_clrbits( REG_RXQ_CMD, RXQ_START );
xMicrelDevice.tx_space = ksz8851_reg_read( REG_TX_MEM_INFO ) & TX_MEM_AVAILABLE_MASK;
/* TX step12.1: enqueue frame in TXQ. */
ksz8851_reg_setbits( REG_TXQ_CMD, TXQ_ENQUEUE );
/* RX step13: enable INT_RX flag. */
/* ksz8851_reg_write( REG_INT_MASK, INT_RX ); */
/* Buffer sent, free the corresponding buffer and mark descriptor as owned by software. */
vReleaseNetworkBufferAndDescriptor( pxNetworkBuffer );
xMicrelDevice.tx_buffers[ txTail ] = NULL;
xMicrelDevice.tx_busy[ txTail ] = pdFALSE;
if( ++txTail == MICREL_TX_BUFFERS )
{
txTail = 0;
}
xMicrelDevice.us_tx_tail = txTail;
/* Experiment. */
/*xMicrelDevice.ul_had_intn_interrupt = 1; */
if( xTransmitHandle != NULL )
{
xTaskNotifyGive( xTransmitHandle );
}
#warning moved downward
/* RX step13: enable INT_RX flag. */
ksz8851_reg_write( REG_INT_MASK, INT_RX );
/* Prevent the EMAC task from sleeping a single time. */
ulISREvents |= EMAC_IF_TX_EVENT;
} /* case SPI_PDC_TX_COMPLETE */
break;
} /* switch( xMicrelDevice.ul_spi_pdc_status ) */
}