if_i82544.c

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

C
2,053
字号
//==========================================================================
//
//      if_i82544.c
//
//	Intel 82544 ethernet driver
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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####
//####BSDCOPYRIGHTBEGIN####
//
// -------------------------------------------
//
// Portions of this software may have been derived from OpenBSD or
// other sources, and are covered by the appropriate copyright
// disclaimers included herein.
//
// -------------------------------------------
//
//####BSDCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    hmt, gthomas
// Contributors: Ron Spence, Pacific Softworks, jskov
// Date:         2000-02-01
// Purpose:      
// Description:  hardware driver for 82544 Intel PRO/100+ ethernet
// Notes:        CU commands such as dump and config should, according
//               to the docs, set the CU active state while executing.
//               That does not seem to be the case though, and the
//               driver polls the completion bit in the packet status
//               word instead.
//
//               Platform code may provide this vector:
//               CYGNUM_DEVS_ETH_INTEL_I82544_SEPARATE_MUX_INTERRUPT if it
//               requires the interrupts to be handled via demuxers
//               attached to a distinct interrupt.
//
//               Platform code may alternatively define:
//               CYGHWR_DEVS_ETH_INTEL_I82544_DEMUX_ALL if it is necessary
//               to demux all interrupt sources - for example if they are
//               wire-or'd together on some hardware but distinct on
//               others.  In this circumstance it is permitted for
//               cyg_pci_translate_interrupt [HAL_PCI_TRANSLATE_INTERRUPT]
//               to return invalid for 2nd and subsequent devices.
//
//               Platform code can also define these three:
//               CYGPRI_DEVS_ETH_INTEL_I82544_MASK_INTERRUPTS(p_i82544,old)
//               CYGPRI_DEVS_ETH_INTEL_I82544_UNMASK_INTERRUPTS(p_i82544,old)
//               CYGPRI_DEVS_ETH_INTEL_I82544_ACK_INTERRUPTS(p_i82544)
//               which are particularly useful when nested interrupt
//               management is needed (which is always IMHO).
//
//               Platform code can define this:
//               CYGHWR_DEVS_ETH_INTEL_I82544_MISSED_INTERRUPT(p_i82544)
//               to detect a dropped interrupt and loop again or
//               direct-call the DSR to reschedule the delivery routine.
//               Only a problem on edge-triggered interrupt systems.
//
//               Platform code can also provide this macro:
//               CYGPRI_DEVS_ETH_INTEL_I82544_INTERRUPT_ACK_LOOP(p_i82544)
//               to handle delaying for acks to register on the interrupt
//               controller as necessary on the EBSA.
//
//               Platform can define CYGHWR_DEVS_ETH_INTEL_I82544_GET_ESA()
//               as an external means to get ESAs, possibly from RedBoot
//               configuration info that's stored in flash memory.
//
//               Platform def CYGHWR_DEVS_ETH_INTEL_I82544_HAS_NO_EEPROM
//               removes all code for dealing with the EEPROM for those
//               targets where there is none fitted.  Either an external
//               means to get ESAs should be used, or we must rely on
//               hard-wiring the ESA's into each executable by means of the
//               usual CDL configuration.
//
//               Platform def CYGHWR_DEVS_ETH_INTEL_I82544_HAS_ONE_EEPROM
//               is for hardware with multiple devices, but only one with a
//               serial EEPROM installed.  The 2nd device would get either
//               the same ESA - because they are certain to be on different
//               segment and internets - or the same ESA incremented by
//               CYGHWR_DEVS_ETH_INTEL_I82544_HAS_ONE_EEPROM_MAC_ADJUST.
//               CYGHWR_DEVS_ETH_INTEL_I82544_HAS_ONE_EEPROM should be the
//               number (0 or 1) of the device that does have the EEPROM.
//
//               CYGHWR_DEVS_ETH_INTEL_I82544_PCIMEM_DISCONTIGUOUS enables
//               checking code for breaks in the physical address of PCI
//               window memory.  This can happen on some boards where a
//               smaller SDRAM is fitted than the hardware allows, so some
//               higher-order address bits are ignored.  We make SDRAM
//               contiguous in mapped memory, but what the i82544 sees
//               might be discontiguous.  The checking code skips any
//               allocated chunk who appears to contain such a break, and
//               tries again.
//
//               CYGHWR_DEVS_ETH_INTEL_I82544_RESET_TIMEOUT( int32 )
//               CYGHWR_DEVS_ETH_INTEL_I82544_TIMEOUT_FIRED( int32 ) if
//               both defined give the driver a means to detect that we
//               have been fixated on the same transmit operation for too
//               long - we missed an interrupt or the device crashed.  The
//               int32 argument is used to hold a eg. the value of a
//               fast-running hardware timer.
//
//               Platform def CYGHWR_DEVS_ETH_INTEL_I82544_USE_ASD is
//               used to select Auto Speed Detection for setting up the
//               link parameters.
//
//        FIXME: replace -1/-2 return values with proper E-defines
//        FIXME: For 82557/8 compatibility i82544_configure() function
//               probably needs some tweaking - config bits differ
//               slightly but crucially.
//        FIXME: EEPROM code not tested on a BE system.
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/system.h>
#ifdef CYGPKG_IO_ETH_DRIVERS
#include <pkgconf/io_eth_drivers.h>
#endif
#include <pkgconf/devs_eth_intel_i82544.h>

