static void ksz8851snl_update()

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 ) */
}