if_mcf5272.c

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

C
1,887
字号
//==========================================================================////      dev/if_MCF5272_fec.c////      Ethernet device driver for MCF5272's Fast Ethernet Controller (FEC)////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================// Ethernet device driver for Fast Ethernet MCF5272_fec#include <pkgconf/io_eth_drivers.h>#include <cyg/hal/drv_api.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/eth/eth_drv.h>#include <cyg/devs/eth/nbuf.h>#include <cyg/devs/eth/if_mcf5272.h>#include <cyg/devs/eth/if_mcf5272_private_data.h>#include <cyg/infra/cyg_ass.h>#include <sys/param.h>#include <net/if.h>/* Function to retrieve the Ethernet address of the device from the device's   database. We declare it weak so that other routines can overide it.   */externC const void*db_get_eth_address(void) __attribute__ ((weak));/*****************************************************************************     The following  functions  provide  an  interface  directly  to  theethernet driver for applications that wish to circumvent the IP stack.     Applications that wish  to take advantage  of this should  overridethese routine with their own.  Leaving these routines as default  routesall data through the IP stack.*****************************************************************************/externC int_teth_rx_pkt_filter(u8_t* pkt, uint_t pkt_len) __attribute__ ((weak));externC voideth_tx_check(struct eth_drv_sg * sg_list, unsigned int sg_len)             __attribute__ ((weak));externC voideth_send_done(unsigned long tag) __attribute__ ((weak));externC int_teth_send(struct eth_drv_sg * sg_list, unsigned int sg_len, int total_len,         unsigned long tag);static MCF5272_fec_priv_data_t MCF5272_fec_priv_data;/* Interrupt strcture and handles. */static cyg_interrupt MCF5272_fec_rx_interrupt;static cyg_interrupt MCF5272_fec_tx_interrupt;static cyg_handle_t MCF5272_fec_rx_interrupt_handle;static cyg_handle_t MCF5272_fec_tx_interrupt_handle;// Interrupt handlerstatic void MCF5272_fec_int(struct eth_drv_sc *sc);static int MCF5272_fec_int_vector(struct eth_drv_sc *sc);// This DSR handles the ethernet [logical] processingstatic void MCF5272_fec_deliver(struct eth_drv_sc * sc);static void MCF5272_fec_stop(struct eth_drv_sc *sc);static voidMCF5272_fec_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,            int total_len, unsigned long key);static voidMCF5272_fec_common_send(struct eth_drv_sc *sc,                        struct eth_drv_sg *sg_list, int sg_len,                        int total_len,                        unsigned long key,                        tx_key_type_t key_type);static intMCF5272_fec_isr(cyg_vector_t vector, cyg_addrword_t data,                HAL_SavedRegisters *regs);// One-second call back alarmstatic void one_second_alarm_func(cyg_handle_t alarm, cyg_addrword_t data);// Retrieve statisticsstatic void MCF5272_get_stats(struct eth_drv_sc *sc, MCF5272_FEC_DIAG* stats);ETH_DRV_SC(MCF5272_fec_sc,           &MCF5272_fec_priv_data, // Driver specific data           "eth0",             // Name for this interface           MCF5272_fec_start,           MCF5272_fec_stop,           MCF5272_fec_control,           MCF5272_fec_can_send,           MCF5272_fec_send,           MCF5272_fec_recv,           MCF5272_fec_deliver,           MCF5272_fec_int,           MCF5272_fec_int_vector);/* Device name */static const char ether_device_name[] =  "MCF5272-eth";NETDEVTAB_ENTRY(MCF5272_fec_netdev,                ether_device_name,                MCF5272_fec_init,                &MCF5272_fec_sc);/*******************************************************************************    db_get_eth_address() - Returns the default Ethernet address.*/const void* db_get_eth_address(void){    /*   Just use an obviously invalid address until someone overrides this */    /* routine to provide their own address.                                */    static const unsigned char enaddr[] =    {        0x00, 0x11, 0x22, 0x33, 0x44, 0x55    };    return  (const void*)enaddr;}/******************************************************************************* MCF5272_fec_init() - Routine that initializes the FEC. INPUT:    tab - Pointer to the network device table. */static bool MCF5272_fec_init(struct cyg_netdevtab_entry *tab){    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;    const u8_t *enaddr;    /*   Indicate that the ethernet driver is down.                         */    PMCF5272_FEC_DATA(sc)->operational = ETH_DEV_DOWN;    /*   Initialize the entire driver private area to zero.                 */    memset((char*)sc->driver_private, sizeof(MCF5272_fec_priv_data_t), 0);    /*   Initialize the buffers structure.  This strucre contains  transmit */    /* and receive buffer descriptor managment information.                 */    nbuf_init(PBUF_INFO(sc));    /*   Start a alarm that  will trigger  every second.   This alarm  will */    /* periodically update the recevie and transmit statistics.             */    cyg_clock_to_counter(cyg_real_time_clock(),                         &(((MCF5272_fec_priv_data_t*)sc->driver_private)->counter_h));    cyg_alarm_create(((MCF5272_fec_priv_data_t*)sc->driver_private)->counter_h,                      one_second_alarm_func,                     (cyg_addrword_t)(MCF5272_fec_priv_data_t*)sc->driver_private,                      &(((MCF5272_fec_priv_data_t*)sc->driver_private)->alarm_h),                      &(((MCF5272_fec_priv_data_t*)sc->driver_private)->alarm));    cyg_alarm_initialize(((MCF5272_fec_priv_data_t*)sc->driver_private)->alarm_h,                         cyg_current_time()+                         (1*SEC_IN_NS)/CYGNUM_KERNEL_COUNTERS_RTC_PERIOD,                         (1*SEC_IN_NS)/CYGNUM_KERNEL_COUNTERS_RTC_PERIOD);    /*   Initialize environment, setup  receive, transmit and  non-critical */    /* interrupt handlers.                                                  */    cyg_drv_interrupt_create(CYGNUM_HAL_VECTOR_ERX,                             MCF5272_INT_LEVEL, // Priority                             (cyg_addrword_t)sc, //  Data item passed to interrupt handler                             (cyg_ISR_t *)MCF5272_fec_isr,                             (cyg_DSR_t *)eth_drv_dsr,                             &MCF5272_fec_rx_interrupt_handle,                             &MCF5272_fec_rx_interrupt);    cyg_drv_interrupt_create(CYGNUM_HAL_VECTOR_ETX,                             MCF5272_INT_LEVEL, // Priority                             (cyg_addrword_t)sc, //  Data item passed to interrupt handler                             (cyg_ISR_t *)MCF5272_fec_isr,                             (cyg_DSR_t *)eth_drv_dsr,                             &MCF5272_fec_tx_interrupt_handle,                             &MCF5272_fec_tx_interrupt);    /*   Attach interrupt here in order  to start receiving interrupt  from */    /* the FEC.                                                             */    cyg_drv_interrupt_attach(MCF5272_fec_rx_interrupt_handle);    cyg_drv_interrupt_attach(MCF5272_fec_tx_interrupt_handle);    put_reg(MCF5272_SIM->gpio.pbcnt, 0x55550000 |            (get_reg(MCF5272_SIM->gpio.pbcnt) & 0x0000FFFF));    /*   Reset the FEC - equivalent to a hard reset.                        */    put_reg(MCF5272_SIM->enet.ecr, MCF5272_FEC_ECR_RESET);    /*   Wait for the reset sequence to complete.                           */    while(get_reg(MCF5272_SIM->enet.ecr) & MCF5272_FEC_ECR_RESET);    /*   Set the Ethernet control register to zero to disable the FEC.      */    put_reg(MCF5272_SIM->enet.ecr, 0);    /*   Set the source address for the controller.                         */    /*   Initialize  physical  address  register  by  copying  our  adapter */    /* address from the device's permanent storage.                         */    enaddr = (cyg_uint8*)db_get_eth_address();    put_reg(MCF5272_SIM->enet.malr,0                    		       | (enaddr[0] <<24)                    		       | (enaddr[1] <<16)	                    		       | (enaddr[2] <<8)                    		       | (enaddr[3] <<0));    put_reg(MCF5272_SIM->enet.maur,0                    		       | (enaddr[4] <<24)                    		       | (enaddr[5] <<16));    /*   Initialize the hash  table registers  to ignore  hash checking  to */    /* detect multicast Etherhet addresses.                                 */    put_reg(MCF5272_SIM->enet.htur, 0);    put_reg(MCF5272_SIM->enet.htlr, 0);    /*   Set Receive Buffer Size.   This  is  the  size  for  each  receive */    /* buffer.                                                              */    put_reg(MCF5272_SIM->enet.emrbr, (uint16)RX_BUFFER_SIZE);    /*   Point to the start of the circular Rx buffer descriptor queue.     */    put_reg(MCF5272_SIM->enet.erdsr, nbuf_get_start(PBUF_INFO(sc), Rx));    /*   Point to the start of the circular Tx buffer descriptor queue.     */    put_reg(MCF5272_SIM->enet.etdsr, nbuf_get_start(PBUF_INFO(sc), Tx));    /*   Set  the  FIFO  transmit  highwater  mark  to  128  bytes.   Frame */    /* transmission begins when the number of bytes selected by this  field */    /* are written into the  transmit FIFO,  if an  end of  frame has  been */    /* written to the FIFIO, or if the FIFO is full before selected  number */    /* of bytes are written.                                                */    put_reg(MCF5272_SIM->enet.tfwr, MCF5272_FEC_XWMRK_128);    /*   Clear any interrupts by setting all bits in the EIR register.      */    put_reg(MCF5272_SIM->enet.eir, 0xFFFFFFFF);    /*   Set the tranceiver interface to MII mode.                          */    put_reg(MCF5272_SIM->enet.rcr, 0 | MCF5272_FEC_RCR_MII_MODE);                                   // | MCF5272_FEC_RCR_DRT);    /*   Set the mode is ETH_MODE_SIMPLEX.   We are assuming the device  is */    /* half-duplex mode.                                                    */    PMCF5272_FEC_DATA(sc)->duplex = ETH_MODE_SIMPLEX;    /* The default speed is 10 Mbs. */    PMCF5272_FEC_DATA(sc)->speed = ETH_SPEED_10MB;    /*   Write the maximum  frame  length  and  setup  so  we  can  receive */    /* broadcast packets.                                                   */    put_reg(MCF5272_SIM->enet.mflr, MCF5272_FEC_MFLR_BRDCAST |            sizeof(eth_frame_hdr));    /*   Check for heartbeat count  and enable  full-duplex transmit.   The */    /* hearbeat check is performed following end of transmission and the HB */    /* bit in the status  reguster is set if  the collision input does  not */    /* assert within the heartbeat window.                                  */    /*   NOTE: We disable full  duplex mode  because we  notice that  we're */    /* getting Receive CRC erors.                                           */    put_reg(MCF5272_SIM->enet.tcr, 0 |MCF5272_FEC_TCR_HBC);                                   //| MCF5272_FEC_TCR_FDEN);    /*   Set  the  MII  frequency  divider.   The  MII_SPEED  controls  the */    /* frequency of the MII management  interface  clock  relative  to  the */    /* system clock.  We set MII  speed  to  7  because  the  system  clock */    /* frequency is 66 Mhz.                                                 */    put_reg(MCF5272_SIM->enet.mscr, 7<<1);    /*   Initialize upper level driver.                                     */    (sc->funs->eth_drv->init)(sc, (unsigned char *)enaddr);    /*   Return  true  to  indicate  that  the  driver  initialization  has */    /* completed successfully.                                              */    return true;}/*      This function is called to  "start up"  the interface.   It may  be *//* called multiple times, even  when the hardware  is already running.   It *//* will be called whenever something "hardware oriented" changes and should *//* leave the hardware ready to send/receive packets.                        */static voidMCF5272_fec_start(struct eth_drv_sc *sc, cyg_uint8 *enaddr, int flags){    	    /*   Initialize the buffers structure.  This strucre contains  transmit */    /* and receive buffer descriptor managment information.  We  initialize */    /* again here becuase we don't  know the internal  state of the  buffer */    /* descriptor pointer in the FEC if the FEC was disabled after  calling */    /* MCF5272_fec_stop.                                                    */    if (PMCF5272_FEC_DATA(sc)->operational != ETH_DEV_UP)    {        nbuf_init(PBUF_INFO(sc));    }    /*   Unmask the Transmit and Receive  frame  interrupt  to  handle  the */    /* interrupts.                                                          */    /*   Unmask the Internal Bus  Errorso we  can detect  any internal  bus */    /* error when the FEC tries to acess the internal bus.                  */    put_reg(MCF5272_SIM->enet.eimr,            get_reg(MCF5272_SIM->enet.eimr) | MCF5272_FEC_INTERRUPT_MASK);    /*   Enable FEC.                                                        */    put_reg(MCF5272_SIM->enet.ecr, MCF5272_FEC_ECR_ETHER_EN);    /*   Indicate that there have been empty receive buffers produced.      */

⌨️ 快捷键说明

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