if_i82559.c

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

C
1,724
字号
//==========================================================================
//
//      if_i82559.c
//
//	Intel 82559 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.
// 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####
//####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 82559 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_I82559_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_I82559_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_I82559_MASK_INTERRUPTS(p_i82559,old)
//               CYGPRI_DEVS_ETH_INTEL_I82559_UNMASK_INTERRUPTS(p_i82559,old)
//               CYGPRI_DEVS_ETH_INTEL_I82559_ACK_INTERRUPTS(p_i82559)
//               which are particularly useful when nested interrupt
//               management is needed (which is always IMHO).
//
//               Platform code can define this:
//               CYGHWR_DEVS_ETH_INTEL_I82559_MISSED_INTERRUPT(p_i82559)
//               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_I82559_INTERRUPT_ACK_LOOP(p_i82559)
//               to handle delaying for acks to register on the interrupt
//               controller as necessary on the EBSA.
//
//               Platform can define CYGHWR_DEVS_ETH_INTEL_I82559_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_I82559_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_I82559_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_I82559_HAS_ONE_EEPROM_MAC_ADJUST.
//               CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM should be the
//               number (0 or 1) of the device that does have the EEPROM.
//
//               CYGHWR_DEVS_ETH_INTEL_I82559_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 i82559 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_I82559_RESET_TIMEOUT( int32 )
//               CYGHWR_DEVS_ETH_INTEL_I82559_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.
//
//               CYGHWR_DEVS_ETH_INTEL_I82559_ENDIAN_NEUTRAL_IO if PCI IO
//               access is not affected by CPU endianess.
//
//        FIXME: replace -1/-2 return values with proper E-defines
//        FIXME: For 82557/8 compatibility i82559_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_i82559.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>

#include <string.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

// Exported statistics and the like
#include <cyg/devs/eth/i82559_info.h>
#include <cyg/io/eth/eth_drv_stats.h>
#include CYGDAT_DEVS_ETH_INTEL_I82559_INL

#include <cyg/hal/hal_if.h>

// Use with care!  Local variable defined!
#define START_CONSOLE()                                                                 \
{   /* NEW BLOCK */                                                                     \
    int _cur_console =                                                                  \
        CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);      \
    {                                                                                   \
        int i;                                                                          \
        if ( CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,                 \
                                          "info_console_force", &i,                     \
                                          CYGNUM_FLASH_CFG_TYPE_CONFIG_BOOL ) ) {       \
            if ( i ) {                                                                  \
                if ( CYGACC_CALL_IF_FLASH_CFG_OP( CYGNUM_CALL_IF_FLASH_CFG_GET,         \
                                                  "info_console_number", &i,            \
                                                  CYGNUM_FLASH_CFG_TYPE_CONFIG_INT ) ){ \
                    /* Then i is the console to force it to: */                         \
                    CYGACC_CALL_IF_SET_CONSOLE_COMM( i );                               \
                }                                                                       \
            }                                                                           \
        }                                                                               \
    }

#define END_CONSOLE()                                   \
    CYGACC_CALL_IF_SET_CONSOLE_COMM(_cur_console);      \
}   /* END BLOCK */

void CheckRxRing(struct i82559* p_i82559, const char * func, int line);

// ------------------------------------------------------------------------
// Check on the environment.
// 
// These are not CDL type config points; they are set up for your platform
// in the platform driver's include file and that's that.  These messages
// are for the eCos driver writer, not config tool users.

#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_DEMUX_ALL
#ifdef CYGNUM_DEVS_ETH_INTEL_I82559_SEPARATE_MUX_INTERRUPT
#error Both a separate demux interrupt *and* DEMUX_ALL are defined
#endif
#endif

#ifdef CYGPKG_DEVS_ETH_INTEL_I82559_WRITE_EEPROM
#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_NO_EEPROM
#error This platform has no EEPROM, yet WRITE_EEPROM is enabled
#endif
#endif

