⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ln97xend.c

📁 vxWorks下AMD973芯片的驱动源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* ln97xEnd.c - END style AMD Am79C97X PCnet-PCI Ethernet driver */

#include "copyright_wrs.h"

/*
modification history
--------------------
01c,08dec98,snk  made architecture independant, by teamF1 Inc.
		 tested with x86 & power Pc architectures.
01b,21sep98,dat  modified to stand alone
01a,01aug98,dmb  written from if_lnPci.c, ver 01e
*/

/*
DESCRIPTION  
This module implements the Advanced Micro Devices Am79C971
Am79C972 and Am79C973 PCnet-PCI Ethernet 32 bit network interface driver.

The PCnet-PCI ethernet controller is inherently little endian because
the chip is designed to operate on a PCI bus which is a little endian
bus. The software interface to the driver is divided into three parts.
The first part is the PCI configuration registers and their set up. 
This part is done at the BSP level in the various BSPs which use this
driver. The second and third part are dealt in the driver. The second
part of the interface comprises of the I/O control registers and their
programming. The third part of the interface comprises of the descriptors
and the buffers. 

This driver is designed to be moderately generic, operating unmodified
across the range of architectures and targets supported by VxWorks.  To
achieve this, the driver must be given several target-specific parameters,
and some external support routines must be provided. These target-specific
values and the external support routines are described below.

This driver supports multiple units per CPU.  The driver can be
configured to support big-endian or little-endian architectures.  It
contains error recovery code to handle known device errata related to DMA
activity. 

Big endian processors can be connected to the PCI bus through some controllers
which take care of hardware byte swapping. In such cases all the registers 
which the chip DMA s to have to be swapped and written to, so that when the
hardware swaps the accesses, the chip would see them correctly. The chip still
has to be programmed to operated in little endian mode as it is on the PCI bus.
If the cpu board hardware automatically swaps all the accesses to and from the
PCI bus, then input and output byte stream need not be swapped. 

BOARD LAYOUT
This device is on-board.  No jumpering diagram is necessary.

EXTERNAL INTERFACE
The only external interface is the ln97xEndLoad() routine, which expects
the <initString> parameter as input.  This parameter passes in a 
colon-delimited string of the format:

<unit>:<devMemAddr>:<devIoAddr>:<pciMemBase:<vecNum>:<intLvl>:<memAdrs>:
<memSize>:<memWidth>:<csr3b>:<offset>:<flags>

The ln97xEndLoad() function uses strtok() to parse the string.

TARGET-SPECIFIC PARAMETERS
.IP <unit>
A convenient holdover from the former model.  This parameter is used only
in the string name for the driver.

.IP <devMemAddr>
This parameter in the memory base address of the device registers in the
memory map of the CPU. It indicates to the driver where to find the
RDP register.
The LANCE presents two registers to the external interface, the RDP (register
data port) and RAP (register address port) registers.  This driver assumes 
that these two registers occupy two unique addresses in a memory space
that is directly accessible by the CPU executing this driver.  The driver
assumes that the RDP register is mapped at a lower address than the RAP
register; the RDP register is therefore derived from the "base address."
This parameter should be equal to NONE if memory map is not used.

.IP <devIoAddr>
This parameter in the IO base address of the device registers in the
IO map of some CPUs. It indicates to the driver where to find the RDP
register. If both <devIoAddr> and <devMemAddr> are given then the device
chooses <devMemAddr> which is a memory mapped register base address.
This parameter should be equal to NONE if IO map is not used.

.IP <pciMemBase>
This parameter is the base address of the CPU memory as seen from the
PCI bus. This parameter is zero for most intel architectures.

.IP <vecNum>
This parameter is the vector associated with the device interrupt.
This driver configures the LANCE device to generate hardware interrupts
for various events within the device; thus it contains
an interrupt handler routine.  The driver calls intConnect() to connect 
its interrupt handler to the interrupt vector generated as a result of 
the LANCE interrupt.

.IP <intLvl>
Some targets use additional interrupt controller devices to help organize
and service the various interrupt sources.  This driver avoids all
board-specific knowledge of such devices.  During the driver's
initialization, the external routine sysLan97xIntEnable() is called to
perform any board-specific operations required to allow the servicing of a
LANCE interrupt.  For a description of sysLan97xIntEnable(), see "External
Support Requirements" below.

.IP <memAdrs>
This parameter gives the driver the memory address to carve out its
buffers and data structures. If this parameter is specified to be
NONE then the driver allocates cache coherent memory for buffers
and descriptors from the system pool.
The LANCE device is a DMA type of device and typically shares access to
some region of memory with the CPU.  This driver is designed for systems
that directly share memory between the CPU and the LANCE.  It
assumes that this shared memory is directly available to it
without any arbitration or timing concerns.

.IP <memSize>
This parameter can be used to explicitly limit the amount of shared
memory (bytes) this driver will use.  The constant NONE can be used to
indicate no specific size limitation.  This parameter is used only if
a specific memory region is provided to the driver.

.IP <memWidth>
Some target hardware that restricts the shared memory region to a
specific location also restricts the access width to this region by
the CPU.  On these targets, performing an access of an invalid width
will cause a bus error.

This parameter can be used to specify the number of bytes of access
width to be used by the driver during access to the shared memory.
The constant NONE can be used to indicate no restrictions.

Current internal support for this mechanism is not robust; implementation 
may not work on all targets requiring these restrictions.

.IP <csr3b>
The LANCE control register #3 determines the bus mode of the device,
allowing the support of big-endian and little-endian architectures.
This parameter, defined as "UINT32 lnCSR_3B", is the value that will
be placed into LANCE control register #3.  The default value supports
Motorola-type buses.  For information about changing this parameter, see 
the manual. Normally for devices on the PCI bus this should always be
little endian. This value is zero normally

.IP <offset>
This parameter specifies the offset from which the packet has to be
loaded from the begining of the device buffer. Normally this parameter is
zero except for architectures which access long words only on aligned
addresses. For these architectures the value of this offset should be 2.

.IP <flags>
This is parameter is used for future use, currently its value should be
zero.

EXTERNAL SUPPORT REQUIREMENTS
This driver requires several external support functions, defined as macros:
.CS
    SYS_INT_CONNECT(pDrvCtrl, routine, arg)
    SYS_INT_DISCONNECT (pDrvCtrl, routine, arg)
    SYS_INT_ENABLE(pDrvCtrl)
    SYS_INT_DISABLE(pDrvCtrl)
    SYS_OUT_BYTE(pDrvCtrl, reg, data)
    SYS_IN_BYTE(pDrvCtrl, reg, data)
    SYS_OUT_WORD(pDrvCtrl, reg, data)
    SYS_IN_WORD(pDrvCtrl, reg, data)
    SYS_OUT_LONG(pDrvCtrl, reg, data)
    SYS_IN_LONG(pDrvCtrl, reg, data)
    SYS_ENET_ADDR_GET(pDrvCtrl, pAddress)    
    sysLan97xIntEnable(pDrvCtrl->intLevel) 
    sysLan97xIntDisable(pDrvCtrl->intLevel) 
    sysLan97xEnetAddrGet(pDrvCtrl, enetAdrs)
.CE

There are default values in the source code for these macros.  They presume
memory mapped accesses to the device registers and the normal intConnect(),
and intEnable() BSP functions.  The first argument to each is the device
controller structure. Thus, each has access back to all the device-specific
information.  Having the pointer in the macro facilitates the addition 
of new features to this driver.

The macros SYS_INT_CONNECT, SYS_INT_DISCONNECT, SYS_INT_ENABLE and
SYS_INT_DISABLE allow the driver to be customized for BSPs that use special
versions of these routines.

The macro SYS_INT_CONNECT is used to connect the interrupt handler to
the appropriate vector.  By default it is the routine intConnect().

The macro SYS_INT_DISCONNECT is used to disconnect the interrupt handler prior
to unloading the module.  By default this is a dummy routine that
returns OK.

The macro SYS_INT_ENABLE is used to enable the interrupt level for the
end device.  It is called once during initialization.  It calls an
external board level routine sysLan97xIntEnable(). 

The macro SYS_INT_DISABLE is used to disable the interrupt level for the
end device.  It is called during stop.  It calls an
external board level routine sysLan97xIntDisable(). 

The macro SYS_ENET_ADDR_GET is used get the ethernet hardware of the
chip. This macro calls an external board level routine namely
sysLan97xEnetAddrGet() to get the ethernet address.

SYSTEM RESOURCE USAGE
When implemented, this driver requires the following system resources:

    - one mutual exclusion semaphore
    - one interrupt vector
    - 13288 bytes in text for a I80486 target
    - 64 bytes in the initialized data section (data)
    - 0 bytes in the uninitialized data section (BSS)

The driver allocates clusters of size 1520 bytes for receive frames and
and transmit frames.

INCLUDES:
end.h endLib.h etherMultiLib.h ln97xEnd.h

SEE ALSO: muxLib, endLib, netBufLib
.I "Writing and Enhanced Network Driver"
.I "Advanced Micro Devices PCnet-PCI Ethernet Controller for PCI."
*/

