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 + -
显示快捷键?