Sort of patch: Ethernet driver for National Semiconductor DP83815 for linux-2.2.16

From: Adam J. Richter (adam@yggdrasil.com)
Date: Thu Jul 27 2000 - 19:56:37 EDT

  • Next message: David S. Miller: "Re: br_read_lock SMP race fix"

            I have received a patch from Dave Gotwisner at Wyse Technologies
    for an ethernet driver for the National Semiconductor dp83815 chip
    for Linux 2.2.16. Unless someone else wants to do it, I will port it
    to 2.4.0 and submit it to Linus. However, I don't want to force
    anyone to wait for me, so I am posting the patch that I received,
    verbatim, to this mailing list in case anyone wants access now and so
    anyone searching for it on dejanews will be able to find it. (I have
    already emailed a copy to Don Becker.)

    Adam J. Richter __ ______________ 4880 Stevens Creek Blvd, Suite 104
    adam@yggdrasil.com \ / San Jose, California 95129-1034
    +1 408 261-6630 | g g d r a s i l United States of America
    fax +1 408 261-6631 "Free Software For The Rest Of Us."
    --------------------------CUT HERE------------------------------------
    diff -Naur linux-baseline/Documentation/Configure.help linux/Documentation/Configure.help
    --- linux-baseline/Documentation/Configure.help Wed Jun 7 21:26:42 2000
    +++ linux/Documentation/Configure.help Thu Jul 6 00:26:45 2000
    @@ -6584,6 +6584,16 @@
       module, say M here and read Documentation/modules.txt as well as
       Documentation/networking/net-modules.txt.
     
    +National DP83815 PCI support
    +CONFIG_DP83815
    + National provided DP83815 Ethernet chip driver.
    +
    + This driver is also available as a module ( = code which can be
    + inserted in and removed from the running kernel whenever you want).
    + The module will be called dp83815.o. If you want to compile it as a
    + module, say M here and read Documentation/modules.txt as well as
    + Documentation/networking/net-modules.txt.
    +
     DECchip Tulip (dc21x4x) PCI support
     CONFIG_DEC_ELCP
       This driver is developed for the SMC EtherPower series Ethernet
    diff -Naur linux-baseline/drivers/net/Config.in linux/drivers/net/Config.in
    --- linux-baseline/drivers/net/Config.in Wed Jun 7 21:26:43 2000
    +++ linux/drivers/net/Config.in Thu Jul 6 00:30:16 2000
    @@ -132,6 +132,7 @@
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
           tristate 'DM9102 PCI Fast Ethernet Adapter support (EXPERIMENTAL)' CONFIG_DM9102
         fi
    + tristate 'National DP83815 PCI support' CONFIG_DP83815
         tristate 'Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
         tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
         if [ "$CONFIG_DEC_ELCP" != "y" ]; then
    diff -Naur linux-baseline/drivers/net/Makefile linux/drivers/net/Makefile
    --- linux-baseline/drivers/net/Makefile Wed Jun 7 21:26:43 2000
    +++ linux/drivers/net/Makefile Thu Jul 6 00:30:48 2000
    @@ -751,6 +751,14 @@
       endif
     endif
     
    +ifeq ($(CONFIG_DP83815),y)
    +L_OBJS += dp83815.o
    +else
    + ifeq ($(CONFIG_DP83815),m)
    + M_OBJS += dp83815.o
    + endif
    +endif
    +
     ifeq ($(CONFIG_DEC_ELCP),y)
     L_OBJS += tulip.o
     else
    diff -Naur linux-baseline/drivers/net/Space.c linux/drivers/net/Space.c
    --- linux-baseline/drivers/net/Space.c Wed Jun 7 21:26:43 2000
    +++ linux/drivers/net/Space.c Thu Jul 6 00:44:06 2000
    @@ -40,6 +40,7 @@
        */
     
     extern int ne2_probe(struct device *dev);
    +extern int dp83815_probe(struct device *dev);
     extern int tulip_probe(struct device *dev);
     extern int hp100_probe(struct device *dev);
     extern int ultra_probe(struct device *dev);
    @@ -207,6 +208,9 @@
     #endif
     #ifdef CONFIG_LANMEDIA /* Lanmedia must be before Tulip */
             {lmc_probe_fake, 0},
    +#endif
    +#ifdef CONFIG_DP83815
    + {dp83815_probe, 0},
     #endif
     #if defined(CONFIG_DEC_ELCP) || defined(CONFIG_DEC_ELCP_OLD)
             {tulip_probe, 0},
    diff -Naur linux-baseline/drivers/net/dp83815.h linux/drivers/net/dp83815.h
    --- linux-baseline/drivers/net/dp83815.h Thu Jan 1 00:00:00 1970
    +++ linux/drivers/net/dp83815.h Thu Jul 6 00:45:03 2000
    @@ -0,0 +1,636 @@
    +/* dp83815.h -- National Semiconductor DP83815 Ethernet Controller Interface */
    +/* Changes for the Rev C of DP83815 have been included */
    +
    +#ifndef __DP83815_H__
    +#define __DP83815_H__
    +
    +#ifdef __KERNEL__
    +#include <linux/types.h>
    +#endif
    +
    +#define DP_DEV_NAME "National Semiconductor DP83815 PCI Ethernet"
    +#define DP_DRV_NAME "dp83815"
    +
    +/* PCI Confiugration Registers */
    +
    +#undef PCI_VENDOR_ID_NS_83815
    +#define PCI_VENDOR_ID_NS_83815 0x0020 /* DP83815 */
    +
    +#define DP83815_PCI_IO_SIZE 256
    +
    +/*
    + * Operational Registers:
    + * These registers are mapped either into PCI memory space or I/O space.
    + */
    +
    +/* MAC/BIU Registers */
    +
    +#define DP_CR 0x00 /* Command Register */
    +#define DP_CFG 0x04 /* Configuration Register */
    +#define DP_MEAR 0x08 /* EEPROM Access Register */
    +#define DP_PTSCR 0x0C /* PCI Test Control Register */
    +#define DP_ISR 0x10 /* Intr Status Register */
    +#define DP_IMR 0x14 /* Intr Mask Register */
    +#define DP_IER 0x18 /* Intr Enable Register */
    +#define DP_TXDP 0x20 /* Tx Descriptor Pointer Register */
    +#define DP_TXCFG 0x24 /* Tx Configuration Register */
    +#define DP_RXDP 0x30 /* Rx Descriptor Pointer Register */
    +#define DP_RXCFG 0x34 /* Rx Configuration Register */
    +#define DP_WCSR 0x40 /* Wake on LAN Control/Status Register */
    +#define DP_PCR 0x44 /* Pause Control/Status Register */
    +#define DP_RFCR 0x48 /* Rx Filter/Match Control Register */
    +#define DP_RFDR 0x4C /* Rx Filter/Match Data Register */
    +#define DP_BRAR 0x50 /* Boot ROM Address */
    +#define DP_BRDR 0x54 /* Boot ROM Data */
    +#define DP_SRR 0x58 /* Silicon Revision Register (RO) */
    +#define DP_MIBC 0x5C /* MIB Control Registor */
    +#define DP_MIB 0x60 /* MIB Data Register Base (RO) */
    +
    +/* MIB Registers */
    +
    +#define DP_MIB_RX_PKT_ERR 0x60 /* Pkts recvd with errors */
    +#define DP_MIB_RX_FCS_ERR 0x64 /* Pkts recvd with frame check seq errs */
    +#define DP_MIB_RX_MISS_PKT 0x68 /* Pkts missed due to FIFO overruns*/
    +#define DP_MIB_RX_FA_ERR 0x6C /* Pkts recvd with frame alignment errs */
    +#define DP_MIB_RX_SYM_ERR 0x70 /* Pkts recvd with symbol errs */
    +#define DP_MIB_RX_LONG_FRM 0x74 /* Pkts > 1518 bytes */
    +#define DP_MIB_TXSQE_ERR 0x78 /* Loss of coll. heartbeat on Tx */
    +
    +/* Internal Phy Registers */
    +
    +#define DP_BMCR 0x80 /* Basic Mode Control Register */
    +#define DP_BMSR 0x84 /* Basic Mode Status Register (RO) */
    +#define DP_PHYIDR1 0x88 /* PHY Identifier Register #1 (RO) */
    +#define DP_PHYIDR2 0x8C /* PHY Identifier Register #2 (RO) */
    +#define DP_ANAR 0x90 /* Auto-Nego Advertisment Reg */
    +#define DP_ANLPAR 0x94 /* Auto-Nego Link Partner Ability Reg */
    +#define DP_ANER 0x98 /* Auto-Negotiation Expansion Reg */
    +#define DP_ANNPTR 0x9C /* Auto-Negotiation Next Page TX */
    +#define DP_PHYSTS 0xC0 /* PHY Status Register (RO) */
    +#define DP_FCSCR 0xD0 /* False Carrier Sense Counter Reg */
    +#define DP_RECR 0xD4 /* Recv Error Counter Register */
    +#define DP_PHYCR 0xE4 /* PHY Control Register */
    +#define DP_10BTSCR 0xE8 /* 10Base-TStatus/Control Reg */
    +
    +/* New Phy registers and their bit mask values for Rev 3 */
    +
    +#define DP_PHY_PAGE 0xCC /* */
    +#define DP_PHY_DSPCFG 0xF4 /* */
    +#define DP_PHY_SDCFG 0xF8 /* */
    +#define DP_PHY_TDATA 0xFC /* */
    +
    +#define DP_PHY_PAGE_VAL (u16)0x0001 /* */
    +#define DP_PHY_DSPCFG_VAL (u16)0x5040 /* Load/Kill C2 */
    +#define DP_PHY_SDCFG_VAL (u16)0x008C /* Raise SD off, from 4 to C */
    +#define DP_PHY_TDATA_VAL (u16)0x0000 /* Set value for C2 */
    +#define DP_PHYCR_PMDCSR_VAL (u16)0x189C /* DC Speed = 01 */
    +
    +/*
    + * Command Register Bit Masks (DP_CR)
    + *
    + * This register is used for issuing commands to DP83815. A global software
    + * reset along with individual reset and enable/disable switches for
    + * transmitter and receiver are provided here.
    + */
    +
    +#define DP_CR_TXE 0x00000001 /* Transmit Enable */
    +#define DP_CR_TXD 0x00000002 /* Transmit Disable */
    +#define DP_CR_RXE 0x00000004 /* Receiver Enable */
    +#define DP_CR_RXD 0x00000008 /* Receiver Disable */
    +#define DP_CR_TXR 0x00000010 /* Transmit Reset */
    +#define DP_CR_RXR 0x00000020 /* Receiver Reset */
    +#define DP_CR_SWI 0x00000080 /* Software Interrupt */
    +#define DP_CR_RST 0x00000100 /* Reset */
    +
    +/*
    + * Configuration and Media Status Register Bit Masks (DP_CFG)
    + *
    + * This register allows configuration of a various device and phy options,
    + * and provide phy status information.
    + */
    +
    +#define DP_CFG_BEM (u32)0x00000001 /* Big Endian Mode (BM xfers) */
    +#define DP_CFG_BROM_DIS (u32)0x00000004 /* Disable Boot ROM interface */
    +#define DP_CFG_PESEL (u32)0x00000008 /* Parity Err Det (BM xfer) */
    +#define DP_CFG_EXD (u32)0x00000010 /* Excessv Deferl Tmr disbl */
    +#define DP_CFG_POW (u32)0x00000020 /* Prog Out of Window Timer */
    +#define DP_CFG_SB (u32)0x00000040 /* Single Back-off */
    +#define DP_CFG_REQALG (u32)0x00000080 /* PCI Bus Request Algorithm */
    +#define DP_CFG_EUPHCOMP (u32)0x00000100 /* DP83810 Descriptor Compat */
    +#define DP_CFG_PHY_DIS (u32)0x00000200 /* Disable internal Phy */
    +#define DP_CFG_PHY_RST (u32)0x00000400 /* Reset internal Phy */
    +#define DP_CFG_ANEG_SEL (u32)0x0000E000 /* Auto-nego Sel - Mask */
    +#define DP_CFG_ANEG_SEL_10_HD (u32)0x00000000 /* Force 10Mb Half duplex */
    +#define DP_CFG_ANEG_SEL_100_HD (u32)0x00004000 /* Force 100Mb Half duplex */
    +#define DP_CFG_ANEG_SEL_10_FD (u32)0x00008000 /* Force 10Mb Full duplex */
    +#define DP_CFG_ANEG_SEL_100_FD (u32)0x0000C000 /* Force 100Mb Full duplex */
    +#define DP_CFG_ANEG_SEL_10_XD (u32)0x00002000 /* Nego 10Mb Half/Full dplx */
    +#define DP_CFG_ANEG_SEL_ALL_HD (u32)0x00006000 /* Nego 10/100 Half duplex */
    +#define DP_CFG_ANEG_SEL_100_XD (u32)0x0000A000 /* Nego 100 Half/Full duplex */
    +#define DP_CFG_ANEG_SEL_ALL_XD (u32)0x0000E000 /* Nego 10/100 Half/Full dplx*/
    +#define DP_CFG_PAUSE_ADV (u32)0x00010000 /* Strap for pause capable */
    +#define DP_CFG_PINT_ACEN (u32)0x00020000 /* Phy Intr Auto Clr Enable */
    +#define DP_CFG_PHY_CFG (u32)0x00FC0000 /* Phy Configuration */
    +#define DP_CFG_ANEG_DN (u32)0x08000000 /* Auto-negotiation Done */
    +#define DP_CFG_POL (u32)0x10000000 /* 10Mb Polarity Indication */
    +#define DP_CFG_FDUP (u32)0x20000000 /* Full Duplex */
    +#define DP_CFG_SPEED100 (u32)0x40000000 /* Speed 100Mb */
    +#define DP_CFG_LNKSTS (u32)0x80000000 /* Link status */
    +
    +/*
    + * EEPROM Access Register Bit Masks (DP_MEAR)
    + *
    + * Provides an interface for software access to the NMC9306 style EEPROM. The
    + * default values given assume that the EEDO line has a pullup resistor to
    + * VDD.
    + */
    +
    +#define DP_MEAR_EEDI (u32)0x00000001 /* EEPROM data in */
    +#define DP_MEAR_EEDO (u32)0x00000002 /* EEPROM data out */
    +#define DP_MEAR_EECLK (u32)0x00000004 /* EEPROM Serial Clock */
    +#define DP_MEAR_EESEL (u32)0x00000008 /* EEPROM Chip Select */
    +
    +/* PCI Test Control Register Bit Masks (DP_PTSCR) */
    +
    +#define DP_PTSCR_EEBIST_FAIL (u32)0x00000001 /* EE BIST Fail Indication */
    +#define DP_PTSCR_EEBIST_EN (u32)0x00000002 /* Enable EEPROM BIST */
    +#define DP_PTSCR_EELOAD_EN (u32)0x00000004 /* Enable EEPROM Load */
    +#define DP_PTSCR_RBIST_RXFFAIL (u32)0x00000008 /* RX Filter RAM BIST Fail */
    +#define DP_PTSCR_RBIST_TXFAIL (u32)0x00000010 /* TX FiFO Fail */
    +#define DP_PTSCR_RBIST_RXFAIL (u32)0x00000020 /* RX FIFO BIST Fail */
    +#define DP_PTSCR_RBIST_ACT (u32)0x00000040 /* SRAM BIST Active*/
    +#define DP_PTSCR_RBIST_EN (u32)0x00000080 /* SRAM BIST Enable */
    +#define DP_PTSCR_RBIST_MODE (u32)0x00000100 /* SRAM BIST Mode */
    +#define DP_PTSCR_RBIST_CLKD (u32)0x00000200 /* SRAM BIST Clock */
    +#define DP_PTSCR_RBIST_RST (u32)0x00000400 /* SRAM BIST Reset */
    +#define DP_PTSCR_RESVD (u32)0x00001000 /* Reserved -- Must be 1 */
    +
    +/*
    + * Interrupt Status Register Bit Masks (DP_ISR)
    + *
    + * Indicates the source of an interrupt when the INTA pin goes active.
    + * Enabling the corresponding bit in the IMR allows bits in this reg to produce
    + * an interrupt. ISR reflects all pending iterrupts regardless of the status
    + * of the corresponding mask bit in the IMR.
    + */
    +
    +#define DP_ISR_RXOK (u32)0x00000001 /* Rx OK */
    +#define DP_ISR_RXDESC (u32)0x00000002 /* Rx Descriptor */
    +#define DP_ISR_RXERR (u32)0x00000004 /* Rx packet Error */
    +#define DP_ISR_RXEARLY (u32)0x00000008 /* Rx Early Threshold */
    +#define DP_ISR_RXIDLE (u32)0x00000010 /* Rx Idle */
    +#define DP_ISR_RXORN (u32)0x00000020 /* Rx Overrun */
    +#define DP_ISR_TXOK (u32)0x00000040 /* Tx Packet OK */
    +#define DP_ISR_TXDESC (u32)0x00000080 /* Tx Descriptor */
    +#define DP_ISR_TXERR (u32)0x00000100 /* Tx Packet Error */
    +#define DP_ISR_TXIDLE (u32)0x00000200 /* Tx Idle */
    +#define DP_ISR_TXURN (u32)0x00000400 /* Tx Underrun */
    +#define DP_ISR_MIB (u32)0x00000800 /* MIB Service */
    +#define DP_ISR_SWI (u32)0x00001000 /* Software Interrupt */
    +#define DP_ISR_PME (u32)0x00002000 /* Power Management Event */
    +#define DP_ISR_PHY (u32)0x00004000 /* Phy Interrupt */
    +#define DP_ISR_HIBERR (u32)0x00008000 /* High Bits error set */
    +#define DP_ISR_RXSOVR (u32)0x00010000 /* Rx Status FIFO Overrun */
    +#define DP_ISR_RTABT (u32)0x00100000 /* Recieved Target Abort */
    +#define DP_ISR_RMABT (u32)0x00200000 /* Recieved Master Abort */
    +#define DP_ISR_SSERR (u32)0x00400000 /* Signaled System Error */
    +#define DP_ISR_DPERR (u32)0x00800000 /* Detected Parity Error */
    +#define DP_ISR_RXRCMP (u32)0x01000000 /* Receive Reset Complete */
    +#define DP_ISR_TXRCMP (u32)0x02000000 /* Transmit Reset Complete */
    +
    +/*
    + * Interrupt Mask Register Bit Masks (DP_IMR)
    + *
    + * Interrupts are enabled by setting the appropriate bit-mask.
    + */
    +
    +#define DP_IMR_RXOK (u32)0x00000001 /* Rx ok */
    +#define DP_IMR_RXDESC (u32)0x00000002 /* Rx Descriptor */
    +#define DP_IMR_RXERR (u32)0x00000004 /* Rx packet Error */
    +#define DP_IMR_RXEARLY (u32)0x00000008 /* Rx Early Threshold */
    +#define DP_IMR_RXIDLE (u32)0x00000010 /* Rx Idle */
    +#define DP_IMR_RXORN (u32)0x00000020 /* Rx Overrun */
    +#define DP_IMR_TXOK (u32)0x00000040 /* Tx Packet Ok */
    +#define DP_IMR_TXDESC (u32)0x00000080 /* Tx Descriptor */
    +#define DP_IMR_TXERR (u32)0x00000100 /* Tx Packet Error */
    +#define DP_IMR_TXIDLE (u32)0x00000200 /* Tx Idle */
    +#define DP_IMR_TXURN (u32)0x00000400 /* Tx Underrun */
    +#define DP_IMR_MIB (u32)0x00000800 /* MIB Service */
    +#define DP_IMR_SWI (u32)0x00001000 /* Software Interrupt */
    +#define DP_IMR_PME (u32)0x00002000 /* Power Management Event */
    +#define DP_IMR_PHY (u32)0x00004000 /* Phy Interrupt */
    +#define DP_IMR_HIERR (u32)0x00008000 /* High Bits error set */
    +#define DP_IMR_RXSOVR (u32)0x00010000 /* Rx Status FIFO Overrun */
    +#define DP_IMR_RTABT (u32)0x00100000 /* Recieved Target Abort */
    +#define DP_IMR_RMABT (u32)0x00200000 /* Recieved Master Abort */
    +#define DP_IMR_SSERR (u32)0x00400000 /* Signaled System Error */
    +#define DP_IMR_DPERR (u32)0x00800000 /* Detected Parity Error */
    +#define DP_IMR_RXRCMP (u32)0x01000000 /* Receive Reset Complete */
    +#define DP_IMR_TXRCMP (u32)0x02000000 /* Transmit Reset Complete */
    +
    +/*
    + * Interrupt Enable Register Bit Masks (DP_IER)
    + *
    + * Enable or disable DP chip interrupts
    + */
    +
    +#define DP_IER_IE (u32)0x00000001 /* Interrupt Enable */
    +#define DP_IER_ID (u32)0x00000000 /* Interrupt Disable */
    +
    +/* Transmit descriptor Pointer Register Bit Mask (DP_TXDP) */
    +
    +#define DP_TXDP_MSK (u32)0xFFFFFFFE /* Transmit Descriptor Ptr */
    +
    +/* Transmit Configuration Register Bit Masks (DP_TXCFG) */
    +
    +#define DP_TXCFG_DRTH (u32)0x0000003F /* Tx Drain Threshold */
    +#define DP_TXCFG_FLTH (u32)0x00003F00 /* Tx Fill Threshold */
    +#define DP_TXCFG_MXDMA (u32)0x00700000 /* Max DMA Burst Size */
    +#define DP_TXCFG_MXDMA_1 (u32)0x00100000 /* 1 32-bit word */
    +#define DP_TXCFG_MXDMA_2 (u32)0x00200000 /* 2 32-bit words */
    +#define DP_TXCFG_MXDMA_4 (u32)0x00300000 /* 4 32-bit words */
    +#define DP_TXCFG_MXDMA_8 (u32)0x00400000 /* 8 32-bit words */
    +#define DP_TXCFG_MXDMA_16 (u32)0x00500000 /* 16 32-bit words */
    +#define DP_TXCFG_MXDMA_32 (u32)0x00600000 /* 32 32-bit words */
    +#define DP_TXCFG_MXDMA_64 (u32)0x00700000 /* 64 32-bit words */
    +#define DP_TXCFG_MXDMA_128 (u32)0x00000000 /* 128 32-bit words */
    +#define DP_TXCFG_IFG (u32)0x0C000000 /* Interframe gap Time */
    +#define DP_TXCFG_ATP (u32)0x10000000 /* Automatic Transmit Pad */
    +#define DP_TXCFG_MLB (u32)0x20000000 /* MAC Loopback */
    +#define DP_TXCFG_HBI (u32)0x40000000 /* HeartBeat Ignore */
    +#define DP_TXCFG_CSI (u32)0x80000000 /* Carrier Sense Ignore */
    +
    +#define DP_TXCFG_DRTH_SET(X) ((X) & DP_TXCFG_DRTH)
    +#define DP_TXCFG_FLTH_SET(X) (((X) << 8) & DP_TXCFG_FLTH)
    +
    +/* Recieve Descriptor Pointer Register Bit Mask (DP_RXDP) */
    +
    +#define DP_RXDP_MSK (u32)0xFFFFFFFC /* Receive Descriptor Ptr */
    +
    +/* Recieve Configuration Register Bit Masks (DP_RXCFG) */
    +
    +#define DP_RXCFG_DRTH (u32)0x0000003E /* Rx Drain Threshold */
    +#define DP_RXCFG_MXDMA (u32)0x00700000 /* Max DMA Burst size */
    +#define DP_RXCFG_MXDMA_1 (u32)0x00100000 /* 1 32-bit words */
    +#define DP_RXCFG_MXDMA_2 (u32)0x00200000 /* 2 32-bit words */
    +#define DP_RXCFG_MXDMA_4 (u32)0x00300000 /* 4 32-bit words */
    +#define DP_RXCFG_MXDMA_8 (u32)0x00400000 /* 8 32-bit words */
    +#define DP_RXCFG_MXDMA_16 (u32)0x00500000 /* 16 32-bit words */
    +#define DP_RXCFG_MXDMA_32 (u32)0x00600000 /* 32 32-bit words */
    +#define DP_RXCFG_MXDMA_64 (u32)0x00700000 /* 64 32-bit words */
    +#define DP_RXCFG_MXDMA_128 (u32)0x00000000 /* 128 32-bit words */
    +#define DP_RXCFG_ALP (u32)0x08000000 /* Accept Long Packets */
    +#define DP_RXCFG_ATX (u32)0x10000000 /* Accept transmit packets */
    +#define DP_RXCFG_ARP (u32)0x40000000 /* Accept Runt Packets */
    +#define DP_RXCFG_AEP (u32)0x80000000 /* Accept Errored Packets */
    +
    +#define DP_RXCFG_DRTH_SET(X) ((X) & DP_RXCFG_DRTH)
    +
    +/*
    + * Wake Command/status Register Bit Masks (DP_WCSR)
    + *
    + * It is used to configure/control and monitor DP83815 Wake Od LAN Logic
    + * The Wake On LAN logic is used to monitor the incoming packet stream while
    + * in a low-power state, and provide a wake event to the system if desired
    + * packet type, contents, or Link change are detected.
    + */
    +
    +#define DP_WCSR_WKPHY (u32)0x00000001 /* Wake on Phy Interrupt */
    +#define DP_WCSR_WKUCP (u32)0x00000002 /* Wake on unicast */
    +#define DP_WCSR_WKMCP (u32)0x00000004 /* Wake on Multicast */
    +#define DP_WCSR_WKBCP (u32)0x00000008 /* Wake on Broadcast */
    +#define DP_WCSR_WKARP (u32)0x00000010 /* Wake on ARP */
    +#define DP_WCSR_WKPAT0 (u32)0x00000020 /* Wake on Pattern 0 match */
    +#define DP_WCSR_WKPAT1 (u32)0x00000040 /* Wake on Pattern 1 match */
    +#define DP_WCSR_WKPAT2 (u32)0x00000080 /* Wake on Pattern 2 match */
    +#define DP_WCSR_WKPAT3 (u32)0x00000100 /* Wake on Pattern 3 match */
    +#define DP_WCSR_WKMAG (u32)0x00000200 /* Wake on Magic Packet */
    +#define DP_WCSR_MPSOE (u32)0x00000400 /* Magic Packet SecureOn Enbl */
    +#define DP_WCSR_SOHACK (u32)0x00200000 /* SecureOn Hack Attempt */
    +#define DP_WCSR_PHYINT (u32)0x00400000 /* Phy Interrupt */
    +#define DP_WCSR_UCASTR (u32)0x00800000 /* Unicast Recieved */
    +#define DP_WCSR_MCASTR (u32)0x01000000 /* Multicast Recieved */
    +#define DP_WCSR_BCASTR (u32)0x02000000 /* Broadcast Recieved */
    +#define DP_WCSR_ARPR (u32)0x04000000 /* ARP Recieved */
    +#define DP_WCSR_PATM0 (u32)0x08000000 /* Pattern 0 match */
    +#define DP_WCSR_PATM1 (u32)0x10000000 /* Pattern 1 match */
    +#define DP_WCSR_PATM2 (u32)0x20000000 /* Pattern 2 match */
    +#define DP_WCSR_PATM3 (u32)0x40000000 /* Pattern 3 match */
    +#define DP_WCSR_MPR (u32)0x80000000 /* Magic Packet Recieved */
    +
    +/*
    + * Pause Control/Status Register Bit Masks (DP_PCR)
    + *
    + * It is used to control and monitor the DP 83815 Pause Frame reception logic
    + * The Pause frame reception logic is used to accept 802.3x Pause frames,
    + * extract the pause length value, and initiate a TXMAV pause interval of the
    + * specified number of slot times.
    + */
    +
    +#define DP_PCR_PAUSE_CNT (u32)0x0000FFFF /* Pause Counter value */
    +#define DP_PCR_MLD_EN (u32)0x00010000 /* Manual Load Enable */
    +#define DP_PCR_PSNEG (u32)0x00200000 /* Pause negotiated */
    +#define DP_PCR_PS_RCVD (u32)0x00400000 /* Pause frame recieved */
    +#define DP_PCR_PS_ACT (u32)0x00800000 /* Pause Active */
    +#define DP_PCR_PS_DA (u32)0x20000000 /* Pause on DA */
    +#define DP_PCR_PS_MCAST (u32)0x40000000 /* Pause on Multicast */
    +#define DP_PCR_PSEN (u32)0x80000000 /* Pause Enable */
    +
    +/*
    + * Recieve Filter/Match Control Register Bit Masks (DP_RFCR)
    + *
    + * It is used to control and configure the DP83815 Recieve Filter Control logic
    + * The RFC logic is used to configure destination address filtering of incoming
    + * packets.
    + */
    +
    +#define DP_RFCR_RFADDR (u32)0x000003FF /* Rx Filter Extended RegAdd */
    +#define DP_RFCR_RFADDR_PMATCH1 (u32)0x00000000 /* Perfect Match octets 1-0 */
    +#define DP_RFCR_RFADDR_PMATCH2 (u32)0x00000002 /* Perfect Match octets 3-2 */
    +#define DP_RFCR_RFADDR_PMATCH3 (u32)0x00000004 /* Perfect Match octets 5-4 */
    +#define DP_RFCR_RFADDR_PCOUNT1 (u32)0x00000006 /* Pattern Count 1-0 */
    +#define DP_RFCR_RFADDR_PCOUNT2 (u32)0x00000008 /* Pattern Count 3-2 */
    +#define DP_RFCR_RFADDR_SOPAS1 (u32)0x0000000A /* SecureOn Password 1-0 */
    +#define DP_RFCR_RFADDR_SOPAS2 (u32)0x0000000C /* SecureOn Password 3-2 */
    +#define DP_RFCR_RFADDR_SOPAS3 (u32)0x0000000E /* SecureOn Password 5-4 */
    +#define DP_RFCR_RFADDR_FMEM_LO (u32)0x00000200 /* Rx filter memory start */
    +#define DP_RFCR_RFADDR_FMEM_HI (u32)0x000003FE /* Rx filter memory end */
    +#define DP_RFCR_ULM (u32)0x00080000 /* U/L bit Mask */
    +#define DP_RFCR_UHEN (u32)0x00100000 /* Unicast Hash Enable */
    +#define DP_RFCR_MHEN (u32)0x00200000 /* Multicast Hash Enable */
    +#define DP_RFCR_AARP (u32)0x00400000 /* Accept ARP Packets */
    +#define DP_RFCR_APAT (u32)0x07800000 /* Accept On Pattern Match */
    +#define DP_RFCR_APM (u32)0x08000000 /* Accept on Perfect match */
    +#define DP_RFCR_AAU (u32)0x10000000 /* Accept All Unicast */
    +#define DP_RFCR_AAM (u32)0x20000000 /* Accept All Multicast */
    +#define DP_RFCR_AAB (u32)0x40000000 /* Accept All Broadcast */
    +#define DP_RFCR_RFEN (u32)0x80000000 /* Rx Filter Enable */
    +
    +/*
    + * Recieve Filter/Match Data Register Bit Masks (DP_RFDR)
    + *
    + * This register is used to read and write internal recieve filter registers,
    + * the pattern buffer memory and the hash table memory.
    + */
    +
    +#define DP_RFDR_RFDATA (u32)0x0000FFFF /* Recieve Filter data */
    +#define DP_RFDR_BMASK (u32)0x00030000 /* Byte Mask */
    +
    +/* Boot ROM Address Register Bit Masks (DP_BRAR) */
    +
    +#define DP_BRAR_ADDR (u32)0x0000FFFF /* Boot ROM Address */
    +#define DP_BRAR_AUTOINC (u32)0x80000000 /* Auto-Increment */
    +
    +/* Boot ROM Data Register Bit Masks (DP_BRDR) */
    +
    +#define DP_BRDR_DATA (u32)0xFFFFFFFF /* Boot ROM Data */
    +
    +/* Silicon Revision Register Bit Masks (DP_SRR) */
    +
    +#define DP_SRR_MIN (u32)0x000000FF /* Minor Revision Level */
    +#define DP_SRR_MAJ (u32)0x0000FF00 /* Major Revision Level */
    +#define DP_SRR_MAJ_SHF 8 /* Shift bits */
    +
    +/*
    + * Management Information Base Control Register Bit Masks (DP_MIBC)
    + *
    + * It is used to control access to the statistics block and the warning bits
    + * and to control the collection of management info statistics.
    + */
    +
    +#define DP_MIBC_WRN (u32)0x00000001 /* Warning Tst Indicator (RO) */
    +#define DP_MIBC_FRZ (u32)0x00000002 /* Freeze All Counters */
    +#define DP_MIBC_ACLR (u32)0x00000004 /* Clear all Counters */
    +#define DP_MIBC_MIBS (u32)0x00000008 /* MIB Counter Strobe (TEST) */
    +
    +/* BMCR - (Internal Phy) Basic Mode Control Register */
    +
    +#define DP_BMCR_COL_TST (u16)0x0080 /* Collision Test */
    +#define DP_BMCR_HDX (u16)0x0000 /* Half duplex mode */
    +#define DP_BMCR_FDX (u16)0x0100 /* Full duplex mode */
    +#define DP_BMCR_ANEG_RES (u16)0x0200 /* Restart Auto negotiation */
    +#define DP_BMCR_ISOLATE (u16)0x0400 /* Isolate */
    +#define DP_BMCR_PWRDWN (u16)0x0800 /* Power Down */
    +#define DP_BMCR_ANEG_EN (u16)0x3100 /* Auto Negotiation Enable */
    +#define DP_BMCR_SPD_100 (u16)0x2000 /* Speed Select 100Mbps */
    +#define DP_BMCR_SPD_10 (u16)0x0000 /* Speed Select 100Mbps */
    +#define DP_BMCR_LOOP (u16)0x4000 /* Loopback */
    +#define DP_BMCR_RESET (u16)0xB100 /* Reset */
    +
    +/* BMSR - (Internal Phy) Basic Mode Status Register */
    +
    +#define DP_BMSR_XREG_ABLE (u16)0x0001 /* Extended Register Capability */
    +#define DP_BMSR_JABR_DET (u16)0x0002 /* Jabber Detected */
    +#define DP_BMSR_LNK_VALID (u16)0x0004 /* Valid Link Status */
    +#define DP_BMSR_AN_ABLE (u16)0x0008 /* Auto-Neg Ability */
    +#define DP_BMSR_REM_FLT (u16)0x0010 /* Remote Fault Detected */
    +#define DP_BMSR_AN_DONE (u16)0x0020 /* Auto Nego Complete */
    +#define DP_BMSR_PRS_ABLE (u16)0x0040 /* Preamble Supr Capable */
    +#define DP_BMSR_10_HD_ABLE (u16)0x0800 /* 10BASE-T Half Duplex Capable */
    +#define DP_BMSR_10_FD_ABLE (u16)0x1000 /* 10BASE-T Full Duplex Capable */
    +#define DP_BMSR_100_HD_ABLE (u16)0x2000 /* 100BASE-TX Half Duplex Capable */
    +#define DP_BMSR_100_FD_ABLE (u16)0x4000 /* 100BASE-TX Full Duplex Capable */
    +#define DP_BMSR_100T4_ABLE (u16)0x8000 /* 100BASE -T4 Capable */
    +
    +/* PHY Identifier Register #1 */
    +
    +#define DP_PHYIDR1_OUI_MSB (u16)0xFFFF /* OUI Most significant Bits */
    +
    +/* PHY Identifier Register #2 */
    +
    +#define DP_PHYIDR2_MDL_REV (u16)0x000F /* Model Revision number */
    +#define DP_PHYIDR2_VNDR_MDL (u16)0x03F0 /* Vendor Model Number */
    +#define DP_PHYIDR2_OUI_LSB (u16)0xFC00 /* OUI Last Significant Bits */
    +
    +/*
    + * Auto-Negotiation Advertisement Register
    + *
    + * Contains the advertised abilities of this device as they will be transmitted
    + * to its link partner during Auto-Negotiation.
    + */
    +
    +#define DP_ANAR_SEL (u16)0x001F /* Protocol Selection Bits */
    +#define DP_ANAR_10T (u16)0x0020 /* 10BASE-T Support */
    +#define DP_ANAR_10_FD (u16)0x0040 /* 10BASE-T Full Duplex Support */
    +#define DP_ANAR_TX (u16)0x0080 /* 100BASE-TX Support */
    +#define DP_ANAR_TX_FD (u16)0x0100 /* 100BASE-TX Full Duplex Support */
    +#define DP_ANAR_T4 (u16)0x0200 /* 100BASE-T4 Support */
    +#define DP_ANAR_PAUSE (u16)0x0400 /* Pause */
    +#define DP_ANAR_RF (u16)0x2000 /* Remote Fault */
    +#define DP_ANAR_NP (u16)0x8000 /* Next Page Indication */
    +
    +/*
    + * Auto-Negotiation Link Partner Ability Register
    + *
    + * Contains the advertised abilities of the Link Partner as recieved during
    + * Auto Negotiation. The content changes after the successful autonegotiation
    + * if Next-Pages are supported.
    + */
    +
    +#define DP_ANLPAR_SEL (u16)0x001F /* Protocol Selection Bits */
    +#define DP_ANLPAR_10T (u16)0x0020 /* 10BASE-T Support */
    +#define DP_ANLPAR_10_FD (u16)0x0040 /* 10BASE-T Full Duplex */
    +#define DP_ANLPAR_TX (u16)0x0080 /* 100BASE-TX Support */
    +#define DP_ANLPAR_TX_FD (u16)0x0100 /* 100BASE-TX Full Duplex */
    +#define DP_ANLPAR_T4 (u16)0x0200 /* 100BASE-T4 Support */
    +#define DP_ANLPAR_RF (u16)0x2000 /* Remote Fault */
    +#define DP_ANLPAR_ACK (u16)0x4000 /* Acknowledge */
    +#define DP_ANLPAR_NP (u16)0x8000 /* Next Page Indication */
    +
    +/*
    + * Auto-Negotiation Expansion Register
    + *
    + * contains additional Local device and Link Partner status info
    + */
    +
    +#define DP_ANER_LP_AN_ABLE (u16)0x0001 /* Link Partner Auto Neg Able */
    +#define DP_ANER_PAGE_RX (u16)0x0002 /* Link Code Word Page Recvd */
    +#define DP_ANER_NP_ABLE (u16)0x0004 /* Next Page Able */
    +#define DP_ANER_LP_NP_ABLE (u16)0x0008 /* Link Partner NextPage Able */
    +#define DP_ANER_PDF (u16)0x0010 /* Parallel Detection Fault */
    +
    +/*
    + * Auto-Negotiation Next page Transmit Register
    + *
    + * contains the next page Info sent by this device to its Link Partner
    + * during Auto-Negotiation
    + */
    +
    +#define DP_ANNPTR_CODE (u16)0x07FF /* Code Field */
    +#define DP_ANNPTR_TOG_TX (u16)0x0800 /* Toggle */
    +#define DP_ANNPTR_ACK2 (u16)0x1000 /* Acknowledge2 */
    +#define DP_ANNPTR_MP (u16)0x2000 /* Message Page */
    +#define DP_ANNPTR_NP (u16)0x8000 /* Next Page Indication */
    +
    +/*
    + * PHY Status Register
    + *
    + * provides a single location within the register set for quick access to
    + * commonly accessed information
    + */
    +
    +#define DP_PHYSTS_LNK_VALID (u16)0x0001 /* Valid Link */
    +#define DP_PHYSTS_SPEED_10 (u16)0x0002 /* 10 Mbps Mode */
    +#define DP_PHYSTS_FDX (u16)0x0004 /* Full Duplex Mode */
    +#define DP_PHYSTS_LOOP (u16)0x0008 /* Loopback Enabled */
    +#define DP_PHYSTS_ANEG_DONE (u16)0x0010 /* Auto-Neg Complete */
    +#define DP_PHYSTS_JABBER (u16)0x0020 /* Jabbler Detected */
    +#define DP_PHYSTS_REM_FAULT (u16)0x0040 /* Remote Fault Detected */
    +#define DP_PHYSTS_MII_INTR (u16)0x0080 /* MII Interrupt Pending */
    +#define DP_PHYSTS_LCWP_RX (u16)0x0100 /* Link Code Word Page Rx'd */
    +#define DP_PHYSTS_DSCRMBL_LCK (u16)0x0200 /* 100TX Descrambler Lock */
    +#define DP_PHYSTS_SIG_DET (u16)0x0400 /* 100TX Uncond Signal Detect */
    +#define DP_PHYSTS_FCSL (u16)0x0800 /* False Carrier Sense Latch */
    +#define DP_PHYSTS_POL_INV (u16)0x1000 /* Polarity status */
    +#define DP_PHYSTS_RX_ERR_LATCH (u16)0x2000 /* Received error latch */
    +
    +/*
    + * False carrier Sense Counter Register
    + *
    + * provides info required to implement the "FalseCarriers" attribute within
    + * the MAJ managed object class of Clause 30 of the IEEE 802.3u specification.
    + */
    +
    +#define DP_FCSCR_FCSCNT (u16)0x00FF /* False Carrier Event Counter */
    +
    +/*
    + * Receiver Error Counter Register
    + *
    + * provides info required to implement the "SymbolErrorDuringCarrier" attribute
    + * within the PHY managed object class of Clause 30 of the IEEE 802.3u
    + * specification.
    + */
    +
    +#define DP_RECR_RXERCNT (u16)0x00FF /* RX_ER Counter*/
    +
    +/* 100Mb/s PCS Configuration and Status Register */
    +
    +#define DP_PCSR_NRZI_BYP (u16)0x0004 /* NRZI Bypass Enable */
    +#define DP_PCSR_FRC_100_OK (u16)0x0020 /* Force 100Mb/s Good Link */
    +#define DP_PCSR_SD_OPT (u16)0x0100 /* Signal Detect Option */
    +#define DP_PCSR_SD_F_B (u16)0x0200 /* Signal Detect Force */
    +#define DP_PCSR_TQ_EN (u16)0x0400 /* 100Mbs True Quite Mode En */
    +#define DP_PCSR_FREE_CLK (u16)0x0800 /* Receive Clock */
    +#define DP_PCSR_BYP_4B5B (u16)0x1000 /* Bypass 4B/5B Encoding */
    +
    +/* PHY Control Register */
    +
    +#define DP_PHYCR_PHYADDR (u16)0x001F /* PHY Address */
    +#define DP_PHYCR_LED_CFG (u16)0x0060 /* LED Configuration */
    +#define DP_PHYCR_LED_CFG_10_HI (u16)0x0000 /* Speed10 HIGH */
    +#define DP_PHYCR_LED_CFG_10 (u16)0x0020 /* Speed10 selected */
    +#define DP_PHYCR_LED_CFG_DPLXHI (u16)0x0040 /* DPLX active HIGH */
    +#define DP_PHYCR_LED_CFG_DPLX (u16)0x0060 /* DPLX selected */
    +#define DP_PHYCR_PAUSE_PASS (u16)0x0080 /* Pause Compare Pass */
    +#define DP_PHYCR_BP_STRETCH (u16)0x0100 /* Bypass LED Stretch*/
    +#define DP_PHYCR_BIST_START (u16)0x0200 /* BIST Start */
    +#define DP_PHYCR_BIST_PASS (u16)0x0400 /* BIST Pass */
    +#define DP_PHYCR_PSR_15 (u16)0x0800 /* BIST Sequence Sel PSR15 (PSR9) */
    +
    +/* 10Base-T Status/Control Register(10BTSCR) */
    +
    +#define DP_10BTSCR_JABR_DIS (u16)0x0001 /* Jabber Disable */
    +#define DP_10BTSCR_HB_DIS (u16)0x0002 /* Heartbeat Disable */
    +#define DP_10BTSCR_LOW_SQL (u16)0x0004 /* Reduced Sqyelch Enable */
    +#define DP_10BTSCR_AUTOPOL_DIS (u16)0x0008 /* Auto Polarity Disable */
    +#define DP_10BTSCR_POL (u16)0x0010 /* 10Mb Polarity Status */
    +#define DP_10BTSCR_FRC_POL_COR (u16)0x0020 /* Force 10Mb Polarity Correction */
    +#define DP_10BTSCR_FRC_10 (u16)0x0040 /* Force 10Mb Good Link */
    +#define DP_10BTSCR_LP_DIS (u16)0x0080 /* Normal Link Pulse Disable */
    +#define DP_10BTSCR_LB10_DIS (u16)0x0100 /* 10Base-T Loopback Disable */
    +
    +
    +/*
    + * Transmit and receive descriptors
    + *
    + * DP83815 uses the same descriptor layout for both transmit and receive
    + * descriptors.
    + */
    +
    +#define DP_DESC_SIZE 0x0C /* 3 words */
    +
    +/* Descriptor Layout */
    +
    +#define DP_DESC_LNK 0x00 /* Link field offset */
    +#define DP_DESC_CMDSTS 0x04 /* Command & Status offset */
    +#define DP_DESC_BUFPTR 0x08 /* Buffer pointer offset */
    +
    +/* DP_DESC_CMDSTS - Descriptor Command and Status Definitions */
    +
    +#define DP_DESC_CMDSTS_SIZE (u32)0x00000FFF /* Size of data in bytes */
    +#define DP_DESC_CMDSTS_TX_CCNT (u32)0x000F0000 /* Collision Count */
    +#define DP_DESC_CMDSTS_TX_EC (u32)0x00100000 /* Excessive Collisions */
    +#define DP_DESC_CMDSTS_TX_OWC (u32)0x00200000 /* Out of window collns */
    +#define DP_DESC_CMDSTS_TX_ED (u32)0x00400000 /* Excessive deferrals */
    +#define DP_DESC_CMDSTS_TX_TD (u32)0x00800000 /* Transmit deferrals */
    +#define DP_DESC_CMDSTS_TX_CRS (u32)0x01000000 /* Carrier sense lost */
    +#define DP_DESC_CMDSTS_TX_TFU (u32)0x02000000 /* Tx FIFO underrun */
    +#define DP_DESC_CMDSTS_TX_TXA (u32)0x04000000 /* Tx abort */
    +#define DP_DESC_CMDSTS_RX_COL (u32)0x00010000 /* Collision */
    +#define DP_DESC_CMDSTS_RX_LBP (u32)0x00020000 /* Loopback packet */
    +#define DP_DESC_CMDSTS_RX_FAE (u32)0x00040000 /* Frame align error */
    +#define DP_DESC_CMDSTS_RX_CRCE (u32)0x00080000 /* CRC error */
    +#define DP_DESC_CMDSTS_RX_ISE (u32)0x00100000 /* Invalid symbol error */
    +#define DP_DESC_CMDSTS_RX_RUNT (u32)0x00200000 /* Runt packet */
    +#define DP_DESC_CMDSTS_RX_LONG (u32)0x00400000 /* Long packet */
    +#define DP_DESC_CMDSTS_RX_DEST (u32)0x01800000 /* Destination Class */
    +#define DP_DESC_CMDSTS_RX_DEST_REJ (u32)0x00000000 /* Packet Rejected */
    +#define DP_DESC_CMDSTS_RX_DEST_UNI (u32)0x00800000 /* Unicast packet */
    +#define DP_DESC_CMDSTS_RX_DEST_MC (u32)0x01000000 /* Multicast packet */
    +#define DP_DESC_CMDSTS_RX_DEST_BC (u32)0x01800000 /* Broadcast packet */
    +#define DP_DESC_CMDSTS_RX_RXO (u32)0x02000000 /* Receive overrun */
    +#define DP_DESC_CMDSTS_RX_RXA (u32)0x04000000 /* Receive aborted */
    +#define DP_DESC_CMDSTS_OK (u32)0x08000000 /* Packet OK */
    +#define DP_DESC_CMDSTS_TX_SUPCRC (u32)0x10000000 /* Supress CRC */
    +#define DP_DESC_CMDSTS_RX_INCCRC (u32)0x10000000 /* Include CRC */
    +#define DP_DESC_CMDSTS_INTR (u32)0x20000000 /* Interrupt */
    +#define DP_DESC_CMDSTS_MORE (u32)0x40000000 /* More descriptors */
    +#define DP_DESC_CMDSTS_OWN (u32)0x80000000 /* Desc owner (consumer) */
    +
    +#define DP_DESC_CMDSTS_TX_COLLISIONS_GET(cmdsts) (((cmdsts) & DP_DESC_CMDSTS_TX_CCNT) >> 16)
    +
    +#define DP_DESC_CMDSTS_TX_ERRORS (DP_DESC_CMDSTS_TX_CCNT | DP_DESC_CMDSTS_TX_EC | DP_DESC_CMDSTS_TX_OWC | DP_DESC_CMDSTS_TX_ED | DP_DESC_CMDSTS_TX_CRS | DP_DESC_CMDSTS_TX_TFU | DP_DESC_CMDSTS_TX_TXA)
    +
    +#define DP_DESC_CMDSTS_RX_ERRORS (DP_DESC_CMDSTS_RX_RXA | DP_DESC_CMDSTS_RX_RXO | DP_DESC_CMDSTS_RX_LONG | DP_DESC_CMDSTS_RX_RUNT | DP_DESC_CMDSTS_RX_CRCE | DP_DESC_CMDSTS_RX_FAE)
    +
    +#endif /* __DP83815_H__ */
    diff -Naur linux-baseline/drivers/net/dp83815.c linux/drivers/net/dp83815.c
    --- linux-baseline/drivers/net/dp83815.c Thu Jan 1 00:00:00 1970
    +++ linux/drivers/net/dp83815.c Mon Jul 10 20:55:02 2000
    @@ -0,0 +1,1538 @@
    +/* DP83815.c -- National Semiconductor DP83815 PCI Ethernet Controller Driver */
    +
    +static const char product_version[] = "dp83815.c:v1.30 National Semiconductor DP83815 PCI Ethernet Driver\n";
    +
    +/*
    +1. INTRODUCTION
    +---------------
    +
    +The DP83815 is a PCI bus based single chip 10/100 Mbps ethernet
    +controller targeted for PC mother boards, adapter cards, and embedded
    +systems. It fully implements the V2.2 33MHz PCI bus interface for host
    +communications with power management support. Packet descriptors and
    +data are transferred via bus-mastering, reducing the burden on the
    +host CPU. The DP83815 can support full duplex 10/100 Mbps transmission
    +and reception. This driver has been updated to support rev C of the chip.
    +
    +The DP83815 driver is developed for use on Linux v2.0.X and v2.2.X and
    +has been tested with 2.0.36 and 2.2.13 versions of the kernel.It can be
    +configured either as a static driver into the kernel or as a loadable
    +module. The driver is capable of 10/100 Mbps Full/Half duplex mode
    +operation via an internal PHY. Detailed features are given below.
    +
    +2.1 Chip Features
    +
    + o The chip is bus-master capable and transfers packet descriptors
    + and data using DMA with burst sizes upto 128 words.
    +
    + o It supports 10 Mbps Ethernet and 100 Mbps Fast Ethernet via
    + an internal PHY and emerging 1-2 Mbps home networking
    + solutions via external PHY.
    +
    + o Flexible Rx packet filtration including: perfect match, broadcast,
    + multicast/unicast hash table, deep packet pattern matching.
    +
    + o Internal Tx and Rx data FIFOs of 2KB each
    +
    + o 802.3u Auto-Negotiation - advertised features configurable via
    + EEPROM
    +
    + o Full duplex support for 10 and 100Mb/s data rates
    +
    +
    +2.2 Driver Features
    +
    +2.2.1 Supported Features
    +
    + o 10 Mbps full duplex and half duplex
    + o 100 Mbps full duplex and half duplex
    + o Auto Negotiation
    + o Broadcast and perfect match transmit and receive
    + o ARP transmit and receive
    + o Promiscuous mode
    + o Multicast support
    + o Loadable Kernel Module
    + o PCI bus probe for auto-configuration when configured as a static
    + driver or a loadable kernel module
    + o Endian, and CPU architecture neutral
    + o Supports rev C of the chip
    + o 2.0.xx and 2.2.xx Linux kernels
    +
    +2.2.2 Unsupported Features
    +
    + o ACPI
    + o Multiple ethernet addresses
    + o Wake on LAN and OnNow support for PC98/99, and other power-management
    + features.
    + o Magic packets with SecureON, VLAN
    + o Programming EEPROM/Flash
    + o Old Linux kernels 1.xx.xx
    + o Newer MP kernels 2.2.xx
    + o Remote boot
    +
    +
    +3. DRIVER OPERATION
    +-------------------
    +
    +Buffer management used in this version of the driver sets up the
    +transmit and receive buffer descriptors in a ring. The rings, shared
    +between the driver and the device, are located in memory buffers
    +allocated in the kernel. The device accesses these buffers via DMA.
    +
    +Each device will be allocated two similar queues of descriptors, one
    +for transmit and the other for receive. These queues are linked
    +together into a ring. For the default size of the transmit rings is
    +10, while the size of the receive ring is 30. These values can be
    +changed via macros in the driver source file.
    +
    +The driver implements no copy transmits. All transmit descriptors are
    +created with no associated buffers, but the descriptor uses the
    +sk_buff passed to it via the transmit routine. The sk_buff is held by
    +the driver until the next transmit operation that follows the actual
    +transmit of the packet.
    +
    +Each receive descriptor is initialized, at creation time, with an
    +sk_buff. Each sk_buff has a data buffer that can hold a max ethernet
    +packet. When a packet is suceesfully received, the skb is directly
    +sent to the stack with no copy, and it is replaced with a newly
    +allocated sk_buff. But if the packet less than 128 bytes
    +was received, the data is instead copied into a new skb.
    +
    +The driver makes of appropriate macros to adjust for endian-ness of
    +the host CPU, PCI bus, Ethernet, and the DP device. It also performs
    +appropriate translations of addresses for device use. These builtin
    +features makes the driver extremely portable to run on Linux systems
    +with non-Intel CPUs with minimum changes.
    +
    +The driver has a table, dp83815_hw_id_tbl[] to store the hardware_id
    +information for the DP83815 device from all Vendors. In this version
    +of the driver, the dp83815_hw_id_tbl has only one entry for the
    +vendor_id and board_id of the NS_DP83815. If the device's ID differs
    +from these values, the table should be extended with the new values.
    +
    +
    +4. FUNCTIONALITY TESTING
    +------------------------
    +
    +When the driver is loaded into the system via `insmod' it probes the
    +PCI bus to locate all DP83815 devices, and creates control structures
    +for each. The driver logs a couple of messages available in
    +`/var/log/messages' for each device with information about its PCI
    +geographic location, IRQ, IO address, and some basic debug information
    +(addresses of some important structures).
    +
    +All the devices on the PCI bus can be listed by,
    +
    + # cat /proc/pci
    +
    +IRQ and IO address information from this can be correlated with the
    +information displayed by the driver in `/var/log/messages'
    +
    +When the TCP/IP stack is initialized, it opens all configured ethernet
    +devices, and initializes them for use. At this time, the driver will
    +perform autonegotiation and log information about the link status.
    +The driver can then be tested by running ping, telnet, ftp, NFS etc.
    +
    +
    +5. KNOWN DRIVER PROBLEMS
    +------------------------
    +
    +o Since the device requires that the receive buffer be aligned on a
    + 4-byte (word) boundary, it is not possible to align the IP header
    + on a word boundary unless the received packet is copied. Since this
    + version of the driver support a no-copy receive operation, the IP
    + header will not be aligned. This is not a problem for Intel CPUs,
    + but will cause exceptions on RISC CPUs (PowerPC, Alpha, ...). While
    + porting the driver to these platforms, the no-copy receive can be
    + turned off, but setting the DP_RX_COPY_THRESHOLD to ETH_MAX_PKT_SIZE,
    + whereby forcing all receive buffers to be copied.
    +
    + The driver ensures that the IP headers in a copied buffer is aligned
    + on a word-boundary.
    +
    +6. REVISION HISTORY
    +--------------------
    +
    +v1.30 : support for Linux Kernel 2.2 was added
    +
    +v1.20 : proper initialisation of TXCFG and RXCFG registers for full duplex
    + mode was done.
    + in start_xmit, BUFPTR was updated prior to CMDSTS of the descriptor
    + infinite loop in case of dev_reset failure was corrected.
    +
    +v1.10 : this is the first release of the driver
    +
    +7. DOCUMENTATION REFERENCES
    +---------------------------
    +
    +1. National Semiconductor DP83815 10/100 Mb/s Integrated PCI Ethernet
    + Media Access Controller and Physical Layer, 1998.
    +2. Linux Device Drivers, Alessandro Rubini, 1998.
    +
    +
    +*/
    +
    +/* Generic Kernel Module/Driver Headers */
    +
    +#include <linux/module.h>
    +#include <linux/kernel.h>
    +#include <linux/version.h>
    +
    +#include <linux/pci.h>
    +#include <linux/ioport.h>
    +#include <asm/io.h> /* IO stuff */
    +#include <asm/byteorder.h>
    +#include <linux/delay.h>
    +
    +/* Ethernet Driver Specific Headers */
    +
    +#include <linux/netdevice.h>
    +#include <linux/etherdevice.h>
    +#include <linux/skbuff.h>
    +#include <linux/malloc.h>
    +#include <linux/if_ether.h>
    +
    +#include "dp83815.h"
    +
    +/* Macros */
    +
    +/* Macros to make the driver compatible with both 2.0.x and 2.2.x kernels */
    +
    +/* to convert Linux kernel version into hexadecimal number */
    +#define DP_KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
    +
    +/* For Linux Kernel 2.0.x */
    +#if ((LINUX_VERSION_CODE >= DP_KERNEL_VERSION (2,0,0)) && (LINUX_VERSION_CODE < DP_KERNEL_VERSION (2,1,0)))
    +#include <linux/bios32.h> /* PCI BIOS support*/
    +int dp_dev_cur; /* current pci device count*/
    +#define DP_PCIBIOS_FIND_DEVICE /* pcibios_find_device API is available */
    +#undef DP_PCI_FIND_DEVICE /* pci_find_device API is not available */
    +#define DP_KFREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE)
    +#define DP_INW(io_port) __inw (io_port)
    +#define DP_OUTW(data, io_port) __outw (data, io_port)
    +#define DP_INL(io_port) __inl (io_port)
    +#define DP_OUTL(data, io_port) __outl (data, io_port)
    +
    +/* for 2.2.X kernel */
    +#elif (LINUX_VERSION_CODE >= DP_KERNEL_VERSION (2,2,0))
    +struct pci_dev *dp_pci_dev; /* pci device structure */
    +#undef DP_PCIBIOS_FIND_DEVICE /* pcibios_find_device API is not available */
    +#define DP_PCI_FIND_DEVICE /* pci_find_device API is available */
    +#define DP_KFREE_SKB(skb) dev_kfree_skb (skb)
    +#define DP_INW(io_port) inw (io_port)
    +#define DP_OUTW(data, io_port) outw (data, io_port)
    +#define DP_INL(io_port) inl (io_port)
    +#define DP_OUTL(data, io_port) outl (data, io_port)
    +
    +#else /* for all other versions of the kernel */
    +#error "KERNEL VERSIONS OTHER THAN 2.0.X and 2.2.X ARE NOT SUPPORTED!!\n"
    +#endif
    +
    +
    +/*
    + * SWAP_BUS_TO_CPU_XX and SWAP_CPU_TO_BUS_XX macros swap 16 and 32 bit values
    + * between the PCI bus' little endian byte-order and the CPU's native
    + * byte-order.
    + */
    +#ifdef __BIG_ENDIAN
    +#define BUS_TO_CPU_SWAP_16(X) swap_16(X)
    +#define BUS_TO_CPU_SWAP_32(X) swap_32(X)
    +#define CPU_TO_BUS_SWAP_16(X) swap_16(X)
    +#define CPU_TO_BUS_SWAP_32(X) swap_32(X)
    +#define CPU_TO_NET_SWAP_16(X) ((u16)(X))
    +#define CPU_TO_NET_SWAP_32(X) ((u32)(X))
    +#define NET_TO_CPU_SWAP_16(X) ((u16)(X))
    +#define NET_TO_CPU_SWAP_32(X) ((u32)(X))
    +#else
    +#define BUS_TO_CPU_SWAP_32(X) ((u32)(X))
    +#define BUS_TO_CPU_SWAP_16(X) ((u16)(X))
    +#define CPU_TO_BUS_SWAP_32(X) ((u32)(X))
    +#define CPU_TO_BUS_SWAP_16(X) ((u16)(X))
    +#define CPU_TO_NET_SWAP_16(X) swap_16(X)
    +#define CPU_TO_NET_SWAP_32(X) swap_32(X)
    +#define NET_TO_CPU_SWAP_16(X) swap_16(X)
    +#define NET_TO_CPU_SWAP_32(X) swap_32(X)
    +#endif
    +
    +/* Macros translate addresses between PCI bus and CPU */
    +#define BUS_TO_CPU_ADDR_XLATE(X) BUS_TO_CPU_SWAP_32(bus_to_virt(X))
    +#define CPU_TO_BUS_ADDR_XLATE(X) CPU_TO_BUS_SWAP_32(virt_to_bus(X))
    +
    +/* Macros to read/write 32/16 bit data to/from DP83815 device registers. */
    +#define DP_REG32_WRITE(reg, val) io_write_32 (iobase+(reg), \
    + CPU_TO_BUS_SWAP_32(val))
    +#define DP_REG32_READ(reg) BUS_TO_CPU_SWAP_32(io_read_32 (iobase+(reg)))
    +#define DP_REG16_WRITE(reg, val) io_write_16 (iobase+(reg), \
    + CPU_TO_BUS_SWAP_16(val))
    +#define DP_REG16_READ(reg) BUS_TO_CPU_SWAP_16(io_read_16 (iobase+(reg)))
    +#define DP_REG32_SET(reg, val) DP_REG32_WRITE(reg,DP_REG32_READ(reg)|(val))
    +#define DP_REG32_CLR(reg, val) DP_REG32_WRITE(reg,DP_REG32_READ(reg)&~(val))
    +#define DP_REG16_SET(reg, val) DP_REG16_WRITE(reg,DP_REG16_READ(reg)|(val))
    +#define DP_REG16_CLR(reg, val) DP_REG16_WRITE(reg,DP_REG16_READ(reg)&~(val))
    +
    +/* Debug Macros */
    +#define DP_DEBUG_PROBE 0x00000001
    +#define DP_DEBUG_OPEN 0x00000002
    +#define DP_DEBUG_CLOSE 0x00000004
    +#define DP_DEBUG_IOCTL 0x00000008
    +#define DP_DEBUG_TX 0x00000010
    +#define DP_DEBUG_RX 0x00000020
    +#define DP_DEBUG_MC 0x00000040
    +#define DP_DEBUG_ANEG 0x00000080
    +#define DP_DEBUG_INTR 0x00000100
    +#define DP_DEBUG_LOAD 0x00000200
    +#define DP_DEBUG_UNLOAD 0x00000400
    +
    +#if (DRV_DEBUG > 0)
    +u32 dp_debug_level=DRV_DEBUG;
    +#define DP_DEBUG(level, X) if (level & dp_debug_level) printk X
    +#else
    +#define DP_DEBUG(level, X)
    +#endif
    +
    +/* data types */
    +typedef u32 status; /* return status */
    +typedef volatile u8 * virt_addr; /* CPU virtual address */
    +typedef volatile u8 * bus_addr; /* BUS physical address */
    +typedef u8 bool;
    +
    +#define OK 0 /* status: OK */
    +#define ERROR -1 /* status: ERROR */
    +#define TRUE 1
    +#define FALSE 0
    +
    +bool dp_full_duplex; /* flag for full duplex mode */
    +
    +/* Default Driver Parameters */
    +#define DP_DEFAULT_TXQ_SIZE 10
    +#define DP_DEFAULT_RXQ_SIZE 30
    +#define DP_RX_COPY_THRESHOLD 128 /* upper limit for rx packet copy */
    +#define DP_POLYNOMIAL 0x04C11DB6
    +
    +/* Alignment and packet sizes */
    +#define ETH_CRC_LEN 4
    +#define ETH_MAX_PKT_SIZE (ETH_FRAME_LEN + ETH_CRC_LEN)
    +#define DP_ALIGN 4 /* word alignment */
    +
    +/* Driver private descriptor macros */
    +#define DP_DESC_SKBPTR 0x0c /* SKB pointer offset */
    +#define DP_QUEUE_ELE_SIZE (DP_DESC_SIZE + 4)
    +#define DP_QUEUE_ELE_NEXT(q) \
    + q->cur_desc_addr = DP_QUEUE_ELE_NEXT_GET(q, q->cur_desc_addr)
    +#define DP_QUEUE_ELE_NEXT_GET(q, desc_addr) \
    + ((desc_addr) == (q)->last_desc_addr) ? (q)->first_desc_addr : \
    + (desc_addr) + DP_QUEUE_ELE_SIZE
    +
    +/* Macros to get/set the values of the descriptor fields */
    +#define DP_DESC_LNK_GET(ptr) *(u32 *)((virt_addr)ptr + DP_DESC_LNK)
    +#define DP_DESC_CMDSTS_GET(ptr) *(u32 *)((virt_addr)ptr + DP_DESC_CMDSTS)
    +#define DP_DESC_BUFPTR_GET(ptr) *(u32 *)((virt_addr)ptr + DP_DESC_BUFPTR)
    +#define DP_DESC_SKBPTR_GET(ptr) *(u32 *)((virt_addr)ptr + DP_DESC_SKBPTR)
    +
    +#define DP_DESC_LNK_SET(ptr, val) DP_DESC_LNK_GET(ptr) = (val)
    +#define DP_DESC_CMDSTS_SET(ptr, val) DP_DESC_CMDSTS_GET(ptr) = (val)
    +#define DP_DESC_BUFPTR_SET(ptr,val) DP_DESC_BUFPTR_GET(ptr) = (val)
    +#define DP_DESC_SKBPTR_SET(ptr,val) DP_DESC_SKBPTR_GET(ptr) = (val)
    +
    +/*
    + * Macros to get/set the values of descriptor fields with
    + * appropriate address and byte order translations
    + */
    +#define DP_DESC_LNK_XLATE_GET(p) BUS_TO_CPU_ADDR_XLATE(DP_DESC_LNK_GET(p))
    +#define DP_DESC_CMDSTS_XLATE_GET(p) BUS_TO_CPU_SWAP_32(DP_DESC_CMDSTS_GET(p))
    +#define DP_DESC_BUFPTR_XLATE_GET(p) BUS_TO_CPU_ADDR_XLATE(DP_DESC_BUFPTR_GET(p))
    +
    +#define DP_DESC_LNK_XLATE_SET(p, v) \
    + DP_DESC_LNK_SET(p, CPU_TO_BUS_ADDR_XLATE(v))
    +#define DP_DESC_CMDSTS_XLATE_SET(p, v) \
    + DP_DESC_CMDSTS_SET(p, CPU_TO_BUS_SWAP_32(v))
    +#define DP_DESC_BUFPTR_XLATE_SET(p,v) \
    + DP_DESC_BUFPTR_SET(p, CPU_TO_BUS_ADDR_XLATE(v))
    +
    +#ifndef PCI_VENDOR_ID_NS
    +#define PCI_VENDOR_ID_NS 0x100b
    +#endif
    +
    +/* Descriptor queue */
    +struct dp83815_queue
    +{
    + virt_addr first_desc_addr; /* descriptor array address */
    + virt_addr last_desc_addr; /* last descriptor address */
    + virt_addr cur_desc_addr; /* current descriptor address */
    + virt_addr qbuf; /* allocated queue buffer */
    + u16 count; /* number of elements */
    +};
    +
    +/* Queue types -- qtype */
    +#define DP_QUEUE_TYPE_TX 1 /* Transmit queue */
    +#define DP_QUEUE_TYPE_RX 2 /* Receive queue */
    +
    +/* Device private data */
    +struct dp83815_priv
    +{
    + struct device * next; /* Next dp83815 device */
    + struct dp83815_queue tx_queue; /* Transmit Descriptor Queue */
    + struct dp83815_queue rx_queue; /* Receive Descriptor Queue */
    + struct enet_statistics stats; /* MIB data */
    + char hw_mac_addr [ETH_ALEN]; /* Factory Ethernet Address */
    +};
    +
    +static struct device * dp83815_dev_list=NULL; /* List of dp83815 devices */
    +
    +/* structure for hardware_id information of the device */
    +struct dp83815_hw_id
    +{
    + u16 vendor_id;
    + u16 board_id;
    +};
    +
    +#define MAX_CHIPS 8 /* Maximum number of devices to probe for of this type */
    +static struct
    +{
    + char macaddr[ETH_ALEN];
    +} chiplist[MAX_CHIPS];
    +static int chipcount = 0; /* index into next available for above structure */
    +
    +/* Table for hardware_id information of the DP device. The first entry
    + to the table is the vendor_id and board_id for NS's Dp83815. Other
    + Vendors' extensions to the DP device should be added to this table.
    +*/
    +
    +static struct dp83815_hw_id dp83815_hw_id_tbl[] =
    +{
    + { PCI_VENDOR_ID_NS, PCI_VENDOR_ID_NS_83815 }
    + /* add vendor extensions here */
    +};
    +
    +/* Linux Network Driver interface routines */
    +extern int dp83815_probe (struct device *dev);
    +static int dp83815_open (struct device *dev);
    +static int dp83815_close (struct device *dev);
    +static int dp83815_start_xmit (struct sk_buff *skb, struct device *dev);
    +static void dp83815_set_multicast_list (struct device *dev);
    +static int dp83815_ioctl (struct device *dev, struct ifreq *rq, int cmd);
    +static void dp83815_interrupt (int irq, void *dev_id, struct pt_regs *regs);
    +static struct enet_statistics *dp83815_get_stats (struct device *dev);
    +
    +/* Support Functions */
    +static u16 swap_16 (u16 us);
    +/*static u32 swap_32 (u32 ui);*/
    +static u32 io_read_32 (u16 io_port);
    +static void io_write_32 (u16 io_port, u32 data);
    +static u16 io_read_16 (u16 io_port);
    +/*static void io_write_16 (u16 io_port, u16 data);*/
    +
    +/* Driver Private Routines */
    +static void dp83815_pci_init (void);
    +static int dp83815_pci_find_device (u16 pci_vendor_id, u16 pci_board_id,
    + u8 *pbus, u8 *pfunc);
    +static void dp83815_mac_address_set (u32 iobase, char *mac_addr);
    +static void dp83815_mac_address_get (u32 iobase, char *mac_addr);
    +static status dp83815_dev_reset (u32 iobase);
    +static status dp83815_queue_create (struct dp83815_queue *q, int count, int qtype);
    +static status dp83815_queue_delete (struct dp83815_queue *q);
    +static virt_addr dp83815_tx_desc_get (struct device *dev);
    +static virt_addr dp83815_rx_desc_get (struct device *dev);
    +static status dp83815_phy_setup (struct device *dev);
    +static int dp83815_crc (char * mc_addr);
    +static void dp83815_tx_skb_reclaim (struct device *dev, virt_addr desc_addr);
    +
    +/* Driver Debug Routines */
    +#if (DRV_DEBUG > 0)
    +static void dp83815_regs_info (u16 iobase);
    +#endif
    +
    +/*
    + * dp83815_probe - enumerate the PCI bus for instances of DP83815
    + *
    + * This routine enumerates DP83815 ethernet devices on the PCI bus, and
    + * registers each DP83815 device found.
    + */
    +int
    +dp83815_probe (struct device *dev)
    +{
    + int i, j;
    + int board_count = (sizeof (dp83815_hw_id_tbl) / sizeof (struct dp83815_hw_id));
    + u16 pci_vendor_id;
    + u16 pci_board_id;
    + int dev_count;
    + u8 bus;
    + u8 func;
    + u8 irq;
    + u32 iobase;
    + u32 version;
    + char ether_addr[ETH_ALEN];
    + struct dp83815_priv * priv;
    +
    + if (! pcibios_present())
    + return -ENODEV; /* No such device */
    +
    + if (chipcount >= MAX_CHIPS)
    + return -ENODEV; /* too many devices, bump MAX_CHIPS define and rebuild */
    +
    + for (i=0, dev_count=0; i<board_count; i++)
    + {
    + /* get vendor id and board id from table */
    + pci_vendor_id = dp83815_hw_id_tbl[i].vendor_id;
    + pci_board_id = dp83815_hw_id_tbl[i].board_id;
    +
    + /* reset the search from the first device */
    + dp83815_pci_init();
    +
    + /* find the devices for each set of vendor and board id */
    + for ( ; (dp83815_pci_find_device (pci_vendor_id, pci_board_id, &bus, &func) == TRUE); dev = NULL)
    + {
    + /* Read PCI Configuration Registers */
    + pcibios_read_config_byte (bus, func, PCI_INTERRUPT_LINE, &irq);
    + pcibios_read_config_dword (bus, func, PCI_BASE_ADDRESS_0, &iobase);
    + iobase &= PCI_BASE_ADDRESS_IO_MASK;
    +
    + /* Get the ethernet address */
    + dp83815_mac_address_get (iobase, ether_addr);
    +
    + /* Has this device already been probed? */
    + for (j = 0; j < chipcount; j++)
    + if (memcmp(ether_addr, chiplist[j].macaddr, ETH_ALEN) == 0)
    + return -ENODEV; /* Already probed */
    +
    + /* Put the device in a quiescent state */
    + if (dp83815_dev_reset (iobase) != OK) {
    + printk (KERN_INFO "%s: Device Reset failed -- bus=%d func=%d "
    + "iobase=0x%x.\n",
    + DP_DRV_NAME, bus, func, iobase);
    + continue; /* Try the next device */
    + }
    +
    + /* Allocate, name the device and add to ethernet device list */
    + dev = init_etherdev(dev, sizeof (struct dp83815_priv));
    +
    + if (dev == NULL)
    + {
    + printk (KERN_INFO "%s: Failed to allocate device struct -- "
    + "bus=%d func=%d iobase=0x%x\n",
    + DP_DRV_NAME, bus, func, iobase);
    + break;
    + }
    +
    + if (dev->priv == NULL)
    + dev->priv = kmalloc(sizeof(struct dp83815_priv), GFP_KERNEL);
    + if (dev->priv == NULL)
    + return -ENOMEM;
    + memset(dev->priv, 0, sizeof(struct dp83815_priv));
    + priv=(struct dp83815_priv *)dev->priv;
    +
    + /* Save ethernet address */
    + memcpy (dev->dev_addr, ether_addr, ETH_ALEN);
    + memcpy (priv->hw_mac_addr, ether_addr, ETH_ALEN);
    +
    + /* If address is not set, set up a default one */
    + if ((dev->dev_addr[0] == 0) && (dev->dev_addr[1] == 0) &&
    + (dev->dev_addr[2] == 0) && (dev->dev_addr[3] == 0) &&
    + (dev->dev_addr[4] == 0) && (dev->dev_addr[5] == 0))
    + {
    + u32 random = jiffies;
    + u8 * ptr = (u8 *) &random;
    +
    + dev->dev_addr[0] = 0x08; /* National's Ethernet ID 0 */
    + dev->dev_addr[1] = 0x00; /* National's Ethernet ID 1 */
    + dev->dev_addr[2] = 0x17; /* National's Ethernet ID 2 */
    + dev->dev_addr[3] = *ptr++;
    + dev->dev_addr[4] = *ptr++;
    + dev->dev_addr[5] = *ptr;
    + } else if ((dev->dev_addr[0] == 0x00) && (dev->dev_addr[1] == 0x08))
    + {
    + /* Buggy ethernet address; needs swapping */
    + u16 * ptr = (u16 *) dev->dev_addr;
    + u8 i;
    +
    + for (i=0; i<3; i++)
    + {
    + *ptr = swap_16(*ptr);
    + ptr++;
    + }
    + }
    +
    + dp83815_mac_address_set (iobase, dev->dev_addr);
    +
    + /* initialize the device data */
    + dev->base_addr = iobase;
    + dev->irq = irq;
    + dev->open = dp83815_open;
    + dev->stop = dp83815_close;
    + dev->get_stats = dp83815_get_stats;
    + dev->do_ioctl = dp83815_ioctl;
    + dev->hard_start_xmit = dp83815_start_xmit;
    + dev->set_multicast_list = dp83815_set_multicast_list;
    +
    + ether_setup (dev); /* initialize generic fields */
    +
    + /* reserve IO region */
    + request_region (iobase, DP83815_PCI_IO_SIZE, dev->name);
    +
    + /* Display board info */
    + version = DP_REG32_READ(DP_SRR);
    + printk (KERN_INFO "%s: bus=%d func=%d io=0x%x irq=%d ver=%d.%d\n",
    + dev->name, bus, func, iobase, irq,
    + (version & DP_SRR_MAJ) >> DP_SRR_MAJ_SHF,
    + (version & DP_SRR_MIN));
    +
    + printk (KERN_INFO "%s: ethernet addr=%02x:%02x:%02x:%02x:%02x:%02x\n",
    + dev->name,
    + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
    + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
    + /* Chain the device */
    + ((struct dp83815_priv *)(dev->priv))->next = dp83815_dev_list;
    + dp83815_dev_list = dev;
    +
    +#ifdef DEBUG
    + printk (KERN_INFO "%s: DebugInfo: dev=0x%x priv=0x%x "
    + "&dp_debug_level=0x%x\n",
    + dev->name, (u32)dev, (u32)dev->priv, (u32)&dp_debug_level);
    +#endif
    + /* Update Counters */
    + dev_count++;
    +
    + /* mark it as found by preserving the MAC address */
    + memcpy(chiplist[chipcount++].macaddr, ether_addr, ETH_ALEN);
    + }
    + }
    + return dev_count ? OK : -ENODEV;
    +}
    +
    +/* dp83815_open - open and initialize a device */
    +static int
    +dp83815_open (struct device *dev)
    +{
    + u32 iobase = dev->base_addr;
    + struct dp83815_priv* priv = dev->priv;
    +
    + /* Allocate Tx and Rx queues */
    + if (dp83815_queue_create (&priv->tx_queue, DP_DEFAULT_TXQ_SIZE, DP_QUEUE_TYPE_TX) != OK)
    + {
    + printk (KERN_INFO "%s: Failed to create tx queue\n", dev->name);
    + return -EAGAIN;
    + }
    +
    + if (dp83815_queue_create (&priv->rx_queue, DP_DEFAULT_RXQ_SIZE, DP_QUEUE_TYPE_RX) != OK)
    + {
    + dp83815_queue_delete (&priv->tx_queue);
    + printk (KERN_INFO "%s: Failed to create rx queue\n", dev->name);
    + return -EAGAIN;
    + }
    +
    + /* Install the Tx and Rx queues on the device */
    + DP_REG32_WRITE (DP_TXDP, virt_to_bus(priv->tx_queue.first_desc_addr));
    + DP_REG32_WRITE (DP_RXDP, virt_to_bus(priv->rx_queue.first_desc_addr));
    +
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "dp: setting TXDP=0x%x RXDP=0x%x\n",
    + (u32)virt_to_bus (priv->tx_queue.first_desc_addr),
    + (u32)virt_to_bus (priv->rx_queue.first_desc_addr)));
    +
    + /* Install interrupt vector */
    + if (request_irq (dev->irq, &dp83815_interrupt, SA_SHIRQ, dev->name, dev) != OK)
    + {
    + dp83815_queue_delete (&priv->tx_queue);
    + dp83815_queue_delete (&priv->rx_queue);
    + return -EAGAIN;
    + }
    +
    + /* Setup phy capabilities */
    + if (dp83815_phy_setup (dev) != OK)
    + {
    + printk (KERN_INFO "%s: Warning PHY setup did not complete. Check cable.\n",
    + dev->name);
    + }
    +
    + /* setup transmit and receive control according to duplexity of Phy */
    +
    + if (dp_full_duplex)
    + {
    + /* Setup transmit control */
    +
    + DP_REG32_WRITE (DP_TXCFG, (DP_TXCFG_DRTH_SET(0x30) |
    + DP_TXCFG_FLTH_SET(0x10) |
    + DP_TXCFG_MXDMA_32 |
    + DP_TXCFG_ATP |
    + DP_TXCFG_CSI |
    + DP_TXCFG_HBI));
    +
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "dp (Full Duplex): TXCFG set to 0x%x\n",
    + (DP_TXCFG_DRTH_SET(0x30) | DP_TXCFG_FLTH_SET(0x10) |
    + DP_TXCFG_MXDMA_32 | DP_TXCFG_ATP |
    + DP_TXCFG_CSI | DP_TXCFG_HBI)));
    +
    + /* Setup receive control */
    +
    + DP_REG32_WRITE (DP_RXCFG, (DP_RXCFG_DRTH_SET(0x08) |
    + DP_RXCFG_MXDMA_32 |
    + DP_RXCFG_ATX));
    +
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "dp (Full Duplex): RXCFG set to 0x%x\n",
    + (DP_RXCFG_DRTH_SET(0x08) | DP_RXCFG_MXDMA_32 |
    + DP_RXCFG_ATX)));
    + } else
    + {
    + /* Setup transmit control */
    +
    + DP_REG32_WRITE (DP_TXCFG, (DP_TXCFG_DRTH_SET(0x30) |
    + DP_TXCFG_FLTH_SET(0x10) |
    + DP_TXCFG_MXDMA_32 |
    + DP_TXCFG_ATP));
    +
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "dp (Half Duplex): TXCFG set to 0x%x\n",
    + (DP_TXCFG_DRTH_SET(0x30) | DP_TXCFG_FLTH_SET(0x10) |
    + DP_TXCFG_MXDMA_32 | DP_TXCFG_ATP)));
    +
    + /* Setup receive control */
    +
    + DP_REG32_WRITE (DP_RXCFG, (DP_RXCFG_DRTH_SET(0x08) |
    + DP_RXCFG_MXDMA_32));
    +
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "dp (Half Duplex): RXCFG set to 0x%x\n",
    + (DP_RXCFG_DRTH_SET(0x08) | DP_RXCFG_MXDMA_32)));
    + }
    +
    + /* Setup the ethernet address */
    + dp83815_mac_address_set (iobase, dev->dev_addr);
    +
    + /* Receive perfect match and broadcast packets */
    + DP_REG32_WRITE (DP_RFCR, 0);
    + DP_REG32_WRITE (DP_RFCR, (DP_RFCR_AAB | /* all broadcast pkts */
    + DP_RFCR_APM | /* perfect match pkts */
    + DP_RFCR_RFEN));
    +
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "dp: RFCR set to 0x%x\n",
    + DP_RFCR_RFEN | DP_RFCR_APM | DP_RFCR_AAB));
    +
    + /* Turn on device interrupts -- the driver only looks at RXOK, not any of
    + * the others, so we might as well not turn them on.
    + */
    + //DP_REG32_WRITE (DP_IMR, (DP_IMR_RXOK | DP_IMR_MIB |
    + //DP_IMR_RTABT | DP_IMR_RMABT |
    + //DP_IMR_SSERR | DP_IMR_PHY));
    + DP_REG32_WRITE (DP_IMR, (DP_IMR_RXOK));
    + DP_REG32_WRITE (DP_IER, DP_IER_IE);
    +
    + /* Enable Tx/Rx */
    + DP_REG32_WRITE (DP_CR, DP_CR_TXE | DP_CR_RXE);
    +
    + /* Increment module reference count */
    + MOD_INC_USE_COUNT;
    +
    + return OK;
    +}
    +
    +/* dp83815_close - close a device, and reclaim resources */
    +static int
    +dp83815_close (struct device *dev)
    +{
    + u32 iobase = dev->base_addr;
    + struct dp83815_priv* priv = dev->priv;
    +
    + /* Stop the Tx/Rx */
    + /* Do we need to do this ??? */
    + DP_REG32_WRITE (DP_CR, (DP_CR_TXD | DP_CR_RXD));
    +
    + /* Restore factory ethernet address */
    + dp83815_mac_address_set (iobase, priv->hw_mac_addr);
    +
    + /* Uninstall the interrupt vector */
    + free_irq (dev->irq, dev);
    +
    + /* Free the Tx and Rx queues */
    + dp83815_queue_delete (&priv->tx_queue);
    + dp83815_queue_delete (&priv->rx_queue);
    +
    + /* Decrement module reference count */
    + MOD_DEC_USE_COUNT;
    +
    + return OK;
    +}
    +
    +/*
    + * dp83815_start_xmit - transmit an ethernet packet.
    + *
    + * This routine writes to a tx descriptor, sets the ownership bit of the
    + * CMDSTS, and signals the chip
    + */
    +static int
    +dp83815_start_xmit (struct sk_buff *skb, struct device *dev)
    +{
    + u32 iobase = dev->base_addr;
    + u32 cmdsts;
    + virt_addr tx_desc;
    + struct enet_statistics *stats_p;
    +
    + if (skb->len > ETH_MAX_PKT_SIZE)
    + return ERROR;
    +
    + tx_desc = dp83815_tx_desc_get(dev);
    + if (tx_desc == NULL)
    + {
    + set_bit (0, &dev->tbusy);
    + DP_REG32_SET (DP_IMR, DP_IMR_TXOK | DP_IMR_TXIDLE);
    + tx_desc = dp83815_tx_desc_get (dev);
    + }
    +
    + stats_p = &((struct dp83815_priv *)(dev->priv))->stats;
    +
    + /* Update tx_desc to point to SKB data, set CMDSTS, and signal the chip */
    + if (tx_desc != NULL)
    + {
    + /* Reclaim SKBs from the TX queue */
    + if (DP_DESC_SKBPTR_GET (tx_desc))
    + dp83815_tx_skb_reclaim (dev, tx_desc);
    +
    + /* update statistics of the previous transmit */
    + cmdsts = DP_DESC_CMDSTS_XLATE_GET (tx_desc);
    + if (cmdsts & DP_DESC_CMDSTS_TX_ERRORS)
    + {
    + stats_p->tx_errors++;
    +
    + /* Update individual counters */
    +
    + stats_p->collisions += DP_DESC_CMDSTS_TX_COLLISIONS_GET(cmdsts);
    +
    + if (cmdsts & DP_DESC_CMDSTS_TX_TXA) /* tx aborted */
    + stats_p->tx_packets--;
    +
    + if (cmdsts & DP_DESC_CMDSTS_TX_TFU) /* fifo errors */
    + stats_p->tx_fifo_errors++;
    +
    + if (cmdsts & DP_DESC_CMDSTS_TX_CRS) /* lost carrier */
    + stats_p->tx_carrier_errors++;
    +
    + if (cmdsts & DP_DESC_CMDSTS_TX_OWC) /* out of window collisions */
    + stats_p->tx_window_errors++;
    + }
    +
    + /* Update the descriptor */
    +
    + DP_DESC_BUFPTR_XLATE_SET (tx_desc, skb->data);
    + DP_DESC_SKBPTR_SET (tx_desc, (u32)skb);
    + DP_DESC_CMDSTS_XLATE_SET (tx_desc, DP_DESC_CMDSTS_OWN|skb->len);
    +
    + dev->trans_start = jiffies;
    + DP_REG32_SET (DP_CR, DP_CR_TXE);
    + DP_DEBUG (DP_DEBUG_TX,
    + (KERN_INFO "Tx: tx_desc=0x%x ", (u32)tx_desc));
    + stats_p->tx_packets++;
    + } else
    + stats_p->tx_dropped++;
    +
    + return OK;
    +}
    +
    +/*
    + * dp83815_start_receive - receive the data from a Rx Queue descriptor
    + *
    + * This routine receives the data from Rx queue as long as it gets a valid
    + * rx_descriptor and resets the descriptor's CMDSTS field back to the Buffer
    + * size, and updates the BUFPTR and SKBPTR fields to the newly allocated SKB.
    + */
    +static int
    +dp83815_start_receive (struct device *dev)
    +{
    + u32 iobase = dev->base_addr;
    + u32 cmdsts;
    + int len;
    + bool do_copy;
    + virt_addr rx_desc;
    + struct sk_buff *cur_skb;
    + struct sk_buff *new_skb;
    + struct sk_buff *rx_skb;
    + struct enet_statistics *stats_p;
    +
    + stats_p = &((struct dp83815_priv *)(dev->priv))->stats;
    +
    + for (rx_desc = dp83815_rx_desc_get(dev); (rx_desc != NULL); rx_desc = dp83815_rx_desc_get(dev))
    + {
    + DP_DEBUG (DP_DEBUG_RX,
    + (KERN_INFO "Rx: rx_desc=0x%x, CMDSTS = 0x%x",
    + (u32)rx_desc, DP_DESC_CMDSTS_XLATE_GET(rx_desc)));
    +
    + cmdsts = DP_DESC_CMDSTS_XLATE_GET (rx_desc);
    +
    + /* Send the packet to the stack if no errors */
    + if ((cmdsts & DP_DESC_CMDSTS_RX_ERRORS) == 0)
    + {
    + len = (cmdsts & DP_DESC_CMDSTS_SIZE) - ETH_CRC_LEN;
    + if (len > 0)
    + {
    + /*
    + * Allocate a new SKB
    + * small data packets less than DP_RX_COPY_THRESHOLD are copied
    + * into the new SKB, other allocate one to replace the current SKB.
    + */
    + if (len < DP_RX_COPY_THRESHOLD)
    + {
    + do_copy = TRUE;
    + new_skb = alloc_skb (len + 2, GFP_ATOMIC);
    + } else {
    + do_copy = FALSE;
    + new_skb = alloc_skb (ETH_MAX_PKT_SIZE, GFP_ATOMIC);
    + }
    +
    + if (new_skb)
    + {
    + cur_skb = (struct sk_buff *) DP_DESC_SKBPTR_GET (rx_desc);
    +
    + if (do_copy)
    + {
    + /* Copy data from current SKB and send the new SKB up */
    + rx_skb = new_skb;
    + skb_reserve (rx_skb, 2);
    + memcpy (skb_put(rx_skb, len), cur_skb->data, len);
    + } else {
    + /* Replace the the current SKB with the new SKB */
    + rx_skb = cur_skb;
    + DP_DESC_BUFPTR_XLATE_SET (rx_desc, new_skb->data);
    + DP_DESC_SKBPTR_SET (rx_desc, (u32) new_skb);
    + (void) skb_put(rx_skb, len);
    + }
    +
    + /* update the SKB and set it up */
    + rx_skb->dev = dev;
    + rx_skb->protocol = eth_type_trans (rx_skb, dev);
    +
    + netif_rx (rx_skb);
    +
    + dev->last_rx = jiffies;
    + stats_p->rx_packets++;
    + } else
    + stats_p->rx_dropped++; /* no resources */
    + if (cmdsts & DP_DESC_CMDSTS_RX_DEST_MC)
    + stats_p->multicast++;
    + }
    + else /* code to deal with packets who's length is <= 0 */
    + /* this case should not happen but somehow, it happens */
    + {
    + stats_p->rx_errors++; /* bad packet */
    +
    + /* Update individual counters */
    + if (cmdsts & (DP_DESC_CMDSTS_RX_RUNT | DP_DESC_CMDSTS_RX_LONG))
    + stats_p->rx_length_errors++;
    +
    + if (cmdsts & DP_DESC_CMDSTS_RX_CRCE)
    + stats_p->rx_crc_errors++;
    +
    + if (cmdsts & DP_DESC_CMDSTS_RX_FAE)
    + stats_p->rx_frame_errors++;
    +
    + if (cmdsts & DP_DESC_CMDSTS_RX_RXO)
    + stats_p->rx_fifo_errors++;
    + }
    + }
    + else
    + {
    + stats_p->rx_errors++; /* bad packet */
    +
    + /* Update individual counters */
    + if (cmdsts & (DP_DESC_CMDSTS_RX_RUNT | DP_DESC_CMDSTS_RX_LONG))
    + stats_p->rx_length_errors++;
    +
    + if (cmdsts & DP_DESC_CMDSTS_RX_CRCE)
    + stats_p->rx_crc_errors++;
    +
    + if (cmdsts & DP_DESC_CMDSTS_RX_FAE)
    + stats_p->rx_frame_errors++;
    +
    + if (cmdsts & DP_DESC_CMDSTS_RX_RXO)
    + stats_p->rx_fifo_errors++;
    + }
    +
    + /* Cleanup the descriptor and make available for reception */
    + DP_DESC_CMDSTS_XLATE_SET (rx_desc, ETH_MAX_PKT_SIZE);
    + DP_REG32_SET (DP_CR, DP_CR_RXE);
    + }
    + return OK;
    +}
    +
    +/* dp83815_get_stats - get current device statistics */
    +static struct enet_statistics *
    +dp83815_get_stats (struct device *dev)
    +{
    + return &((struct dp83815_priv *)(dev->priv))->stats;
    +}
    +
    +/* dp83815_set_multicast_list - sets multicast, & promiscuous mode */
    +static void
    +dp83815_set_multicast_list (struct device *dev)
    +{
    + u32 iobase = dev->base_addr;
    + u16 hash_table[32];
    + u32 rfcr_flags;
    + int i;
    + struct dev_mc_list * mc_list;
    +
    + /* default RFCR mode */
    + rfcr_flags = DP_RFCR_APM | DP_RFCR_AAB | DP_RFCR_RFEN;
    +
    + /* Setup promiscuous mode */
    + if (dev->flags & IFF_PROMISC)
    + {
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "IFF_PROMISC\n"));
    + rfcr_flags = (DP_RFCR_AAU | DP_RFCR_AAM | DP_RFCR_AAB |
    + DP_RFCR_RFEN);
    + } else if (dev->flags & IFF_ALLMULTI)
    + {
    + /* Receive all multicast packets */
    + DP_DEBUG (DP_DEBUG_OPEN, (KERN_INFO "IFF_ALLMULTI\n"));
    + rfcr_flags |= DP_RFCR_AAM;
    + } else
    + {
    + /* Setup to receive programmed multicast packets */
    + memset (hash_table, 0, 32);
    + for (i=0, mc_list=dev->mc_list; mc_list && i < dev->mc_count; i++, mc_list = mc_list->next)
    + {
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "mc_addr=%p\n", mc_list->dmi_addr));
    + set_bit (dp83815_crc((char *)mc_list->dmi_addr) & 0x1ff, hash_table);
    + }
    +
    + /* install the hash table */
    + for (i=0; i<32; i++)
    + {
    + DP_REG32_WRITE (DP_RFCR, DP_RFCR_RFADDR_FMEM_LO + i*2);
    + DP_REG32_WRITE (DP_RFDR, (u32) hash_table[i]);
    + }
    +
    + rfcr_flags |= DP_RFCR_MHEN;
    + }
    +
    + DP_REG32_WRITE (DP_RFCR, 0);
    + DP_REG32_WRITE (DP_RFCR, rfcr_flags);
    + DP_DEBUG (DP_DEBUG_OPEN,
    + (KERN_INFO "MC Setup RFCR flags=0x%x\n", rfcr_flags));
    +
    + return;
    +}
    +
    +/* dp83815_crc - computer CRC for hash table entries */
    +static int
    +dp83815_crc (char * mc_addr)
    +{
    + u32 crc;
    + u8 cur_byte;
    + u8 msb;
    + u8 byte, bit;
    +
    + crc = ~0;
    + for (byte=0; byte<6; byte++)
    + {
    + cur_byte = *mc_addr++;
    + for (bit=0; bit<8; bit++)
    + {
    + msb = crc >> 31;
    + crc <<= 1;
    + if (msb ^ (cur_byte & 1))
    + {
    + crc ^= DP_POLYNOMIAL;
    + crc |= 1;
    + }
    + cur_byte >>= 1;
    + }
    + }
    + crc >>= 23;
    +
    + return (crc);
    +}
    +
    +/* dp83815_ioctl - handle driver specific ioctls */
    +static int
    +dp83815_ioctl (struct device *dev, struct ifreq *rq, int cmd)
    +{
    + return -EOPNOTSUPP;
    +}
    +
    +/* dp83815_interrupt - handle the interrupts */
    +static void
    +dp83815_interrupt (int irq, void *dev_id, struct pt_regs *regs)
    +{
    + struct device * dev = dev_id;
    + u16 iobase = dev->base_addr;
    + u32 reg_isr;
    +
    + reg_isr = DP_REG32_READ (DP_ISR);
    +
    + DP_DEBUG (DP_DEBUG_IOCTL,
    + (KERN_INFO "%s: intr_status=0x%x\n", dev->name,
    + reg_isr));
    +
    + if (reg_isr & DP_ISR_RXOK)
    + dp83815_start_receive (dev);
    +
    + /* The only place where these bits should be tested for is if
    + * we turned them on ourselves (out of buffers)
    + */
    + //if (reg_isr & (DP_ISR_TXOK | DP_ISR_TXIDLE))
    + if (test_bit(0, &dev->tbusy) && (reg_isr & (DP_ISR_TXOK | DP_ISR_TXIDLE)))
    + {
    + DP_REG32_CLR (DP_IMR, (DP_IMR_TXOK|DP_IMR_TXIDLE));
    + printk("dp83815_interrupt: making transmitter non-idle\n");
    + clear_bit (0, &dev->tbusy);
    + mark_bh (NET_BH);
    + }
    +}
    +
    +/* dp83815_mac_address_set - set the ethernet address */
    +static void
    +dp83815_mac_address_set (u32 iobase, char *mac_addr)
    +{
    + u16 * mac_addr_ptr;
    + int i;
    +
    + for (i=0, mac_addr_ptr = (u16 *)mac_addr; i<3; i++, mac_addr_ptr++)
    + {
    + DP_REG32_WRITE (DP_RFCR, DP_RFCR_RFADDR_PMATCH1 + i*2);
    + DP_REG32_WRITE (DP_RFDR, CPU_TO_BUS_SWAP_16 (*mac_addr_ptr));
    + }
    +}
    +
    +/* dp83815_pci_init - reset the device search from the first device
    + */
    +static void
    +dp83815_pci_init ()
    +{
    +#ifdef DP_PCIBIOS_FIND_DEVICE
    + dp_dev_cur = 0; /* current pci device count */
    +#endif
    +#ifdef DP_PCI_FIND_DEVICE
    + dp_pci_dev = NULL;
    +#endif
    +}
    +
    +/* dp83815_pci_find_device - call the kernel-version appropriate routine to
    + find the pci devices
    +*/
    +static int
    +dp83815_pci_find_device (u16 pci_vendor_id, u16 pci_board_id,
    + u8 *pbus, u8 *pfunc)
    +{
    +#ifdef DP_PCIBIOS_FIND_DEVICE
    + if (pcibios_find_device (pci_vendor_id, pci_board_id, dp_dev_cur,
    + pbus, pfunc) == PCIBIOS_SUCCESSFUL)
    + {
    + dp_dev_cur++;
    + return TRUE;
    + } else
    + return FALSE;
    +#endif
    +#ifdef DP_PCI_FIND_DEVICE
    + dp_pci_dev = pci_find_device (pci_vendor_id, pci_board_id, dp_pci_dev);
    + if (dp_pci_dev)
    + {
    + *pbus = dp_pci_dev->bus->number;
    + *pfunc = dp_pci_dev->devfn;
    + return TRUE;
    + } else
    + return FALSE;
    +#endif
    +}
    +
    +/* dp83815_mac_address_get - get the ethernet address */
    +static void
    +dp83815_mac_address_get (u32 iobase, char *mac_addr)
    +{
    + u16 * mac_addr_ptr;
    + int i;
    +
    + for (i=0, mac_addr_ptr = (u16*)mac_addr; i<3; i++, mac_addr_ptr++)
    + {
    + DP_REG32_WRITE (DP_RFCR, DP_RFCR_RFADDR_PMATCH1 + i*2);
    + *mac_addr_ptr = BUS_TO_CPU_SWAP_16 (DP_REG32_READ (DP_RFDR));
    + }
    +}
    +
    +/* dp83815_dev_reset - soft reset DP83815 */
    +static status
    +dp83815_dev_reset (u32 iobase)
    +{
    + int timeout = 2000;
    + DP_REG32_WRITE (DP_CR, DP_CR_RST);
    + while ((timeout -= 5) > 0)
    + {
    + if ((DP_REG32_READ (DP_CR) & DP_CR_RST) == 0)
    + { /* Wait until bit clears */
    + DP_REG32_WRITE (DP_PTSCR, 0x04); /* Restore registers from EEROM */
    + udelay (2000);
    + /* Software reset of the controller has been successful. Reset the
    + * internal PHY Registers as well
    + */
    + DP_REG32_WRITE (DP_BMCR, DP_BMCR_RESET);
    +
    + /* Wait awhile and check to see if it has cleared */
    + udelay (2000);
    + if ((DP_REG32_READ (DP_BMCR) & DP_BMCR_RESET) == DP_BMCR_RESET)
    + { /* Bad */
    + return ERROR;
    + }
    + return (OK);
    + }
    + udelay (5);
    + }
    + return ERROR;
    +}
    +
    +/*
    + * dp83815_queue_create - create a circular queue of descriptors
    + *
    + * This routine allocates a descriptor buffer array aligned on a word
    + * boundary, initializes and links the array to make a circular queue.
    + */
    +static status
    +dp83815_queue_create (struct dp83815_queue *q, int count, int qtype)
    +{
    + virt_addr desc_addr;
    + int i;
    + struct sk_buff *skb;
    +
    + /* allocate the desc buffer array */
    + q->qbuf = (virt_addr) kmalloc (DP_QUEUE_ELE_SIZE * count + DP_ALIGN, GFP_DMA);
    + if (q->qbuf == (virt_addr) NULL)
    + return ERROR;
    +
    + memset ((char *)q->qbuf, 0, DP_QUEUE_ELE_SIZE * count + DP_ALIGN);
    +
    + /* Adjust alignment and Initialize queue data */
    + q->cur_desc_addr =
    + q->first_desc_addr =
    + (virt_addr)(((u32)q->qbuf + DP_ALIGN) & ~(DP_ALIGN - 1));
    + q->last_desc_addr = q->first_desc_addr + ((count -1) * DP_QUEUE_ELE_SIZE);
    + q->count = count;
    +
    + /* Initialize each buffer descriptor, and link them into circular queue */
    + for (i=0, desc_addr=q->first_desc_addr; i<count;
    + i++, desc_addr+=DP_QUEUE_ELE_SIZE)
    + {
    + DP_DESC_LNK_XLATE_SET (desc_addr, desc_addr + DP_QUEUE_ELE_SIZE);
    +
    + /* Update the size, BUFPTR, and SKBPTR fields for RX descriptors */
    + if (qtype == DP_QUEUE_TYPE_RX)
    + {
    + skb = alloc_skb (ETH_MAX_PKT_SIZE, GFP_ATOMIC);
    + if (skb == NULL)
    + {
    + dp83815_queue_delete (q);
    + return (ERROR);
    + }
    + DP_DESC_CMDSTS_XLATE_SET (desc_addr, ETH_MAX_PKT_SIZE);
    + DP_DESC_BUFPTR_XLATE_SET (desc_addr, skb->data);
    + DP_DESC_SKBPTR_SET (desc_addr, (u32) skb);
    + }
    + }
    + /* Make the queue circular */
    + DP_DESC_LNK_XLATE_SET (q->last_desc_addr, q->first_desc_addr);
    +
    + return OK;
    +}
    +
    +/* dp83815_queue_delete - frees an allocated descriptor queue */
    +static status
    +dp83815_queue_delete (struct dp83815_queue *q)
    +{
    + int i;
    + virt_addr desc_addr;
    + struct sk_buff *skb;
    +
    + /* Free all SKBs in the queue */
    + for (i=0, desc_addr=q->first_desc_addr;
    + (i < q->count);
    + i++, desc_addr += DP_QUEUE_ELE_SIZE)
    + {
    + skb = (struct sk_buff *) DP_DESC_SKBPTR_GET (desc_addr);
    + if (skb != NULL)
    + DP_KFREE_SKB (skb);
    + }
    +
    + /* Free the queue buffer */
    + kfree ((char *)q->qbuf);
    +
    + return (OK);
    +}
    +
    +/*
    + * dp83815_tx_desc_get - get a valid transmit descriptor
    + *
    + * This routine returns the current descriptor from the tx_queue if driver is
    + * the owner, else returns NULL
    + */
    +static virt_addr
    +dp83815_tx_desc_get (struct device *dev)
    +{
    + struct dp83815_queue * q;
    + virt_addr desc_addr = NULL;
    +
    + q = &((struct dp83815_priv *)(dev->priv))->tx_queue;
    +
    + /* Check if we own the descriptor */
    + if ((DP_DESC_CMDSTS_XLATE_GET (q->cur_desc_addr) & DP_DESC_CMDSTS_OWN) == 0)
    + {
    + desc_addr = q->cur_desc_addr;
    + DP_QUEUE_ELE_NEXT (q); /* Move to the next element */
    + }
    +
    + return desc_addr;
    +}
    +
    +/* dp83815_tx_skb_reclaim - reclaim SKBs in transmitted descriptors */
    +static void
    +dp83815_tx_skb_reclaim (struct device *dev, virt_addr desc_addr)
    +{
    + struct sk_buff * skb;
    + struct dp83815_queue * q;
    +
    + /* Reclaim buffers from all descriptors we own. */
    + q = &((struct dp83815_priv *)(dev->priv))->tx_queue;
    + while (((DP_DESC_CMDSTS_XLATE_GET(desc_addr) & DP_DESC_CMDSTS_OWN) == 0) &&
    + ((skb=(struct sk_buff *) DP_DESC_SKBPTR_GET(desc_addr)) != NULL))
    + {
    + DP_KFREE_SKB (skb);
    + DP_DESC_SKBPTR_SET (desc_addr, 0);
    + desc_addr = DP_QUEUE_ELE_NEXT_GET (q, desc_addr);
    + }
    +}
    +
    +/*
    + * dp83815_rx_desc_get - get a valid receive descriptor
    + *
    + * This routine returns the current descriptor from the rx_queue if driver is
    + * the owner, else returns NULL
    + */
    +static virt_addr
    +dp83815_rx_desc_get (struct device *dev)
    +{
    + struct dp83815_queue * q;
    + virt_addr desc_addr = NULL;
    +
    + q = &((struct dp83815_priv *)(dev->priv))->rx_queue;
    +
    + /* Check if we own the descriptor */
    + if (DP_DESC_CMDSTS_XLATE_GET (q->cur_desc_addr) & DP_DESC_CMDSTS_OWN)
    + {
    + desc_addr = q->cur_desc_addr;
    + DP_QUEUE_ELE_NEXT(q); /* Move to the next element */
    + }
    +
    + return desc_addr;
    +}
    +
    +/* dp83815_phy_setup - reset and setup the PHY device */
    +static status
    +dp83815_phy_setup (struct device *dev)
    +{
    + u32 iobase = dev->base_addr;
    + u32 dp_cfg_val;
    + u16 phy_status;
    + u16 timeout;
    +
    + dp_cfg_val = (DP_CFG_PESEL | /* parity error detect */
    + DP_CFG_ANEG_SEL_ALL_XD | /* negotiate 10/100 full/half */
    + DP_CFG_PAUSE_ADV | /* pause capable */
    + DP_CFG_PINT_ACEN | /* phy intr auto clear */
    + 0x00040000); /* phy config */
    +
    + DP_REG32_WRITE (DP_CFG, dp_cfg_val | DP_CFG_PHY_RST);
    + udelay (500);
    +
    + DP_REG32_WRITE (DP_CFG, dp_cfg_val);
    + for (timeout=10000; timeout; timeout--)
    + {
    + if (DP_REG32_READ (DP_CFG) & DP_CFG_ANEG_DN)
    + break;
    + udelay (500);
    + }
    +
    + if (timeout == 0)
    + {
    + DP_DEBUG (DP_DEBUG_ANEG, (KERN_INFO "Phy Autonegotiate Failed\n"));
    + return (ERROR);
    + }
    + DP_REG32_WRITE (DP_PHY_PAGE, DP_PHY_PAGE_VAL);
    + DP_REG32_WRITE (DP_PHYCR, DP_PHYCR_PMDCSR_VAL);
    + DP_REG32_WRITE (DP_PHY_TDATA, DP_PHY_TDATA_VAL);
    + DP_REG32_WRITE (DP_PHY_DSPCFG, DP_PHY_DSPCFG_VAL);
    + DP_REG32_WRITE (DP_PHY_SDCFG, DP_PHY_SDCFG_VAL);
    + DP_REG32_WRITE (DP_PHY_PAGE, (u16) 0x0000);
    +
    + phy_status = DP_REG16_READ (DP_PHYSTS);
    +
    + /* Flag is set for full duplex mode, else cleared */
    +
    + if (phy_status & DP_PHYSTS_FDX)
    + dp_full_duplex = TRUE;
    + else
    + dp_full_duplex = FALSE;
    +
    + printk (KERN_INFO "%s: speed=%d duplex=%s link=%s\n",
    + dev->name,
    + (phy_status & DP_PHYSTS_SPEED_10) ? 10 : 100,
    + (phy_status & DP_PHYSTS_FDX)? "full" : "half",
    + (phy_status & DP_PHYSTS_LNK_VALID) ? "up" : "down");
    +
    + return (OK);
    +}
    +
    +#if 1
    +/* swap_16 - swap a 16 bit value between little endian & big endian byteorder */
    +static u16 swap_16 (u16 us)
    +{
    + return ((us << 8) & 0xff00) | ((us >> 8) & 0x00ff);
    +}
    +#endif
    +
    +#if 0 /* Not used */
    +/* swap_32 - swap a 32 bit value between little endian & big endian byteorder */
    +static u32 swap_32 (u32 ui)
    +{
    + return ((swap_16 (ui & 0x0000ffff) << 16) | swap_16 (ui >> 16));
    +}
    +#endif
    +
    +/* io_read_16 - read the 16 bit value stored at given io address */
    +static u16 io_read_16 (u16 io_port)
    +{
    + return DP_INW (io_port);
    +}
    +
    +#if 0 /* Not used */
    +/* io_write_16 - write the 16 bit data at given io address */
    +static void io_write_16 (u16 io_port, u16 data)
    +{
    + DP_OUTW (data, io_port);
    +}
    +#endif
    +
    +/* io_read_32 - read the 32 bit value stored at given io address*/
    +static u32 io_read_32 (u16 io_port)
    +{
    + return DP_INL (io_port);
    +}
    +
    +/* io_write_32 - write the 32 bit data at given io address */
    +static void io_write_32 (u16 io_port, u32 data)
    +{
    + DP_OUTL (data, io_port);
    +}
    +
    +#if (DRV_DEBUG > 0)
    +/* dp83815_desc_info - print info on descriptors
    + *
    + * This routine displays values of the elements of dp83815_queue;
    + * if option is -1, prints info on all the descs and their field vals;
    + * and in all other cases prints info on the specified descriptor.
    + */
    +
    +static void dp83815_desc_info (struct dp83815_queue * q, int option)
    +{
    + virt_addr desc_addr;
    + u32 i;
    +
    + /* Display info header */
    + printk ( KERN_DEBUG "dp83815_desc_info(): q=0x%x, "
    + "first_desc_addr=0x%x, last_desc_addr=0x%x cur_desc_addr=0x%x\n",
    + (u32)q, (u32)q->first_desc_addr,
    + (u32)q->last_desc_addr, (u32)q->cur_desc_addr);
    +
    + /* Print requested element info */
    + switch (option)
    + {
    + case -1: /* all elements */
    + desc_addr = q->first_desc_addr;
    + for (i=0; i<q->count; i++)
    + {
    + printk (KERN_DEBUG "desc_addr=0x%x link=0x%x "
    + "cmdsts=0x%x bufptr=0x%x\n",
    + (u32)desc_addr, DP_DESC_LNK_GET (desc_addr),
    + DP_DESC_CMDSTS_GET (desc_addr),
    + DP_DESC_BUFPTR_GET (desc_addr));
    + desc_addr += DP_QUEUE_ELE_SIZE;
    + }
    + break;
    +
    + default: /* a specific element */
    + if (option > q->count)
    + {
    + printk (KERN_DEBUG "Can't print info for ele=%d when count=%d\n",
    + option, q->count);
    + } else
    + {
    + desc_addr = q->first_desc_addr + (DP_QUEUE_ELE_SIZE * (option - 1));
    + printk (KERN_DEBUG "ele=%d desc_addr=0x%x link=0x%x "
    + "cmdsts=0x%x bufptr=0x%x\n",
    + option, (u32)desc_addr, DP_DESC_LNK_GET (desc_addr),
    + DP_DESC_CMDSTS_GET (desc_addr),
    + DP_DESC_BUFPTR_GET (desc_addr));
    + }
    + }
    +}
    +
    +
    +/* dp83815_regs_info - prints values of registers */
    +static void dp83815_regs_info (u16 iobase)
    +{
    + printk (KERN_INFO "dp(0x%x): CFG=0x%x IMR=0x%x IER=0x%x\n",
    + iobase, DP_REG32_READ (DP_CFG), DP_REG32_READ (DP_IMR),
    + DP_REG32_READ (DP_IER));
    + printk (KERN_INFO " ++ TXDP=0x%x TXCFG=0x%x RXDP=0x%x RXCFG=0x%x\n",
    + DP_REG32_READ (DP_TXDP), DP_REG32_READ (DP_TXCFG),
    + DP_REG32_READ (DP_RXDP), DP_REG32_READ (DP_RXCFG));
    +}
    +#endif /* (DRV_DEBUG > 0) */
    +
    +#ifdef MODULE
    +
    +/*
    + * init_module - Initialize the driver module
    + *
    + * This routine is called to initialize the driver when the module is
    + * installed into a running kernel via insmod.
    + *
    + */
    +
    +int
    +init_module (void)
    +{
    + printk (KERN_INFO "%s", version);
    + return dp83815_probe (NULL);
    +}
    +
    +/*
    + * cleanup_module - Deinstall the driver module.
    + *
    + * This routine is called when removing the driver module from a running
    + * kernel via rmmod.
    + *
    + */
    +
    +void
    +cleanup_module (void)
    +{
    + struct device *cur_dev;
    +
    + cur_dev=dp83815_dev_list;
    + while (cur_dev)
    + {
    + dp83815_dev_list = ((struct dp83815_priv *)(cur_dev->priv))->next;
    + unregister_netdev (cur_dev);
    + release_region (cur_dev->base_addr, DP83815_PCI_IO_SIZE);
    + kfree (cur_dev);
    + cur_dev = dp83815_dev_list;
    + }
    +}
    +#endif /* MODULE */
    +
    +
    +/*
    + * Local variables:
    + * version-control: t
    + * kept-new-versions: 5
    + * End:
    + */

    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.rutgers.edu
    Please read the FAQ at http://www.tux.org/lkml/



    This archive was generated by hypermail 2b29 : Thu Jul 27 2000 - 20:05:41 EDT