#include "vxWorks.h"
#include "wdLib.h"
#include "stdlib.h"
#include "taskLib.h"
#include "logLib.h"
#include "intLib.h"
#include "netLib.h"
#include "stdio.h"
#include "stdlib.h"
#include "sysLib.h"
#include "iv.h"
#include "memLib.h"
#include "semLib.h"
#include "cacheLib.h"
#include "sys/ioctl.h"
#include "etherLib.h"


#ifndef DOC             /* don't include when building documentation */
#include "net/mbuf.h"
#endif  /* DOC */

#include "net/protosw.h"
#include "sys/socket.h"
#include "errno.h"
#include "net/if.h"
#include "net/route.h"
#include "netinet/in.h"
#include "netinet/in_systm.h"
#include "netinet/in_var.h"
#include "netinet/ip.h"
#include "netinet/if_ether.h"
#include "net/if_subr.h"
#include "m2Lib.h"

#include "etherMultiLib.h"              /* multicast stuff. */
#include "end.h"                        /* Common END structures. */
#include "netBufLib.h"
#include "muxLib.h"

#undef END_MACROS

#include "endLib.h"
#include "lstLib.h"                     /* Needed to maintain protocol list. */
#include "ln97xEnd.h"
#include "bsp8240.h"


#include "drv/pci/pciConfigLib.h"
#include "drv/pci/pciAutoConfigLib.h"
/* local defines */

