if_etherc.c
来自「eCos操作系统源码」· C语言 代码 · 共 1,128 行 · 第 1/3 页
C
1,128 行
//==========================================================================//// dev/if_etherc.c//// Ethernet device driver for SH EtherC CPU module controller////==========================================================================//####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####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s): jskov// Contributors: jskov// Date: 2002-01-30// Purpose: // Description: Hardware driver for SH EtherC CPU module controller//// Notes: The KEEP_STATISTICS code is not implemented yet. Look// for FIXME macro.////####DESCRIPTIONEND####////==========================================================================#include <pkgconf/system.h>#include <pkgconf/devs_eth_sh_etherc.h>#include <pkgconf/io_eth_drivers.h>#include <cyg/infra/cyg_type.h>#include <cyg/hal/hal_arch.h>#include <cyg/hal/hal_intr.h>#include <cyg/infra/cyg_ass.h>#include <cyg/infra/diag.h>#include <cyg/hal/drv_api.h>#include <cyg/hal/hal_if.h> // delays#include <string.h>#include <cyg/io/eth/netdev.h>#include <cyg/io/eth/eth_drv.h>#ifdef CYGPKG_NET#include <pkgconf/net.h>#include <cyg/kernel/kapi.h>#include <net/if.h> /* Needed for struct ifnet */#include <pkgconf/io_eth_drivers.h>#endif#include CYGHWR_MEMORY_LAYOUT_H#define FIXME 0// Set size so it is 16-byte aligned#define _BUF_SIZE (1544+8)#define IEEE_8023_MIN_FRAME 64 // Smallest possible ethernet frame#ifdef CYGPKG_INFRA_DEBUG// Then we log, OOI, the number of times we get a bad packet number// from the tx done fifo.int etherc_txfifo_good = 0;int etherc_txfifo_bad = 0;#endif#include "sh_etherc.h"#define __WANT_DEVS#include CYGDAT_DEVS_ETH_SH_ETHERC_INL#undef __WANT_DEVSstatic void etherc_poll(struct eth_drv_sc *sc);static cyg_uint16 etherc_read_MII(struct etherc_priv_data *cpd, int id, int reg);static void etherc_write_MII(struct etherc_priv_data *cpd, int id, int reg, cyg_uint16 value);#define _MII_READ(_priv_, _id_, _reg_) etherc_read_MII(_priv_, _id_, _reg_)#define _MII_WRITE(_priv_, _id_, _reg_, _val_) etherc_write_MII(_priv_, _id_, _reg_, _val_)#define _MII_HAS_EXTENDED#include "phyter.inl"#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE// This ISR is called when the ethernet interrupt occursstatic cyg_uint32etherc_isr(cyg_vector_t vector, cyg_addrword_t data){ struct etherc_priv_data *cpd = (struct etherc_priv_data *)data; DEBUG_FUNCTION(); INCR_STAT( interrupts ); cyg_drv_interrupt_mask(cpd->interrupt); cyg_drv_interrupt_acknowledge(cpd->interrupt); return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR); // Run the DSR}static voidetherc_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data){ // This conditioning out is necessary because of explicit calls to this // DSR - which would not ever be called in the case of a polled mode // usage ie. in RedBoot.#ifdef CYGPKG_IO_ETH_DRIVERS_NET struct etherc_priv_data* cpd = (struct etherc_priv_data *)data; struct cyg_netdevtab_entry *ndp = (struct cyg_netdevtab_entry *)(cpd->ndp); struct eth_drv_sc *sc = (struct eth_drv_sc *)(ndp->device_instance); // but here, it must be a *sc: eth_drv_dsr( vector, count, (cyg_addrword_t)sc );#else# ifndef CYGPKG_REDBOOT# error Empty Etherc ethernet DSR is compiled. Is this what you want?# endif#endif}#endif // CYGPKG_IO_ETH_DRIVERS_STAND_ALONE// The deliver function (ex-DSR) handles the ethernet [logical] processingstatic voidetherc_deliver(struct eth_drv_sc *sc){ struct etherc_priv_data *cpd = (struct etherc_priv_data *)sc->driver_private; DEBUG_FUNCTION(); // Service the interrupt: etherc_poll(sc); // Allow interrupts to happen again cyg_drv_interrupt_unmask(cpd->interrupt);}static intetherc_int_vector(struct eth_drv_sc *sc){ struct etherc_priv_data *cpd = (struct etherc_priv_data *)sc->driver_private; return (cpd->interrupt);}static bool sh_etherc_init(struct cyg_netdevtab_entry *tab){ struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance; struct etherc_priv_data *cpd = (struct etherc_priv_data *)sc->driver_private; cyg_uint8 *p, *d; cyg_uint32 reg; int i; bool esa_configured = true; DEBUG_FUNCTION(); cpd->txbusy = 0; // Ensure that addresses of ring descriptors and buffers are properly aligned // and in uncached memory. cpd->rx_buffers = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS(((cyg_uint32)cpd->rx_buffers+16-1) & ~(16-1)); cpd->rx_ring = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS(((cyg_uint32)cpd->rx_ring+16-1) & ~(16-1)); cpd->tx_buffers = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS(((cyg_uint32)cpd->tx_buffers+16-1) & ~(16-1)); cpd->tx_ring = (cyg_uint8*)CYGARC_UNCACHED_ADDRESS(((cyg_uint32)cpd->tx_ring+16-1) & ~(16-1));#if DEBUG & 8 db_printf("Etherc at base 0x%08x\n", cpd->base);#endif // Find ESA - check possible sources in sequence and stop when // one provides the ESA: // RedBoot option (via provide_esa) // Compile-time configuration // EEPROM // <fail configuration of device> if (NULL != cpd->provide_esa) { esa_configured = cpd->provide_esa(cpd);# if DEBUG & 8 if (esa_configured) diag_printf("Got ESA from RedBoot option\n");# endif } if (!esa_configured && cpd->hardwired_esa) { // ESA is already set in cpd->esa[] esa_configured = true; } if (!esa_configured) {# if DEBUG & 8 diag_printf("EtherC - no EEPROM, static ESA or RedBoot config option.\n");# endif return false; }#if DEBUG & 9 db_printf("ETHERC ESA: %02x:%02x:%02x:%02x:%02x:%02x\n", cpd->esa[0], cpd->esa[1], cpd->esa[2], cpd->esa[3], cpd->esa[4], cpd->esa[5] );#endif // Prepare RX and TX rings p = cpd->rx_ring; d = cpd->rx_buffers; for (i = 0; i < cpd->rx_ring_cnt; i++) { _SU32(p, ETHERC_RD_STAT) = ETHERC_RD_STAT_RACT | ETHERC_RD_STAT_RFP_OTO; _SU16(p, ETHERC_RD_RBL) = _BUF_SIZE; _SU16(p, ETHERC_RD_RDL) = 0; _SU32(p, ETHERC_RD_RBA) = (cyg_uint32)d; _SU32(p, ETHERC_RD_PAD) = 0; p += ETHERC_RD_SIZE; d += _BUF_SIZE; } // Set ring-end marker p -= ETHERC_RD_SIZE; _SU32(p, ETHERC_RD_STAT) |= ETHERC_RD_STAT_RDLE; cpd->rx_ring_next = 0; p = cpd->tx_ring; d = cpd->tx_buffers; for (i = 0; i < cpd->tx_ring_cnt; i++) { _SU32(p, ETHERC_TD_STAT) = ETHERC_TD_STAT_TFP_OTO; _SU16(p, ETHERC_TD_TDL) = 0; _SU16(p, ETHERC_TD_PAD0) = 0; _SU32(p, ETHERC_TD_TBA) = (cyg_uint32)d; _SU32(p, ETHERC_TD_PAD1) = 0; p += ETHERC_TD_SIZE; d += _BUF_SIZE; } // Set ring-end marker p -= ETHERC_RD_SIZE; _SU32(p, ETHERC_TD_STAT) |= ETHERC_TD_STAT_TDLE; cpd->tx_ring_free = cpd->tx_ring_alloc = cpd->tx_ring_owned = 0; // Reset ethernet module, then wait for (at least) 16 clocks. put_reg(cpd, _REG_EDMR, CYGARC_REG_EDMR_SWR | CYGARC_REG_EDMR_DL16); for (i = 0; i < 16; i++); put_reg(cpd, _REG_EDMR, CYGARC_REG_EDMR_DL16); // Program ring data into controller put_reg(cpd, _REG_RDLAR, (cyg_uint32)cpd->rx_ring); put_reg(cpd, _REG_TDLAR, (cyg_uint32)cpd->tx_ring); // Set ESA put_reg(cpd, _REG_MAHR, (cpd->esa[0] << 24) | (cpd->esa[1] << 16) | (cpd->esa[2] << 8) | cpd->esa[3]); put_reg(cpd, _REG_MALR, (cpd->esa[4] << 8) | cpd->esa[5]); // Set receive mode: receive continuously put_reg(cpd, _REG_RCR, CYGARC_REG_RCR_RNC); // Stop controller, set duplex mode put_reg(cpd, _REG_ECMR, CYGARC_REG_ECMR_DM); cpd->active = 0; // Clear pending interrupt flags reg = get_reg(cpd, _REG_EESR); put_reg(cpd, _REG_EESR, reg);#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE // Attach ISR/DSRs. cpd->interrupt = CYGNUM_HAL_INTERRUPT_EDMAC_EINT; cyg_drv_interrupt_create(cpd->interrupt, 1, // Priority (cyg_addrword_t)cpd, // Data item passed to ISR & DSR etherc_isr, // ISR etherc_dsr, // DSR &cpd->interrupt_handle, // handle to intr obj &cpd->interrupt_object ); // space for int obj cyg_drv_interrupt_attach(cpd->interrupt_handle); cyg_drv_interrupt_unmask(cpd->interrupt); put_reg(cpd, _REG_EESIPR, CYGARC_REG_EESIPR_TCIP|CYGARC_REG_EESIPR_FRIP);#if DEBUG & 8 db_printf("Attached interrupt on vector %d\n", cpd->interrupt);#endif#endif // Record the net dev pointer cpd->ndp = (void *)tab; // Initialize the PHY#ifdef CYGSEM_DEVS_ETH_SH_ETHERC_FORCE_10MBPS#if DEBUG & 8 db_printf("Forcing 10Mb link\n");#endif _MII_SPEED_FORCE_10MB(cpd, 1); _MII_RENEGOTIATE(cpd, 1);#else // Wait for automatic negotiation to complete _MII_RENEGOTIATION_WAIT(cpd, 1);#endif // Initialize upper level driver (sc->funs->eth_drv->init)(sc, cpd->esa);#if DEBUG & 9 db_printf("Done\n");#endif return true;}static voidetherc_suspend(struct etherc_priv_data *cpd){ cyg_uint32 reg;#if 0 bool still_active;#endif reg = get_reg(cpd, _REG_ECMR); reg &= ~(CYGARC_REG_ECMR_TE | CYGARC_REG_ECMR_RE); put_reg(cpd, _REG_ECMR, reg);#if 0 // // Try to find out if controller stopped. Supposedly, it should // communicate this by clearing the active signal of the active // RX/TX descriptors. // Check RX do { still_active = false; reg = get_reg(cpd, _REG_RDFAR);#if 1 { int i; cyg_uint8* p; p = cpd->rx_ring; for (i = 0; i < cpd->rx_ring_cnt; i++) { if ((cyg_uint32)p == reg) { if (_SU32(reg, ETHERC_RD_STAT) & ETHERC_RD_STAT_RACT) { still_active = true; break; } } } }#else if (_SU32(reg, ETHERC_RD_STAT) & ETHERC_RD_STAT_RACT) still_active = true;#endif } while (still_active); // Check TX do { still_active = false; reg = get_reg(cpd, _REG_TDFAR);#if 1 { int i; cyg_uint8* p; p = cpd->tx_ring; for (i = 0; i < cpd->tx_ring_cnt; i++) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?