#include <cyg/infra/cyg_type.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_intr.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_if.h>
#include <cyg/hal/drv_api.h>
#include <cyg/io/eth/netdev.h>
#include <cyg/io/eth/eth_drv.h>

#ifdef CYGPKG_NET
#include <pkgconf/net.h>
#include <net/if.h>  /* Needed for struct ifnet */
#endif

#ifdef CYGPKG_IO_PCI
#include <cyg/io/pci.h>
// So we can check the validity of the PCI window against the MLTs opinion,
// and thereby what the malloc heap consumes willy-nilly:
#include CYGHWR_MEMORY_LAYOUT_H
#else
#error "Need PCI package here"
#endif

#include <cyg/devs/eth/i82544_info.h>

#include CYGDAT_DEVS_ETH_INTEL_I82544_INL

// ------------------------------------------------------------------------

#ifdef CYGDBG_DEVS_ETH_INTEL_I82544_CHATTER
#define DEBUG_82544 // This one prints stuff as packets come and go
#define DEBUG          // Startup printing mainly
#define noDEBUG_EE       // Some EEPROM specific retries &c
#endif

#ifdef CYGDBG_USE_ASSERTS
static struct {
    int can_send;
    int deliver;
    int stats;
    int waitcmd_timeouts;
    int waitcmd_timeouts_cu;
    int lockup_timeouts;
    int bad_cu_idles;
} missed_interrupt = { 0,0,0, 0,0, 0, 0 };
#endif

#ifndef CYGPKG_REDBOOT

#define os_printf diag_printf
#define db_printf diag_printf

#else

static void os_printf( char *fmt, ... )
{
    extern int start_console(void);
    extern void end_console(int);
    va_list a;
    int old_console;
    va_start( a, fmt );
    old_console = start_console();  
    diag_vprintf( fmt, a );
    end_console(old_console);
    va_end( a );
}

#define db_printf os_printf

#endif

// ------------------------------------------------------------------------
//
//                             MEMORY ADDRESSING
// 
// ------------------------------------------------------------------------
// Macros for writing shared memory structures - no need for byte flipping

