if_mcf5272.c

来自「开放源码实时操作系统源码.」· C语言 代码 · 共 1,887 行 · 第 1/5 页

C
1,887
字号
                buf_ptr = (u8_t*)&eth_data->pkt_buf;


            }

            /*   If there is  a copy  wrap error  or the  Rx packet  filter */
            /* rejected the packet, pass it to the upper layer.  Otherwise, */
            /* release the buffer descriptors.                              */

            if (!eth_rx_pkt_filter(buf_ptr, len))
            {

                /*   Inform the upper layer of a complete packet.           */

                 (sc->funs->eth_drv->recv)(sc, len);
            }
            else
            {

                /*   Release the buffer descriptors.                        */

                nbuf_rx_release_good_pkt(p_buf_info);


                /*   Notify the FEC that there is at least a receive buffer */
                /* descriptos available for the FEC.                        */

                put_reg(MCF5272_SIM->enet.rdar, MCF5272_FEC_RDAR_DESTACT);

            }

        }

    }
    else
    {

        /*   Indicates that there are no more receive packets.              */

        return false;
    }
    return true;

}
/*******************************************************************************
MCF5272_fec_transmit_handler() - Transmit handler informs the upper
layer packet of a completion of a transmit packet.
*/

static
bool MCF5272_fec_transmit_handler(struct eth_drv_sc * sc)

/*      If the FEC has successfull transmitted a packet, then realease  the */
/* buffer used for the packet so that the buffer can be reused.             */

{

    /*   Check to see which frame has completed sending so we can tell  the */
    /* upper layer to free up ts buffer.                                    */

    buf_info_t* p_buf_info = PBUF_INFO(sc);
    MCF5272_fec_priv_data_t* eth_data = PMCF5272_FEC_DATA(sc);
    NBUF* pNbd = NULL;
    int_t index, i;
    tx_keys_t key_entry;
    bool result = true;
    NBUF* next_bd;


    /*   Check wether there is any pending transmit buffer descriptors that */
    /* are to deallocated.                                                  */

    if ((index = nbuf_peek_tx_key(p_buf_info)) != -1)
    {

        /*   Get the pointer to the buffer descriptor so that the flags  in */
        /* the status word in the buffer descriptor can be examined.        */

        NBUF* pNbuf = nbuf_tx_get(p_buf_info, index);

        CYG_ASSERT(pNbuf->status & TX_BD_L, "Index to BD is not the last BD");

        if (pNbuf->status & TX_BD_R)
        {


            /*   Increment the number of times the device driver  discovers */
            /* that the buffer descriptor is still in use by the FEC and it */
            /* has been skipped.                                            */

            if ((next_bd = nbuf_peek_bd_ahead(p_buf_info)))
            {
                if (!(next_bd->status & TX_BD_R) &&
                    pNbuf->status & TX_BD_R)
                {

                    eth_data->diag_counters.tx_not_complete_cnt++;
                    goto RELEASE_BUF;

                }
            }

            /*   If the buffer not ready we return immediatly.               */

            return false;

         }

RELEASE_BUF:

        /*   Dequeue the packet from the trasnmt packet queue to  indicate */
        /* that the packet is not being transmitted by the FEC.            */

        nbuf_deq_tx_key(p_buf_info, &key_entry);

        /*   Release the used buffers.                                     */

        for ( i = 0; i < key_entry.num_dbufs; i++)

        {

            /*   Get the BD based on the index.                            */

            pNbd = nbuf_tx_get(p_buf_info,
                              (key_entry.start_index + i) % NUM_TXBDS);

            /*   The last buffer descriptor of the packet.                 */

            if (pNbd->status & TX_BD_L)
            {

                if (pNbd->status & TX_BD_RL)
                {

                    /*   Update the number of retries.                     */

                    eth_data->diag_counters.tx_retry_cnt += 16;
                    eth_data->diag_counters.tx_err_cnt++;
                    eth_data->diag_counters.tx_exes_retry_cnt++;
                }
                else
                {

                    /*   Check for  error status.   If there  is an  error */
                    /* proceed the  increment  the  appropriate  statistic */
                    /* counter.                                            */

                    if (pNbd->status  & (TX_BD_UN |
                                         TX_BD_LC |
                                         TX_BD_CSL |
                                         TX_BD_HB))
                    {

                        if (pNbd->status & TX_BD_HB)
                        {

                            /*   Heartbeat error count.                     */

                            eth_data->diag_counters.tx_hb_err_cnt++;
                        }

                        if (pNbd->status & TX_BD_UN)
                        {

                            /*   Transmit underrun error count.             */

                            eth_data->diag_counters.tx_underrun_cnt++;
                        }

                        if (pNbd->status & TX_BD_CSL)
                        {

                            /*   Transmit carrier loss count.               */

                            eth_data->diag_counters.tx_carrrier_loss_cnt++;
                        }

                        if (pNbd->status & TX_BD_LC)
                        {

                            /*   Update the late collision counter.         */

                            eth_data->diag_counters.tx_late_col_cnt++;
                        }

                        /*   Update the number transmit error count.       */

                        eth_data->diag_counters.tx_err_cnt++;
                    }
                    else
                    {
                        /* Update the diagnostic counters */

                        if (pNbd->status & TX_BD_DEF)
                        {
                            /* Defer indication count. */
                            eth_data->diag_counters.tx_def_cnt++;
                        }

                        /*   Update the number of transmitted packets.     */

                        eth_data->diag_counters.tx_pk_cnt++;

                        /*   Update the  transmitted packet  size.  If  the */
                        /* size is less than the minimum size then take the */
                        /* minimum size as the  actual frame length.   This */
                        /* is because we take account of the pad bytes that */
                        /* the FEC appends when  it sends  out frames  that */
                        /* has less than the minimum length.                */

                        eth_data->diag_counters.tx_bytes_cnt +=
                            key_entry.pk_len < ETH_MIN_SIZE ? ETH_MIN_SIZE :
                            key_entry.pk_len;
                    }

                    /*   Get the number of retries.                        */

                    eth_data->diag_counters.tx_retry_cnt +=
                        (pNbd->status >> 2) & 0xF;
                }

            }

            /*   Release the buffer descriptor so that it can be reused to */
            /* transmit the next packet.                                   */

            nbuf_tx_release(pNbd);

            /*   If the start_index is the same  as the index to the  last */
            /* buffer descriptor, then quit the loop.                      */

        }

        /*   Decrement the number of busy descriptors.                     */

        p_buf_info->num_busy_bd -=  key_entry.num_dbufs;

         switch(key_entry.key_type)
         {
             case TX_KEY_ECOS:

             /*   Inform the upper layer of a completion of the packet.     */

             (sc->funs->eth_drv->tx_done)(sc,
                                         key_entry.tx_key,
                                         0);
             break;
         case TX_KEY_USER:

             /*   Inform the application of the completion of the packet.   */

             eth_send_done(key_entry.tx_key);
             break;
         }

    }
    else
    {

        /*   Retrun false to indicate that the transmit buffer is empty.    */

        result =  false;
    }

    /*   Indicate  that  the  packet  at  the  transmit  buffer  has   been */
    /* successfully handled.                                                */

    return result;
}


