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 : Mon Jul 31 2000 - 21:00:25 EST