if_fec.c

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

C
800
字号
//==========================================================================////      dev/if_fec.c////      Fast ethernet device driver for PowerPC MPC8xxT boards////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2002, 2003 Gary Thomas//// 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####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):    gthomas// Contributors: gthomas// Date:         2001-01-21// Purpose:      // Description:  hardware driver for MPC8xxT FEC//              ////####DESCRIPTIONEND####////==========================================================================// Ethernet device driver for MPC8xx FEC#include <pkgconf/system.h>#include <pkgconf/devs_eth_powerpc_fec.h>#include <pkgconf/io_eth_drivers.h>#include CYGDAT_DEVS_FEC_ETH_INL#ifdef CYGPKG_NET#include <pkgconf/net.h>#endif#include <cyg/infra/cyg_type.h>#include <cyg/infra/diag.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_cache.h>#include <cyg/hal/hal_intr.h>#include <cyg/hal/drv_api.h>#include <cyg/hal/hal_if.h>#include <cyg/hal/ppc_regs.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/eth/eth_drv.h>#include "fec.h"// Align buffers on a cache boundary#define RxBUFSIZE CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM*CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE#define TxBUFSIZE CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM*CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZEstatic unsigned char fec_eth_rxbufs[RxBUFSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));static unsigned char fec_eth_txbufs[TxBUFSIZE] __attribute__((aligned(HAL_DCACHE_LINE_SIZE)));static struct fec_eth_info fec_eth0_info;static unsigned char _default_enaddr[] = { 0x08, 0x00, 0x3E, 0x28, 0x7A, 0xBA};static unsigned char enaddr[6];#ifdef CYGPKG_REDBOOT#include <pkgconf/redboot.h>#ifdef CYGSEM_REDBOOT_FLASH_CONFIG#include <redboot.h>#include <flash_config.h>RedBoot_config_option("Network hardware address [MAC]",                      fec_esa,                      ALWAYS_ENABLED, true,                      CONFIG_ESA, 0    );#endif#endif#define os_printf diag_printf// For fetching the ESA from RedBoot#include <cyg/hal/hal_if.h>#ifndef CONFIG_ESA#define CONFIG_ESA 6#endifETH_DRV_SC(fec_eth0_sc,           &fec_eth0_info,   // Driver specific data           "eth0",             // Name for this interface           fec_eth_start,           fec_eth_stop,           fec_eth_control,           fec_eth_can_send,           fec_eth_send,           fec_eth_recv,           fec_eth_deliver,           fec_eth_int,           fec_eth_int_vector);NETDEVTAB_ENTRY(fec_netdev,                 "fec_eth",                 fec_eth_init,                 &fec_eth0_sc);#ifdef CYGINT_IO_ETH_INT_SUPPORT_REQUIRED#define _FEC_USE_INTS#ifdef _FEC_USE_INTSstatic cyg_interrupt fec_eth_interrupt;static cyg_handle_t  fec_eth_interrupt_handle;#else#define STACK_SIZE CYGNUM_HAL_STACK_SIZE_MINIMUMstatic char fec_fake_int_stack[STACK_SIZE];static cyg_thread fec_fake_int_thread_data;static cyg_handle_t fec_fake_int_thread_handle;static void fec_fake_int(cyg_addrword_t);#endif // _FEC_USE_INTS#endif // CYGINT_IO_ETH_INT_SUPPORT_REQUIREDstatic void          fec_eth_int(struct eth_drv_sc *data);#ifndef FEC_ETH_INT#error  FEC_ETH_INT must be defined#endif#ifndef FEC_ETH_PHY#error  FEC_ETH_PHY must be defined#endif#ifndef FEC_ETH_RESET_PHY#define FEC_ETH_RESET_PHY()#endif#ifndef FEC_EPPC_BD_OFFSET#define FEC_EPPC_BD_OFFSET CYGNUM_DEVS_ETH_POWERPC_FEC_BD_OFFSET#endif#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_STATUS_LEDS// LED activity [exclusive of hardware bits]#ifndef _get_led#define _get_led()  #define _set_led(v) #endif#ifndef LED_TxACTIVE#define LED_TxACTIVE  7#define LED_RxACTIVE  6#define LED_IntACTIVE 5#endifstatic voidset_led(int bit){  _set_led(_get_led() | (1<<bit));}static voidclear_led(int bit){  _set_led(_get_led() & ~(1<<bit));}#else#define set_led(b)#define clear_led(b)#endif#ifdef _FEC_USE_INTS// This ISR is called when the ethernet interrupt occursstatic intfec_eth_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs){    cyg_drv_interrupt_mask(FEC_ETH_INT);    return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR}#endif// Deliver function (ex-DSR) handles the ethernet [logical] processingstatic voidfec_eth_deliver(struct eth_drv_sc * sc){    fec_eth_int(sc);#ifdef _FEC_USE_INTS    // Allow interrupts to happen again    cyg_drv_interrupt_acknowledge(FEC_ETH_INT);    cyg_drv_interrupt_unmask(FEC_ETH_INT);#endif}#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY//// PHY unit access (via MII channel)//static voidphy_write(int reg, int addr, unsigned short data){    volatile EPPC *eppc = (volatile EPPC *)eppc_base();    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);    int timeout = 0x100000;    fec->iEvent = iEvent_MII;        fec->MiiData = MII_Start | MII_Write | MII_Phy(addr) | MII_Reg(reg) | MII_TA | data;    while (!(fec->iEvent & iEvent_MII) && (--timeout > 0)) ;}static boolphy_read(int reg, int addr, unsigned short *val){    volatile EPPC *eppc = (volatile EPPC *)eppc_base();    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);    int timeout = 0x100000;    fec->iEvent = iEvent_MII;        fec->MiiData = MII_Start | MII_Read | MII_Phy(addr) | MII_Reg(reg) | MII_TA;    while (!(fec->iEvent & iEvent_MII)) {        if (--timeout <= 0) {            return false;        }    }    *val = fec->MiiData & 0x0000FFFF;    return true;}#endif // CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY//// [re]Initialize the ethernet controller//   Done separately since shutting down the device requires a //   full reconfiguration when re-enabling.//   when static boolfec_eth_reset(struct eth_drv_sc *sc, unsigned char *enaddr, int flags){    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;    volatile EPPC *eppc = (volatile EPPC *)eppc_base();    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);    volatile struct fec_bd *rxbd, *txbd;    unsigned char *RxBUF, *TxBUF;    int cache_state, int_state;    int i;    int TxBD, RxBD;    // Ignore unless device is idle/stopped    if ((qi->fec->eControl & eControl_EN) != 0) {        return true;    }    // Make sure interrupts are off while we mess with the device    HAL_DISABLE_INTERRUPTS(int_state);    // Ensure consistent state between cache and what the FEC sees    HAL_DCACHE_IS_ENABLED(cache_state);    if (cache_state) {      HAL_DCACHE_SYNC();      HAL_DCACHE_DISABLE();    }    // Shut down ethernet controller, in case it is already running    fec->eControl = eControl_RESET;    i = 0;    while ((fec->eControl & eControl_RESET) != 0) {      if (++i >= 500000) {	os_printf("FEC Ethernet does not reset\n");	if (cache_state)	  HAL_DCACHE_ENABLE();        HAL_RESTORE_INTERRUPTS(int_state);	return false;      }    }    fec->iMask  = 0x0000000;  // Disables all interrupts    fec->iEvent = 0xFFFFFFFF; // Clear all interrupts    fec->iVector = (1<<29);   // Caution - must match FEC_ETH_INT above    TxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM * sizeof(struct cp_bufdesc));    RxBD = _mpc8xx_allocBd(CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM * sizeof(struct cp_bufdesc));    txbd = (struct fec_bd *)(TxBD + (cyg_uint32)eppc);    rxbd = (struct fec_bd *)(RxBD + (cyg_uint32)eppc);    qi->tbase = qi->txbd = qi->tnext = txbd;    qi->rbase = qi->rxbd = qi->rnext = rxbd;    qi->txactive = 0;    RxBUF = &fec_eth_rxbufs[0];    TxBUF = &fec_eth_txbufs[0];    // setup buffer descriptors    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_FEC_RxNUM;  i++) {        rxbd->length = 0;        rxbd->buffer = RxBUF;        rxbd->ctrl   = FEC_BD_Rx_Empty;        RxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;        rxbd++;    }    rxbd--;    rxbd->ctrl |= FEC_BD_Rx_Wrap;  // Last buffer    for (i = 0;  i < CYGNUM_DEVS_ETH_POWERPC_FEC_TxNUM;  i++) {        txbd->length = 0;        txbd->buffer = TxBUF;        txbd->ctrl   = 0;        TxBUF += CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;        txbd++;    }    txbd--;    txbd->ctrl |= FEC_BD_Tx_Wrap;  // Last buffer    // Reset interrupts    fec->iMask  = 0x00000000;  // No interrupts enabled    fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts    // Initialize shared PRAM    fec->RxRing = qi->rbase;    fec->TxRing = qi->tbase;    // Size of receive buffers    fec->RxBufSize = CYGNUM_DEVS_ETH_POWERPC_FEC_BUFSIZE;    // Receiver control    fec->RxControl = RxControl_MII | RxControl_DRT;//    fec->RxControl = RxControl_MII | RxControl_LOOP | RxControl_PROM;    fec->RxHash = IEEE_8023_MAX_FRAME; // Largest possible ethernet frame    // Transmit control    fec->TxControl = 4+0;    // Use largest possible Tx FIFO    fec->TxWater = 3;    // DMA control    fec->FunCode = ((2<<29) | (2<<27) | (0<<24));    // MII speed control (50MHz)    fec->MiiSpeed = 0x14;    // Group address hash    fec->hash[0] = 0;    fec->hash[1] = 0;    // Device physical address    fec->addr[0] = *(unsigned long *)&enaddr[0];    fec->addr[1] = *(unsigned long *)&enaddr[4];    // os_printf("FEC ESA = %08x/%08x\n", fec->addr[0], fec->addr[1]);    // Enable device    fec->eControl = eControl_EN | eControl_MUX;    fec->RxUpdate = 0x0F0F0F0F;  // Any write tells machine to look for work#ifdef _FEC_USE_INTS    // Set up for interrupts    fec->iMask = iEvent_TFINT | iEvent_TXB |                 iEvent_RFINT | iEvent_RXB;    fec->iEvent = 0xFFFFFFFF;  // Clear all interrupts#endif    if (cache_state)        HAL_DCACHE_ENABLE();    // Set LED state    clear_led(LED_TxACTIVE);    clear_led(LED_RxACTIVE);    HAL_RESTORE_INTERRUPTS(int_state);    return true;}//// Initialize the interface - performed at system startup// This function must set up the interface, including arranging to// handle interrupts, etc, so that it may be "started" cheaply later.//static bool fec_eth_init(struct cyg_netdevtab_entry *tab){    struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;    struct fec_eth_info *qi = (struct fec_eth_info *)sc->driver_private;    volatile EPPC *eppc = (volatile EPPC *)eppc_base();    volatile struct fec *fec = (volatile struct fec *)((unsigned char *)eppc + FEC_OFFSET);    int cache_state;    unsigned long proc_rev;    bool esa_ok;#ifdef CYGSEM_DEVS_ETH_POWERPC_FEC_RESET_PHY    int phy_timeout = 5*1000;  // Wait 5 seconds max for link to clear

⌨️ 快捷键说明

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