/*
 * If LN_KICKSTART_TX is TRUE the transmitter is kick-started to force a
 * read of the transmit descriptors, otherwise the internal polling (1.6msec)
 * will initiate a read of the descriptors.  This should be FALSE is there
 * is any chance of memory latency or chip accesses detaining the LANCE DMA,
 * which results in a transmitter UFLO error.  This can be changed with the
 * global lnKickStartTx below.
 */

#define LN_KICKSTART_TX TRUE

/* Cache macros */

#define LN_CACHE_INVALIDATE(address, len) \
        CACHE_DRV_INVALIDATE (&pDrvCtrl->cacheFuncs, (address), (len))

#define LN_CACHE_VIRT_TO_PHYS(address) \
        CACHE_DRV_VIRT_TO_PHYS (&pDrvCtrl->cacheFuncs, (address))

#define LN_CACHE_PHYS_TO_VIRT(address) \
        CACHE_DRV_PHYS_TO_VIRT (&pDrvCtrl->cacheFuncs, (address))

/* memory to PCI address translation macros */

#define PCI_TO_MEM_PHYS(pciAdrs) \
    ((pciAdrs) - (pDrvCtrl->pciMemBase))
	
#define MEM_TO_PCI_PHYS(memAdrs) \
    ((memAdrs) + (pDrvCtrl->pciMemBase))
    
/*
 * Default macro definitions for BSP interface.
 * These macros can be redefined in a wrapper file, to generate
 * a new module with an optimized interface.
 */

#ifndef SYS_INT_CONNECT
#define SYS_INT_CONNECT(pDrvCtrl,rtn,arg,pResult) \
    { \
    IMPORT STATUS sysIntConnect(); \
    *pResult = intConnect ((VOIDFUNCPTR *)INUM_TO_IVEC (pDrvCtrl->ivec), \
                             rtn, (int)arg); \
    }
