This message generated a parse failure. Raw output follows here. Please use 'back' to navigate. From devnull@lkml.org Thu Apr 25 15:47:49 2024 Received: from nic.funet.fi (nic.funet.fi [193.166.0.145]) by herbie.ucs.indiana.edu (8.10.1/8.10.1) with ESMTP id e6S07el07582 for ; Thu, 27 Jul 2000 19:07:40 -0500 (EST) Received: from vger.rutgers.edu ([128.6.190.2]:17053 "EHLO vger.rutgers.edu" ident: "NO-IDENT-SERVICE[2]" smtp-auth: TLS-CIPHER: ) by nic.funet.fi with ESMTP id ; Fri, 28 Jul 2000 03:06:33 +0300 Received: (majordomo@vger.rutgers.edu) by vger.rutgers.edu via listexpand id ; Thu, 27 Jul 2000 19:42:46 -0400 Received: by vger.rutgers.edu id ; Thu, 27 Jul 2000 19:41:52 -0400 Received: from [209.249.10.20] ([209.249.10.20]:2894 "EHLO freya.yggdrasil.com") by vger.rutgers.edu with ESMTP id ; Thu, 27 Jul 2000 19:41:26 -0400 Received: from adam.yggdrasil.com (adam.yggdrasil.com [209.249.10.6]) by freya.yggdrasil.com (8.9.3/8.9.0) with ESMTP id RAA02794; Thu, 27 Jul 2000 17:07:49 -0700 From: "Adam J. Richter" Received: (from adam@localhost) by adam.yggdrasil.com (8.9.3/8.9.3) id QAA09134; Thu, 27 Jul 2000 16:56:37 -0700 Date: Thu, 27 Jul 2000 16:56:37 -0700 Message-Id: <200007272356.QAA09134@adam.yggdrasil.com> To: linux-kernel@vger.rutgers.edu Subject: Sort of patch: Ethernet driver for National Semiconductor DP83815 for linux-2.2.16 Sender: owner-linux-kernel@vger.rutgers.edu Precedence: bulk X-Loop: majordomo@vger.rutgers.edu 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 +#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 +#include +#include + +#include +#include +#include /* IO stuff */ +#include +#include + +/* Ethernet Driver Specific Headers */ + +#include +#include +#include +#include +#include + +#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 /* 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; ipriv == 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; idata); + 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; icount; 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/