#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_NO_EEPROM
#ifdef CYGHWR_DEVS_ETH_INTEL_I82559_HAS_ONE_EEPROM
#error This platform has no EEPROM, yet it also HAS_ONE_EEPROM
#endif
#endif

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

#ifdef CYGDBG_DEVS_ETH_INTEL_I82559_CHATTER
#define DEBUG          // Startup printing mainly
#define DEBUG_EE       // Some EEPROM specific retries &c
#if (CYGDBG_DEVS_ETH_INTEL_I82559_CHATTER > 1)
#define DEBUG_82559 // This one prints stuff as packets come and go
#endif
#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

int 
console_printf(const char *fmt, ...)
{
    va_list ap;
    int ret;
    
    START_CONSOLE();

    va_start(ap, fmt);
    ret = diag_vprintf(fmt, ap);
    va_end(ap);
    
    END_CONSOLE();
    return (ret);
}

#define os_printf console_printf
#define db_printf console_printf

// ------------------------------------------------------------------------
//
//                             MEMORY ADDRESSING
// 
// There is scope for confusion here; we deal with LE/BE systems and
// addressing issues in two separate ways depending on the type of access
// in question.
//
// 1) IO-style access to the device regsiters over the PCI bus
// 2) Memory access to build and read the structures in shared memory
// 
// In detail:
// 
// 1) IO-style access to the device regsiters over the PCI bus
// 
// All such access is via macros which perform byte-swapping as necessary
// for the endianness of the CPU.  These macros are called INL, INW, INB
// and OUTL, OUTW, OUTB - for Long (32) Word (16) and Byte (8).  Intel
// nomenclature seems to have crept in here for shorts.
// 
// Consequently, all the constants only have to be expressed once, in their
// true LE format - bit 15 is 0x8000, bit 0 is 1.
// 
// All the offsets are also only expressed once.  This is OK so long as GIB
// endian addressing (sic, see below) is not employed - or so long as is
// does not affect the PCI bus accesses.
//
// 
// 2) Memory access to build and read the structures in shared memory
// 
// These accesses are by means of peek and poke to an address created from
// a base + offset.  No swapping occurs within the access so all constants
// and flags need to be defined twice, once for BE and once for LE
// accesses.  Worse, for BE, constants need to be defined in flavours for
// 16-bit versus 32-bit accesses, ie. 0x8000 sets bit 7 only in BE; for a
// 32-bit access you must instead write 0x80000000 to set bit 7.
//
// Thus all constants are defined twice depending on the CPU's endianness.
//
// For most BE/LE machines, this is sufficient; the layout of memory is the
// same.  Specifically, within a 32-bit word, byte[0] will be data[0:7],
// short[0] will be data [0:15] and so on.  &byte[0] == &short[0] == &word
// regardless.  But data[0:7] *OF THE MEMORY SYSTEM* will hold either the
// LSbyte (0xFF) on a LE machine, and the MSbyte (0xFF000000) on a BE
// machine, for a 32-bit access.
// 
// It is in terms of the memory system that the i82559 defines its view of
// the world.
// 
// Therefore the structure layouts remain the same for both BE and LE
// machines.  This means that the offsets for, specifically, the status
// word in command blocks is always zero, and the offset for the command
// word is always two.
//
// But there is one furter variant: so-called GIB endian.  (BIG endian
// backwards) Some architectures support BE only for software
// compatibility; they allow code to run which relies on overlaid C
// structures behaving in a certain way; specifically
//     *(char *)&i == (i >> 24)
// ARM's BE mode is an example of this.
// 
// But while such an operation would use data[0:7] for the char access in a
// true BE or any LE system, in a GE system, data[24:31] are used here.
// The implementation is that for memory accesses, A0 and A1 are inverted
// before going outside to the memory system.  So if &i == 0x1000,
// accessing i uses address 0x1000, A0 and A1 being ignored for a 32-bit

⌨️ 快捷键说明

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