#endif /*SYS_INT_CONNECT*/

#ifndef SYS_INT_DISCONNECT
#define SYS_INT_DISCONNECT(pDrvCtrl,rtn,arg,pResult) \
    { \
    *pResult = OK; /* HELP: need a real routine */ \
    }
#endif /*SYS_INT_DISCONNECT*/

#ifndef SYS_INT_ENABLE
#define SYS_INT_ENABLE() \
    { \
    IMPORT STATUS sysLan97xIntEnable(); \
    sysLan97xIntEnable (pDrvCtrl->ilevel); \
    }
#endif /* SYS_INT_ENABLE*/

/* Macro to disable the appropriate interrupt level */

#ifndef SYS_INT_DISABLE
#define SYS_INT_DISABLE(pDrvCtrl) \
    { \
    IMPORT STATUS sysLan97xIntDisable (); \
    sysLan97xIntDisable (pDrvCtrl->ilevel); \
    }
#endif

#ifndef SYS_OUT_LONG
#define SYS_OUT_LONG(pDrvCtrl,addr,value) \
    { \
    *((ULONG *)(addr)) = (value); \
    }
#endif /* SYS_OUT_LONG */

#ifndef SYS_IN_LONG
#define SYS_IN_LONG(pDrvCtrl,addr,data) \
    { \
    ((data) = *((ULONG *)(addr))); \
    }
#endif /* SYS_IN_LONG */

#ifndef SYS_OUT_SHORT
#define SYS_OUT_SHORT(pDrvCtrl,addr,value) \
    { \
    *((USHORT *)(addr)) = (value); \
    }
#endif /* SYS_OUT_SHORT*/

#ifndef SYS_IN_SHORT
#define SYS_IN_SHORT(pDrvCtrl,addr,data) \
    { \
    ((data) = *((USHORT *)(addr))); \
    }      
#endif /* SYS_IN_SHORT*/

#ifndef SYS_OUT_BYTE
#define SYS_OUT_BYTE(pDrvCtrl,addr,value) \
    { \
    *((UCHAR *)(addr)) = (value); \
    }
#endif /* SYS_OUT_BYTE */

#ifndef SYS_IN_BYTE
#define SYS_IN_BYTE(pDrvCtrl,addr,data) \
    { \
    ((data) = *((UCHAR *)(addr))); \
    }
#endif /* SYS_IN_BYTE */
#ifndef SYS_ENET_ADDR_GET
#define SYS_ENET_ADDR_GET(pDrvCtrl, pAddress) \
    { \
    IMPORT STATUS sysLan97xEnetAddrGet (LN_97X_DRV_CTRL *pDrvCtrl, \
                                     char * enetAdrs); \
    sysLan97xEnetAddrGet (pDrvCtrl, pAddress); \
    }
#endif /* SYS_ENET_ADDR_GET */

/* A shortcut for getting the hardware address from the MIB II stuff. */

#define END_HADDR(pEnd) \
                ((pEnd)->mib2Tbl.ifPhysAddress.phyAddress)

#define END_HADDR_LEN(pEnd) \
                ((pEnd)->mib2Tbl.ifPhysAddress.addrLength)

#define END_FLAGS_ISSET(pEnd, setBits) \
            ((pEnd)->flags & (setBits))

/* externs */

IMPORT int endMultiLstCnt (END_OBJ *);

#ifdef DRV_DEBUG	/* if debugging driver */

int      ln97xDebug = DRV_DEBUG_LOAD | DRV_DEBUG_INT | DRV_DEBUG_TX;
NET_POOL * pLan97xNetPool;

#define DRV_LOG(FLG, X0, X1, X2, X3, X4, X5, X6) \
        if (ln97xDebug & FLG) \
            logMsg((char *)X0, (int)X1, (int)X2, (int)X3, (int)X4, \
		    (int)X5, (int)X6);

#define DRV_PRINT(FLG,X) \
        if (ln97xDebug & FLG) printf X;

#else /*DRV_DEBUG*/

#define DRV_LOG(DBG_SW, X0, X1, X2, X3, X4, X5, X6)
#define DRV_PRINT(DBG_SW,X)

⌨️ 快捷键说明

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