#define READMEM8(   _reg_, _val_ ) ((CYG_BYTE)(_val_) = *((volatile CYG_BYTE *)(_reg_)))
#define WRITEMEM8(  _reg_, _val_ ) (*((volatile CYG_BYTE *)(_reg_)) = (CYG_BYTE)(_val_))
#define READMEM16(  _reg_, _val_ ) ((CYG_WORD16)(_val_) = *((volatile CYG_WORD16 *)(_reg_)))
#define WRITEMEM16( _reg_, _val_ ) (*((volatile CYG_WORD16 *)(_reg_)) = (CYG_WORD16)(_val_))
#define READMEM32(  _reg_, _val_ ) ((CYG_WORD32)(_val_) = *((volatile CYG_WORD32 *)(_reg_)))
#define WRITEMEM32( _reg_, _val_ ) (*((volatile CYG_WORD32 *)(_reg_)) = (CYG_WORD32)(_val_))
#define READMEM64(  _reg_, _val_ ) ((CYG_WORD64)(_val_) = *((volatile CYG_WORD64 *)(_reg_)))
#define WRITEMEM64( _reg_, _val_ ) (*((volatile CYG_WORD64 *)(_reg_)) = (CYG_WORD64)(_val_))

#define OUTL( _v_, _a_ ) WRITEMEM32( _a_, _v_ )

static inline cyg_uint32 INL(cyg_uint32 io_address)
 {   cyg_uint32 _t_; READMEM32( io_address, _t_ ); return _t_;   }


// ------------------------------------------------------------------------
// Map from CPU-view addresses to PCI-bus master's view - however that is:

#ifdef CYGHWR_INTEL_I82544_PCI_VIRT_TO_BUS

#define VIRT_TO_BUS( _x_ ) CYGHWR_INTEL_I82544_PCI_VIRT_TO_BUS( _x_ )
#define BUS_TO_VIRT( _x_ ) CYGHWR_INTEL_I82544_PCI_BUS_TO_VIRT( _x_ )

#else // use default mappings: get a physical address to give to the device

#define VIRT_TO_BUS( _x_ ) virt_to_bus((cyg_uint32)(_x_))
static inline cyg_uint32 virt_to_bus(cyg_uint32 p_memory)
{ return CYGARC_PHYSICAL_ADDRESS(p_memory);    }

#define BUS_TO_VIRT( _x_ ) bus_to_virt((cyg_uint32)(_x_))
static inline cyg_uint32 bus_to_virt(cyg_uint32 p_bus)
{ return CYGARC_UNCACHED_ADDRESS(p_bus);    }

#endif // not defined CYGHWR_INTEL_I82544_PCI_VIRT_TO_BUS

// ------------------------------------------------------------------------
//                                                                      
//                   82544 REGISTER OFFSETS
//                                                                      
// ------------------------------------------------------------------------

// General registers
#define I82544_CTRL     0x00000
#define I82544_STATUS   0x00008
#define I82544_EECD     0x00010
#define I82544_CTRL_EXT 0x00018
#define I82544_MDIC     0x00020
#define I82544_FCAL     0x00028
#define I82544_FCAH     0x0002c
#define I82544_FCT      0x00030
#define I82544_VET      0x00038
#define I82544_FCTTV    0x00170
#define I82544_TXCW     0x00178
#define I82544_RXCW     0x00180
#define I82544_PBA      0x01000

// Interrupt control registers
#define I82544_ICR      0x000c0
#define I82544_ICS      0x000c8
#define I82544_IMS      0x000d0
#define I82544_IMC      0x000d8

// Receive registers
#define I82544_RCTL     0x00100
#define I82544_FCRTL    0x02160
#define I82544_FCRTH    0x02168
#define I82544_RDBAL    0x02800
#define I82544_RDBAH    0x02804
#define I82544_RDLEN    0x02808
#define I82544_RDH      0x02810
#define I82544_RDT      0x02818
#define I82544_RDTR     0x02820
#define I82544_RXDCTL   0x02828
#define I82544_RXCSUM   0x05000
#define I82544_MTA      0x05200
#define I82544_RAT      0x05400
#define I82544_VFTA     0x05600

#define I82544_RCTL_EN  (1<<1)
#define I82544_RCTL_BAM (1<<15)