/*      This routine informs  the upper  layer of  a completion  of a  sent */
/* frame and a reception of a frame.                                        */

static void
MCF5272_fec_deliver(struct eth_drv_sc * sc)
{
    u32_t event;


    /*   Clear the event register.                                          */

    put_reg(MCF5272_SIM->enet.eir,
            (event = (get_reg(MCF5272_SIM->enet.eir) &
                      MCF5272_FEC_INTERRUPT_MASK)));

    while(event & MCF5272_FEC_INTERRUPT_MASK)
    {

        /*   This flag will  specifies  whether  we  need  to  service  the */
        /* transmit or receive sides of the Ethernet controller.            */

        bool packet_status;


        /*   Keep count of  any bus  error that  might occur  when the  FEC */
        /* attempts while the FEC accessing the internal bus.               */

        if (event & MCF5272_FEC_EIR_EBERR)
        {
            PMCF5272_FEC_DATA(sc)->diag_counters.internal_bus_error_cnt++;
        }

        do
        {
            packet_status = false;

            /*   Call receive the handler to receive packets.               */

            packet_status |= MCF5252_fec_recv_handler(sc);

            /*   Call transit the handed to release the transmit buffers.   */

            packet_status |= MCF5272_fec_transmit_handler(sc);

            /*   Loop back up  until all the  receive and transmit  buffers */
            /* are empty.                                                   */

        }while(packet_status);

        /*   Retrieve the next interrupt event.                             */

        /*   Clear the event register.                                      */

        put_reg(MCF5272_SIM->enet.eir,
                event = (get_reg(MCF5272_SIM->enet.eir) &
                         MCF5272_FEC_INTERRUPT_MASK));

    }

    /*   NOTE: If the a bit in the eir is set after clearing the bit in the */
    /* eir, unmasking the bit in the imr will generate an interrupt.   This */
    /* assumption is true only if the interrupt line to the  microprocessor */
    /* core is level sensitive.                                             */

    /*   Allow interrupts by setting IMR register.                          */

	put_reg(MCF5272_SIM->enet.eimr, get_reg(MCF5272_SIM->enet.eimr) |
                                    MCF5272_FEC_INTERRUPT_MASK
                                    );

}

/*      Generic Interrupt Service Routine.  This  routine wakes up the  DSR */
/* for further processing.                                                  */

static int
MCF5272_fec_isr(cyg_vector_t vector, cyg_addrword_t data,
                HAL_SavedRegisters *regs)
{

    /*   Mask  the  FEC's  interrupts  so  that  it  won't  generate  these */
    /* interrupts anymore as the driver  reads the packets or  acknowledges */
    /* packets.                                                             */

    put_reg(MCF5272_SIM->enet.eimr, get_reg(MCF5272_SIM->enet.eimr) &
            ~(MCF5272_FEC_INTERRUPT_MASK));

    return CYG_ISR_CALL_DSR;
}


/*      Call MCF5272_fec_deliver() to poll the FEC.                         */

static void
MCF5272_fec_int(struct eth_drv_sc *sc)
{
    MCF5272_fec_deliver(sc);
}

static int
MCF5272_fec_int_vector(struct eth_drv_sc *sc)
{

    /*   How do you return multiple interrupt vector?                       */

    return CYGNUM_HAL_VECTOR_ERX;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?