// Transmit registers
#define I82544_TCTL     0x00400
#define I82544_TIPG     0x00410
#define I82544_TBT      0x00448
#define I82544_AIT      0x00458
#define I82544_TXDMAC   0x03000
#define I82544_TDBAL    0x03800
#define I82544_TDBAH    0x03804
#define I82544_TDLEN    0x03808
#define I82544_TDH      0x03810
#define I82544_TDT      0x03818
#define I82544_TIDV     0x03820
#define I82544_TXDCTL   0x03828
#define I82544_TSPMT    0x03830


#define I82544_TCTL_EN  (1<<1)
#define I82544_TCTL_PSP (1<<3)


// ------------------------------------------------------------------------
//
//               82544 DEVICE CONTROL WORD DEFNITIONS
//
// ------------------------------------------------------------------------

#define I82544_CTRL_FD          (1<<0)
#define I82544_CTRL_BEM         (1<<1)
#define I82544_CTRL_LRST        (1<<3)
#define I82544_CTRL_ASDE        (1<<5)
#define I82544_CTRL_SLU         (1<<6)
#define I82544_CTRL_ILOS        (1<<7)
#define I82544_CTRL_SPEED       (3<<8)
#define I82544_CTRL_FRCSPD      (1<<11)
#define I82544_CTRL_FRCDPLX     (1<<12)
#define I82544_CTRL_SWDPINSLO   (15<<18)
#define I82544_CTRL_SWDPINSIO   (15<<22)
#define I82544_CTRL_RST         (1<<26)
#define I82544_CTRL_RFCE        (1<<27)
#define I82544_CTRL_TFCE        (1<<28)
#define I82544_CTRL_VME         (1<<30)
#define I82544_CTRL_PHY_RST     (1<<31)

#define I82544_CTRL_PHY_RESET           (1<<18)
#define I82544_CTRL_PHY_RESET_DIR       (1<<22)
#define I82544_CTRL_MDIO                (1<<20)
#define I82544_CTRL_MDIO_DIR            (1<<24)
#define I82544_CTRL_MDC                 (1<<21)
#define I82544_CTRL_MDC_DIR             (1<<25)

#define I82544_CTRL_EXT_PHY_RESET4      (1<<4)
#define I82544_CTRL_EXT_PHY_RESET_DIR4  (1<<8)

#define PHY_ADDRESS 1

// ------------------------------------------------------------------------
//
//               82544 DEVICE STATUS WORD DEFNITIONS
//
// ------------------------------------------------------------------------

#define I82544_STATUS_FD        0x0001
#define I82544_STATUS_LU        0x0002
#define I82544_STATUS_TXOFF     0x0010
#define I82544_STATUS_TBIMODE   0x0020
#define I82544_STATUS_SPEED     0x00C0
#define I82544_STATUS_ASDV      0x0300
#define I82544_STATUS_PCI_SPD   0x0800
#define I82544_STATUS_BUS64     0x1000
#define I82544_STATUS_PCIX_MODE 0x2000
#define I82544_STATUS_PCIXSPD   0xC000

// ------------------------------------------------------------------------
//
//                   82544 EEPROM INTERFACE
//
// ------------------------------------------------------------------------

//  EEPROM_Ctrl bits.
#define EE_SHIFT_CLK	0x01            // EEPROM shift clock.
#define EE_CS		0x02            // EEPROM chip select.
#define EE_DATA_WRITE	0x04            // EEPROM chip data in.
#define EE_DATA_READ	0x08            // EEPROM chip data out.
#define EE_REQ          0x40            // EEPROM request (82546 only)
#define EE_GNT          0x80            // EEPROM grant   (82546 only)
#define EE_PRES         0x100           // EEPROM present (82546 only)
#define EE_SIZE         0x200           // EEPROM size    (82546 only)
#define EE_ENB		(0x10|EE_CS)


// ------------------------------------------------------------------------
//
//               RECEIVE DESCRIPTORS
//
// ------------------------------------------------------------------------

#define I82544_RD_BUFFER        0
#define I82544_RD_LENGTH        8

⌨️ 快捷键说明

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